APLpy-2.0.3/0000755000077000000240000000000013432765724012434 5ustar tomstaff00000000000000APLpy-2.0.3/CHANGES.rst0000644000077000000240000003716113432765635014247 0ustar tomstaff00000000000000CHANGES -------- 2.0.3 (2019-02-19) ------------------ - Fix 'arcsinh' stretch and fix definition of vmid to match that in 1.x. [#421] 2.0.2 (2019-02-18) ------------------ - Fixed ``set_nan_color``. [#419] 2.0.1 (2019-02-18) ------------------ - Remove unused arguments in ``make_rgb_cube`` and fix behavior of ``north=False``. [#417] - Fixed bug in image extent for non-square RGB images. [#417] 2.0 (2019-02-17) ---------------- - Refactored APLpy to make use of WCSAxes to draw coordinate frames and astropy.visualization to deal with image stretching. [#239, #364, #365] - Use reproject package instead of montage-wrapper and Montage. [#360] 1.1.1 (2016-10-04) ------------------ - Added missing LICENSE and README to tarball. - Fix undefined ``HDUList``. [#317] 1.1 (2016-09-23) ---------------- - Fixed compatibility of Scalebar.set with Matplotlib 1.5.x. [#272, #286] - Fixed compatibility with Python 3.5. - Astropy is now a required dependency, and PyFITS and PyWCS are no longer supported. 1.0 (2015-02-18) ---------------- New features ~~~~~~~~~~~~ - Added new ``show_vectors`` to show vector maps. [#220] Improvements ~~~~~~~~~~~~ - The ``auto_refresh`` option now defaults to ``False`` unless IPython is being used and the Matplotlib backend is interactive. [#238] Bug fixes ~~~~~~~~~ - Fix a bug that caused RGB images to be incorrectly displayed when zooming in. [#235] 0.9.14 (2014-11-05) ------------------- Bug fixes ~~~~~~~~~ - Fix a bug that caused smoothing to fail with integer arrays. [#165] Improvements ~~~~~~~~~~~~ - Fix deprecation warnings from Astropy. [#173] 0.9.13 (2014-10-04) ------------------- New features ~~~~~~~~~~~~ - Added ``FITSFigure.set_title`` method that can be used to set the title of a figure. [#175] Improvements ~~~~~~~~~~~~ - Beams and scalebars can now optionally be instantiated with Astropy angular units and quantities. [#186] - APLpy now includes image tests to ensure reliability over time. [#200] - The code is now all Python 2 and 3 compatible without requiring 2to3. [#198] Bug fixes ~~~~~~~~~ - Fix bug that caused a crash when plotting an image with a single valid pixel [#197] - Fixed a severe bug that caused rotated images to have incorrect pixel scales determined. [#211] - Fixed a bug that caused set_nan_color to modify Matplotlib colormaps globally rather than apply just to the desired FITSFigure. [#214] 0.9.12 (2014-07-17) ------------------- This version fixes compatibility with Astropy 0.4 New features ~~~~~~~~~~~~ - Added the ability to call ``fig.show_contour()`` without arguments and used the data used to initialize ``FITSFigure``. [#170] - Added the ability to format colorbar ticks in exponential notation using the ``log_format`` argument. [#143] - Added the ability to make NaNs transparent in RGB image output, using the ``make_nans_transparent`` argument. [#138] API Changes ~~~~~~~~~~~ - astropy.wcs.WCS no longer contains information about the original image size. Any attempt to instantiate a FITSFigure from a WCS object will raise a DeprecationException. A workaround is to add `naxisn` attributes to your WCS object:: mywcs = wcs.WCS(header) mywcs.naxis1 = header['NAXIS1'] mywcs.naxis2 = header['NAXIS2'] Bug fixes ~~~~~~~~~ - FITSFigure can now be instantiated using an astropy.io.fits.CompImageHDU object. [#188] - The coordinate grid is now plotted on the whole axes, not just the subset containing the image (noticeable when zooming out). [#118] 0.9.11 (2013-11-29) ------------------- Bug fixes ~~~~~~~~~ - Fix a bug that meant that pixel scales were incorrectly extracted for some WCS settings. [#156] 0.9.10 (2013-11-25) ------------------- This version restores compatibility with Astropy 0.3 New Features ~~~~~~~~~~~~ - `FITSFigure.recenter` can now be used with sliced data cubes. [#122] Bug fixes ~~~~~~~~~ - Fixed issues related to bugs in matplotlib in `match_original` when using patch collections. [#124] - Fixed a bug that made images containing NaN or Inf values crash APLpy. [#113] - Fixed a bug that meant that world2pix and pix2world could not take Astropy table columns. [#114] 0.9.9 (2013-04-25) ------------------ The main change in this version is that APLpy is now an Astropy-affiliated package. This means that the Astropy core package is now required, but PyFITS and PyWCS are no longer required as dependencies. This release is now no longer compatible with python-montage, and users should use the montage-wrapper package instead: http://www.astropy.org/montage-wrapper/ Similarly, PyAVM 0.9.1 or later is now required, and APLpy cannot use earlier versions: http://astrofrog.github.io/pyavm/ This release is also the first release fully compatible with Python 3. New features ~~~~~~~~~~~~ - file-like objects can now be passed to ``FITSFigure.save()`` - the subplot= argument to ``FITSFigure`` can now take the tuple syntax ``(2, 2, 1)`` instead of the full axes box, e.g. ``[0.1, 0.1, 0.9, 0.9]`` (thanks to Anika Schmiedeke for a patch). - a colorbar label can now be set (thanks to Daniel Goering for a patch). API changes ~~~~~~~~~~~ - the ``smooth`` argument used for images and contours can no longer take a tuple. It takes either a single value for symmetric kernels (``gauss`` and ``box``), or it can take a Numpy array for any other kernel shape. Bug fixes ~~~~~~~~~ - fixed bug that caused regions read from a ds9 region file to be offset by one pixel. - fixed bug that caused an exception when adding a Beam - fixed bug that caused labels in decimal degrees to disappear for images near the poles. - fixed a bug that caused RGB images to appear vertically flipped with certain versions of Matplotlib. - added a workaround for a bug in Matplotlib that caused patches to appear filled even with ``facecolor='none'``. - fixed bug that caused images with NaN or Inf values to not be smoothed correctly. Version 0.9.8 This version fixes issues that occurred when using APLpy with PyFITS 3.0.5. This version also contains the first unit/regression tests (which we will include many more of in future). New features ~~~~~~~~~~~~ - APLpy now includes regression tests that can be run with: python setup.py test - FITSFigure can now be initialized with files or HDUs with missing WCS information. - FITSFigure can now be initialized directly with Numpy arrays - Added methods to show/hide ticks Bug fixes ~~~~~~~~~ - Fixed a major bug that prevented data cube slicing with PyFITS 3.0.5 - Fixed a few bugs that occurred when plotting a grid for a few specific projections. - Fixed a bug that cause the error: 'Figure' object has no attribute '_auto_refresh' Version 0.9.7 This version sees the re-write of the WCS support to enable plotting of FITS files with arbitrary coordinates rather than just sky coordinates, and to allow slicing of multi-dimensional data cubes. It is now very easy for example to make position-velocity plots from a 3D FITS cube. See http://aplpy.github.com/documentation/slicing.html for details. New features ~~~~~~~~~~~~ - added the ability to plot arbitrary coordinate systems rather than just sky coordinates. - added the ability to slice multi-dimensional data cubes. - added minor ticks. - pressing 'c' toggles between showing world and pixel coordinates in the bottom of the interactive window. - added the ability to specify slice indices for 3D FITS cubes in make_rgb_image. - allow pyregion.ShapeList instance to be passed to show_regions. - the 'logging' module is now used for any stdout output. - added an overlap= argument to show_contour to force only contours with at least one point in the image to be shown. This can result in significantly improved performance, and smaller files, when large FITS files are used to display contours. Changes ~~~~~~~ - the default frame color for the 'pretty' theme (the default) is now black Version 0.9.6 APLpy is now released under an MIT license New Features ~~~~~~~~~~~~ - support for plotting AVM-tagged images (requires PyAVM) - make_rgb_image can now optionally embed AVM Spatial.* meta-data into images (off by default, requires PyAVM) - added support for multiple beams - added method to show arrows - added method to show lines (thanks to Moritz Guenther) - added close() method to FITSFigure to free up memory (useful when making many finder charts for example) - added B1950 <-> J2000 conversion - added axis_labels.set_x/yposition and tick_labels.set_x/yposition to control whether labels are on top/bottom or left/right of the axes. - now uses python-montage wrapper for reprojection - added support for passing a WCS object to FITSFigure instead of a file - allow a custom box to be specified for the colorbar API changes ~~~~~~~~~~~ - vmid has changed meaning for log image scaling. It is now the baseline value to subtract from pixel values before taking the log (defaults to zero) - added interpolation= option to show_grayscale and show_colorscale - added support for zorder= in methods to show shapes (controls which layers appear on top of which) - added north=, system=, and equinox= to make_rgb_cube for more control over the final projection Bug fixes ~~~~~~~~~ - added a few workaround for matplotlib bugs - fixed a major bug with downsampling - fixed bug with import of local modules - other minor bug fixes Version 0.9.5 New Features ~~~~~~~~~~~~ - Support for image and contour smoothing - Support for slicing of n-dimensional datacubes - Support for beam: -> add_beam() -> remove_beam() - Support for colorbar: -> add_colorbar() -> remove_colorbar() - Support for scalebar: -> add_scalebar() -> remove_scalebar() - Support for plotting ds9 region files: -> show_regions() - Support for automatic bounding box adjustments when saving - New method to set the color to use for NaN values: -> set_nan_color() - Auto refreshing has been improved. Figures only refresh once per user command if refreshing is turned on. - Ensure tick spacing / label format consistency - New method to overlay polygons API changes ~~~~~~~~~~~ - The API has been majorly overhauled. Methods that have been deprecated will give instructions on the new methods to use. Bug fixes ~~~~~~~~~ - Fixed a bug with filled contours - Fixed bug with remove_layer - Fixed bug with montage commands Version 0.9.4 Important changes ~~~~~~~~~~~~~~~~~ Matplotlib 0.99 is now required for APLpy New Features ~~~~~~~~~~~~ - methods such as show_contour, show_markers, etc. now return the contour, marker, etc. object - added a method to retrieve the object in a specific layer: -> get_layer() - ability to show the beam for the observations: -> show_beam() -> hide_beam() -> set_beam_properties() - added the ability to show/hide only the x or y axis/tick labels: -> show_xtick_labels() -> hide_xtick_labels() -> show_ytick_labels() -> hide_ytick_labels() -> show_xaxis_labels() -> hide_xaxis_labels() -> show_yaxis_labels() -> hide_yaxis_labels() - convenience functions for world to pixel and pixel to world conversion: -> world2pixel() -> pixel2world() - added a convention= argument to FITSFigure() and show_contour(). This is to be used in cases where the WCS interpretation is ambiguous. For example, a -CAR projection with CRVAL2<>0 can be interpreted in two different ways. If an ambiguous case pops up, APLpy will raise an exception and ask for the convention to be specified. API changes ~~~~~~~~~~~ - set_labels_latex() is now set_system_latex() Bug fixes ~~~~~~~~~ - the current position of the cursor in world coordinates is now correctly shown in interactive mode - fixed an issue which caused RGB FITS cubes to be 64-bit - fixed a bug which meant that the coordinate grid was not updated immediately during pan and zoom Version 0.9.3 New Features ~~~~~~~~~~~~ - added aplpy.make_rgb_cube() that allows users to make a FITS RGB cube from three FITS files with different projections - added aplpy.make_rgb_image() that allows users to make an RGB file in standard image formats from a FITS RGB cube - added width= and height= arguments to aplpy.FITSFigure.recenter() method. - added show_circles(), show_ellipses(), and show_rectangles() to aplpy.FITSFigure - new hide_grayscale() and hide_colorscale() methods API changes ~~~~~~~~~~~ - changes to the API for set_tick_labels_* and set_axis_labels_* methods - percentiles values are now specified between 0 and 100 Bug fixes ~~~~~~~~~ - fixed an issue which ocurred when reading in FITS cubes - fixed an issue which led to the last tick along an axis being missing for coarse images - fixed a bug that occured if set_theme was called before showing the image - fixed a bug that occured when show_contour was called after removing a layer Acknowledgments ~~~~~~~~~~~~~~~ Thanks to Paul Ray, Adam Ginsburg, Gus Muench, and forum user hatchell for bug reports and feature suggestions. Version 0.9.2 Improvements ~~~~~~~~~~~~ - Improved compatibility issues with matplotlib 0.98.6svn - Improved speed of initialization of FITSFigure Version 0.9.1.2 Bug fixes ~~~~~~~~~ - fixed a major bug that occured when reading in Galactic -CAR images Version 0.9.1 SciPy Dependency Dropped ~~~~~~~~~~~~~~~~~~~~~~~~ While SciPy is a great python package, it can be troublesome to build and install from scratch. Thanks to Tom Aldcroft's suggestion and highlighting some of his own code we were able to easily drop the SciPy dependency. New Features ~~~~~~~~~~~~ - Users can now pass a pyfits HDU instance instead of filenames for both FITSFigure() and show_contour() if desired. - Users can now specify an existing figure with the figure= argument. - Users with a recent enough version of matplotlib (0.98.6svn) can now use the subplot= argument to place multiple plots in a single figure. - New hide/show_tick_labels() and hide/show_axis_labels() methods. - Show_grayscale and show_colorscale() now accept percentile_lower= and percentile_higher= as arguments. - Show_grayscale and show_colorscale() now print out vmin and vmax if chosen automatically. - New recenter() method to pan and zoom non-interactively. General Fixes and Optimization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Added HDU keyword for the show_contour() method. - More robust reading in FITS file for the show_contour() method. - Warning if FITS files do not exist for FITSFigure() or show_contour(). Version 0.9.0 First public beta release APLpy-2.0.3/CITATION0000644000077000000240000000246213432763221013563 0ustar tomstaff00000000000000If you use APLpy for a publication, you can use the following acknowledgment: This research made use of APLpy, an open-source plotting package for Python (Robitaille and Bressert, 2012; Robitaille, 2019) where (Robitaille and Bressert, 2012) is a citation to this ADS/ASCL entry: http://adsabs.harvard.edu/abs/2012ascl.soft08017R and (Robitaille, 2019) is a citation to the following Zenodo entry: https://zenodo.org/record/2567476#.XGmAA5P7RZo The BibTex entries are: @misc{aplpy2012, author = {{Robitaille}, T. and {Bressert}, E.}, title = "{APLpy: Astronomical Plotting Library in Python}", keywords = {Software }, howpublished = {Astrophysics Source Code Library}, year = 2012, month = aug, archivePrefix = "ascl", eprint = {1208.017}, adsurl = {http://adsabs.harvard.edu/abs/2012ascl.soft08017R}, adsnote = {Provided by the SAO/NASA Astrophysics Data System} } @misc{aplpy2019, author = {Robitaille, Thomas}, title = {{APLpy v2.0: The Astronomical Plotting Library in Python}}, month = feb, year = 2019, doi = {10.5281/zenodo.2567476}, url = {https://doi.org/10.5281/zenodo.2567476} } APLpy-2.0.3/LICENSE.md0000644000077000000240000000216213432273771014035 0ustar tomstaff00000000000000APLpy - The Astronomical Plotting Library in Python Copyright (c) 2010-2013 Thomas P. Robitaille and Eli Bressert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. APLpy-2.0.3/PKG-INFO0000644000077000000240000000466513432765724013544 0ustar tomstaff00000000000000Metadata-Version: 2.1 Name: APLpy Version: 2.0.3 Summary: The Astronomical Plotting Library in Python Home-page: http://aplpy.github.io Author: Thomas Robitaille and Eli Bressert Author-email: thomas.robitaille@gmail.com, elibre@users.sourceforge.net License: MIT Description: |Build Status| |CircleCI| |codecov| |Documentation Status| About ----- APLpy (the Astronomical Plotting Library in Python) is a Python module aimed at producing publication-quality plots of astronomical imaging data in FITS format. PyPI: https://pypi.python.org/pypi/APLpy Website: http://aplpy.github.io Documentation: http://aplpy.readthedocs.io APLpy is released under an MIT open-source license. Installing ---------- The following dependencies are required: - `Numpy `__ 1.11 or later - `Matplotlib `__ 2.0 or later - `Astropy `__ 3.1 or later - `reproject `__ 0.4 or later - `PyAVM `__ 0.9.4 or later - `pyregion `__ 2.0 or later - `pillow `__ 4.0 or later - `scikit-image `__ 0.14 or later - `shapely `__ 1.6 or later You can install APLpy and all its dependencies with:: pip install aplpy or if you use conda:: conda install -c astropy aplpy .. |Build Status| image:: https://travis-ci.org/aplpy/aplpy.svg?branch=master :target: https://travis-ci.org/aplpy/aplpy .. |CircleCI| image:: https://circleci.com/gh/aplpy/aplpy/tree/master.svg?style=svg :target: https://circleci.com/gh/aplpy/aplpy/tree/master .. |codecov| image:: https://codecov.io/gh/aplpy/aplpy/branch/master/graph/badge.svg :target: https://codecov.io/gh/aplpy/aplpy .. |Documentation Status| image:: https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat :target: https://aplpy.readthedocs.io/en/latest/ Platform: UNKNOWN Requires-Python: >=3.5 Provides-Extra: test Provides-Extra: docs APLpy-2.0.3/README.rst0000644000077000000240000000331413432765613014121 0ustar tomstaff00000000000000|Build Status| |CircleCI| |codecov| |Documentation Status| About ----- APLpy (the Astronomical Plotting Library in Python) is a Python module aimed at producing publication-quality plots of astronomical imaging data in FITS format. PyPI: https://pypi.python.org/pypi/APLpy Website: http://aplpy.github.io Documentation: http://aplpy.readthedocs.io APLpy is released under an MIT open-source license. Installing ---------- The following dependencies are required: - `Numpy `__ 1.11 or later - `Matplotlib `__ 2.0 or later - `Astropy `__ 3.1 or later - `reproject `__ 0.4 or later - `PyAVM `__ 0.9.4 or later - `pyregion `__ 2.0 or later - `pillow `__ 4.0 or later - `scikit-image `__ 0.14 or later - `shapely `__ 1.6 or later You can install APLpy and all its dependencies with:: pip install aplpy or if you use conda:: conda install -c astropy aplpy .. |Build Status| image:: https://travis-ci.org/aplpy/aplpy.svg?branch=master :target: https://travis-ci.org/aplpy/aplpy .. |CircleCI| image:: https://circleci.com/gh/aplpy/aplpy/tree/master.svg?style=svg :target: https://circleci.com/gh/aplpy/aplpy/tree/master .. |codecov| image:: https://codecov.io/gh/aplpy/aplpy/branch/master/graph/badge.svg :target: https://codecov.io/gh/aplpy/aplpy .. |Documentation Status| image:: https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat :target: https://aplpy.readthedocs.io/en/latest/ APLpy-2.0.3/ah_bootstrap.py0000644000077000000240000010550613432763221015470 0ustar tomstaff00000000000000""" This bootstrap module contains code for ensuring that the astropy_helpers package will be importable by the time the setup.py script runs. It also includes some workarounds to ensure that a recent-enough version of setuptools is being used for the installation. This module should be the first thing imported in the setup.py of distributions that make use of the utilities in astropy_helpers. If the distribution ships with its own copy of astropy_helpers, this module will first attempt to import from the shipped copy. However, it will also check PyPI to see if there are any bug-fix releases on top of the current version that may be useful to get past platform-specific bugs that have been fixed. When running setup.py, use the ``--offline`` command-line option to disable the auto-upgrade checks. When this module is imported or otherwise executed it automatically calls a main function that attempts to read the project's setup.cfg file, which it checks for a configuration section called ``[ah_bootstrap]`` the presences of that section, and options therein, determine the next step taken: If it contains an option called ``auto_use`` with a value of ``True``, it will automatically call the main function of this module called `use_astropy_helpers` (see that function's docstring for full details). Otherwise no further action is taken and by default the system-installed version of astropy-helpers will be used (however, ``ah_bootstrap.use_astropy_helpers`` may be called manually from within the setup.py script). This behavior can also be controlled using the ``--auto-use`` and ``--no-auto-use`` command-line flags. For clarity, an alias for ``--no-auto-use`` is ``--use-system-astropy-helpers``, and we recommend using the latter if needed. Additional options in the ``[ah_boostrap]`` section of setup.cfg have the same names as the arguments to `use_astropy_helpers`, and can be used to configure the bootstrap script when ``auto_use = True``. See https://github.com/astropy/astropy-helpers for more details, and for the latest version of this module. """ import contextlib import errno import io import locale import os import re import subprocess as sp import sys __minimum_python_version__ = (3, 5) if sys.version_info < __minimum_python_version__: print("ERROR: Python {} or later is required by astropy-helpers".format( __minimum_python_version__)) sys.exit(1) try: from ConfigParser import ConfigParser, RawConfigParser except ImportError: from configparser import ConfigParser, RawConfigParser _str_types = (str, bytes) # What follows are several import statements meant to deal with install-time # issues with either missing or misbehaving pacakges (including making sure # setuptools itself is installed): # Check that setuptools 1.0 or later is present from distutils.version import LooseVersion try: import setuptools assert LooseVersion(setuptools.__version__) >= LooseVersion('1.0') except (ImportError, AssertionError): print("ERROR: setuptools 1.0 or later is required by astropy-helpers") sys.exit(1) # typing as a dependency for 1.6.1+ Sphinx causes issues when imported after # initializing submodule with ah_boostrap.py # See discussion and references in # https://github.com/astropy/astropy-helpers/issues/302 try: import typing # noqa except ImportError: pass # Note: The following import is required as a workaround to # https://github.com/astropy/astropy-helpers/issues/89; if we don't import this # module now, it will get cleaned up after `run_setup` is called, but that will # later cause the TemporaryDirectory class defined in it to stop working when # used later on by setuptools try: import setuptools.py31compat # noqa except ImportError: pass # matplotlib can cause problems if it is imported from within a call of # run_setup(), because in some circumstances it will try to write to the user's # home directory, resulting in a SandboxViolation. See # https://github.com/matplotlib/matplotlib/pull/4165 # Making sure matplotlib, if it is available, is imported early in the setup # process can mitigate this (note importing matplotlib.pyplot has the same # issue) try: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot except: # Ignore if this fails for *any* reason* pass # End compatibility imports... # In case it didn't successfully import before the ez_setup checks import pkg_resources from setuptools import Distribution from setuptools.package_index import PackageIndex from distutils import log from distutils.debug import DEBUG # TODO: Maybe enable checking for a specific version of astropy_helpers? DIST_NAME = 'astropy-helpers' PACKAGE_NAME = 'astropy_helpers' UPPER_VERSION_EXCLUSIVE = None # Defaults for other options DOWNLOAD_IF_NEEDED = True INDEX_URL = 'https://pypi.python.org/simple' USE_GIT = True OFFLINE = False AUTO_UPGRADE = True # A list of all the configuration options and their required types CFG_OPTIONS = [ ('auto_use', bool), ('path', str), ('download_if_needed', bool), ('index_url', str), ('use_git', bool), ('offline', bool), ('auto_upgrade', bool) ] class _Bootstrapper(object): """ Bootstrapper implementation. See ``use_astropy_helpers`` for parameter documentation. """ def __init__(self, path=None, index_url=None, use_git=None, offline=None, download_if_needed=None, auto_upgrade=None): if path is None: path = PACKAGE_NAME if not (isinstance(path, _str_types) or path is False): raise TypeError('path must be a string or False') if not isinstance(path, str): fs_encoding = sys.getfilesystemencoding() path = path.decode(fs_encoding) # path to unicode self.path = path # Set other option attributes, using defaults where necessary self.index_url = index_url if index_url is not None else INDEX_URL self.offline = offline if offline is not None else OFFLINE # If offline=True, override download and auto-upgrade if self.offline: download_if_needed = False auto_upgrade = False self.download = (download_if_needed if download_if_needed is not None else DOWNLOAD_IF_NEEDED) self.auto_upgrade = (auto_upgrade if auto_upgrade is not None else AUTO_UPGRADE) # If this is a release then the .git directory will not exist so we # should not use git. git_dir_exists = os.path.exists(os.path.join(os.path.dirname(__file__), '.git')) if use_git is None and not git_dir_exists: use_git = False self.use_git = use_git if use_git is not None else USE_GIT # Declared as False by default--later we check if astropy-helpers can be # upgraded from PyPI, but only if not using a source distribution (as in # the case of import from a git submodule) self.is_submodule = False @classmethod def main(cls, argv=None): if argv is None: argv = sys.argv config = cls.parse_config() config.update(cls.parse_command_line(argv)) auto_use = config.pop('auto_use', False) bootstrapper = cls(**config) if auto_use: # Run the bootstrapper, otherwise the setup.py is using the old # use_astropy_helpers() interface, in which case it will run the # bootstrapper manually after reconfiguring it. bootstrapper.run() return bootstrapper @classmethod def parse_config(cls): if not os.path.exists('setup.cfg'): return {} cfg = ConfigParser() try: cfg.read('setup.cfg') except Exception as e: if DEBUG: raise log.error( "Error reading setup.cfg: {0!r}\n{1} will not be " "automatically bootstrapped and package installation may fail." "\n{2}".format(e, PACKAGE_NAME, _err_help_msg)) return {} if not cfg.has_section('ah_bootstrap'): return {} config = {} for option, type_ in CFG_OPTIONS: if not cfg.has_option('ah_bootstrap', option): continue if type_ is bool: value = cfg.getboolean('ah_bootstrap', option) else: value = cfg.get('ah_bootstrap', option) config[option] = value return config @classmethod def parse_command_line(cls, argv=None): if argv is None: argv = sys.argv config = {} # For now we just pop recognized ah_bootstrap options out of the # arg list. This is imperfect; in the unlikely case that a setup.py # custom command or even custom Distribution class defines an argument # of the same name then we will break that. However there's a catch22 # here that we can't just do full argument parsing right here, because # we don't yet know *how* to parse all possible command-line arguments. if '--no-git' in argv: config['use_git'] = False argv.remove('--no-git') if '--offline' in argv: config['offline'] = True argv.remove('--offline') if '--auto-use' in argv: config['auto_use'] = True argv.remove('--auto-use') if '--no-auto-use' in argv: config['auto_use'] = False argv.remove('--no-auto-use') if '--use-system-astropy-helpers' in argv: config['auto_use'] = False argv.remove('--use-system-astropy-helpers') return config def run(self): strategies = ['local_directory', 'local_file', 'index'] dist = None # First, remove any previously imported versions of astropy_helpers; # this is necessary for nested installs where one package's installer # is installing another package via setuptools.sandbox.run_setup, as in # the case of setup_requires for key in list(sys.modules): try: if key == PACKAGE_NAME or key.startswith(PACKAGE_NAME + '.'): del sys.modules[key] except AttributeError: # Sometimes mysterious non-string things can turn up in # sys.modules continue # Check to see if the path is a submodule self.is_submodule = self._check_submodule() for strategy in strategies: method = getattr(self, 'get_{0}_dist'.format(strategy)) dist = method() if dist is not None: break else: raise _AHBootstrapSystemExit( "No source found for the {0!r} package; {0} must be " "available and importable as a prerequisite to building " "or installing this package.".format(PACKAGE_NAME)) # This is a bit hacky, but if astropy_helpers was loaded from a # directory/submodule its Distribution object gets a "precedence" of # "DEVELOP_DIST". However, in other cases it gets a precedence of # "EGG_DIST". However, when activing the distribution it will only be # placed early on sys.path if it is treated as an EGG_DIST, so always # do that dist = dist.clone(precedence=pkg_resources.EGG_DIST) # Otherwise we found a version of astropy-helpers, so we're done # Just active the found distribution on sys.path--if we did a # download this usually happens automatically but it doesn't hurt to # do it again # Note: Adding the dist to the global working set also activates it # (makes it importable on sys.path) by default. try: pkg_resources.working_set.add(dist, replace=True) except TypeError: # Some (much) older versions of setuptools do not have the # replace=True option here. These versions are old enough that all # bets may be off anyways, but it's easy enough to work around just # in case... if dist.key in pkg_resources.working_set.by_key: del pkg_resources.working_set.by_key[dist.key] pkg_resources.working_set.add(dist) @property def config(self): """ A `dict` containing the options this `_Bootstrapper` was configured with. """ return dict((optname, getattr(self, optname)) for optname, _ in CFG_OPTIONS if hasattr(self, optname)) def get_local_directory_dist(self): """ Handle importing a vendored package from a subdirectory of the source distribution. """ if not os.path.isdir(self.path): return log.info('Attempting to import astropy_helpers from {0} {1!r}'.format( 'submodule' if self.is_submodule else 'directory', self.path)) dist = self._directory_import() if dist is None: log.warn( 'The requested path {0!r} for importing {1} does not ' 'exist, or does not contain a copy of the {1} ' 'package.'.format(self.path, PACKAGE_NAME)) elif self.auto_upgrade and not self.is_submodule: # A version of astropy-helpers was found on the available path, but # check to see if a bugfix release is available on PyPI upgrade = self._do_upgrade(dist) if upgrade is not None: dist = upgrade return dist def get_local_file_dist(self): """ Handle importing from a source archive; this also uses setup_requires but points easy_install directly to the source archive. """ if not os.path.isfile(self.path): return log.info('Attempting to unpack and import astropy_helpers from ' '{0!r}'.format(self.path)) try: dist = self._do_download(find_links=[self.path]) except Exception as e: if DEBUG: raise log.warn( 'Failed to import {0} from the specified archive {1!r}: ' '{2}'.format(PACKAGE_NAME, self.path, str(e))) dist = None if dist is not None and self.auto_upgrade: # A version of astropy-helpers was found on the available path, but # check to see if a bugfix release is available on PyPI upgrade = self._do_upgrade(dist) if upgrade is not None: dist = upgrade return dist def get_index_dist(self): if not self.download: log.warn('Downloading {0!r} disabled.'.format(DIST_NAME)) return None log.warn( "Downloading {0!r}; run setup.py with the --offline option to " "force offline installation.".format(DIST_NAME)) try: dist = self._do_download() except Exception as e: if DEBUG: raise log.warn( 'Failed to download and/or install {0!r} from {1!r}:\n' '{2}'.format(DIST_NAME, self.index_url, str(e))) dist = None # No need to run auto-upgrade here since we've already presumably # gotten the most up-to-date version from the package index return dist def _directory_import(self): """ Import astropy_helpers from the given path, which will be added to sys.path. Must return True if the import succeeded, and False otherwise. """ # Return True on success, False on failure but download is allowed, and # otherwise raise SystemExit path = os.path.abspath(self.path) # Use an empty WorkingSet rather than the man # pkg_resources.working_set, since on older versions of setuptools this # will invoke a VersionConflict when trying to install an upgrade ws = pkg_resources.WorkingSet([]) ws.add_entry(path) dist = ws.by_key.get(DIST_NAME) if dist is None: # We didn't find an egg-info/dist-info in the given path, but if a # setup.py exists we can generate it setup_py = os.path.join(path, 'setup.py') if os.path.isfile(setup_py): # We use subprocess instead of run_setup from setuptools to # avoid segmentation faults - see the following for more details: # https://github.com/cython/cython/issues/2104 sp.check_output([sys.executable, 'setup.py', 'egg_info'], cwd=path) for dist in pkg_resources.find_distributions(path, True): # There should be only one... return dist return dist def _do_download(self, version='', find_links=None): if find_links: allow_hosts = '' index_url = None else: allow_hosts = None index_url = self.index_url # Annoyingly, setuptools will not handle other arguments to # Distribution (such as options) before handling setup_requires, so it # is not straightforward to programmatically augment the arguments which # are passed to easy_install class _Distribution(Distribution): def get_option_dict(self, command_name): opts = Distribution.get_option_dict(self, command_name) if command_name == 'easy_install': if find_links is not None: opts['find_links'] = ('setup script', find_links) if index_url is not None: opts['index_url'] = ('setup script', index_url) if allow_hosts is not None: opts['allow_hosts'] = ('setup script', allow_hosts) return opts if version: req = '{0}=={1}'.format(DIST_NAME, version) else: if UPPER_VERSION_EXCLUSIVE is None: req = DIST_NAME else: req = '{0}<{1}'.format(DIST_NAME, UPPER_VERSION_EXCLUSIVE) attrs = {'setup_requires': [req]} # NOTE: we need to parse the config file (e.g. setup.cfg) to make sure # it honours the options set in the [easy_install] section, and we need # to explicitly fetch the requirement eggs as setup_requires does not # get honored in recent versions of setuptools: # https://github.com/pypa/setuptools/issues/1273 try: context = _verbose if DEBUG else _silence with context(): dist = _Distribution(attrs=attrs) try: dist.parse_config_files(ignore_option_errors=True) dist.fetch_build_eggs(req) except TypeError: # On older versions of setuptools, ignore_option_errors # doesn't exist, and the above two lines are not needed # so we can just continue pass # If the setup_requires succeeded it will have added the new dist to # the main working_set return pkg_resources.working_set.by_key.get(DIST_NAME) except Exception as e: if DEBUG: raise msg = 'Error retrieving {0} from {1}:\n{2}' if find_links: source = find_links[0] elif index_url != INDEX_URL: source = index_url else: source = 'PyPI' raise Exception(msg.format(DIST_NAME, source, repr(e))) def _do_upgrade(self, dist): # Build up a requirement for a higher bugfix release but a lower minor # release (so API compatibility is guaranteed) next_version = _next_version(dist.parsed_version) req = pkg_resources.Requirement.parse( '{0}>{1},<{2}'.format(DIST_NAME, dist.version, next_version)) package_index = PackageIndex(index_url=self.index_url) upgrade = package_index.obtain(req) if upgrade is not None: return self._do_download(version=upgrade.version) def _check_submodule(self): """ Check if the given path is a git submodule. See the docstrings for ``_check_submodule_using_git`` and ``_check_submodule_no_git`` for further details. """ if (self.path is None or (os.path.exists(self.path) and not os.path.isdir(self.path))): return False if self.use_git: return self._check_submodule_using_git() else: return self._check_submodule_no_git() def _check_submodule_using_git(self): """ Check if the given path is a git submodule. If so, attempt to initialize and/or update the submodule if needed. This function makes calls to the ``git`` command in subprocesses. The ``_check_submodule_no_git`` option uses pure Python to check if the given path looks like a git submodule, but it cannot perform updates. """ cmd = ['git', 'submodule', 'status', '--', self.path] try: log.info('Running `{0}`; use the --no-git option to disable git ' 'commands'.format(' '.join(cmd))) returncode, stdout, stderr = run_cmd(cmd) except _CommandNotFound: # The git command simply wasn't found; this is most likely the # case on user systems that don't have git and are simply # trying to install the package from PyPI or a source # distribution. Silently ignore this case and simply don't try # to use submodules return False stderr = stderr.strip() if returncode != 0 and stderr: # Unfortunately the return code alone cannot be relied on, as # earlier versions of git returned 0 even if the requested submodule # does not exist # This is a warning that occurs in perl (from running git submodule) # which only occurs with a malformatted locale setting which can # happen sometimes on OSX. See again # https://github.com/astropy/astropy/issues/2749 perl_warning = ('perl: warning: Falling back to the standard locale ' '("C").') if not stderr.strip().endswith(perl_warning): # Some other unknown error condition occurred log.warn('git submodule command failed ' 'unexpectedly:\n{0}'.format(stderr)) return False # Output of `git submodule status` is as follows: # # 1: Status indicator: '-' for submodule is uninitialized, '+' if # submodule is initialized but is not at the commit currently indicated # in .gitmodules (and thus needs to be updated), or 'U' if the # submodule is in an unstable state (i.e. has merge conflicts) # # 2. SHA-1 hash of the current commit of the submodule (we don't really # need this information but it's useful for checking that the output is # correct) # # 3. The output of `git describe` for the submodule's current commit # hash (this includes for example what branches the commit is on) but # only if the submodule is initialized. We ignore this information for # now _git_submodule_status_re = re.compile( '^(?P[+-U ])(?P[0-9a-f]{40}) ' '(?P\S+)( .*)?$') # The stdout should only contain one line--the status of the # requested submodule m = _git_submodule_status_re.match(stdout) if m: # Yes, the path *is* a git submodule self._update_submodule(m.group('submodule'), m.group('status')) return True else: log.warn( 'Unexpected output from `git submodule status`:\n{0}\n' 'Will attempt import from {1!r} regardless.'.format( stdout, self.path)) return False def _check_submodule_no_git(self): """ Like ``_check_submodule_using_git``, but simply parses the .gitmodules file to determine if the supplied path is a git submodule, and does not exec any subprocesses. This can only determine if a path is a submodule--it does not perform updates, etc. This function may need to be updated if the format of the .gitmodules file is changed between git versions. """ gitmodules_path = os.path.abspath('.gitmodules') if not os.path.isfile(gitmodules_path): return False # This is a minimal reader for gitconfig-style files. It handles a few of # the quirks that make gitconfig files incompatible with ConfigParser-style # files, but does not support the full gitconfig syntax (just enough # needed to read a .gitmodules file). gitmodules_fileobj = io.StringIO() # Must use io.open for cross-Python-compatible behavior wrt unicode with io.open(gitmodules_path) as f: for line in f: # gitconfig files are more flexible with leading whitespace; just # go ahead and remove it line = line.lstrip() # comments can start with either # or ; if line and line[0] in (':', ';'): continue gitmodules_fileobj.write(line) gitmodules_fileobj.seek(0) cfg = RawConfigParser() try: cfg.readfp(gitmodules_fileobj) except Exception as exc: log.warn('Malformatted .gitmodules file: {0}\n' '{1} cannot be assumed to be a git submodule.'.format( exc, self.path)) return False for section in cfg.sections(): if not cfg.has_option(section, 'path'): continue submodule_path = cfg.get(section, 'path').rstrip(os.sep) if submodule_path == self.path.rstrip(os.sep): return True return False def _update_submodule(self, submodule, status): if status == ' ': # The submodule is up to date; no action necessary return elif status == '-': if self.offline: raise _AHBootstrapSystemExit( "Cannot initialize the {0} submodule in --offline mode; " "this requires being able to clone the submodule from an " "online repository.".format(submodule)) cmd = ['update', '--init'] action = 'Initializing' elif status == '+': cmd = ['update'] action = 'Updating' if self.offline: cmd.append('--no-fetch') elif status == 'U': raise _AHBootstrapSystemExit( 'Error: Submodule {0} contains unresolved merge conflicts. ' 'Please complete or abandon any changes in the submodule so that ' 'it is in a usable state, then try again.'.format(submodule)) else: log.warn('Unknown status {0!r} for git submodule {1!r}. Will ' 'attempt to use the submodule as-is, but try to ensure ' 'that the submodule is in a clean state and contains no ' 'conflicts or errors.\n{2}'.format(status, submodule, _err_help_msg)) return err_msg = None cmd = ['git', 'submodule'] + cmd + ['--', submodule] log.warn('{0} {1} submodule with: `{2}`'.format( action, submodule, ' '.join(cmd))) try: log.info('Running `{0}`; use the --no-git option to disable git ' 'commands'.format(' '.join(cmd))) returncode, stdout, stderr = run_cmd(cmd) except OSError as e: err_msg = str(e) else: if returncode != 0: err_msg = stderr if err_msg is not None: log.warn('An unexpected error occurred updating the git submodule ' '{0!r}:\n{1}\n{2}'.format(submodule, err_msg, _err_help_msg)) class _CommandNotFound(OSError): """ An exception raised when a command run with run_cmd is not found on the system. """ def run_cmd(cmd): """ Run a command in a subprocess, given as a list of command-line arguments. Returns a ``(returncode, stdout, stderr)`` tuple. """ try: p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE) # XXX: May block if either stdout or stderr fill their buffers; # however for the commands this is currently used for that is # unlikely (they should have very brief output) stdout, stderr = p.communicate() except OSError as e: if DEBUG: raise if e.errno == errno.ENOENT: msg = 'Command not found: `{0}`'.format(' '.join(cmd)) raise _CommandNotFound(msg, cmd) else: raise _AHBootstrapSystemExit( 'An unexpected error occurred when running the ' '`{0}` command:\n{1}'.format(' '.join(cmd), str(e))) # Can fail of the default locale is not configured properly. See # https://github.com/astropy/astropy/issues/2749. For the purposes under # consideration 'latin1' is an acceptable fallback. try: stdio_encoding = locale.getdefaultlocale()[1] or 'latin1' except ValueError: # Due to an OSX oddity locale.getdefaultlocale() can also crash # depending on the user's locale/language settings. See: # http://bugs.python.org/issue18378 stdio_encoding = 'latin1' # Unlikely to fail at this point but even then let's be flexible if not isinstance(stdout, str): stdout = stdout.decode(stdio_encoding, 'replace') if not isinstance(stderr, str): stderr = stderr.decode(stdio_encoding, 'replace') return (p.returncode, stdout, stderr) def _next_version(version): """ Given a parsed version from pkg_resources.parse_version, returns a new version string with the next minor version. Examples ======== >>> _next_version(pkg_resources.parse_version('1.2.3')) '1.3.0' """ if hasattr(version, 'base_version'): # New version parsing from setuptools >= 8.0 if version.base_version: parts = version.base_version.split('.') else: parts = [] else: parts = [] for part in version: if part.startswith('*'): break parts.append(part) parts = [int(p) for p in parts] if len(parts) < 3: parts += [0] * (3 - len(parts)) major, minor, micro = parts[:3] return '{0}.{1}.{2}'.format(major, minor + 1, 0) class _DummyFile(object): """A noop writeable object.""" errors = '' # Required for Python 3.x encoding = 'utf-8' def write(self, s): pass def flush(self): pass @contextlib.contextmanager def _verbose(): yield @contextlib.contextmanager def _silence(): """A context manager that silences sys.stdout and sys.stderr.""" old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = _DummyFile() sys.stderr = _DummyFile() exception_occurred = False try: yield except: exception_occurred = True # Go ahead and clean up so that exception handling can work normally sys.stdout = old_stdout sys.stderr = old_stderr raise if not exception_occurred: sys.stdout = old_stdout sys.stderr = old_stderr _err_help_msg = """ If the problem persists consider installing astropy_helpers manually using pip (`pip install astropy_helpers`) or by manually downloading the source archive, extracting it, and installing by running `python setup.py install` from the root of the extracted source code. """ class _AHBootstrapSystemExit(SystemExit): def __init__(self, *args): if not args: msg = 'An unknown problem occurred bootstrapping astropy_helpers.' else: msg = args[0] msg += '\n' + _err_help_msg super(_AHBootstrapSystemExit, self).__init__(msg, *args[1:]) BOOTSTRAPPER = _Bootstrapper.main() def use_astropy_helpers(**kwargs): """ Ensure that the `astropy_helpers` module is available and is importable. This supports automatic submodule initialization if astropy_helpers is included in a project as a git submodule, or will download it from PyPI if necessary. Parameters ---------- path : str or None, optional A filesystem path relative to the root of the project's source code that should be added to `sys.path` so that `astropy_helpers` can be imported from that path. If the path is a git submodule it will automatically be initialized and/or updated. The path may also be to a ``.tar.gz`` archive of the astropy_helpers source distribution. In this case the archive is automatically unpacked and made temporarily available on `sys.path` as a ``.egg`` archive. If `None` skip straight to downloading. download_if_needed : bool, optional If the provided filesystem path is not found an attempt will be made to download astropy_helpers from PyPI. It will then be made temporarily available on `sys.path` as a ``.egg`` archive (using the ``setup_requires`` feature of setuptools. If the ``--offline`` option is given at the command line the value of this argument is overridden to `False`. index_url : str, optional If provided, use a different URL for the Python package index than the main PyPI server. use_git : bool, optional If `False` no git commands will be used--this effectively disables support for git submodules. If the ``--no-git`` option is given at the command line the value of this argument is overridden to `False`. auto_upgrade : bool, optional By default, when installing a package from a non-development source distribution ah_boostrap will try to automatically check for patch releases to astropy-helpers on PyPI and use the patched version over any bundled versions. Setting this to `False` will disable that functionality. If the ``--offline`` option is given at the command line the value of this argument is overridden to `False`. offline : bool, optional If `False` disable all actions that require an internet connection, including downloading packages from the package index and fetching updates to any git submodule. Defaults to `True`. """ global BOOTSTRAPPER config = BOOTSTRAPPER.config config.update(**kwargs) # Create a new bootstrapper with the updated configuration and run it BOOTSTRAPPER = _Bootstrapper(**config) BOOTSTRAPPER.run() APLpy-2.0.3/aplpy/0000755000077000000240000000000013432765724013561 5ustar tomstaff00000000000000APLpy-2.0.3/aplpy/__init__.py0000644000077000000240000000152613432763221015664 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst """ APLpy : Astronomical Plotting Library in Python """ # Affiliated packages may add whatever they like to this file, but # should keep this content at the top. # ---------------------------------------------------------------------------- from ._astropy_init import * # noqa # ---------------------------------------------------------------------------- if not _ASTROPY_SETUP_: # noqa from .core import FITSFigure # noqa from .rgb import make_rgb_image, make_rgb_cube # noqa from .frame import Frame # noqa from .overlays import Scalebar, Beam # noqa from .colorbar import Colorbar # noqa from .grid import Grid # noqa from .ticks import Ticks # noqa from .tick_labels import TickLabels # noqa from .axis_labels import AxisLabels # noqa APLpy-2.0.3/aplpy/_astropy_init.py0000644000077000000240000001204113432763221017002 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst __all__ = ['__version__', '__githash__', 'test'] # this indicates whether or not we are in the package's setup.py try: _ASTROPY_SETUP_ except NameError: from sys import version_info if version_info[0] >= 3: import builtins else: import __builtin__ as builtins builtins._ASTROPY_SETUP_ = False try: from .version import version as __version__ except ImportError: __version__ = '' try: from .version import githash as __githash__ except ImportError: __githash__ = '' # set up the test command def _get_test_runner(): import os from astropy.tests.helper import TestRunner return TestRunner(os.path.dirname(__file__)) def test(package=None, test_path=None, args=None, plugins=None, verbose=False, pastebin=None, remote_data=False, pep8=False, pdb=False, coverage=False, open_files=False, **kwargs): """ Run the tests using `py.test `__. Parameters ---------- package : str, optional The name of a specific package to test, e.g. 'io.fits' or 'utils'. If nothing is specified all default tests are run. test_path : str, optional Specify location to test by path. May be a single file or directory. Must be specified absolutely or relative to the calling directory. args : str, optional Additional arguments to be passed to pytest.main in the ``args`` keyword argument. plugins : list, optional Plugins to be passed to pytest.main in the ``plugins`` keyword argument. verbose : bool, optional Convenience option to turn on verbose output from py.test. Passing True is the same as specifying ``'-v'`` in ``args``. pastebin : {'failed','all',None}, optional Convenience option for turning on py.test pastebin output. Set to ``'failed'`` to upload info for failed tests, or ``'all'`` to upload info for all tests. remote_data : bool, optional Controls whether to run tests marked with @remote_data. These tests use online data and are not run by default. Set to True to run these tests. pep8 : bool, optional Turn on PEP8 checking via the `pytest-pep8 plugin `_ and disable normal tests. Same as specifying ``'--pep8 -k pep8'`` in ``args``. pdb : bool, optional Turn on PDB post-mortem analysis for failing tests. Same as specifying ``'--pdb'`` in ``args``. coverage : bool, optional Generate a test coverage report. The result will be placed in the directory htmlcov. open_files : bool, optional Fail when any tests leave files open. Off by default, because this adds extra run time to the test suite. Requires the `psutil `_ package. parallel : int, optional When provided, run the tests in parallel on the specified number of CPUs. If parallel is negative, it will use the all the cores on the machine. Requires the `pytest-xdist `_ plugin installed. Only available when using Astropy 0.3 or later. kwargs Any additional keywords passed into this function will be passed on to the astropy test runner. This allows use of test-related functionality implemented in later versions of astropy without explicitly updating the package template. """ test_runner = _get_test_runner() return test_runner.run_tests( package=package, test_path=test_path, args=args, plugins=plugins, verbose=verbose, pastebin=pastebin, remote_data=remote_data, pep8=pep8, pdb=pdb, coverage=coverage, open_files=open_files, **kwargs) if not _ASTROPY_SETUP_: # noqa import os from warnings import warn from astropy.config.configuration import ( update_default_config, ConfigurationDefaultMissingError, ConfigurationDefaultMissingWarning) # add these here so we only need to cleanup the namespace at the end config_dir = None if not os.environ.get('ASTROPY_SKIP_CONFIG_UPDATE', False): config_dir = os.path.dirname(__file__) config_template = os.path.join(config_dir, __package__ + ".cfg") if os.path.isfile(config_template): try: update_default_config( __package__, config_dir, version=__version__) except TypeError as orig_error: try: update_default_config(__package__, config_dir) except ConfigurationDefaultMissingError as e: wmsg = (e.args[0] + " Cannot install default profile. If you are " "importing from source, this is expected.") warn(ConfigurationDefaultMissingWarning(wmsg)) del e except Exception: raise orig_error APLpy-2.0.3/aplpy/axis_labels.py0000644000077000000240000001523313432763221016413 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from astropy.wcs.utils import wcs_to_celestial_frame from astropy.coordinates import (ICRS, FK5, FK4, Galactic, HeliocentricTrueEcliptic, BarycentricTrueEcliptic) from .decorators import auto_refresh, fixdocstring __all__ = ['AxisLabels'] class AxisLabels(object): def __init__(self, parent): self._ax = parent.ax self._wcs = parent.ax.wcs self.x = parent.x self.y = parent.y self._ax.coords[self.x].set_axislabel_visibility_rule('always') self._ax.coords[self.y].set_axislabel_visibility_rule('always') xcoord_type = self._ax.coords[self.x].coord_type ycoord_type = self._ax.coords[self.y].coord_type if xcoord_type == 'longitude' and ycoord_type == 'latitude': celestial = True inverted = False elif xcoord_type == 'latitude' and ycoord_type == 'longitude': celestial = True inverted = True else: celestial = inverted = False if celestial: frame = wcs_to_celestial_frame(self._wcs) else: frame = None if isinstance(frame, ICRS): xtext = 'RA (ICRS)' ytext = 'Dec (ICRS)' elif isinstance(frame, FK5): equinox = "{:g}".format(FK5.equinox.jyear) xtext = 'RA (J{0})'.format(equinox) ytext = 'Dec (J{0})'.format(equinox) elif isinstance(frame, FK4): equinox = "{:g}".format(FK4.equinox.byear) xtext = 'RA (B{0})'.format(equinox) ytext = 'Dec (B{0})'.format(equinox) elif isinstance(frame, Galactic): xtext = 'Galactic Longitude' ytext = 'Galactic Latitude' elif isinstance(frame, (HeliocentricTrueEcliptic, BarycentricTrueEcliptic)): # NOTE: once we support only Astropy 2.0+, we can use BaseEclipticFrame xtext = 'Ecliptic Longitude' ytext = 'Ecliptic Latitude' else: cunit_x = self._wcs.wcs.cunit[self.x] cunit_y = self._wcs.wcs.cunit[self.y] cname_x = self._wcs.wcs.cname[self.x] cname_y = self._wcs.wcs.cname[self.y] ctype_x = self._wcs.wcs.ctype[self.x] ctype_y = self._wcs.wcs.ctype[self.y] xunit = " (%s)" % cunit_x if cunit_x not in ["", None] else "" yunit = " (%s)" % cunit_y if cunit_y not in ["", None] else "" if len(cname_x) > 0: xtext = cname_x + xunit else: if len(ctype_x) == 8 and ctype_x[4] == '-': xtext = ctype_x[:4].replace('-', '') + xunit else: xtext = ctype_x + xunit if len(cname_y) > 0: ytext = cname_y + yunit else: if len(ctype_y) == 8 and ctype_y[4] == '-': ytext = ctype_y[:4].replace('-', '') + yunit else: ytext = ctype_y + yunit if inverted: xtext, ytext = ytext, xtext self.set_xtext(xtext) self.set_ytext(ytext) self.set_xposition('bottom') self.set_yposition('left') @auto_refresh def set_xtext(self, label): """ Set the x-axis label text. """ self._x_text = label self._ax.coords[self.x].set_axislabel(label) @auto_refresh def set_ytext(self, label): """ Set the y-axis label text. """ self._y_text = label self._ax.coords[self.y].set_axislabel(label) @auto_refresh def set_xpad(self, pad): """ Set the x-axis label displacement in terms of the axis label font size. """ self._ax.coords[self.x].axislabels.set_minpad(pad) @auto_refresh def set_ypad(self, pad): """ Set the y-axis label displacement in terms of the axis label font size. """ self._ax.coords[self.y].axislabels.set_minpad(pad) @auto_refresh @fixdocstring def set_font(self, **kwargs): """ Set the font of the axis labels. Parameters ---------- common: family, style, variant, stretch, weight, size, fontproperties Notes ----- Default values are set by matplotlib or previously set values if set_font has already been called. Global default values can be set by editing the matplotlibrc file. """ self._ax.coords[self.x].axislabels.set(**kwargs) self._ax.coords[self.y].axislabels.set(**kwargs) @auto_refresh def show(self): """ Show the x- and y-axis labels. """ self.show_x() self.show_y() @auto_refresh def hide(self): """ Hide the x- and y-axis labels. """ self.hide_x() self.hide_y() @auto_refresh def show_x(self): """ Show the x-axis label. """ if self._xposition == 'bottom': self._ax.coords[self.x].set_axislabel_position('b') else: self._ax.coords[self.x].set_axislabel_position('t') @auto_refresh def hide_x(self): """ Hide the x-axis label. """ self._ax.coords[self.x].set_axislabel_position('') @auto_refresh def show_y(self): """ Show the y-axis label. """ if self._yposition == 'left': self._ax.coords[self.y].set_axislabel_position('l') else: self._ax.coords[self.y].set_axislabel_position('r') @auto_refresh def hide_y(self): """ Hide the y-axis label. """ self._ax.coords[self.y].set_axislabel_position('') @auto_refresh def set_xposition(self, position): """ Set the position of the x-axis label ('top' or 'bottom') """ if position == 'bottom': self._ax.coords[self.x].set_axislabel_position('b') elif position == 'top': self._ax.coords[self.x].set_axislabel_position('t') else: raise ValueError("position should be one of 'top' or 'bottom'") self._xposition = position @auto_refresh def set_yposition(self, position): """ Set the position of the y-axis label ('left' or 'right') """ if position == 'left': self._ax.coords[self.y].set_axislabel_position('l') elif position == 'right': self._ax.coords[self.y].set_axislabel_position('r') else: raise ValueError("position should be one of 'left' or 'right'") self._yposition = position APLpy-2.0.3/aplpy/colorbar.py0000644000077000000240000003567213432763221015741 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import warnings import matplotlib.axes as maxes from mpl_toolkits.axes_grid1 import make_axes_locatable from matplotlib.font_manager import FontProperties from matplotlib.ticker import LogFormatterMathtext from .decorators import auto_refresh, fixdocstring class Colorbar(object): def __init__(self, parent): self._figure = parent._figure self._colorbar_axes = None self._parent = parent self._base_settings = {} self._ticklabel_fontproperties = FontProperties() self._axislabel_fontproperties = FontProperties() @auto_refresh def show(self, location='right', width=0.2, pad=0.05, ticks=None, labels=True, log_format=False, box=None, box_orientation='vertical', axis_label_text=None, axis_label_rotation=None, axis_label_pad=5): """ Show a colorbar on the side of the image. Parameters ---------- location : str, optional Where to place the colorbar. Should be one of 'left', 'right', 'top', 'bottom'. width : float, optional The width of the colorbar relative to the canvas size. pad : float, optional The spacing between the colorbar and the image relative to the canvas size. ticks : list, optional The position of the ticks on the colorbar. labels : bool, optional Whether to show numerical labels. log_format : bool, optional Whether to format ticks in exponential notation box : list, optional A custom box within which to place the colorbar. This should be in the form [xmin, ymin, dx, dy] and be in relative figure units. This overrides the location argument. box_orientation str, optional The orientation of the colorbar within the box. Can be 'horizontal' or 'vertical' axis_label_text str, optional Optional text label of the colorbar. """ self._base_settings['location'] = location self._base_settings['width'] = width self._base_settings['pad'] = pad self._base_settings['ticks'] = ticks self._base_settings['labels'] = labels self._base_settings['log_format'] = log_format self._base_settings['box'] = box self._base_settings['box_orientation'] = box_orientation self._base_settings['axis_label_text'] = axis_label_text self._base_settings['axis_label_rotation'] = axis_label_rotation self._base_settings['axis_label_pad'] = axis_label_pad if self._parent.image: if self._colorbar_axes: self._figure.delaxes(self._colorbar_axes) if box is None: divider = make_axes_locatable(self._parent.ax) if location == 'right': self._colorbar_axes = divider.new_horizontal(size=width, pad=pad, axes_class=maxes.Axes) orientation = 'vertical' elif location == 'top': self._colorbar_axes = divider.new_vertical(size=width, pad=pad, axes_class=maxes.Axes) orientation = 'horizontal' elif location == 'left': warnings.warn("Left colorbar not fully implemented") self._colorbar_axes = divider.new_horizontal(size=width, pad=pad, pack_start=True, axes_class=maxes.Axes) locator = divider.new_locator(nx=0, ny=0) self._colorbar_axes.set_axes_locator(locator) orientation = 'vertical' elif location == 'bottom': warnings.warn("Bottom colorbar not fully implemented") self._colorbar_axes = divider.new_vertical(size=width, pad=pad, pack_start=True, axes_class=maxes.Axes) locator = divider.new_locator(nx=0, ny=0) self._colorbar_axes.set_axes_locator(locator) orientation = 'horizontal' else: raise Exception("location should be one of: right/top") self._figure.add_axes(self._colorbar_axes) else: self._colorbar_axes = self._figure.add_axes(box) orientation = box_orientation if log_format: format = LogFormatterMathtext() else: format = None self._colorbar = self._figure.colorbar(self._parent.image, cax=self._colorbar_axes, orientation=orientation, format=format, ticks=ticks) if axis_label_text: if axis_label_rotation: self._colorbar.set_label(axis_label_text, rotation=axis_label_rotation) else: self._colorbar.set_label(axis_label_text) if location == 'right': for tick in self._colorbar_axes.yaxis.get_major_ticks(): tick.tick1line.set_visible(True) tick.tick2line.set_visible(True) tick.label1.set_visible(False) tick.label2.set_visible(labels) self._colorbar_axes.yaxis.set_label_position('right') self._colorbar_axes.yaxis.labelpad = axis_label_pad elif location == 'top': for tick in self._colorbar_axes.xaxis.get_major_ticks(): tick.tick1line.set_visible(True) tick.tick2line.set_visible(True) tick.label1.set_visible(False) tick.label2.set_visible(labels) self._colorbar_axes.xaxis.set_label_position('top') self._colorbar_axes.xaxis.labelpad = axis_label_pad elif location == 'left': for tick in self._colorbar_axes.yaxis.get_major_ticks(): tick.tick1line.set_visible(True) tick.tick2line.set_visible(True) tick.label1.set_visible(labels) tick.label2.set_visible(False) self._colorbar_axes.yaxis.set_label_position('left') self._colorbar_axes.yaxis.labelpad = axis_label_pad elif location == 'bottom': for tick in self._colorbar_axes.xaxis.get_major_ticks(): tick.tick1line.set_visible(True) tick.tick2line.set_visible(True) tick.label1.set_visible(labels) tick.label2.set_visible(False) self._colorbar_axes.xaxis.set_label_position('bottom') self._colorbar_axes.xaxis.labelpad = axis_label_pad else: warnings.warn("No image is shown, therefore, no colorbar will be plotted") @auto_refresh def update(self): if self._colorbar_axes: self.show(**self._base_settings) @auto_refresh def hide(self): self._figure.delaxes(self._colorbar_axes) self._colorbar_axes = None @auto_refresh def _remove(self): self._figure.delaxes(self._colorbar_axes) # LOCATION AND SIZE @auto_refresh def set_location(self, location): """ Set the location of the colorbar. Should be one of 'left', 'right', 'top', 'bottom'. """ self._base_settings['location'] = location self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_width(self, width): """ Set the width of the colorbar relative to the canvas size. """ self._base_settings['width'] = width self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_pad(self, pad): """ Set the spacing between the colorbar and the image relative to the canvas size. """ self._base_settings['pad'] = pad self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_ticks(self, ticks): """ Set the position of the ticks on the colorbar. """ self._base_settings['ticks'] = ticks self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_labels(self, labels): """ Set whether to show numerical labels. """ self._base_settings['labels'] = labels self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_box(self, box, box_orientation='vertical'): """ Set the box within which to place the colorbar. This should be in the form [xmin, ymin, dx, dy] and be in relative figure units. The orientation of the colorbar within the box can be controlled with the box_orientation argument. """ self._base_settings['box'] = box self._base_settings['box_orientation'] = box_orientation self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_axis_label_text(self, axis_label_text): """ Set the colorbar label text. """ self._base_settings['axis_label_text'] = axis_label_text self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_axis_label_rotation(self, axis_label_rotation): """ Set the colorbar label rotation. """ self._base_settings['axis_label_rotation'] = axis_label_rotation self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) @auto_refresh def set_axis_label_pad(self, axis_label_pad): """ Set the colorbar label displacement, in points. """ self._base_settings['axis_label_pad'] = axis_label_pad self.show(**self._base_settings) self.set_font(fontproperties=self._ticklabel_fontproperties) self.set_axis_label_font(fontproperties=self._axislabel_fontproperties) # FONT PROPERTIES @auto_refresh def set_label_properties(self, *args, **kwargs): warnings.warn("set_label_properties is deprecated - use set_font instead", DeprecationWarning) self.set_font(*args, **kwargs) @auto_refresh @fixdocstring def set_font(self, family=None, style=None, variant=None, stretch=None, weight=None, size=None, fontproperties=None): """ Set the font of the tick labels. Parameters ---------- common: family, style, variant, stretch, weight, size, fontproperties Notes ----- Default values are set by matplotlib or previously set values if set_font has already been called. Global default values can be set by editing the matplotlibrc file. """ if family: self._ticklabel_fontproperties.set_family(family) if style: self._ticklabel_fontproperties.set_style(style) if variant: self._ticklabel_fontproperties.set_variant(variant) if stretch: self._ticklabel_fontproperties.set_stretch(stretch) if weight: self._ticklabel_fontproperties.set_weight(weight) if size: self._ticklabel_fontproperties.set_size(size) if fontproperties: self._ticklabel_fontproperties = fontproperties # Update the tick label font properties for label in self._colorbar_axes.get_xticklabels(): label.set_fontproperties(self._ticklabel_fontproperties) for label in self._colorbar_axes.get_yticklabels(): label.set_fontproperties(self._ticklabel_fontproperties) # Also update the offset text font properties label = self._colorbar_axes.xaxis.get_offset_text() label.set_fontproperties(self._ticklabel_fontproperties) label = self._colorbar_axes.yaxis.get_offset_text() label.set_fontproperties(self._ticklabel_fontproperties) @auto_refresh @fixdocstring def set_axis_label_font(self, family=None, style=None, variant=None, stretch=None, weight=None, size=None, fontproperties=None): """ Set the font of the tick labels. Parameters ---------- common: family, style, variant, stretch, weight, size, fontproperties Notes ----- Default values are set by matplotlib or previously set values if set_font has already been called. Global default values can be set by editing the matplotlibrc file. """ if family: self._axislabel_fontproperties.set_family(family) if style: self._axislabel_fontproperties.set_style(style) if variant: self._axislabel_fontproperties.set_variant(variant) if stretch: self._axislabel_fontproperties.set_stretch(stretch) if weight: self._axislabel_fontproperties.set_weight(weight) if size: self._axislabel_fontproperties.set_size(size) if fontproperties: self._axislabel_fontproperties = fontproperties # Update the label font properties label = self._colorbar_axes.xaxis.get_label() label.set_fontproperties(self._axislabel_fontproperties) label = self._colorbar_axes.yaxis.get_label() label.set_fontproperties(self._axislabel_fontproperties) # FRAME PROPERTIES @auto_refresh def set_frame_linewidth(self, linewidth): """ Set the linewidth of the colorbar frame, in points. """ warnings.warn("This method is not functional at this time") for key in self._colorbar_axes.spines: self._colorbar_axes.spines[key].set_linewidth(linewidth) @auto_refresh def set_frame_color(self, color): """ Set the color of the colorbar frame, in points. """ warnings.warn("This method is not functional at this time") for key in self._colorbar_axes.spines: self._colorbar_axes.spines[key].set_edgecolor(color) APLpy-2.0.3/aplpy/compat.py0000644000077000000240000000347413432765627015430 0ustar tomstaff00000000000000# The simple_norm function in astropy is missing a control for the log # scaling as described in https://github.com/astropy/astropy/issues/8432, # so for now we include a copy of the fixed function here. from astropy.visualization.interval import (PercentileInterval, AsymmetricPercentileInterval, ManualInterval, MinMaxInterval) from astropy.visualization.stretch import (LinearStretch, SqrtStretch, PowerStretch, LogStretch, AsinhStretch) from astropy.visualization.mpl_normalize import ImageNormalize __all__ = ['simple_norm'] def simple_norm(data, stretch='linear', power=1.0, asinh_a=0.1, log_a=1000, min_cut=None, max_cut=None, min_percent=None, max_percent=None, percent=None, clip=True): if percent is not None: interval = PercentileInterval(percent) elif min_percent is not None or max_percent is not None: interval = AsymmetricPercentileInterval(min_percent or 0., max_percent or 100.) elif min_cut is not None or max_cut is not None: interval = ManualInterval(min_cut, max_cut) else: interval = MinMaxInterval() if stretch == 'linear': stretch = LinearStretch() elif stretch == 'sqrt': stretch = SqrtStretch() elif stretch == 'power': stretch = PowerStretch(power) elif stretch == 'log': stretch = LogStretch(log_a) elif stretch == 'asinh': stretch = AsinhStretch(asinh_a) else: raise ValueError('Unknown stretch: {0}.'.format(stretch)) vmin, vmax = interval.get_limits(data) return ImageNormalize(vmin=vmin, vmax=vmax, stretch=stretch, clip=clip) APLpy-2.0.3/aplpy/conftest.py0000644000077000000240000000514513432763221015753 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division # Force the backend to Agg when testing import matplotlib matplotlib.use('Agg') # This file is used to configure the behavior of pytest when using the Astropy # test infrastructure. from astropy.version import version as astropy_version if astropy_version < '3.0': # With older versions of Astropy, we actually need to import the pytest # plugins themselves in order to make them discoverable by pytest. from astropy.tests.pytest_plugins import * # noqa else: # As of Astropy 3.0, the pytest plugins provided by Astropy are # automatically made available when Astropy is installed. This means it's # not necessary to import them here, but we still need to import global # variables that are used for configuration. from astropy.tests.plugins.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS from astropy.tests.helper import enable_deprecations_as_exceptions # Uncomment the following line to treat all DeprecationWarnings as # exceptions. For Astropy v2.0 or later, there are 2 additional keywords, # as follow (although default should work for most cases). # To ignore some packages that produce deprecation warnings on import # (in addition to 'compiler', 'scipy', 'pygments', 'ipykernel', and # 'setuptools'), add: # modules_to_ignore_on_import=['module_1', 'module_2'] # To ignore some specific deprecation warning messages for Python version # MAJOR.MINOR or later, add: # warnings_to_ignore_by_pyver={(MAJOR, MINOR): ['Message to ignore']} enable_deprecations_as_exceptions() # Uncomment and customize the following lines to add/remove entries from # the list of packages for which version numbers are displayed when running # the tests. Making it pass for KeyError is essential in some cases when # the package uses other astropy affiliated packages. try: PYTEST_HEADER_MODULES['Astropy'] = 'astropy' PYTEST_HEADER_MODULES['pyregion'] = 'pyregion' PYTEST_HEADER_MODULES['PyAVM'] = 'PyAVM' PYTEST_HEADER_MODULES['reproject'] = 'reproject' del PYTEST_HEADER_MODULES['h5py'] except (NameError, KeyError): pass # Uncomment the following lines to display the version number of the # package rather than the version number of Astropy in the top line when # running the tests. import os # This is to figure out the package version, rather than # using Astropy's try: from .version import version except ImportError: version = 'dev' try: packagename = os.path.basename(os.path.dirname(__file__)) TESTED_VERSIONS[packagename] = version except NameError: # Needed to support Astropy <= 1.0.0 pass APLpy-2.0.3/aplpy/convolve_util.py0000644000077000000240000000235713432763221017020 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from astropy.convolution import (convolve as astropy_convolve, Gaussian2DKernel, Box2DKernel) def convolve(image, smooth=3, kernel='gauss'): if smooth is None and isinstance(kernel, str) and kernel in ['box', 'gauss']: return image if smooth is not None and not np.isscalar(smooth): raise ValueError("smooth= should be an integer - for more complex " "kernels, pass an array containing the kernel " "to the kernel= option") # The Astropy convolution doesn't treat +/-Inf values correctly yet, so we # convert to NaN here. image_fixed = np.array(image, dtype=float, copy=True) image_fixed[np.isinf(image)] = np.nan if isinstance(kernel, str): if kernel == 'gauss': kernel = Gaussian2DKernel(smooth, x_size=smooth * 5, y_size=smooth * 5) elif kernel == 'box': kernel = Box2DKernel(smooth, x_size=smooth * 5, y_size=smooth * 5) else: raise ValueError("Unknown kernel: {0}".format(kernel)) else: kernel = kernel return astropy_convolve(image, kernel, boundary='extend') APLpy-2.0.3/aplpy/core.py0000644000077000000240000022604113432765627015072 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from distutils import version import os import operator from functools import reduce import matplotlib import matplotlib.pyplot as plt from matplotlib.patches import Circle, Rectangle, Ellipse, Polygon, FancyArrow from matplotlib.collections import PatchCollection, LineCollection import numpy as np from astropy import log from astropy.wcs import WCS from astropy.wcs.utils import proj_plane_pixel_scales from astropy.io import fits from astropy.nddata.utils import block_reduce from astropy.visualization import AsymmetricPercentileInterval from astropy.visualization.wcsaxes import WCSAxes, WCSAxesSubplot from astropy.coordinates import ICRS from . import convolve_util from . import header as header_util from . import slicer from .compat import simple_norm from .layers import Layers from .grid import Grid from .ticks import Ticks from .tick_labels import TickLabels from .axis_labels import AxisLabels from .overlays import Beam, Scalebar from .regions import Regions from .colorbar import Colorbar from .frame import Frame from .decorators import auto_refresh, fixdocstring HDU_TYPES = tuple([fits.PrimaryHDU, fits.ImageHDU, fits.CompImageHDU]) def uniformize_1d(*args): if len(args) > 1: return np.broadcast_arrays(np.atleast_1d(args[0]), *args[1:]) elif len(args) == 1: return np.atleast_1d(args[0]) else: raise ValueError("No arguments passed to uniformize_1d") class FITSFigure(Layers, Regions): """ Create a FITSFigure instance. This class is a wrapper around the Astropy WCSAxes class and provides the same API as historical versions of APLpy. Parameters ---------- data : see below The FITS file to open. The following data types can be passed: string astropy.io.fits.PrimaryHDU astropy.io.fits.ImageHDU astropy.wcs.WCS np.ndarray RGB image with AVM meta-data hdu : int, optional By default, the image in the primary HDU is read in. If a different HDU is required, use this argument. figure : ~matplotlib.figure.Figure, optional If specified, a subplot will be added to this existing matplotlib figure() instance, rather than a new figure being created from scratch. subplot : tuple or list, optional If specified, a subplot will be added at this position. If a tuple of three values, the tuple should contain the standard matplotlib subplot parameters, i.e. (ny, nx, subplot). If a list of four values, the list should contain [xmin, ymin, dx, dy] where xmin and ymin are the position of the bottom left corner of the subplot, and dx and dy are the width and height of the subplot respectively. These should all be given in units of the figure width and height. For example, [0.1, 0.1, 0.8, 0.8] will almost fill the entire figure, leaving a 10 percent margin on all sides. downsample : int, optional If this option is specified, the image will be downsampled by a factor *downsample* when reading in the data. north : bool, optional Whether to rotate the image so that north is up. By default, this is assumed to be 'north' in the ICRS frame, but you can also pass any astropy :class:`~astropy.coordinates.BaseCoordinateFrame` to indicate to use the north of that frame. convention : str, optional This is used in cases where a FITS header can be interpreted in multiple ways. For example, for files with a -CAR projection and CRVAL2=0, this can be set to 'wells' or 'calabretta' to choose the appropriate convention. dimensions : tuple or list, optional The index of the axes to use if the data has more than three dimensions. slices : tuple or list, optional If a FITS file with more than two dimensions is specified, then these are the slices to extract. If all extra dimensions only have size 1, then this is not required. auto_refresh : bool, optional Whether to refresh the figure automatically every time a plotting method is called. This can also be set using the set_auto_refresh method. This defaults to `True` if and only if APLpy is being used from IPython and the Matplotlib backend is interactive. kwargs Any additional arguments are passed on to matplotlib's Figure() class. For example, to set the figure size, use the figsize=(xsize, ysize) argument (where xsize and ysize are in inches). For more information on these additional arguments, see the *Optional keyword arguments* section in the documentation for :class:`~matplotlib.figure.Figure`. """ @auto_refresh def __init__(self, data, hdu=0, figure=None, subplot=(1, 1, 1), downsample=False, north=False, convention=None, dimensions=[0, 1], slices=[], auto_refresh=None, **kwargs): self._wcsaxes_slices = ('x', 'y') if 'figsize' not in kwargs: kwargs['figsize'] = (10, 9) # Set the grid type if len(slices) > 0: self.grid_type = 'contours' else: self.grid_type = 'lines' if (isinstance(data, str) and data.split('.')[-1].lower() in ['png', 'jpg', 'tif']): try: from PIL import Image except ImportError: try: import Image except ImportError: raise ImportError("The Python Imaging Library (PIL) is " "required to read in RGB images") try: import pyavm except ImportError: raise ImportError("PyAVM is required to read in AVM " "meta-data from RGB images") if version.LooseVersion(pyavm.__version__) < version.LooseVersion('0.9.1'): raise ImportError("PyAVM installation is not recent enough " "(version 0.9.1 or later is required).") from pyavm import AVM # Remember image filename self._rgb_image = data # Find image size nx, ny = Image.open(data).size # Now convert AVM information to WCS data = AVM.from_image(data).to_wcs() # Need to scale CDELT values sometimes the AVM meta-data is only # really valid for the full-resolution image data.wcs.cdelt = [data.wcs.cdelt[0] * nx / float(nx), data.wcs.cdelt[1] * ny / float(ny)] data.wcs.crpix = [data.wcs.crpix[0] / nx * float(nx), data.wcs.crpix[1] / ny * float(ny)] # Update the NAXIS values with the true dimensions of the RGB image data.nx = nx data.ny = ny data.pixel_shape = (nx, ny) if isinstance(data, WCS): wcs = data if wcs.naxis != 2: raise ValueError("FITSFigure initialization via WCS objects " "can only be done with 2-dimensional WCS " "objects") if wcs.pixel_shape is None: raise ValueError("The WCS object does not contain any size " "information") header = wcs.to_header() header['NAXIS1'], header['NAXIS2'] = wcs.pixel_shape nx = header['NAXIS%i' % (dimensions[0] + 1)] ny = header['NAXIS%i' % (dimensions[1] + 1)] self._data = np.zeros((ny, nx), dtype=float) self._header = header self._wcs = WCS(header, relax=True) self._wcs.nx = nx self._wcs.ny = ny if downsample: log.warning("downsample argument is ignored if data " "passed is a WCS object") downsample = False if north: log.warning("north argument is ignored if data " "passed is a WCS object") north = False else: self._data, self._header, self._wcs, self._wcsaxes_slices = \ self._get_hdu(data, hdu, north, convention=convention, dimensions=dimensions, slices=slices) self._wcs.nx = self._header['NAXIS%i' % (dimensions[0] + 1)] self._wcs.ny = self._header['NAXIS%i' % (dimensions[1] + 1)] # Downsample if requested if downsample: nx_new = self._wcs.nx - np.mod(self._wcs.nx, downsample) ny_new = self._wcs.ny - np.mod(self._wcs.ny, downsample) self._data = self._data[0:ny_new, 0:nx_new] self._data = block_reduce(self._data, downsample, func=np.mean) self._wcs.nx, self._wcs.ny = nx_new, ny_new # Open the figure if figure: self._figure = figure else: self._figure = plt.figure(**kwargs) # Set whether to automatically refresh the display self.set_auto_refresh(auto_refresh) # Initialize axis instance if type(subplot) == list and len(subplot) == 4: self.ax = WCSAxes(self._figure, subplot, wcs=self._wcs, slices=self._wcsaxes_slices, adjustable='datalim') self._figure.add_axes(self.ax) elif type(subplot) == tuple and len(subplot) == 3: self.ax = WCSAxesSubplot(self._figure, *subplot, wcs=self._wcs, slices=self._wcsaxes_slices) self._figure.add_subplot(self.ax) else: raise ValueError("subplot= should be either a tuple of three " "values, or a list of four values") # Turn off autoscaling self.ax.set_autoscale_on(False) # Make sure axes are above everything else self.ax.set_axisbelow(False) # Set view to whole FITS file self._initialize_view() # Set the coordinates for x and y axis self.x = dimensions[0] self.y = dimensions[1] # Initialize tick, label, and frame convenience wrappers (these dispatch # calls to WCSAxes) self.ticks = Ticks(self) self.axis_labels = AxisLabels(self) self.tick_labels = TickLabels(self) self.frame = Frame(self) # Display minor ticks self.ax.coords[self.x].display_minor_ticks(True) self.ax.coords[self.y].display_minor_ticks(True) # Initialize layers list self._initialize_layers() # Set image holder to be empty self.image = None # Set default theme self.set_theme(theme='pretty') def _get_hdu(self, data, hdu, north, convention=None, dimensions=[0, 1], slices=[]): if isinstance(data, str): filename = data # Check file exists if not os.path.exists(filename): raise IOError("File not found: " + filename) # Read in FITS file try: hdulist = fits.open(filename) except Exception: raise IOError("An error occurred while reading the FITS file") # Check whether the HDU specified contains any data, otherwise # cycle through all HDUs to find one that contains valid image data if hdulist[hdu].data is None: found = False for alt_hdu in range(len(hdulist)): if isinstance(hdulist[alt_hdu], HDU_TYPES): if hdulist[alt_hdu].data is not None: log.warning("hdu=%i does not contain any data, " "using hdu=%i instead" % (hdu, alt_hdu)) hdu = hdulist[alt_hdu] found = True break if not found: raise Exception("FITS file does not contain any image data") else: hdu = hdulist[hdu] elif type(data) == np.ndarray: hdu = fits.ImageHDU(data) elif isinstance(data, HDU_TYPES): hdu = data elif isinstance(data, fits.HDUList): hdu = data[hdu] else: raise Exception("data argument should either be a filename, an HDU object from astropy.io.fits, a WCS object from astropy.wcs, or a Numpy array.") # Check that we have at least 2-dimensional data if hdu.header['NAXIS'] < 2: raise ValueError("Data should have at least two dimensions") # Check dimensions= argument if type(dimensions) not in [list, tuple]: raise ValueError('dimensions= should be a list or a tuple') if len(set(dimensions)) != 2 or len(dimensions) != 2: raise ValueError("dimensions= should be a tuple of two different values") if dimensions[0] < 0 or dimensions[0] > hdu.header['NAXIS'] - 1: raise ValueError('values of dimensions= should be between %i and %i' % (0, hdu.header['NAXIS'] - 1)) if dimensions[1] < 0 or dimensions[1] > hdu.header['NAXIS'] - 1: raise ValueError('values of dimensions= should be between %i and %i' % (0, hdu.header['NAXIS'] - 1)) # Reproject to face north if requested if north: # Find rotated WCS frame = ICRS() if north is True else north from reproject.mosaicking import find_optimal_celestial_wcs wcs, shape = find_optimal_celestial_wcs([hdu], frame=frame) from reproject import reproject_interp data, _ = reproject_interp(hdu, wcs, shape_out=shape) header = wcs.to_header() header['NAXIS1'] = shape[1] header['NAXIS2'] = shape[0] else: # Now copy the data and header to new objects, since in astropy.io.fits # the two attributes are linked, which can lead to confusing behavior. # We just need to copy the header to avoid memory issues - as long as # one item is copied, the two variables are decoupled. data = hdu.data header = hdu.header.copy() del hdu # If slices wasn't specified, check if we can guess shape = data.shape if len(shape) > 2: n_total = reduce(operator.mul, shape) n_image = (shape[len(shape) - 1 - dimensions[0]] * shape[len(shape) - 1 - dimensions[1]]) if n_total == n_image: slices = [0 for i in range(1, len(shape) - 1)] log.info("Setting slices=%s" % str(slices)) # Extract slices data, wcsaxes_slices = slicer.slice_hypercube(data, header, dimensions=dimensions, slices=slices) # Check header header = header_util.check(header, convention=convention, dimensions=dimensions) # Parse WCS info wcs = WCS(header, relax=True) return data, header, wcs, wcsaxes_slices @auto_refresh def set_title(self, title, **kwargs): """ Set the figure title """ self.ax.set_title(title, **kwargs) @auto_refresh def set_xaxis_coord_type(self, coord_type): """ Set the type of x coordinate. Options are: * ``scalar``: treat the values are normal decimal scalar values * ``longitude``: treat the values as a longitude in the 0 to 360 range * ``latitude``: treat the values as a latitude in the -90 to 90 range """ self.ax.coords[self.x].set_coord_type(coord_type) @auto_refresh def set_yaxis_coord_type(self, coord_type): """ Set the type of y coordinate. Options are: * ``scalar``: treat the values are normal decimal scalar values * ``longitude``: treat the values as a longitude in the 0 to 360 range * ``latitude``: treat the values as a latitude in the -90 to 90 range """ self.ax.coords[self.y].set_coord_type(coord_type) @auto_refresh def set_system_latex(self, usetex): """ Set whether to use a real LaTeX installation or the built-in matplotlib LaTeX. Parameters ---------- usetex : str Whether to use a real LaTex installation (True) or the built-in matplotlib LaTeX (False). Note that if the former is chosen, an installation of LaTex is required. """ plt.rc('text', usetex=usetex) @auto_refresh def recenter(self, x, y, radius=None, width=None, height=None): """ Center the image on a given position and with a given radius. Either the radius or width/height arguments should be specified. The units of the radius or width/height should be the same as the world coordinates in the WCS. For images of the sky, this is often (but not always) degrees. Parameters ---------- x, y : float Coordinates to center on radius : float, optional Radius of the region to view in degrees. This produces a square plot. width : float, optional Width of the region to view. This should be given in conjunction with the height argument. height : float, optional Height of the region to view. This should be given in conjunction with the width argument. """ xpix, ypix = self.world2pixel(x, y) pix_scale = proj_plane_pixel_scales(self._wcs) sx, sy = pix_scale[self.x], pix_scale[self.y] if radius: dx_pix = radius / sx dy_pix = radius / sy elif width and height: dx_pix = width / sx * 0.5 dy_pix = height / sy * 0.5 else: raise Exception("Need to specify either radius= or width= and height= arguments") if (xpix + dx_pix < -0.5 or xpix - dx_pix > self._wcs.nx - 0.5 or ypix + dy_pix < -0.5 or ypix - dy_pix > self._wcs.ny): raise Exception("Zoom region falls outside the image") self.ax.set_xlim(xpix - dx_pix, xpix + dx_pix) self.ax.set_ylim(ypix - dy_pix, ypix + dy_pix) @auto_refresh def show_grayscale(self, vmin=None, vmid=None, vmax=None, pmin=0.25, pmax=99.75, stretch='linear', exponent=2, invert='default', smooth=None, kernel='gauss', aspect='equal', interpolation='nearest'): """ Show a grayscale image of the FITS file. Parameters ---------- vmin : None or float, optional Minimum pixel value to use for the grayscale. If set to None, the minimum pixel value is determined using pmin (default). vmax : None or float, optional Maximum pixel value to use for the grayscale. If set to None, the maximum pixel value is determined using pmax (default). pmin : float, optional Percentile value used to determine the minimum pixel value to use for the grayscale if vmin is set to None. The default value is 0.25%. pmax : float, optional Percentile value used to determine the maximum pixel value to use for the grayscale if vmax is set to None. The default value is 99.75%. stretch : { 'linear', 'log', 'sqrt', 'arcsinh', 'power' }, optional The stretch function to use vmid : None or float, optional Baseline value used for the log and arcsinh stretches. If set to None, this is set to zero for log stretches and to vmin - (vmax - vmin) / 30. for arcsinh stretches exponent : float, optional If stretch is set to 'power', this is the exponent to use invert : str, optional Whether to invert the grayscale or not. The default is False, unless set_theme is used, in which case the default depends on the theme. smooth : int or tuple, optional Default smoothing scale is 3 pixels across. User can define whether they want an NxN kernel (integer), or NxM kernel (tuple). This argument corresponds to the 'gauss' and 'box' smoothing kernels. kernel : { 'gauss', 'box', numpy.array }, optional Default kernel used for smoothing is 'gauss'. The user can specify if they would prefer 'gauss', 'box', or a custom kernel. All kernels are normalized to ensure flux retention. aspect : { 'auto', 'equal' }, optional Whether to change the aspect ratio of the image to match that of the axes ('auto') or to change the aspect ratio of the axes to match that of the data ('equal'; default) interpolation : str, optional The type of interpolation to use for the image. The default is 'nearest'. Other options include 'none' (no interpolation, meaning that if exported to a postscript file, the grayscale will be output at native resolution irrespective of the dpi setting), 'bilinear', 'bicubic', and many more (see the matplotlib documentation for imshow). """ if invert == 'default': invert = self._get_invert_default() if invert: cmap = 'gist_yarg' else: cmap = 'gray' self.show_colorscale(vmin=vmin, vmid=vmid, vmax=vmax, pmin=pmin, pmax=pmax, stretch=stretch, exponent=exponent, cmap=cmap, smooth=smooth, kernel=kernel, aspect=aspect, interpolation=interpolation) @auto_refresh def hide_grayscale(self, *args, **kwargs): self.hide_colorscale(*args, **kwargs) @auto_refresh def show_colorscale(self, vmin=None, vmid=None, vmax=None, pmin=0.25, pmax=99.75, stretch='linear', exponent=2, cmap='default', smooth=None, kernel='gauss', aspect='equal', interpolation='nearest'): """ Show a colorscale image of the FITS file. Parameters ---------- vmin : None or float, optional Minimum pixel value to use for the colorscale. If set to None, the minimum pixel value is determined using pmin (default). vmax : None or float, optional Maximum pixel value to use for the colorscale. If set to None, the maximum pixel value is determined using pmax (default). pmin : float, optional Percentile value used to determine the minimum pixel value to use for the colorscale if vmin is set to None. The default value is 0.25%. pmax : float, optional Percentile value used to determine the maximum pixel value to use for the colorscale if vmax is set to None. The default value is 99.75%. stretch : { 'linear', 'log', 'sqrt', 'arcsinh', 'power' }, optional The stretch function to use vmid : None or float, optional Baseline value used for the log and arcsinh stretches. If not set, this defaults to zero for log stretches and to vmin - (vmax - vmin) / 30. for arcsinh stretches exponent : float, optional If stretch is set to 'power', this is the exponent to use cmap : str, optional The name of the colormap to use smooth : int or tuple, optional Default smoothing scale is 3 pixels across. User can define whether they want an NxN kernel (integer), or NxM kernel (tuple). This argument corresponds to the 'gauss' and 'box' smoothing kernels. kernel : { 'gauss', 'box', numpy.array }, optional Default kernel used for smoothing is 'gauss'. The user can specify if they would prefer 'gauss', 'box', or a custom kernel. All kernels are normalized to ensure flux retention. aspect : { 'auto', 'equal' }, optional Whether to change the aspect ratio of the image to match that of the axes ('auto') or to change the aspect ratio of the axes to match that of the data ('equal'; default) interpolation : str, optional The type of interpolation to use for the image. The default is 'nearest'. Other options include 'none' (no interpolation, meaning that if exported to a postscript file, the colorscale will be output at native resolution irrespective of the dpi setting), 'bilinear', 'bicubic', and many more (see the matplotlib documentation for imshow). """ if cmap == 'default': cmap = self._get_colormap_default() min_auto = vmin is None max_auto = vmax is None # The set of available functions cmap = plt.cm.get_cmap(cmap) if min_auto or max_auto: interval = AsymmetricPercentileInterval(pmin, pmax, n_samples=10000) try: vmin_auto, vmax_auto = interval.get_limits(self._data) except (IndexError, TypeError): # no valid values vmin_auto = vmax_auto = 0 if min_auto: vmin = vmin_auto if max_auto: vmax = vmax_auto # Prepare normalizer object if stretch == 'arcsinh': stretch = 'asinh' if stretch == 'log': if vmid is None: if vmin < 0: raise ValueError("When using a log stretch, if vmin < 0, then vmid has to be specified") else: vmid = 0. if vmin < vmid: raise ValueError("When using a log stretch, vmin should be larger than vmid") log_a = (vmax - vmid) / (vmin - vmid) norm_kwargs = {'log_a': log_a} elif stretch == 'asinh': if vmid is None: vmid = vmin - (vmax - vmin) / 30. asinh_a = (vmid - vmin) / (vmax - vmin) norm_kwargs = {'asinh_a': asinh_a} else: norm_kwargs = {} normalizer = simple_norm(self._data, stretch=stretch, power=exponent, min_cut=vmin, max_cut=vmax, clip=False, **norm_kwargs) # Adjust vmin/vmax if auto if min_auto: if stretch == 'linear': vmin = -0.1 * (vmax - vmin) + vmin log.info("Auto-setting vmin to %10.3e" % vmin) if max_auto: if stretch == 'linear': vmax = 0.1 * (vmax - vmin) + vmax log.info("Auto-setting vmax to %10.3e" % vmax) # Update normalizer object normalizer.vmin = vmin normalizer.vmax = vmax if self.image: self.image.set_visible(True) self.image.set_norm(normalizer) self.image.set_cmap(cmap=cmap) self.image.origin = 'lower' self.image.set_interpolation(interpolation) self.image.set_data(convolve_util.convolve(self._data, smooth=smooth, kernel=kernel)) else: extent = -0.5, self._wcs.nx - 0.5, -0.5, self._wcs.ny - 0.5 convolved_data = convolve_util.convolve(self._data, smooth=smooth, kernel=kernel) self.image = self.ax.imshow(convolved_data, cmap=cmap, interpolation=interpolation, origin='lower', norm=normalizer, aspect=aspect, extent=extent) xmin, xmax = self.ax.get_xbound() if xmin == 0.0: self.ax.set_xlim(0.5, xmax) ymin, ymax = self.ax.get_ybound() if ymin == 0.0: self.ax.set_ylim(0.5, ymax) if hasattr(self, 'colorbar'): self.colorbar.update() @auto_refresh def hide_colorscale(self): self.image.set_visible(False) @auto_refresh def set_nan_color(self, color): """ Set the color for NaN pixels. Parameters ---------- color : str This can be any valid matplotlib color """ from copy import deepcopy cm = deepcopy(self.image.get_cmap()) cm.set_bad(color) self.image.set_cmap(cm) @auto_refresh def show_rgb(self, filename=None, interpolation='nearest', vertical_flip=False, horizontal_flip=False, flip=False): """ Show a 3-color image instead of the FITS file data. Parameters ---------- filename, optional The 3-color image should have exactly the same dimensions as the FITS file, and will be shown with exactly the same projection. If FITSFigure was initialized with an AVM-tagged RGB image, the filename is not needed here. vertical_flip : str, optional Whether to vertically flip the RGB image horizontal_flip : str, optional Whether to horizontally flip the RGB image """ try: from PIL import Image except ImportError: try: import Image except ImportError: raise ImportError("The Python Imaging Library (PIL) is required to read in RGB images") if flip: log.warning("Note that show_rgb should now correctly flip RGB images, so the flip= argument is now deprecated. If you still need to flip an image vertically or horizontally, you can use the vertical_flip= and horizontal_flip arguments instead.") if filename is None: if hasattr(self, '_rgb_image'): image = Image.open(self._rgb_image) else: raise Exception("Need to specify the filename of an RGB image") else: image = Image.open(filename) if vertical_flip: image = image.transpose(Image.FLIP_TOP_BOTTOM) if horizontal_flip: image = image.transpose(Image.FLIP_LEFT_RIGHT) self.image = self.ax.imshow(image, interpolation=interpolation, origin='lower') @auto_refresh def show_contour(self, data=None, hdu=0, layer=None, levels=5, filled=False, cmap=None, colors=None, returnlevels=False, convention=None, dimensions=[0, 1], slices=[], smooth=None, kernel='gauss', overlap=False, **kwargs): """ Overlay contours on the current plot. Parameters ---------- data : see below The FITS file to plot contours for. The following data types can be passed: string astropy.io.fits.PrimaryHDU astropy.io.fits.ImageHDU astropy.wcs.WCS np.ndarray hdu : int, optional By default, the image in the primary HDU is read in. If a different HDU is required, use this argument. layer : str, optional The name of the contour layer. This is useful for giving custom names to layers (instead of contour_set_n) and for replacing existing layers. levels : int or list, optional This can either be the number of contour levels to compute (if an integer is provided) or the actual list of contours to show (if a list of floats is provided) filled : str, optional Whether to show filled or line contours cmap : str, optional The colormap to use for the contours colors : str or tuple, optional If a single string is provided, all contour levels will be shown in this color. If a tuple of strings is provided, each contour will be colored according to the corresponding tuple element. returnlevels : str, optional Whether to return the list of contours to the caller. convention : str, optional This is used in cases where a FITS header can be interpreted in multiple ways. For example, for files with a -CAR projection and CRVAL2=0, this can be set to 'wells' or 'calabretta' to choose the appropriate convention. dimensions : tuple or list, optional The index of the axes to use if the data has more than three dimensions. slices : tuple or list, optional If a FITS file with more than two dimensions is specified, then these are the slices to extract. If all extra dimensions only have size 1, then this is not required. smooth : int or tuple, optional Default smoothing scale is 3 pixels across. User can define whether they want an NxN kernel (integer), or NxM kernel (tuple). This argument corresponds to the 'gauss' and 'box' smoothing kernels. kernel : { 'gauss' , 'box' , numpy.array }, optional Default kernel used for smoothing is 'gauss'. The user can specify if they would prefer 'gauss', 'box', or a custom kernel. All kernels are normalized to ensure flux retention. overlap str, optional Whether to include only contours that overlap with the image area. This significantly speeds up the drawing of contours and reduces file size when using a file for the contours covering a much larger area than the image. kwargs Additional keyword arguments (such as alpha, linewidths, or linestyles) will be passed on directly to Matplotlib's :meth:`~matplotlib.axes.Axes.contour` or :meth:`~matplotlib.axes.Axes.contourf` methods. For more information on these additional arguments, see the *Optional keyword arguments* sections in the documentation for those methods. """ if layer: self.remove_layer(layer, raise_exception=False) if cmap: cmap = plt.cm.get_cmap(cmap) elif not colors: cmap = plt.cm.get_cmap('viridis') if data is not None: data_contour, header_contour, wcs_contour, wcsaxes_slices = \ self._get_hdu(data, hdu, False, convention=convention, dimensions=dimensions, slices=slices) else: data_contour = self._data header_contour = self._header wcs_contour = self._wcs wcs_contour.nx = header_contour['NAXIS%i' % (dimensions[0] + 1)] wcs_contour.ny = header_contour['NAXIS%i' % (dimensions[1] + 1)] image_contour = convolve_util.convolve(data_contour, smooth=smooth, kernel=kernel) if type(levels) == int: interval = AsymmetricPercentileInterval(0.25, 99.75, n_samples=10000) try: vmin_auto, vmax_auto = interval.get_limits(image_contour) except IndexError: # no valid values vmin_auto = vmax_auto = 0 levels = np.linspace(vmin_auto, vmax_auto, levels) if wcs_contour.wcs.ctype[self.x] == 'PIXEL' or wcs_contour.wcs.ctype[self.y] == 'PIXEL': frame = 'pixel' else: frame = wcs_contour if filled: c = self.ax.contourf(image_contour, levels, transform=self.ax.get_transform(frame), cmap=cmap, colors=colors, **kwargs) else: c = self.ax.contour(image_contour, levels, transform=self.ax.get_transform(frame), cmap=cmap, colors=colors, **kwargs) if layer: contour_set_name = layer else: self._contour_counter += 1 contour_set_name = 'contour_set_' + str(self._contour_counter) self._layers[contour_set_name] = c if returnlevels: return levels @auto_refresh def show_vectors(self, pdata, adata, phdu=0, ahdu=0, step=1, scale=1, rotate=0, cutoff=0, units='degrees', layer=None, convention=None, dimensions=[0, 1], slices=[], **kwargs): """ Overlay vectors on the current plot. Parameters ---------- pdata : see below The FITS file specifying the magnitude of vectors. The following data types can be passed: string astropy.io.fits.PrimaryHDU astropy.io.fits.ImageHDU astropy.wcs.WCS np.ndarray adata : see below The FITS file specifying the angle of vectors. The following data types can be passed: string astropy.io.fits.PrimaryHDU astropy.io.fits.ImageHDU astropy.wcs.WCS np.ndarray phdu : int, optional By default, the image in the primary HDU is read in. If a different HDU is required for pdata, use this argument. ahdu : int, optional By default, the image in the primary HDU is read in. If a different HDU is required for adata, use this argument. step : int, optional Derive a vector only from every 'step' pixels. You will normally want this to be >1 to get sensible vector spacing. scale : int, optional The length, in pixels, of a vector with magnitude 1 in the image specified by pdata. If pdata specifies fractional polarization, make this comparable to step. rotate : float, optional An angle to rotate by, in units the same as those of the angle map. cutoff : float, optional The value of magnitude below which no vectors should be plotted. The default value, zero, excludes negative-length and NaN-masked data. units : str, optional Units to assume for the angle map. Valid values are 'degrees' (the default) or 'radians' (or anything else), which will not apply a scaling factor of pi/180 to the angle data. layer : str, optional The name of the vector layer. This is useful for giving custom names to layers (instead of vector_set_n) and for replacing existing layers. convention : str, optional This is used in cases where a FITS header can be interpreted in multiple ways. For example, for files with a -CAR projection and CRVAL2=0, this can be set to 'wells' or 'calabretta' to choose the appropriate convention. dimensions : tuple or list, optional The index of the axes to use if the data has more than three dimensions. slices : tuple or list, optional If a FITS file with more than two dimensions is specified, then these are the slices to extract. If all extra dimensions only have size 1, then this is not required. kwargs Additional keyword arguments (such as alpha, linewidths, or color) which are passed to Matplotlib's :class:`~matplotlib.collections.LineCollection` class, and can be used to control the appearance of the lines. For more information on these additional arguments, see the *Optional keyword arguments* sections in the documentation for those methods. """ # over-ride default color (none) that will otherwise be set by # show_lines() if 'color' not in kwargs: kwargs.setdefault('color', 'black') if layer: self.remove_layer(layer, raise_exception=False) data_p, header_p, wcs_p, slices_p = \ self._get_hdu(pdata, phdu, False, convention=convention, dimensions=dimensions, slices=slices) data_a, header_a, wcs_a, slices_a = \ self._get_hdu(adata, ahdu, False, convention=convention, dimensions=dimensions, slices=slices) # TODO: use slices correctly wcs_p.nx = header_p['NAXIS%i' % (dimensions[0] + 1)] wcs_p.ny = header_p['NAXIS%i' % (dimensions[1] + 1)] wcs_a.nx = header_a['NAXIS%i' % (dimensions[0] + 1)] wcs_a.ny = header_a['NAXIS%i' % (dimensions[1] + 1)] if (wcs_p.nx != wcs_a.nx or wcs_p.ny != wcs_a.ny): raise Exception("Angle and magnitude images must be same size") angle = data_a + rotate if units == 'degrees': angle = np.radians(angle) linelist = [] for y in range(0, wcs_p.ny, step): for x in range(0, wcs_p.nx, step): if data_p[y, x] > cutoff and np.isfinite(angle[y, x]): r = data_p[y, x] * 0.5 * scale a = angle[y, x] x1 = x + r * np.sin(a) y1 = y - r * np.cos(a) x2 = x - r * np.sin(a) y2 = y + r * np.cos(a) x_world, y_world = self.pixel2world([x1, x2], [y1, y2], wcs=wcs_p) line = np.array([x_world, y_world]) linelist.append(line) if layer: vector_set_name = layer else: self._vector_counter += 1 vector_set_name = 'vector_set_' + str(self._vector_counter) # Use show_lines to finish the process off self.show_lines(linelist, layer=vector_set_name, **kwargs) # This method plots markers. The input should be an Nx2 array with WCS # coordinates in degree format. @auto_refresh def show_markers(self, xw, yw, layer=False, coords_frame='world', **kwargs): """ Overlay markers on the current plot. Parameters ---------- xw : list or `~numpy.ndarray` The x positions of the markers (in world coordinates) yw : list or `~numpy.ndarray` The y positions of the markers (in world coordinates) layer : str, optional The name of the scatter layer. This is useful for giving custom names to layers (instead of marker_set_n) and for replacing existing layers. coords_frame : 'pixel' or 'world' The reference frame in which the coordinates are defined. This is used to interpret the values of ``xw`` and ``yw``. kwargs Additional keyword arguments (such as marker, facecolor, edgecolor, alpha, or linewidth) will be passed on directly to Matplotlib's :meth:`~matplotlib.axes.Axes.scatter` method (in particular, have a look at the *Optional keyword arguments* in the documentation for that method). """ if 'c' not in kwargs: kwargs.setdefault('edgecolor', 'red') kwargs.setdefault('facecolor', 'none') kwargs.setdefault('s', 30) if layer: self.remove_layer(layer, raise_exception=False) s = self.ax.scatter(xw, yw, transform=self.ax.get_transform(coords_frame), **kwargs) if layer: marker_set_name = layer else: self._scatter_counter += 1 marker_set_name = 'marker_set_' + str(self._scatter_counter) self._layers[marker_set_name] = s # Show circles. Different from markers as this method allows more # definitions for the circles. @auto_refresh def show_circles(self, xw, yw, radius, layer=False, coords_frame='world', zorder=None, **kwargs): """ Overlay circles on the current plot. Parameters ---------- xw : list or `~numpy.ndarray` The x positions of the centers of the circles (in world coordinates) yw : list or `~numpy.ndarray` The y positions of the centers of the circles (in world coordinates) radius : int or float or list or `~numpy.ndarray` The radii of the circles (in world coordinates) layer : str, optional The name of the circle layer. This is useful for giving custom names to layers (instead of circle_set_n) and for replacing existing layers. coords_frame : 'pixel' or 'world' The reference frame in which the coordinates are defined. This is used to interpret the values of ``xw`` and ``yw``. kwargs Additional keyword arguments (such as facecolor, edgecolor, alpha, or linewidth) are passed to Matplotlib :class:`~matplotlib.collections.PatchCollection` class, and can be used to control the appearance of the circles. """ xw, yw, radius = uniformize_1d(xw, yw, radius) if 'facecolor' not in kwargs: kwargs.setdefault('facecolor', 'none') if layer: self.remove_layer(layer, raise_exception=False) if coords_frame not in ['pixel', 'world']: raise ValueError("coords_frame should be set to 'pixel' or 'world'") # While we could plot the shape using the get_transform('world') mode # from WCSAxes, the issue is that the rotation angle is also measured in # world coordinates so will not be what the user is expecting. So we allow the user to specify the reference frame for the coordinates and for the rotation. if coords_frame == 'pixel': x, y = xw, yw r = radius else: x, y = self.world2pixel(xw, yw) pix_scale = proj_plane_pixel_scales(self._wcs) sx, sy = pix_scale[self.x], pix_scale[self.y] r = radius / np.sqrt(sx * sy) patches = [] for i in range(len(xw)): patches.append(Circle((x[i], y[i]), radius=r[i])) # Due to bugs in matplotlib, we need to pass the patch properties # directly to the PatchCollection rather than use match_original. p = PatchCollection(patches, **kwargs) if zorder is not None: p.zorder = zorder c = self.ax.add_collection(p) if layer: circle_set_name = layer else: self._circle_counter += 1 circle_set_name = 'circle_set_' + str(self._circle_counter) self._layers[circle_set_name] = c @auto_refresh def show_ellipses(self, xw, yw, width, height, angle=0, layer=False, zorder=None, coords_frame='world', **kwargs): """ Overlay ellipses on the current plot. Parameters ---------- xw : list or `~numpy.ndarray` The x positions of the centers of the ellipses (in world coordinates) yw : list or `~numpy.ndarray` The y positions of the centers of the ellipses (in world coordinates) width : int or float or list or `~numpy.ndarray` The width of the ellipse (in world coordinates) height : int or float or list or `~numpy.ndarray` The height of the ellipse (in world coordinates) angle : int or float or list or `~numpy.ndarray`, optional rotation in degrees (anti-clockwise). Default angle is 0.0. layer : str, optional The name of the ellipse layer. This is useful for giving custom names to layers (instead of ellipse_set_n) and for replacing existing layers. coords_frame : 'pixel' or 'world' The reference frame in which the coordinates are defined. This is used to interpret the values of ``xw``, ``yw``, ``width``, and ``height``. kwargs Additional keyword arguments (such as facecolor, edgecolor, alpha, or linewidth) are passed to Matplotlib :class:`~matplotlib.collections.PatchCollection` class, and can be used to control the appearance of the ellipses. """ xw, yw, width, height, angle = uniformize_1d(xw, yw, width, height, angle) if 'facecolor' not in kwargs: kwargs.setdefault('facecolor', 'none') if 'edgecolor' not in kwargs: kwargs.setdefault('edgecolor', 'black') if layer: self.remove_layer(layer, raise_exception=False) if coords_frame not in ['pixel', 'world']: raise ValueError("coords_frame should be set to 'pixel' or 'world'") # While we could plot the shape using the get_transform('world') mode # from WCSAxes, the issue is that the rotation angle is also measured in # world coordinates so will not be what the user is expecting. So we allow the user to specify the reference frame for the coordinates and for the rotation. if coords_frame == 'pixel': x, y = xw, yw w = width h = height a = angle transform = self.ax.transData else: x, y = self.world2pixel(xw, yw) pix_scale = proj_plane_pixel_scales(self._wcs) sx, sy = pix_scale[self.x], pix_scale[self.y] w = width / sx h = height / sy a = angle transform = self.ax.transData patches = [] for i in range(len(x)): patches.append(Ellipse((x[i], y[i]), width=w[i], height=h[i], angle=a[i])) # Due to bugs in matplotlib, we need to pass the patch properties # directly to the PatchCollection rather than use match_original. p = PatchCollection(patches, transform=transform, **kwargs) if zorder is not None: p.zorder = zorder c = self.ax.add_collection(p) if layer: ellipse_set_name = layer else: self._ellipse_counter += 1 ellipse_set_name = 'ellipse_set_' + str(self._ellipse_counter) self._layers[ellipse_set_name] = c @auto_refresh def show_rectangles(self, xw, yw, width, height, angle=0, layer=False, zorder=None, coords_frame='world', **kwargs): """ Overlay rectangles on the current plot. Parameters ---------- xw : list or `~numpy.ndarray` The x positions of the centers of the rectangles (in world coordinates) yw : list or `~numpy.ndarray` The y positions of the centers of the rectangles (in world coordinates) width : int or float or list or `~numpy.ndarray` The width of the rectangle (in world coordinates) height : int or float or list or `~numpy.ndarray` The height of the rectangle (in world coordinates) angle : int or float or list or `~numpy.ndarray`, optional rotation in degrees (anti-clockwise). Default angle is 0.0. layer : str, optional The name of the rectangle layer. This is useful for giving custom names to layers (instead of rectangle_set_n) and for replacing existing layers. coords_frame : 'pixel' or 'world' The reference frame in which the coordinates are defined. This is used to interpret the values of ``xw``, ``yw``, ``width``, and ``height``. kwargs Additional keyword arguments (such as facecolor, edgecolor, alpha, or linewidth) are passed to Matplotlib :class:`~matplotlib.collections.PatchCollection` class, and can be used to control the appearance of the rectangles. """ xw, yw, width, height, angle = uniformize_1d(xw, yw, width, height, angle) if 'facecolor' not in kwargs: kwargs.setdefault('facecolor', 'none') if layer: self.remove_layer(layer, raise_exception=False) if coords_frame not in ['pixel', 'world']: raise ValueError("coords_frame should be set to 'pixel' or 'world'") # While we could plot the shape using the get_transform('world') mode # from WCSAxes, the issue is that the rotation angle is also measured in # world coordinates so will not be what the user is expecting. So we # allow the user to specify the reference frame for the coordinates and # for the rotation. if coords_frame == 'pixel': x, y = xw, yw w = width h = height a = angle transform = self.ax.transData else: x, y = self.world2pixel(xw, yw) pix_scale = proj_plane_pixel_scales(self._wcs) sx, sy = pix_scale[self.x], pix_scale[self.y] w = width / sx h = height / sy a = angle transform = self.ax.transData x = x - w / 2. y = y - h / 2. patches = [] for i in range(len(x)): patches.append(Rectangle((x[i], y[i]), width=w[i], height=h[i], angle=a[i])) # Due to bugs in matplotlib, we need to pass the patch properties # directly to the PatchCollection rather than use match_original. p = PatchCollection(patches, transform=transform, **kwargs) if zorder is not None: p.zorder = zorder c = self.ax.add_collection(p) if layer: rectangle_set_name = layer else: self._rectangle_counter += 1 rectangle_set_name = 'rectangle_set_' + str(self._rectangle_counter) self._layers[rectangle_set_name] = c @auto_refresh def show_lines(self, line_list, layer=False, zorder=None, **kwargs): """ Overlay lines on the current plot. Parameters ---------- line_list : list A list of one or more 2xN numpy arrays which contain the [x, y] positions of the vertices in world coordinates. layer : str, optional The name of the line(s) layer. This is useful for giving custom names to layers (instead of line_set_n) and for replacing existing layers. kwargs Additional keyword arguments (such as color, offsets, linestyle, or linewidth) are passed to Matplotlib :class:`~matplotlib.collections.LineCollection` class, and can be used to control the appearance of the lines. """ if 'color' not in kwargs: kwargs.setdefault('color', 'none') if layer: self.remove_layer(layer, raise_exception=False) lines = [] for line in line_list: xw, yw = line[0, :], line[1, :] lines.append(np.column_stack((xw, yw))) l = LineCollection(lines, transform=self.ax.get_transform('world'), **kwargs) if zorder is not None: l.zorder = zorder c = self.ax.add_collection(l) if layer: line_set_name = layer else: self._linelist_counter += 1 line_set_name = 'line_set_' + str(self._linelist_counter) self._layers[line_set_name] = c @auto_refresh def show_arrows(self, x, y, dx, dy, width='auto', head_width='auto', head_length='auto', length_includes_head=True, layer=False, zorder=None, **kwargs): """ Overlay arrows on the current plot. Parameters ---------- x, y, dx, dy : float or list or `~numpy.ndarray` Origin and displacement of the arrows in world coordinates. These can either be scalars to plot a single arrow, or lists or arrays to plot multiple arrows. width : float, optional The width of the arrow body, in pixels (default: 2% of the arrow length) head_width : float, optional The width of the arrow head, in pixels (default: 5% of the arrow length) head_length : float, optional The length of the arrow head, in pixels (default: 5% of the arrow length) length_includes_head : bool, optional Whether the head includes the length layer : str, optional The name of the arrow(s) layer. This is useful for giving custom names to layers (instead of line_set_n) and for replacing existing layers. kwargs Additional keyword arguments (such as facecolor, edgecolor, alpha, or linewidth) are passed to Matplotlib :class:`~matplotlib.collections.PatchCollection` class, and can be used to control the appearance of the arrows. """ x, y, dx, dy = uniformize_1d(x, y, dx, dy) if layer: self.remove_layer(layer, raise_exception=False) arrows = [] # Here we don't make use of WCSAxes.get_transform('world') because # otherwise the arrow heads will be distored. Instead, we work in pixel # coordinates. for i in range(len(x)): xp1, yp1 = self.world2pixel(x[i], y[i]) xp2, yp2 = self.world2pixel(x[i] + dx[i], y[i] + dy[i]) if width == 'auto': width = 0.02 * np.sqrt((xp2 - xp1) ** 2 + (yp2 - yp1) ** 2) if head_width == 'auto': head_width = 0.1 * np.sqrt((xp2 - xp1) ** 2 + (yp2 - yp1) ** 2) if head_length == 'auto': head_length = 0.1 * np.sqrt((xp2 - xp1) ** 2 + (yp2 - yp1) ** 2) arrows.append(FancyArrow(xp1, yp1, xp2 - xp1, yp2 - yp1, width=width, head_width=head_width, head_length=head_length, length_includes_head=length_includes_head) ) # Due to bugs in matplotlib, we need to pass the patch properties # directly to the PatchCollection rather than use match_original. p = PatchCollection(arrows, **kwargs) if zorder is not None: p.zorder = zorder c = self.ax.add_collection(p) if layer: line_set_name = layer else: self._linelist_counter += 1 line_set_name = 'arrow_set_' + str(self._linelist_counter) self._layers[line_set_name] = c @auto_refresh def show_polygons(self, polygon_list, layer=False, zorder=None, **kwargs): """ Overlay polygons on the current plot. Parameters ---------- polygon_list : list or tuple A list of one or more 2xN or Nx2 Numpy arrays which contain the [x, y] positions of the vertices in world coordinates. Note that N should be greater than 2. layer : str, optional The name of the circle layer. This is useful for giving custom names to layers (instead of circle_set_n) and for replacing existing layers. kwargs Additional keyword arguments (such as facecolor, edgecolor, alpha, or linewidth) are passed to Matplotlib :class:`~matplotlib.collections.PatchCollection` class, and can be used to control the appearance of the polygons. """ if 'facecolor' not in kwargs: kwargs.setdefault('facecolor', 'none') if layer: self.remove_layer(layer, raise_exception=False) if type(polygon_list) not in [list, tuple]: raise Exception("polygon_list should be a list or tuple of Numpy arrays") pix_polygon_list = [] for polygon in polygon_list: if type(polygon) is not np.ndarray: raise Exception("Polygon should be given as a Numpy array") if polygon.shape[0] == 2 and polygon.shape[1] > 2: xw = polygon[0, :] yw = polygon[1, :] elif polygon.shape[0] > 2 and polygon.shape[1] == 2: xw = polygon[:, 0] yw = polygon[:, 1] else: raise Exception("Polygon should have dimensions 2xN or Nx2 with N>2") pix_polygon_list.append(np.column_stack((xw, yw))) patches = [] for i in range(len(pix_polygon_list)): patches.append(Polygon(pix_polygon_list[i], **kwargs)) # Due to bugs in matplotlib, we need to pass the patch properties # directly to the PatchCollection rather than use match_original. p = PatchCollection(patches, transform=self.ax.get_transform('world'), **kwargs) if zorder is not None: p.zorder = zorder c = self.ax.add_collection(p) if layer: poly_set_name = layer else: self._poly_counter += 1 poly_set_name = 'poly_set_' + str(self._poly_counter) self._layers[poly_set_name] = c @auto_refresh @fixdocstring def add_label(self, x, y, text, relative=False, color='black', family=None, style=None, variant=None, stretch=None, weight=None, size=None, fontproperties=None, horizontalalignment='center', verticalalignment='center', layer=None, **kwargs): """ Add a text label. Parameters ---------- x, y : float Coordinates of the text label text : str The label relative : str, optional Whether the coordinates are to be interpreted as world coordinates (e.g. RA/Dec or longitude/latitude), or coordinates relative to the axes (where 0.0 is left or bottom and 1.0 is right or top). common: color, family, style, variant, stretch, weight, size, fontproperties, horizontalalignment, verticalalignment """ if layer: self.remove_layer(layer, raise_exception=False) # Can't pass fontproperties=None to text. Only pass it if it is not None. if fontproperties: kwargs['fontproperties'] = fontproperties if not np.isscalar(x): raise Exception("x should be a single value") if not np.isscalar(y): raise Exception("y should be a single value") if not np.isscalar(text): raise Exception("text should be a single value") if relative: l = self.ax.text(x, y, text, color=color, family=family, style=style, variant=variant, stretch=stretch, weight=weight, size=size, horizontalalignment=horizontalalignment, verticalalignment=verticalalignment, transform=self.ax.transAxes, **kwargs) else: l = self.ax.text(x, y, text, color=color, family=family, style=style, variant=variant, stretch=stretch, weight=weight, size=size, horizontalalignment=horizontalalignment, verticalalignment=verticalalignment, transform=self.ax.get_transform('world'), **kwargs) if layer: label_name = layer else: self._label_counter += 1 label_name = 'label_' + str(self._label_counter) self._layers[label_name] = l def set_auto_refresh(self, refresh): """ Set whether the display should refresh after each method call. Parameters ---------- refresh : bool Whether to refresh the display every time a FITSFigure method is called. This defaults to `True` if and only if APLpy is being used from IPython and the Matplotlib backend is interactive. """ if refresh is None: if matplotlib.is_interactive(): try: get_ipython() except NameError: refresh = False else: refresh = True else: refresh = False elif not isinstance(refresh, bool): raise TypeError("refresh argument should be boolean or `None`") self._figure._auto_refresh = refresh def refresh(self, force=True): """ Refresh the display. Parameters ---------- force : str, optional If set to False, refresh() will only have an effect if auto refresh is on. If set to True, the display will be refreshed whatever the auto refresh setting is set to. The default is True. """ if self._figure._auto_refresh or force: self._figure.canvas.draw() def save(self, filename, dpi=None, transparent=False, adjust_bbox=True, max_dpi=300, format=None): """ Save the current figure to a file. Parameters ---------- filename : str or fileobj The name of the file to save the plot to. This can be for example a PS, EPS, PDF, PNG, JPEG, or SVG file. Note that it is also possible to pass file-like object. dpi : float, optional The output resolution, in dots per inch. If the output file is a vector graphics format (such as PS, EPS, PDF or SVG) only the image itself will be rasterized. If the output is a PS or EPS file and no dpi is specified, the dpi is automatically calculated to match the resolution of the image. If this value is larger than max_dpi, then dpi is set to max_dpi. transparent : str, optional Whether to preserve transparency adjust_bbox : str, optional Auto-adjust the bounding box for the output max_dpi : float, optional The maximum resolution to output images at. If no maximum is wanted, enter None or 0. format : str, optional By default, APLpy tries to guess the file format based on the file extension, but the format can also be specified explicitly. Should be one of 'eps', 'ps', 'pdf', 'svg', 'png'. """ if isinstance(filename, str) and format is None: format = os.path.splitext(filename)[1].lower()[1:] if dpi is None and format in ['eps', 'ps', 'pdf']: width = self.ax.get_position().width * self._figure.get_figwidth() interval = self.ax.get_xlim() nx = interval[1] - interval[0] if max_dpi: dpi = np.minimum(nx / width, max_dpi) else: dpi = nx / width log.info("Auto-setting resolution to %g dpi" % dpi) if adjust_bbox: self._figure.savefig(filename, dpi=dpi, transparent=transparent, bbox_inches='tight', format=format) else: self._figure.savefig(filename, dpi=dpi, transparent=transparent, format=format) def _initialize_view(self): self.ax.set_xlim(-0.5, self._wcs.nx - 0.5) self.ax.set_ylim(-0.5, self._wcs.ny - 0.5) def _get_invert_default(self): return self._figure.apl_grayscale_invert_default def _get_colormap_default(self): return self._figure.apl_colorscale_cmap_default @auto_refresh def set_theme(self, theme): """ Set the axes, ticks, grid, and image colors to a certain style (experimental). Parameters ---------- theme : str The theme to use. At the moment, this can be 'pretty' (for viewing on-screen) and 'publication' (which makes the ticks and grid black, and displays the image in inverted grayscale) """ if theme == 'pretty': self.frame.set_color('black') self.frame.set_linewidth(1.0) if self.ax.coords[self.x].ticks.get_tick_out(): self.ticks.set_color('black') else: self.ticks.set_color('white') self._figure.apl_grayscale_invert_default = False self._figure.apl_colorscale_cmap_default = 'viridis' if self.image: self.image.set_cmap(cmap=plt.cm.get_cmap('viridis')) elif theme == 'publication': self.frame.set_color('black') self.frame.set_linewidth(1.0) self.ticks.set_color('black') self.ticks.set_length(7) self._figure.apl_grayscale_invert_default = True self._figure.apl_colorscale_cmap_default = 'gist_heat' if self.image: self.image.set_cmap(cmap=plt.cm.get_cmap('gist_yarg')) def world2pixel(self, xw, yw, wcs=None): """ Convert world to pixel coordinates. Parameters ---------- xw : float or iterable x world coordinate yw : float or iterable y world coordinate Returns ------- xp : float or iterable x pixel coordinate yp : float or iterable y pixel coordinate """ if wcs is None: wcs = self._wcs return wcs.wcs_world2pix(xw, yw, 0) def pixel2world(self, xp, yp, wcs=None): """ Convert pixel to world coordinates. Parameters ---------- xp : float or iterable x pixel coordinate yp : float or iterable y pixel coordinate Returns ------- xw : float or iterable x world coordinate yw : float or iterable y world coordinate """ if wcs is None: wcs = self._wcs return wcs.wcs_pix2world(xp, yp, 0) @auto_refresh def add_grid(self): """ Add a coordinate to the current figure. Once this method has been run, a grid attribute becomes available, and can be used to control the aspect of the grid:: >>> f = aplpy.FITSFigure(...) >>> ... >>> f.add_grid() >>> f.grid.set_color('white') >>> f.grid.set_alpha(0.5) >>> ... """ if hasattr(self, 'grid'): raise Exception("Grid already exists") try: self.grid = Grid(self) self.grid.show() except Exception: del self.grid raise @auto_refresh def remove_grid(self): """ Removes the grid from the current figure. """ self.grid.hide() del self.grid @auto_refresh def add_beam(self, *args, **kwargs): """ Add a beam to the current figure. Once this method has been run, a beam attribute becomes available, and can be used to control the aspect of the beam:: >>> f = aplpy.FITSFigure(...) >>> ... >>> f.add_beam() >>> f.beam.set_color('white') >>> f.beam.set_hatch('+') >>> ... If more than one beam is added, the beam object becomes a list. In this case, to control the aspect of one of the beams, you will need to specify the beam index:: >>> ... >>> f.beam[2].set_hatch('/') >>> ... """ # Initalize the beam and set parameters b = Beam(self) b.show(*args, **kwargs) if hasattr(self, 'beam'): if type(self.beam) is list: self.beam.append(b) else: self.beam = [self.beam, b] else: self.beam = b @auto_refresh def remove_beam(self, beam_index=None): """ Removes the beam from the current figure. If more than one beam is present, the index of the beam should be specified using beam_index= """ if type(self.beam) is list: if beam_index is None: raise Exception("More than one beam present - use beam_index= to specify which one to remove") else: b = self.beam.pop(beam_index) b._remove() del b # If only one beam is present, remove containing list if len(self.beam) == 1: self.beam = self.beam[0] else: self.beam._remove() del self.beam @auto_refresh def add_scalebar(self, length, *args, **kwargs): """ Add a scalebar to the current figure. Once this method has been run, a scalebar attribute becomes available, and can be used to control the aspect of the scalebar:: >>> f = aplpy.FITSFigure(...) >>> ... >>> f.add_scalebar(0.01) # length has to be specified >>> f.scalebar.set_label('100 AU') >>> ... Parameters ---------- length : float, or quantity The length of the scalebar in degrees, an angular quantity, or angular unit label : str, optional Label to place below the scalebar corner : int, optional Where to place the scalebar. Acceptable values are:, 'left', 'right', 'top', 'bottom', 'top left', 'top right', 'bottom left' (default), 'bottom right' frame : str, optional Whether to display a frame behind the scalebar (default is False) kwargs Additional arguments are passed to the matplotlib Rectangle and Text classes. See the matplotlib documentation for more details. In cases where the same argument exists for the two objects, the argument is passed to both the Text and Rectangle instance. """ if hasattr(self, 'scalebar'): raise Exception("Scalebar already exists") try: self.scalebar = Scalebar(self) self.scalebar.show(length, *args, **kwargs) except Exception: del self.scalebar raise @auto_refresh def remove_scalebar(self): """ Removes the scalebar from the current figure. """ self.scalebar._remove() del self.scalebar @auto_refresh def add_colorbar(self, *args, **kwargs): """ Add a colorbar to the current figure. Once this method has been run, a colorbar attribute becomes available, and can be used to control the aspect of the colorbar:: >>> f = aplpy.FITSFigure(...) >>> ... >>> f.add_colorbar() >>> f.colorbar.set_width(0.3) >>> f.colorbar.set_location('top') >>> ... """ if hasattr(self, 'colorbar'): raise Exception("Colorbar already exists") if self.image is None: raise Exception("No image is shown, so a colorbar cannot be displayed") try: self.colorbar = Colorbar(self) self.colorbar.show(*args, **kwargs) except Exception: del self.colorbar raise @auto_refresh def remove_colorbar(self): """ Removes the colorbar from the current figure. """ self.colorbar._remove() del self.colorbar def close(self): """ Close the figure and free up the memory. """ plt.close(self._figure) savefig = save APLpy-2.0.3/aplpy/decorators.py0000644000077000000240000000555213432763221016275 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import threading from astropy.utils.decorators import wraps mydata = threading.local() __all__ = ['auto_refresh', 'fixdocstring'] def auto_refresh(f): @wraps(f) def wrapper(*args, **kwargs): if 'refresh' in kwargs: refresh = kwargs.pop('refresh') else: refresh = True # The following is necessary rather than using mydata.nesting = 0 at the # start of the file, because doing the latter caused issues with the Django # development server. mydata.nesting = getattr(mydata, 'nesting', 0) + 1 try: return f(*args, **kwargs) finally: mydata.nesting -= 1 if hasattr(args[0], '_figure'): if refresh and mydata.nesting == 0 and args[0]._figure._auto_refresh: args[0]._figure.canvas.draw() return wrapper doc = {} doc['size'] = """size : str or int or float, optional The size of the font. This can either be a numeric value (e.g. 12), giving the size in points, or one of 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', or 'xx-large'. """ doc['weight'] = """weight : str or int or float, optional The weight (or boldness) of the font. This can either be a numeric value in the range 0-1000 or one of 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'. """ doc['stretch'] = """stretch : str or int or float, optional The stretching (spacing between letters) for the font. This can either be a numeric value in the range 0-1000 or one of 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded' or 'ultra-expanded'. """ doc['family'] = """family : str, optional The family of the font to use. This can either be a generic font family name, either 'serif', 'sans-serif', 'cursive', 'fantasy', or 'monospace', or a list of font names in decreasing order of priority. """ doc['style'] = """style : str, optional The font style. This can be 'normal', 'italic' or 'oblique'. """ doc['variant'] = """variant : str, optional The font variant. This can be 'normal' or 'small-caps' """ def fixdocstring(func): lines = func.__doc__.split('\n') for i, line in enumerate(lines): if 'common:' in line: break header = lines[:i] footer = lines[i + 1:] indent = lines[i].index('common:') common = [] for item in lines[i].split(':')[1].split(','): if item.strip() in doc: common.append(" " * indent + doc[item.strip()].replace('\n', '\n' + " " * indent)) docstring = "\n".join(header + common + footer) func.__doc__ = docstring return func APLpy-2.0.3/aplpy/frame.py0000644000077000000240000000134013432763221015211 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from .decorators import auto_refresh class Frame(object): @auto_refresh def __init__(self, parent): self.ax = parent.ax @auto_refresh def set_linewidth(self, linewidth): """ Set line width of the frame. Parameters ---------- linewidth: The linewidth to use for the frame. """ self.ax.coords.frame.set_linewidth(linewidth) @auto_refresh def set_color(self, color): """ Set color of the frame. Parameters ---------- color: The color to use for the frame. """ self.ax.coords.frame.set_color(color) APLpy-2.0.3/aplpy/grid.py0000644000077000000240000000744713432763221015062 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from .decorators import auto_refresh class Grid(object): @auto_refresh def __init__(self, parent): # Save axes and wcs information self.ax = parent.ax self._wcs = parent._wcs self._figure = parent._figure self.x = parent.x self.y = parent.y self.x_unit = self._wcs.wcs.cunit[self.x] self.y_unit = self._wcs.wcs.cunit[self.y] self.grid_type = parent.grid_type # Set defaults self.default_color = 'white' self.default_alpha = 0.5 @auto_refresh def set_xspacing(self, xspacing): """ Set the grid line spacing in the longitudinal direction Parameters ---------- xspacing : float or str The spacing in the longitudinal direction. To set the spacing to be the same as the ticks, set this to 'tick' """ if xspacing == 'tick': self.ax.coords[self.x].grid(grid_type=self.grid_type) elif np.isreal(xspacing): self.ax.coords[self.x].set_ticks(spacing=xspacing * self.x_unit) else: raise ValueError("Grid spacing should be a scalar or 'tick'") @auto_refresh def set_yspacing(self, yspacing): """ Set the grid line spacing in the latitudinal direction Parameters ---------- yspacing : { float, str } The spacing in the latitudinal direction. To set the spacing to be the same as the ticks, set this to 'tick' """ if yspacing == 'tick': self.ax.coords[self.y].grid(grid_type=self.grid_type) elif np.isreal(yspacing): self.ax.coords[self.y].set_ticks(spacing=yspacing * self.y_unit) else: raise ValueError("Grid spacing should be a scalar or 'tick'") @auto_refresh def set_color(self, color): """ Set the color of the grid lines Parameters ---------- color : str The color of the grid lines """ self.default_color = color self.ax.coords[self.x].grid(color=color, grid_type=self.grid_type) self.ax.coords[self.y].grid(color=color, grid_type=self.grid_type) @auto_refresh def set_alpha(self, alpha): """ Set the alpha (transparency) of the grid lines Parameters ---------- alpha : float The alpha value of the grid. This should be a floating point value between 0 and 1, where 0 is completely transparent, and 1 is completely opaque. """ self.default_alpha = alpha self.ax.coords[self.x].grid(alpha=alpha, grid_type=self.grid_type) self.ax.coords[self.y].grid(alpha=alpha, grid_type=self.grid_type) @auto_refresh def set_linewidth(self, linewidth): self.ax.coords[self.x].grid(linewidth=linewidth, grid_type=self.grid_type) self.ax.coords[self.y].grid(linewidth=linewidth, grid_type=self.grid_type) @auto_refresh def set_linestyle(self, linestyle): self.ax.coords[self.x].grid(linestyle=linestyle, grid_type=self.grid_type) self.ax.coords[self.y].grid(linestyle=linestyle, grid_type=self.grid_type) @auto_refresh def show(self): self.ax.coords[self.x].grid(grid_type=self.grid_type, color=self.default_color, alpha=self.default_alpha) self.ax.coords[self.y].grid(grid_type=self.grid_type, color=self.default_color, alpha=self.default_alpha) @auto_refresh def hide(self): self.ax.coords[self.x].grid(draw_grid=False) self.ax.coords[self.y].grid(draw_grid=False) APLpy-2.0.3/aplpy/header.py0000644000077000000240000000447713432763221015365 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from astropy import log PLATE_CAREE_ERROR = """ Projection is Plate Caree (-CAR) and CRVALy is not zero. This can be interpreted either according to Wells (1981) or Calabretta (2002). The former defines the projection as rectilinear regardless of the value of CRVALy, whereas the latter defines the projection as rectilinear only when CRVALy is zero. You will need to specify the convention to assume by setting either convention='wells' or convention='calabretta' when initializing the FITSFigure instance. """.strip() def check(header, convention=None, dimensions=[0, 1]): ix = dimensions[0] + 1 iy = dimensions[1] + 1 # If header does not contain CTYPE keywords, assume that the WCS is # missing or incomplete, and replace it with a 1-to-1 pixel mapping if 'CTYPE%i' % ix not in header or 'CTYPE%i' % iy not in header: log.warning("No WCS information found in header - using pixel coordinates") header['CTYPE%i' % ix] = 'PIXEL' header['CTYPE%i' % iy] = 'PIXEL' header['CRVAL%i' % ix] = 0. header['CRVAL%i' % iy] = 0. header['CRPIX%i' % ix] = 0. header['CRPIX%i' % iy] = 0. header['CDELT%i' % ix] = 1. header['CDELT%i' % iy] = 1. if header['CTYPE%i' % ix][4:] == '-CAR' and header['CTYPE%i' % iy][4:] == '-CAR': if header['CTYPE%i' % ix][:4] == 'DEC-' or header['CTYPE%i' % ix][1:4] == 'LAT': ilat = ix elif header['CTYPE%i' % iy][:4] == 'DEC-' or header['CTYPE%i' % iy][1:4] == 'LAT': ilat = iy else: ilat = None if ilat is not None and header['CRVAL%i' % ilat] != 0: if convention == 'calabretta': pass # we don't need to do anything elif convention == 'wells': if 'CDELT%i' % ilat not in header: raise Exception("Need CDELT%i to be present for wells convention" % ilat) crpix = header['CRPIX%i' % ilat] crval = header['CRVAL%i' % ilat] cdelt = header['CDELT%i' % ilat] crpix = crpix - crval / cdelt header['CRPIX%i' % ilat] = crpix header['CRVAL%i' % ilat] = 0. else: raise Exception(PLATE_CAREE_ERROR) return header APLpy-2.0.3/aplpy/layers.py0000644000077000000240000001277413432763221015433 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from collections import OrderedDict from matplotlib.contour import ContourSet from matplotlib.collections import RegularPolyCollection, \ PatchCollection, CircleCollection, LineCollection from .regions import ArtistCollection from .decorators import auto_refresh class Layers(object): def __init__(self): pass def _layer_type(self, layer): if isinstance(self._layers[layer], ContourSet): return 'contour' elif isinstance(self._layers[layer], RegularPolyCollection): return 'collection' elif isinstance(self._layers[layer], PatchCollection): return 'collection' elif isinstance(self._layers[layer], CircleCollection): return 'collection' elif isinstance(self._layers[layer], LineCollection): return 'collection' elif isinstance(self._layers[layer], ArtistCollection): return 'collection' elif hasattr(self._layers[layer], 'remove') and hasattr(self._layers[layer], 'get_visible') and hasattr(self._layers[layer], 'set_visible'): return 'collection' else: raise Exception("Unknown layer type: " + str(type(self._layers[layer]))) def _initialize_layers(self): self._layers = OrderedDict() self._contour_counter = 0 self._vector_counter = 0 self._scatter_counter = 0 self._circle_counter = 0 self._ellipse_counter = 0 self._rectangle_counter = 0 self._linelist_counter = 0 self._region_counter = 0 self._label_counter = 0 self._poly_counter = 0 def list_layers(self): """ Print a list of layers to standard output. """ layers_list = [] for layer in self._layers: layer_type = self._layer_type(layer) if layer_type == 'contour': visible = self._layers[layer].collections[0].get_visible() elif layer_type == 'collection': visible = self._layers[layer].get_visible() layers_list.append({'name': layer, 'visible': visible}) n_layers = len(layers_list) if n_layers == 0: print("\n There are no layers in this figure") else: if n_layers == 1: print("\n There is one layer in this figure:\n") else: print("\n There are " + str(n_layers) + " layers in this figure:\n") for layer in layers_list: if layer['visible']: print(" -> " + layer['name']) else: print(" -> " + layer['name'] + " (hidden)") @auto_refresh def remove_layer(self, layer, raise_exception=True): """ Remove a layer. Parameters ---------- layer : str The name of the layer to remove """ if layer in self._layers: layer_type = self._layer_type(layer) if layer_type == 'contour': for contour in self._layers[layer].collections: contour.remove() self._layers.pop(layer) elif layer_type == 'collection': self._layers[layer].remove() self._layers.pop(layer) if (layer + '_txt') in self._layers: self._layers[layer + '_txt'].remove() self._layers.pop(layer + '_txt') else: if raise_exception: raise Exception("Layer " + layer + " does not exist") @auto_refresh def hide_layer(self, layer, raise_exception=True): """ Hide a layer. This differs from remove_layer in that if a layer is hidden it can be shown again using show_layer. Parameters ---------- layer : str The name of the layer to hide """ if layer in self._layers: layer_type = self._layer_type(layer) if layer_type == 'contour': for contour in self._layers[layer].collections: contour.set_visible(False) elif layer_type == 'collection': self._layers[layer].set_visible(False) else: if raise_exception: raise Exception("Layer " + layer + " does not exist") @auto_refresh def show_layer(self, layer, raise_exception=True): """ Show a layer. This shows a layer previously hidden with hide_layer Parameters ---------- layer : str The name of the layer to show """ if layer in self._layers: layer_type = self._layer_type(layer) if layer_type == 'contour': for contour in self._layers[layer].collections: contour.set_visible(True) elif layer_type == 'collection': self._layers[layer].set_visible(True) else: if raise_exception: raise Exception("Layer " + layer + " does not exist") def get_layer(self, layer, raise_exception=True): """ Return a layer object. Parameters ---------- layer : str The name of the layer to return """ if layer in self._layers: return self._layers[layer] else: if raise_exception: raise Exception("Layer " + layer + " does not exist") APLpy-2.0.3/aplpy/overlays.py0000644000077000000240000004311613432763221015772 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import warnings from mpl_toolkits.axes_grid1.anchored_artists import (AnchoredEllipse, AnchoredSizeBar) import numpy as np from matplotlib.font_manager import FontProperties from astropy import units as u from astropy.wcs.utils import proj_plane_pixel_scales from .decorators import auto_refresh corners = {} corners['top right'] = 1 corners['top left'] = 2 corners['bottom left'] = 3 corners['bottom right'] = 4 corners['right'] = 5 corners['left'] = 6 corners['bottom'] = 8 corners['top'] = 9 class Scalebar(object): def __init__(self, parent): # Retrieve info from parent figure self._ax = parent.ax self._wcs = parent._wcs self._figure = parent._figure self._dimensions = [parent.x, parent.y] # Initialize settings self._base_settings = {} self._scalebar_settings = {} self._label_settings = {} self._label_settings['fontproperties'] = FontProperties() # LAYOUT @auto_refresh def show(self, length, label=None, corner='bottom right', frame=False, borderpad=0.4, pad=0.5, **kwargs): """ Overlay a scale bar on the image. Parameters ---------- length : float, or quantity The length of the scalebar in degrees, an angular quantity, or angular unit label : str, optional Label to place below the scalebar corner : int, optional Where to place the scalebar. Acceptable values are:, 'left', 'right', 'top', 'bottom', 'top left', 'top right', 'bottom left' (default), 'bottom right' frame : str, optional Whether to display a frame behind the scalebar (default is False) kwargs Additional arguments are passed to the matplotlib Rectangle and Text classes. See the matplotlib documentation for more details. In cases where the same argument exists for the two objects, the argument is passed to both the Text and Rectangle instance. """ self._length = length self._base_settings['corner'] = corner self._base_settings['frame'] = frame self._base_settings['borderpad'] = borderpad self._base_settings['pad'] = pad if isinstance(length, u.Quantity): length = length.to(u.degree).value elif isinstance(length, u.Unit): length = length.to(u.degree) if self._wcs.is_celestial: pix_scale = proj_plane_pixel_scales(self._wcs) sx = pix_scale[self._dimensions[0]] sy = pix_scale[self._dimensions[1]] degrees_per_pixel = np.sqrt(sx * sy) else: raise ValueError("Cannot show scalebar when WCS is not celestial") length = length / degrees_per_pixel try: self._scalebar.remove() except Exception: pass if isinstance(corner, str): corner = corners[corner] self._scalebar = AnchoredSizeBar(self._ax.transData, length, label, corner, pad=pad, borderpad=borderpad, sep=5, frameon=frame) self._ax.add_artist(self._scalebar) self.set(**kwargs) @auto_refresh def _remove(self): self._scalebar.remove() @auto_refresh def hide(self): """ Hide the scalebar. """ try: self._scalebar.remove() except Exception: pass @auto_refresh def set_length(self, length): """ Set the length of the scale bar. """ self.show(length, **self._base_settings) self._set_scalebar_properties(**self._scalebar_settings) self._set_label_properties(**self._scalebar_settings) @auto_refresh def set_label(self, label): """ Set the label of the scale bar. """ self._set_label_properties(text=label) @auto_refresh def set_corner(self, corner): """ Set where to place the scalebar. Acceptable values are 'left', 'right', 'top', 'bottom', 'top left', 'top right', 'bottom left' (default), and 'bottom right'. """ self._base_settings['corner'] = corner self.show(self._length, **self._base_settings) self._set_scalebar_properties(**self._scalebar_settings) self._set_label_properties(**self._scalebar_settings) @auto_refresh def set_frame(self, frame): """ Set whether to display a frame around the scalebar. """ self._base_settings['frame'] = frame self.show(self._length, **self._base_settings) self._set_scalebar_properties(**self._scalebar_settings) self._set_label_properties(**self._scalebar_settings) # APPEARANCE @auto_refresh def set_linewidth(self, linewidth): """ Set the linewidth of the scalebar, in points. """ self._set_scalebar_properties(linewidth=linewidth) @auto_refresh def set_linestyle(self, linestyle): """ Set the linestyle of the scalebar. Should be one of 'solid', 'dashed', 'dashdot', or 'dotted'. """ self._set_scalebar_properties(linestyle=linestyle) @auto_refresh def set_alpha(self, alpha): """ Set the alpha value (transparency). This should be a floating point value between 0 and 1. """ self._set_scalebar_properties(alpha=alpha) self._set_label_properties(alpha=alpha) @auto_refresh def set_color(self, color): """ Set the label and scalebar color. """ self._set_scalebar_properties(color=color) self._set_label_properties(color=color) @auto_refresh def set_font(self, family=None, style=None, variant=None, stretch=None, weight=None, size=None, fontproperties=None): """ Set the font of the tick labels Parameters ---------- common: family, style, variant, stretch, weight, size, fontproperties Notes ----- Default values are set by matplotlib or previously set values if set_font has already been called. Global default values can be set by editing the matplotlibrc file. """ if family: self._label_settings['fontproperties'].set_family(family) if style: self._label_settings['fontproperties'].set_style(style) if variant: self._label_settings['fontproperties'].set_variant(variant) if stretch: self._label_settings['fontproperties'].set_stretch(stretch) if weight: self._label_settings['fontproperties'].set_weight(weight) if size: self._label_settings['fontproperties'].set_size(size) if fontproperties: self._label_settings['fontproperties'] = fontproperties self._set_label_properties(fontproperties=self._label_settings['fontproperties']) @auto_refresh def _set_label_properties(self, **kwargs): """ Modify the scalebar label properties. All arguments are passed to the matplotlib Text class. See the matplotlib documentation for more details. """ for kwarg, val in kwargs.items(): try: # Only set attributes that exist kvpair = {kwarg: val} self._scalebar.txt_label.get_children()[0].set(**kvpair) self._label_settings[kwarg] = val except AttributeError: warnings.warn("Text labels do not have attribute {0}. Skipping.".format(kwarg)) @auto_refresh def _set_scalebar_properties(self, **kwargs): """ Modify the scalebar properties. All arguments are passed to the matplotlib Rectangle class. See the matplotlib documentation for more details. """ for kwarg, val in kwargs.items(): try: kvpair = {kwarg: val} self._scalebar.size_bar.get_children()[0].set(**kvpair) self._scalebar_settings[kwarg] = val except AttributeError: warnings.warn("Scalebar does not have attribute {0}. Skipping.".format(kwarg)) @auto_refresh def set(self, **kwargs): """ Modify the scalebar and scalebar properties. All arguments are passed to the matplotlib Rectangle and Text classes. See the matplotlib documentation for more details. In cases where the same argument exists for the two objects, the argument is passed to both the Text and Rectangle instance. """ for kwarg in kwargs: kwargs_single = {kwarg: kwargs[kwarg]} try: self._set_label_properties(**kwargs_single) except (AttributeError, TypeError): pass try: self._set_scalebar_properties(**kwargs_single) except (AttributeError, TypeError): pass # DEPRECATED @auto_refresh def set_font_family(self, family): warnings.warn("scalebar.set_font_family is deprecated - use scalebar.set_font instead", DeprecationWarning) self.set_font(family=family) @auto_refresh def set_font_weight(self, weight): warnings.warn("scalebar.set_font_weight is deprecated - use scalebar.set_font instead", DeprecationWarning) self.set_font(weight=weight) @auto_refresh def set_font_size(self, size): warnings.warn("scalebar.set_font_size is deprecated - use scalebar.set_font instead", DeprecationWarning) self.set_font(size=size) @auto_refresh def set_font_style(self, style): warnings.warn("scalebar.set_font_style is deprecated - use scalebar.set_font instead", DeprecationWarning) self.set_font(style=style) # For backward-compatibility ScaleBar = Scalebar class Beam(object): def __init__(self, parent): # Retrieve info from parent figure self._figure = parent._figure self._header = parent._header self._ax = parent.ax self._wcs = parent._wcs self._dimensions = [parent.x, parent.y] # Initialize settings self._base_settings = {} self._beam_settings = {} # LAYOUT @auto_refresh def show(self, major='BMAJ', minor='BMIN', angle='BPA', corner='bottom left', frame=False, borderpad=0.4, pad=0.5, **kwargs): """ Display the beam shape and size for the primary image. By default, this method will search for the BMAJ, BMIN, and BPA keywords in the FITS header to set the major and minor axes and the position angle on the sky. Parameters ---------- major : float, quantity or unit, optional Major axis of the beam in degrees or an angular quantity (overrides BMAJ if present) minor : float, quantity or unit, optional Minor axis of the beam in degrees or an angular quantity (overrides BMIN if present) angle : float, quantity or unit, optional Position angle of the beam on the sky in degrees or an angular quantity (overrides BPA if present) in the anticlockwise direction. corner : int, optional The beam location. Acceptable values are 'left', 'right', 'top', 'bottom', 'top left', 'top right', 'bottom left' (default), and 'bottom right'. frame : str, optional Whether to display a frame behind the beam (default is False) kwargs Additional arguments are passed to the matplotlib Ellipse class. See the matplotlib documentation for more details. """ if isinstance(major, str): major = self._header[major] if isinstance(minor, str): minor = self._header[minor] if isinstance(angle, str): angle = self._header[angle] if isinstance(major, u.Quantity): major = major.to(u.degree).value elif isinstance(major, u.Unit): major = major.to(u.degree) if isinstance(minor, u.Quantity): minor = minor.to(u.degree).value elif isinstance(minor, u.Unit): minor = minor.to(u.degree) if isinstance(angle, u.Quantity): angle = angle.to(u.degree).value elif isinstance(angle, u.Unit): angle = angle.to(u.degree) if self._wcs.is_celestial: pix_scale = proj_plane_pixel_scales(self._wcs) sx = pix_scale[self._dimensions[0]] sy = pix_scale[self._dimensions[1]] degrees_per_pixel = np.sqrt(sx * sy) else: raise ValueError("Cannot show beam when WCS is not celestial") self._base_settings['minor'] = minor self._base_settings['major'] = major self._base_settings['angle'] = angle self._base_settings['corner'] = corner self._base_settings['frame'] = frame self._base_settings['borderpad'] = borderpad self._base_settings['pad'] = pad minor /= degrees_per_pixel major /= degrees_per_pixel try: self._beam.remove() except Exception: pass if isinstance(corner, str): corner = corners[corner] self._beam = AnchoredEllipse(self._ax.transData, width=minor, height=major, angle=angle, loc=corner, pad=pad, borderpad=borderpad, frameon=frame) self._ax.add_artist(self._beam) self.set(**kwargs) @auto_refresh def _remove(self): self._beam.remove() @auto_refresh def hide(self): """ Hide the beam """ try: self._beam.remove() except Exception: pass @auto_refresh def set_major(self, major): """ Set the major axis of the beam, in degrees. """ self._base_settings['major'] = major self.show(**self._base_settings) self.set(**self._beam_settings) @auto_refresh def set_minor(self, minor): """ Set the minor axis of the beam, in degrees. """ self._base_settings['minor'] = minor self.show(**self._base_settings) self.set(**self._beam_settings) @auto_refresh def set_angle(self, angle): """ Set the position angle of the beam on the sky, in degrees. """ self._base_settings['angle'] = angle self.show(**self._base_settings) self.set(**self._beam_settings) @auto_refresh def set_corner(self, corner): """ Set the beam location. Acceptable values are 'left', 'right', 'top', 'bottom', 'top left', 'top right', 'bottom left' (default), and 'bottom right'. """ self._base_settings['corner'] = corner self.show(**self._base_settings) self.set(**self._beam_settings) @auto_refresh def set_frame(self, frame): """ Set whether to display a frame around the beam. """ self._base_settings['frame'] = frame self.show(**self._base_settings) self.set(**self._beam_settings) @auto_refresh def set_borderpad(self, borderpad): """ Set the amount of padding within the beam object, relative to the canvas size. """ self._base_settings['borderpad'] = borderpad self.show(**self._base_settings) self.set(**self._beam_settings) @auto_refresh def set_pad(self, pad): """ Set the amount of padding between the beam object and the image corner/edge, relative to the canvas size. """ self._base_settings['pad'] = pad self.show(**self._base_settings) self.set(**self._beam_settings) # APPEARANCE @auto_refresh def set_alpha(self, alpha): """ Set the alpha value (transparency). This should be a floating point value between 0 and 1. """ self.set(alpha=alpha) @auto_refresh def set_color(self, color): """ Set the beam color. """ self.set(color=color) @auto_refresh def set_edgecolor(self, edgecolor): """ Set the color for the edge of the beam. """ self.set(edgecolor=edgecolor) @auto_refresh def set_facecolor(self, facecolor): """ Set the color for the interior of the beam. """ self.set(facecolor=facecolor) @auto_refresh def set_linestyle(self, linestyle): """ Set the line style for the edge of the beam. This should be one of 'solid', 'dashed', 'dashdot', or 'dotted'. """ self.set(linestyle=linestyle) @auto_refresh def set_linewidth(self, linewidth): """ Set the line width for the edge of the beam, in points. """ self.set(linewidth=linewidth) @auto_refresh def set_hatch(self, hatch): """ Set the hatch pattern. This should be one of '/', '\', '|', '-', '+', 'x', 'o', 'O', '.', or '*'. """ self.set(hatch=hatch) @auto_refresh def set(self, **kwargs): """ Modify the beam properties. All arguments are passed to the matplotlib Ellipse class. See the matplotlib documentation for more details. """ for kwarg in kwargs: self._beam_settings[kwarg] = kwargs[kwarg] self._beam.ellipse.set(**kwargs) APLpy-2.0.3/aplpy/regions.py0000644000077000000240000001353313432763221015574 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from astropy import log from astropy import wcs from .decorators import auto_refresh class Regions(object): """ Regions sub-class of APLpy. Used for overplotting various shapes and annotations on APLpy fitsfigures. Example: # DS9 region file called "test.reg" # (the coordinates are around l=28 in the Galactic Plane) # Filename: test.fits fk5 box(18:42:48.262,-04:01:17.91,505.668",459.714",0) # color=red dash=1 point(18:42:51.797,-03:59:44.82) # point=x color=red dash=1 point(18:42:50.491,-04:03:09.39) # point=box color=red dash=1 # vector(18:42:37.433,-04:02:10.77,107.966",115.201) vector=1 color=red dash=1 ellipse(18:42:37.279,-04:02:11.92,26.4336",40.225",0) # color=red dash=1 polygon(18:42:59.016,-03:58:22.06,18:42:58.219,-03:58:11.30,18:42:57.403,-03:58:35.86,18:42:58.094,-03:58:57.69,18:42:59.861,-03:58:41.60,18:42:59.707,-03:58:23.21) # color=red dash=1 point(18:42:52.284,-04:00:02.80) # point=diamond color=red dash=1 point(18:42:46.561,-03:58:01.57) # point=circle color=red dash=1 point(18:42:42.615,-03:58:25.84) # point=cross color=red dash=1 point(18:42:42.946,-04:01:44.74) # point=arrow color=red dash=1 point(18:42:41.961,-03:57:26.16) # point=boxcircle color=red dash=1 # text(18:42:41.961,-03:57:26.16) text={This is text} color=red Code: import aplpy import regions ff = aplpy.FITSFigure("test.fits") ff.show_grayscale() ff.show_regions('test.reg') """ @auto_refresh def show_regions(self, region_file, layer=False, **kwargs): """ Overplot regions as specified in the region file. Parameters ---------- region_file: string or pyregion.ShapeList Path to a ds9 regions file or a ShapeList already read in by pyregion. layer: str, optional The name of the layer kwargs Additional keyword arguments, e.g. zorder, will be passed to the ds9 call and onto the patchcollections. """ PC, TC = ds9(region_file, flatten_header(self._header), **kwargs) PC.add_to_axes(self.ax) TC.add_to_axes(self.ax) if layer: region_set_name = layer else: self._region_counter += 1 region_set_name = 'region_set_' + str(self._region_counter) self._layers[region_set_name] = PC self._layers[region_set_name + "_txt"] = TC def ds9(region_file, header, zorder=3, **kwargs): """ Wrapper to return a PatchCollection given a ds9 region file and a fits header. zorder - defaults to 3 so that regions are on top of contours """ try: import pyregion except Exception: raise ImportError("The pyregion package is required to load region files") # read region file if isinstance(region_file, str): rr = pyregion.open(region_file) elif isinstance(region_file, pyregion.ShapeList): rr = region_file else: raise Exception("Invalid type for region_file: %s - should be string or pyregion.ShapeList" % type(region_file)) if isinstance(header, wcs.WCS): header = header.to_header() # convert coordinates to image coordinates rrim = rr.as_imagecoord(header) # pyregion and aplpy both correct for the FITS standard origin=1,1 # need to avoid double-correcting. Also, only some items in `coord_list` # are pixel coordinates, so which ones should be corrected depends on the # shape. for r in rrim: if r.name == 'polygon': correct = range(len(r.coord_list)) elif r.name == 'line': correct = range(4) elif r.name in ['rotbox', 'box', 'ellipse', 'annulus', 'circle', 'panda', 'pie', 'epanda', 'text', 'point', 'vector']: correct = range(2) else: log.warning("Unknown region type '{0}' - please report to the developers") correct = range(2) for i in correct: r.coord_list[i] += 1 if 'text_offset' in kwargs: text_offset = kwargs['text_offset'] del kwargs['text_offset'] else: text_offset = 5.0 # grab the shapes to overplot pp, aa = rrim.get_mpl_patches_texts(text_offset=text_offset) PC = ArtistCollection(pp, **kwargs) # preserves line style (dashed) TC = ArtistCollection(aa, **kwargs) PC.set_zorder(zorder) TC.set_zorder(zorder) return PC, TC class ArtistCollection(): """ Matplotlib collections can't handle Text. This is a barebones collection for text objects that supports removing and making (in)visible """ def __init__(self, artistlist): """ Pass in a list of matplotlib.text.Text objects (or possibly any matplotlib Artist will work) """ self.artistlist = artistlist def remove(self): for T in self.artistlist: T.remove() def add_to_axes(self, ax): for T in self.artistlist: ax.add_artist(T) def get_visible(self): visible = True for T in self.artistlist: if not T.get_visible(): visible = False return visible def set_visible(self, visible=True): for T in self.artistlist: T.set_visible(visible) def set_zorder(self, zorder): for T in self.artistlist: T.set_zorder(zorder) def flatten_header(header): """ Attempt to turn an N-dimensional fits header into a 2-dimensional header Turns all CRPIX[>2] etc. into new keywords with suffix 'A' """ orig_wcs = wcs.WCS(header) newheader = orig_wcs.celestial.to_header() newheader['NAXIS'] = 2 newheader['NAXIS1'] = header['NAXIS{0}'.format(orig_wcs.wcs.lng + 1)] newheader['NAXIS2'] = header['NAXIS{0}'.format(orig_wcs.wcs.lat + 1)] return newheader APLpy-2.0.3/aplpy/rgb.py0000644000077000000240000002533113432763221014677 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from distutils import version import os import warnings import numpy as np from astropy import log from astropy.io import fits from astropy.coordinates import ICRS from astropy.visualization import AsymmetricPercentileInterval, simple_norm from reproject import reproject_interp from reproject.mosaicking import find_optimal_celestial_wcs def _data_stretch(image, vmin=None, vmax=None, pmin=0.25, pmax=99.75, stretch='linear', vmid=None, exponent=2): if vmin is None or vmax is None: interval = AsymmetricPercentileInterval(pmin, pmax, n_samples=10000) try: vmin_auto, vmax_auto = interval.get_limits(image) except IndexError: # no valid values vmin_auto = vmax_auto = 0 if vmin is None: log.info("vmin = %10.3e (auto)" % vmin_auto) vmin = vmin_auto else: log.info("vmin = %10.3e" % vmin) if vmax is None: log.info("vmax = %10.3e (auto)" % vmax_auto) vmax = vmax_auto else: log.info("vmax = %10.3e" % vmax) if stretch == 'arcsinh': stretch = 'asinh' normalizer = simple_norm(image, stretch=stretch, power=exponent, asinh_a=vmid, min_cut=vmin, max_cut=vmax, clip=False) data = normalizer(image, clip=True).filled(0) data = np.nan_to_num(data) data = np.clip(data * 255., 0., 255.) return data.astype(np.uint8) def make_rgb_image(data, output, indices=(0, 1, 2), vmin_r=None, vmax_r=None, pmin_r=0.25, pmax_r=99.75, stretch_r='linear', vmid_r=None, exponent_r=2, vmin_g=None, vmax_g=None, pmin_g=0.25, pmax_g=99.75, stretch_g='linear', vmid_g=None, exponent_g=2, vmin_b=None, vmax_b=None, pmin_b=0.25, pmax_b=99.75, stretch_b='linear', vmid_b=None, exponent_b=2, make_nans_transparent=False, embed_avm_tags=True): """ Make an RGB image from a FITS RGB cube or from three FITS files. Parameters ---------- data : str or tuple or list If a string, this is the filename of an RGB FITS cube. If a tuple or list, this should give the filename of three files to use for the red, green, and blue channel. output : str The output filename. The image type (e.g. PNG, JPEG, TIFF, ...) will be determined from the extension. Any image type supported by the Python Imaging Library can be used. indices : tuple, optional If data is the filename of a FITS cube, these indices are the positions in the third dimension to use for red, green, and blue respectively. The default is to use the first three indices. vmin_r, vmin_g, vmin_b : float, optional Minimum pixel value to use for the red, green, and blue channels. If set to None for a given channel, the minimum pixel value for that channel is determined using the corresponding pmin_x argument (default). vmax_r, vmax_g, vmax_b : float, optional Maximum pixel value to use for the red, green, and blue channels. If set to None for a given channel, the maximum pixel value for that channel is determined using the corresponding pmax_x argument (default). pmin_r, pmin_r, pmin_g : float, optional Percentile values used to determine for a given channel the minimum pixel value to use for that channel if the corresponding vmin_x is set to None. The default is 0.25% for all channels. pmax_r, pmax_g, pmax_b : float, optional Percentile values used to determine for a given channel the maximum pixel value to use for that channel if the corresponding vmax_x is set to None. The default is 99.75% for all channels. stretch_r, stretch_g, stretch_b : { 'linear', 'log', 'sqrt', 'arcsinh', 'power' } The stretch function to use for the different channels. vmid_r, vmid_g, vmid_b : float, optional Baseline values used for the log and arcsinh stretches. If set to None, this is set to zero for log stretches and to vmin - (vmax - vmin) / 30. for arcsinh stretches exponent_r, exponent_g, exponent_b : float, optional If stretch_x is set to 'power', this is the exponent to use. make_nans_transparent : bool, optional If set AND output is png, will add an alpha layer that sets pixels containing a NaN to transparent. embed_avm_tags : bool, optional Whether to embed AVM tags inside the image - this can only be done for JPEG and PNG files, and only if PyAVM is installed. """ try: from PIL import Image except ImportError: try: import Image except ImportError: raise ImportError("The Python Imaging Library (PIL) is required to make an RGB image") if isinstance(data, str): image = fits.getdata(data) image_r = image[indices[0], :, :] image_g = image[indices[1], :, :] image_b = image[indices[2], :, :] # Read in header header = fits.getheader(data) # Remove information about third dimension header['NAXIS'] = 2 for key in ['NAXIS', 'CTYPE', 'CRPIX', 'CRVAL', 'CUNIT', 'CDELT', 'CROTA']: for coord in range(3, 6): name = key + str(coord) if name in header: header.__delitem__(name) elif (type(data) == list or type(data) == tuple) and len(data) == 3: filename_r, filename_g, filename_b = data image_r = fits.getdata(filename_r) image_g = fits.getdata(filename_g) image_b = fits.getdata(filename_b) # Read in header header = fits.getheader(filename_r) else: raise Exception("data should either be the filename of a FITS cube or a list/tuple of three images") # are we making a transparent layer? do_alpha = make_nans_transparent and output.lower().endswith('.png') if do_alpha: log.info("Making alpha layer") # initialize alpha layer image_alpha = np.empty_like(image_r, dtype=np.uint8) image_alpha[:] = 255 # look for nans in images for im in [image_r, image_g, image_b]: image_alpha[np.isnan(im)] = 0 log.info("Red:") image_r = Image.fromarray(_data_stretch(image_r, vmin=vmin_r, vmax=vmax_r, pmin=pmin_r, pmax=pmax_r, stretch=stretch_r, vmid=vmid_r, exponent=exponent_r)) log.info("Green:") image_g = Image.fromarray(_data_stretch(image_g, vmin=vmin_g, vmax=vmax_g, pmin=pmin_g, pmax=pmax_g, stretch=stretch_g, vmid=vmid_g, exponent=exponent_g)) log.info("Blue:") image_b = Image.fromarray(_data_stretch(image_b, vmin=vmin_b, vmax=vmax_b, pmin=pmin_b, pmax=pmax_b, stretch=stretch_b, vmid=vmid_b, exponent=exponent_b)) img = Image.merge("RGB", (image_r, image_g, image_b)) if do_alpha: # convert to RGBA and add alpha layer image_alpha = Image.fromarray(image_alpha) img.convert("RGBA") img.putalpha(image_alpha) img = img.transpose(Image.FLIP_TOP_BOTTOM) img.save(output) if embed_avm_tags: try: import pyavm except ImportError: warnings.warn("PyAVM 0.9.1 or later is not installed, so AVM tags will not be embedded in RGB image") return if version.LooseVersion(pyavm.__version__) < version.LooseVersion('0.9.1'): warnings.warn("PyAVM 0.9.1 or later is not installed, so AVM tags will not be embedded in RGB image") return from pyavm import AVM if output.lower().endswith(('.jpg', '.jpeg', '.png')): avm = AVM.from_header(header) avm.embed(output, output) else: warnings.warn("AVM tags will not be embedded in RGB image, as only JPEG and PNG files are supported") def make_rgb_cube(files, output, north=True): """ Make an RGB data cube from a list of three FITS images. This method can read in three FITS files with different projections/sizes/resolutions and uses the `reproject `_ package to reproject them all to the same projection. Two files are produced by this function. The first is a three-dimensional FITS cube with a filename give by ``output``, where the third dimension contains the different channels. The second is a two-dimensional FITS image with a filename given by ``output`` with a `_2d` suffix. This file contains the mean of the different channels, and is required as input to FITSFigure if show_rgb is subsequently used to show a color image generated from the FITS cube (to provide the correct WCS information to FITSFigure). Parameters ---------- files : tuple or list A list of the filenames of three FITS filename to reproject. The order is red, green, blue. output : str The filename of the output RGB FITS cube. north : bool, optional Whether to rotate the image so that north is up. By default, this is assumed to be 'north' in the ICRS frame, but you can also pass any astropy :class:`~astropy.coordinates.BaseCoordinateFrame` to indicate to use the north of that frame. """ # Check that input files exist for f in files: if not os.path.exists(f): raise Exception("File does not exist : " + f) if north is not False: frame = ICRS() if north is True else north auto_rotate = False else: frame = None auto_rotate = True # Find optimal WCS and shape based on input images wcs, shape = find_optimal_celestial_wcs(files, frame=frame, auto_rotate=auto_rotate) header = wcs.to_header() # Generate empty datacube image_cube = np.zeros((len(files),) + shape, dtype=np.float32) # Loop through files and reproject for i, filename in enumerate(files): image_cube[i, :, :] = reproject_interp(filename, wcs, shape_out=shape)[0] # Write out final cube fits.writeto(output, image_cube, header, overwrite=True) # Write out collapsed version of cube fits.writeto(output.replace('.fits', '_2d.fits'), np.mean(image_cube, axis=0), header, overwrite=True) APLpy-2.0.3/aplpy/slicer.py0000644000077000000240000000424513432763221015407 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division def slice_hypercube(data, header, dimensions=[0, 1], slices=[]): """ Extract a slice from an n-dimensional HDU data/header pair, and return the new data (without changing the header). """ if type(slices) == int: slices = (slices, ) else: slices = slices[:] shape = data.shape if len(shape) < 2: raise Exception("FITS file does not have enough dimensions") elif len(shape) == 2: wcsaxes_slices = ('x', 'y') if dimensions[1] < dimensions[0]: data = data.transpose() wcsaxes_slices = ('y', 'x') return data, wcsaxes_slices else: if slices: wcsaxes_slices = slices[:] if dimensions[0] < dimensions[1]: slices.insert(dimensions[0], slice(None, None, None)) slices.insert(dimensions[1], slice(None, None, None)) wcsaxes_slices.insert(dimensions[0], 'x') wcsaxes_slices.insert(dimensions[1], 'y') else: slices.insert(dimensions[1], slice(None, None, None)) slices.insert(dimensions[0], slice(None, None, None)) wcsaxes_slices.insert(dimensions[1], 'y') wcsaxes_slices.insert(dimensions[0], 'x') if type(slices) == list: slices = tuple(slices) wcsaxes_slices = tuple(wcsaxes_slices) data = data[slices[::-1]] if dimensions[1] < dimensions[0]: data = data.transpose() else: message = """ Attempted to read in %i-dimensional FITS cube, but dimensions and slices were not specified. Please specify these using the dimensions= and slices= argument. The cube dimensions are:\n\n""" % len(shape) for i in range(1, len(shape) + 1): message += " " * 10 message += " %i %s %i\n" % (i - 1, header["CTYPE%i" % i], header["NAXIS%i" % i]) raise Exception(message) return data, wcsaxes_slices APLpy-2.0.3/aplpy/tests/0000755000077000000240000000000013432765724014723 5ustar tomstaff00000000000000APLpy-2.0.3/aplpy/tests/__init__.py0000644000077000000240000000026613432763221017026 0ustar tomstaff00000000000000import matplotlib MPL_VERSION = matplotlib.__version__ ROOT = "https://aplpy.github.io/aplpy-data/2.x/2018-10-28T17:43:23.106" baseline_dir = ROOT + '/' + MPL_VERSION[:3] + '.x/' APLpy-2.0.3/aplpy/tests/coveragerc0000644000077000000240000000140013404171222016740 0ustar tomstaff00000000000000[run] source = {packagename} omit = {packagename}/_astropy_init* {packagename}/conftest* {packagename}/cython_version* {packagename}/setup_package* {packagename}/*/setup_package* {packagename}/*/*/setup_package* {packagename}/tests/* {packagename}/*/tests/* {packagename}/*/*/tests/* {packagename}/version* [report] exclude_lines = # Have to re-enable the standard pragma pragma: no cover # Don't complain about packages we have installed except ImportError # Don't complain if tests don't hit assertions raise AssertionError raise NotImplementedError # Don't complain about script hooks def main\(.*\): # Ignore branches that don't pertain to this version of Python pragma: py{ignore_python_version}APLpy-2.0.3/aplpy/tests/data/0000755000077000000240000000000013432765724015634 5ustar tomstaff00000000000000APLpy-2.0.3/aplpy/tests/data/2d_fits/0000755000077000000240000000000013432765724017166 5ustar tomstaff00000000000000APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_AIR.hdr0000644000077000000240000000166713404171222021177 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---AIR' CRPIX1 = 8.339330824421999 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--AIR' CRPIX2 = -234.7545010835 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole PV2_1 = 4.500000000000E+01 / Projection parameter 1 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_AIT.hdr0000644000077000000240000000157713404171222021201 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---AIT' CRPIX1 = 7.115850027049 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--AIT' CRPIX2 = -246.2317116277 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_ARC.hdr0000644000077000000240000000157713404171222021171 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---ARC' CRPIX1 = 5.082274450444 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--ARC' CRPIX2 = -246.941901905 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_AZP.hdr0000644000077000000240000000175713404171222021216 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---AZP' CRPIX1 = -11.34948542534 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--AZP' CRPIX2 = -254.1100848779 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole PV2_1 = 2.000000000000E+00 / Projection parameter 1 PV2_2 = 3.000000000000E+01 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_BON.hdr0000644000077000000240000000166713404171222021202 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---BON' CRPIX1 = -33.0741266819 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--BON' CRPIX2 = -243.1263982441 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole PV2_1 = 4.500000000000E+01 / Projection parameter 1 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_CAR.hdr0000644000077000000240000000157713404171222021171 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---CAR' CRPIX1 = 7.527038199745 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--CAR' CRPIX2 = -248.2173814412 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_CEA.hdr0000644000077000000240000000166713404171222021154 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---CEA' CRPIX1 = 7.688571124876 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--CEA' CRPIX2 = -248.2173814412 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole PV2_1 = 1.000000000000E+00 / Projection parameter 1 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_COD.hdr0000644000077000000240000000175713404171222021171 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---COD' CRPIX1 = 15.61302682707 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--COD' CRPIX2 = -215.3431714695 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -4.500000000000E+01 / Native latitude of celestial pole PV2_1 = 4.500000000000E+01 / Projection parameter 1 PV2_2 = 2.500000000000E+01 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_COE.hdr0000644000077000000240000000175713404171222021172 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---COE' CRPIX1 = -14.35249668783 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--COE' CRPIX2 = -223.0375366798 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 4.500000000000E+01 / Native latitude of celestial pole PV2_1 = -4.500000000000E+01 / Projection parameter 1 PV2_2 = 2.500000000000E+01 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_COO.hdr0000644000077000000240000000175713404171222021204 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---COO' CRPIX1 = 12.92640949564 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--COO' CRPIX2 = -213.6486051767 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -4.500000000000E+01 / Native latitude of celestial pole PV2_1 = 4.500000000000E+01 / Projection parameter 1 PV2_2 = 2.500000000000E+01 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_COP.hdr0000644000077000000240000000175713404171222021205 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---COP' CRPIX1 = 15.05768272737 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--COP' CRPIX2 = -215.1923139086 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -4.500000000000E+01 / Native latitude of celestial pole PV2_1 = 4.500000000000E+01 / Projection parameter 1 PV2_2 = 2.500000000000E+01 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_CSC.hdr0000644000077000000240000000157713404171222021174 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---CSC' CRPIX1 = -7.043520126533 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--CSC' CRPIX2 = -268.6531829635 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_CYP.hdr0000644000077000000240000000175713404171222021217 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---CYP' CRPIX1 = 20.56099939277 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--CYP' CRPIX2 = -147.1055514007 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole PV2_1 = 1.000000000000E+00 / Projection parameter 1 PV2_2 = 7.071067811870E-01 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_HPX.hdr0000644000077000000240000000240313432273771021225 0ustar tomstaff00000000000000SIMPLE = T / file does conform to FITS standard BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 / number of data axes NAXIS1 = 192 / length of data axis 1 NAXIS2 = 192 / length of data axis 2 EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'Astronomy COMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H BUNIT = 'Jy/beam ' / Pixel value is surface brightness CTYPE1 = 'RA---HPX' CRPIX1 = -8.21754831338666 CDELT1 = -0.0666666666666667 CRVAL1 = 0. CTYPE2 = 'DEC--HPX' CRPIX2 = -248.217381441188 CDELT2 = 0.0666666666666667 CRVAL2 = -90. LONPOLE = 180. / Native longitude of celestial pole LATPOLE = 0. / Native latitude of celestial pole RADESYS = 'FK5 ' / Equatorial coordinate system EQUINOX = 2000.0 / Equinox of equatorial coordinates BMAJ = 0.24000 / Beam major axis in degrees BMIN = 0.24000 / Beam minor axis in degrees BPA = 0.0 / Beam position angle in degrees APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_MER.hdr0000644000077000000240000000157713404171222021207 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---MER' CRPIX1 = 7.364978412864 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--MER' CRPIX2 = -248.2173814412 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_MOL.hdr0000644000077000000240000000157713404171222021213 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---MOL' CRPIX1 = -2.310670994515 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--MOL' CRPIX2 = -212.7655947497 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_NCP.hdr0000644000077000000240000000175713404171222021204 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---SIN' CRPIX1 = 7.688572009351 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--SIN' CRPIX2 = -237.1895431541 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole PV2_1 = 0.000000000000E+00 / Projection parameter 1 PV2_2 = -1.216796447506E-08 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_PAR.hdr0000644000077000000240000000157713404171222021206 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---PAR' CRPIX1 = 3.322937769653 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--PAR' CRPIX2 = -246.5551494284 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_PCO.hdr0000644000077000000240000000157713404171222021205 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---PCO' CRPIX1 = 0.3620782775517 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--PCO' CRPIX2 = -246.2486098896 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_QSC.hdr0000644000077000000240000000157713404171222021212 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---QSC' CRPIX1 = -8.258194421088 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--QSC' CRPIX2 = -258.3408175994 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_SFL.hdr0000644000077000000240000000157713404171222021210 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---SFL' CRPIX1 = 7.527038199745 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--SFL' CRPIX2 = -246.3483086237 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_SIN.hdr0000644000077000000240000000175713404171222021215 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---SIN' CRPIX1 = 7.688571124876 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--SIN' CRPIX2 = -237.1895431541 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole PV2_1 = 0.000000000000E+00 / Projection parameter 1 PV2_2 = 0.000000000000E+00 / Projection parameter 2 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_STG.hdr0000644000077000000240000000157713404171222021221 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---STG' CRPIX1 = 3.744942537739 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--STG' CRPIX2 = -251.945990929 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_SZP.hdr0000644000077000000240000000204713404171222021231 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---SZP' CRPIX1 = -22.62051956373 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--SZP' CRPIX2 = -247.8656972779 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole PV2_1 = 2.000000000000E+00 / Projection parameter 1 PV2_2 = 1.800000000000E+02 / Projection parameter 2 PV2_3 = 6.000000000000E+01 / Projection parameter 3 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_TAN.hdr0000644000077000000240000000157713404171222021206 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---TAN' CRPIX1 = -0.5630437201085 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--TAN' CRPIX2 = -268.0658087122 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_TSC.hdr0000644000077000000240000000157713404171222021215 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---TSC' CRPIX1 = 20.37416464676 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--TSC' CRPIX2 = -189.7220156818 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = 0.000000000000E+00 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_ZEA.hdr0000644000077000000240000000157713404171222021203 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---ZEA' CRPIX1 = 5.738055949994 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--ZEA' CRPIX2 = -244.4880690361 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/1904-66_ZPN.hdr0000644000077000000240000000375113404171222021227 0ustar tomstaff00000000000000SIMPLE = T BITPIX = -32 / IEEE (big-endian) 32-bit floating point data NAXIS = 2 NAXIS1 = 192 NAXIS2 = 192 BUNIT = 'JY/BEAM ' CTYPE1 = 'RA---ZPN' CRPIX1 = 22.09211120575 CDELT1 = -6.666666666667E-02 CRVAL1 = 0.000000000000E+00 CTYPE2 = 'DEC--ZPN' CRPIX2 = -183.2937255632 CDELT2 = 6.666666666667E-02 CRVAL2 = -9.000000000000E+01 LONPOLE = 1.800000000000E+02 / Native longitude of celestial pole LATPOLE = -9.000000000000E+01 / Native latitude of celestial pole PV2_0 = 5.000000000000E-02 / Projection parameter 0 PV2_1 = 9.750000000000E-01 / Projection parameter 1 PV2_2 = -8.070000000000E-01 / Projection parameter 2 PV2_3 = 3.370000000000E-01 / Projection parameter 3 PV2_4 = -6.500000000000E-02 / Projection parameter 4 PV2_5 = 1.000000000000E-02 / Projection parameter 5 PV2_6 = 3.000000000000E-03 / Projection parameter 6 PV2_7 = -1.000000000000E-03 / Projection parameter 7 PV2_8 = 0.000000000000E+00 / Projection parameter 8 PV2_9 = 0.000000000000E+00 / Projection parameter 9 PV2_10 = 0.000000000000E+00 / Projection parameter 10 PV2_11 = 0.000000000000E+00 / Projection parameter 11 PV2_12 = 0.000000000000E+00 / Projection parameter 12 PV2_13 = 0.000000000000E+00 / Projection parameter 13 PV2_14 = 0.000000000000E+00 / Projection parameter 14 PV2_15 = 0.000000000000E+00 / Projection parameter 15 PV2_16 = 0.000000000000E+00 / Projection parameter 16 PV2_17 = 0.000000000000E+00 / Projection parameter 17 PV2_18 = 0.000000000000E+00 / Projection parameter 18 PV2_19 = 0.000000000000E+00 / Projection parameter 19 EQUINOX = 2.000000000000E+03 / Equinox of equatorial coordinates BMAJ = 2.399999936422E-01 / Beam major axis in degrees BMIN = 2.399999936422E-01 / Beam minor axis in degrees BPA = 0.000000000000E+00 / Beam position angle in degrees RESTFRQ = 1.420405750000E+09 / Line rest frequency, Hz APLpy-2.0.3/aplpy/tests/data/2d_fits/2MASS_k.hdr0000644000077000000240000000125613404171222021007 0ustar tomstaff00000000000000SIMPLE = T BITPIX = 16 NAXIS = 2 NAXIS1 = 721 NAXIS2 = 720 EXTEND = T / FITS dataset may contain extensions DATASET = '2MASS ' BAND = 'K ' CDATE = 'Wed Feb 25 11:57:21 2009' CTYPE1 = 'RA---TAN' CTYPE2 = 'DEC--TAN' CRVAL1 = 266.400000 CRVAL2 = -28.933330 CRPIX1 = 361. CRPIX2 = 360.5 CDELT1 = -0.001388889 CDELT2 = 0.001388889 CROTA2 = 0.000000 EQUINOX = 2000.0 MAGZP = 19.9757 BSCALE = 0.045777764213996 BZERO = 1500. APLpy-2.0.3/aplpy/tests/data/2d_fits/2MASS_k_rot.hdr0000644000077000000240000000125613432763221021702 0ustar tomstaff00000000000000SIMPLE = T BITPIX = 16 NAXIS = 2 NAXIS1 = 721 NAXIS2 = 720 EXTEND = T / FITS dataset may contain extensions DATASET = '2MASS ' BAND = 'K ' CDATE = 'Wed Feb 25 11:57:21 2009' CTYPE1 = 'RA---TAN' CTYPE2 = 'DEC--TAN' CRVAL1 = 266.400000 CRVAL2 = -28.933330 CRPIX1 = 361. CRPIX2 = 360.5 CDELT1 = -0.001388889 CDELT2 = 0.001388889 CROTA2 = 30.000000 EQUINOX = 2000.0 MAGZP = 19.9757 BSCALE = 0.045777764213996 BZERO = 1500. APLpy-2.0.3/aplpy/tests/data/3d_fits/0000755000077000000240000000000013432765724017167 5ustar tomstaff00000000000000APLpy-2.0.3/aplpy/tests/data/3d_fits/cube.hdr0000644000077000000240000000136213432763221020574 0ustar tomstaff00000000000000SIMPLE = T / Written by IDL: Fri Oct 27 10:49:59 2006 BITPIX = -32 / bits per data value NAXIS = 3 / number of axes NAXIS1 = 11 NAXIS2 = 12 NAXIS3 = 32 EXTEND = T /file may contain extensions CRVAL1 = 57.6599999999 / CRPIX1 = -799.000000000 / CDELT1 = -0.00638888900000 CTYPE1 = 'RA---SFL' / CRVAL2 = 0.00000000000 / CRPIX2 = -4741.91300000 / CDELT2 = 0.00638888900000 CTYPE2 = 'DEC--SFL' / CRVAL3 = -9959.44378305 / CRPIX3 = 1.00000 / CDELT3 = 66.4236100000 / CTYPE3 = 'VOPT' / SPECSYS = 'LSRK' / APLpy-2.0.3/aplpy/tests/data/__init__.py0000644000077000000240000000000013432273771017727 0ustar tomstaff00000000000000APLpy-2.0.3/aplpy/tests/data/shapes.reg0000644000077000000240000000131613432273771017613 0ustar tomstaff00000000000000# Region file format: DS9 version 4.1 global color=green dashlist=8 3 width=1 font="helvetica 10 normal roman" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1 fk5 circle(17:46:26.948,-28:45:11.89,330.498") ellipse(17:44:59.122,-28:44:47.18,505",185",360) # color=red width=2 box(17:45:50.090,-28:55:04.94,320",485",360) # color=blue width=4 line(17:46:39.285,-29:01:56.56,17:45:47.446,-29:06:42.46) # line=0 0 # vector(17:45:32.185,-29:06:07.48,924.175",13.1336) vector=1 color=yellow width=3 # text(17:45:40.580,-29:09:07.48) text={All you regions are belong to us} panda(17:46:26.192,-28:45:41.91,360,720,4,39.1095",78.2191",1) ellipse(17:45:09.384,-28:45:32.33,120",37.5",240",75",360) APLpy-2.0.3/aplpy/tests/helpers.py0000644000077000000240000000257713432763221016740 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import string import random import os import numpy as np from astropy.io import fits from astropy.wcs import WCS def random_id(): return ''.join(random.sample(string.ascii_letters + string.digits, 16)) def generate_header(header_file): # Read in header header = fits.Header.fromtextfile(header_file) return header def generate_data(header_file): # Read in header header = generate_header(header_file) # Find shape of array shape = [] for i in range(header['NAXIS']): shape.append(header['NAXIS%i' % (i + 1)]) # Generate data array data = np.zeros(shape[::-1]) return data def generate_hdu(header_file): # Read in header header = generate_header(header_file) # Generate data array data = generate_data(header_file) # Generate primary HDU hdu = fits.PrimaryHDU(data=data, header=header) return hdu def generate_wcs(header_file): # Read in header header = generate_header(header_file) # Compute WCS object wcs = WCS(header) return wcs def generate_file(header_file, directory): # Generate HDU object hdu = generate_hdu(header_file) # Write out to a temporary file in the specified directory filename = os.path.join(directory, random_id() + '.fits') hdu.writeto(filename) return filename APLpy-2.0.3/aplpy/tests/setup_package.py0000644000077000000240000000030013432763221020067 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division def get_package_data(): return {_ASTROPY_PACKAGE_NAME_ + '.tests': ['coveragerc', 'data/*.reg', 'data/*/*.hdr']} # noqa APLpy-2.0.3/aplpy/tests/test_axis_labels.py0000644000077000000240000000323713432763221020615 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from astropy.tests.helper import pytest from .. import FITSFigure def test_axis_labels_show_hide(): data = np.zeros((16, 16)) f = FITSFigure(data) f.axis_labels.hide() f.axis_labels.show() f.axis_labels.hide_x() f.axis_labels.show_x() f.axis_labels.hide_y() f.axis_labels.show_y() f.close() def test_axis_labels_text(): data = np.zeros((16, 16)) f = FITSFigure(data) f.axis_labels.set_xtext('x') f.axis_labels.set_ytext('y') f.close() def test_axis_labels_pad(): data = np.zeros((16, 16)) f = FITSFigure(data) f.axis_labels.set_xpad(-1.) f.axis_labels.set_ypad(0.5) f.close() def test_axis_labels_position(): data = np.zeros((16, 16)) f = FITSFigure(data) f.axis_labels.set_xposition('top') f.axis_labels.set_xposition('bottom') f.axis_labels.set_yposition('right') f.axis_labels.set_yposition('left') f.close() def test_axis_labels_position_invalid(): data = np.zeros((16, 16)) f = FITSFigure(data) with pytest.raises(ValueError): f.axis_labels.set_xposition('right') with pytest.raises(ValueError): f.axis_labels.set_xposition('left') with pytest.raises(ValueError): f.axis_labels.set_yposition('top') with pytest.raises(ValueError): f.axis_labels.set_yposition('bottom') f.close() def test_axis_labels_font(): data = np.zeros((16, 16)) f = FITSFigure(data) f.axis_labels.set_font(size='small', weight='bold', stretch='normal', family='serif', style='normal', variant='normal') f.close() APLpy-2.0.3/aplpy/tests/test_beam.py0000644000077000000240000001220013432763221017221 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import pytest import numpy as np from astropy import units as u from astropy.io import fits from .. import FITSFigure from ..overlays import Beam header_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/2d_fits') HEADER = fits.Header.fromtextfile(os.path.join(header_dir, '1904-66_TAN.hdr')) HDU = fits.PrimaryHDU(np.zeros((16, 16)), HEADER) def test_beam_add_remove(): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=0.04, angle=10.) f.remove_beam() f.add_beam(major=0.1, minor=0.04, angle=10.) f.remove_beam() f.close() def test_beam_show_hide(): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.hide() f.beam.show(major=0.1, minor=0.04, angle=10.) f.close() def test_beam_major(): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_major(0.5) f.beam.set_major(1.0) f.close() @pytest.mark.parametrize('quantity', [u.arcsec, 5 * u.arcsec, 1 * u.degree, 1 * u.radian]) def test_beam_major_quantity(quantity): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=quantity, minor=0.04, angle=10.) f.beam.set_major(quantity) f.close() def test_beam_minor(): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_minor(0.05) f.beam.set_minor(0.08) f.close() @pytest.mark.parametrize('quantity', [u.arcsec, 5 * u.arcsec, 1 * u.degree, 1 * u.radian]) def test_beam_minor_quantity(quantity): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=quantity, angle=10.) assert type(f.beam) != list f.beam.set_minor(quantity) f.close() def test_beam_angle(): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_angle(0.) f.beam.set_angle(55.) f.close() @pytest.mark.parametrize('quantity', [u.arcsec, 5 * u.arcsec, 1 * u.degree, 1 * u.radian]) def test_beam_angle_quantity(quantity): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=0.04, angle=quantity) f.beam.set_angle(quantity) f.close() def test_beam_corner(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) for corner in ['top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right']: f.beam.set_corner(corner) f.close() def test_beam_frame(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_frame(True) f.beam.set_frame(False) f.close() def test_beam_borderpad(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_borderpad(0.1) f.beam.set_borderpad(0.3) f.close() def test_beam_pad(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_pad(0.1) f.beam.set_pad(0.3) f.close() def test_beam_alpha(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_alpha(0.1) f.beam.set_alpha(0.2) f.beam.set_alpha(0.5) f.close() def test_beam_color(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_color('black') f.beam.set_color('#003344') f.beam.set_color((1.0, 0.4, 0.3)) f.close() def test_beam_facecolor(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_facecolor('black') f.beam.set_facecolor('#003344') f.beam.set_facecolor((1.0, 0.4, 0.3)) f.close() def test_beam_edgecolor(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_edgecolor('black') f.beam.set_edgecolor('#003344') f.beam.set_edgecolor((1.0, 0.4, 0.3)) f.close() def test_beam_linestyle(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_linestyle('solid') f.beam.set_linestyle('dotted') f.beam.set_linestyle('dashed') f.close() def test_beam_linewidth(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) f.beam.set_linewidth(0) f.beam.set_linewidth(1) f.beam.set_linewidth(5) f.close() def test_beam_hatch(): f = FITSFigure(HDU) f.add_beam(major=0.1, minor=0.04, angle=10.) for hatch in ['/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*']: f.beam.set_hatch(hatch) f.close() def test_beam_multiple(): f = FITSFigure(HDU) f.show_grayscale() f.add_beam(major=0.1, minor=0.04, angle=10.) f.add_beam(major=0.2, minor=0.08, angle=10.) f.add_beam(major=0.15, minor=0.08, angle=10.) assert len(f.beam) == 3 with pytest.raises(Exception) as exc: f.remove_beam() assert exc.value.args[0] == ('More than one beam present - use beam_index= ' 'to specify which one to remove') f.remove_beam(beam_index=2) assert len(f.beam) == 2 f.remove_beam(beam_index=1) assert isinstance(f.beam, Beam) f.remove_beam() assert not hasattr(f, 'beam') f.close() APLpy-2.0.3/aplpy/tests/test_colorbar.py0000644000077000000240000000422013432763221020123 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from astropy.tests.helper import pytest from .. import FITSFigure ARRAY = np.arange(256).reshape((16, 16)) def test_colorbar_invalid(): f = FITSFigure(ARRAY) with pytest.raises(Exception): f.add_colorbar() # no grayscale/colorscale was shown def test_colorbar_addremove(): f = FITSFigure(ARRAY) f.show_grayscale() f.add_colorbar() f.remove_colorbar() f.add_colorbar() f.close() def test_colorbar_showhide(): f = FITSFigure(ARRAY) f.show_grayscale() f.add_colorbar() f.colorbar.hide() f.colorbar.show() f.close() def test_colorbar_location(): f = FITSFigure(ARRAY) f.show_grayscale() f.add_colorbar() f.colorbar.set_location('top') with pytest.warns(UserWarning, match='Bottom colorbar not fully implemented'): f.colorbar.set_location('bottom') with pytest.warns(UserWarning, match='Left colorbar not fully implemented'): f.colorbar.set_location('left') f.colorbar.set_location('right') f.close() def test_colorbar_width(): f = FITSFigure(ARRAY) f.show_grayscale() f.add_colorbar() f.colorbar.set_width(0.1) f.colorbar.set_width(0.2) f.colorbar.set_width(0.5) f.close() def test_colorbar_pad(): f = FITSFigure(ARRAY) f.show_grayscale() f.add_colorbar() f.colorbar.set_pad(0.1) f.colorbar.set_pad(0.2) f.colorbar.set_pad(0.5) f.close() def test_colorbar_font(): f = FITSFigure(ARRAY) f.show_grayscale() f.add_colorbar() f.colorbar.set_font(size='small', weight='bold', stretch='normal', family='serif', style='normal', variant='normal') f.close() def test_colorbar_axis_label(): f = FITSFigure(ARRAY) f.show_grayscale() f.add_colorbar() f.colorbar.set_axis_label_text('Surface Brightness (MJy/sr)') f.colorbar.set_axis_label_rotation(45.) f.colorbar.set_axis_label_font(size='small', weight='bold', stretch='normal', family='serif', style='normal', variant='normal') f.colorbar.set_axis_label_pad(5.) f.close() APLpy-2.0.3/aplpy/tests/test_contour.py0000644000077000000240000000067513432763221020023 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import pytest import numpy as np from .. import FITSFigure # Test simple contour generation with Numpy example @pytest.mark.parametrize(('filled'), [True, False]) def test_numpy_contour(filled): data = np.arange(256).reshape((16, 16)) f = FITSFigure(data) f.show_grayscale() f.show_contour(data, levels=np.linspace(1., 254., 10), filled=filled) f.close() APLpy-2.0.3/aplpy/tests/test_convolve.py0000644000077000000240000000163213432763221020157 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from astropy.io import fits from .. import FITSFigure ARRAY = np.arange(256).reshape((16, 16)) def test_convolve_default(): hdu = fits.PrimaryHDU(ARRAY) f = FITSFigure(hdu) f.show_grayscale(smooth=3) f.close() def test_convolve_gauss(): hdu = fits.PrimaryHDU(ARRAY) f = FITSFigure(hdu) f.show_grayscale(kernel='gauss', smooth=3) f.close() def test_convolve_box(): hdu = fits.PrimaryHDU(ARRAY) f = FITSFigure(hdu) f.show_grayscale(kernel='box', smooth=3) f.close() def test_convolve_custom(): hdu = fits.PrimaryHDU(ARRAY) f = FITSFigure(hdu) f.show_grayscale(kernel=np.ones((3, 3))) f.close() def test_convolve_int(): # Regression test for aplpy/aplpy#165 hdu = fits.PrimaryHDU(ARRAY) f = FITSFigure(hdu) f.show_grayscale(smooth=3) f.close() APLpy-2.0.3/aplpy/tests/test_downsample.py0000644000077000000240000000042513432763221020474 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import pytest import numpy as np from .. import FITSFigure def test_numpy_downsample(): data = np.arange(256).reshape((16, 16)) f = FITSFigure(data, downsample=2) f.show_grayscale() f.close() APLpy-2.0.3/aplpy/tests/test_frame.py0000644000077000000240000000076113432763221017420 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from .. import FITSFigure def test_frame_linewidth(): data = np.zeros((16, 16)) f = FITSFigure(data) f.frame.set_linewidth(0) f.frame.set_linewidth(1) f.frame.set_linewidth(10) f.close() def test_frame_color(): data = np.zeros((16, 16)) f = FITSFigure(data) f.frame.set_color('black') f.frame.set_color('#003344') f.frame.set_color((1.0, 0.4, 0.3)) f.close() APLpy-2.0.3/aplpy/tests/test_grid.py0000644000077000000240000000312713432763221017252 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import pytest import numpy as np from .. import FITSFigure def test_grid_addremove(): data = np.zeros((16, 16)) f = FITSFigure(data) f.add_grid() f.remove_grid() f.add_grid() f.close() def test_grid_showhide(): data = np.zeros((16, 16)) f = FITSFigure(data) f.add_grid() f.grid.hide() f.grid.show() f.close() def test_grid_spacing(): data = np.zeros((16, 16)) f = FITSFigure(data) f.add_grid() f.grid.set_xspacing(1.) f.grid.set_xspacing('tick') with pytest.raises(ValueError): f.grid.set_xspacing('auto') f.grid.set_yspacing(2.) f.grid.set_yspacing('tick') with pytest.raises(ValueError): f.grid.set_yspacing('auto') f.close() def test_grid_color(): data = np.zeros((16, 16)) f = FITSFigure(data) f.add_grid() f.grid.set_color('black') f.grid.set_color('#003344') f.grid.set_color((1.0, 0.4, 0.3)) f.close() def test_grid_alpha(): data = np.zeros((16, 16)) f = FITSFigure(data) f.add_grid() f.grid.set_alpha(0.0) f.grid.set_alpha(0.3) f.grid.set_alpha(1.0) f.close() def test_grid_linestyle(): data = np.zeros((16, 16)) f = FITSFigure(data) f.add_grid() f.grid.set_linestyle('solid') f.grid.set_linestyle('dashed') f.grid.set_linestyle('dotted') f.close() def test_grid_linewidth(): data = np.zeros((16, 16)) f = FITSFigure(data) f.add_grid() f.grid.set_linewidth(0) f.grid.set_linewidth(2) f.grid.set_linewidth(5) f.close() APLpy-2.0.3/aplpy/tests/test_images.py0000644000077000000240000002063313432763221017573 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import tempfile import pytest import numpy as np from .. import FITSFigure from .helpers import generate_file from . import baseline_dir MODULEDIR = os.path.dirname(__file__) DATADIR = os.path.abspath(os.path.join(MODULEDIR, 'data')) class BaseImageTests(object): @classmethod def setup_class(cls): cls._baseline_images_dir = os.path.abspath(os.path.join(MODULEDIR, 'baseline_images')) header_1 = os.path.join(DATADIR, '2d_fits/1904-66_AIR.hdr') cls.filename_1 = generate_file(header_1, str(tempfile.mkdtemp())) header_2 = os.path.join(DATADIR, '2d_fits/2MASS_k.hdr') cls.filename_2 = generate_file(header_2, str(tempfile.mkdtemp())) header_3 = os.path.join(DATADIR, '3d_fits/cube.hdr') cls.filename_3 = generate_file(header_3, str(tempfile.mkdtemp())) header_4 = os.path.join(DATADIR, '2d_fits/2MASS_k_rot.hdr') cls.filename_4 = generate_file(header_4, str(tempfile.mkdtemp())) class TestBasic(BaseImageTests): # Test for showing grayscale @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=7.5) def test_basic_image(self): f = FITSFigure(self.filename_2, figsize=(7, 5)) f.show_grayscale(vmin=0, vmax=1) return f._figure @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=7.5) def test_ticks_labels_options(self): f = FITSFigure(self.filename_2, figsize=(7, 5)) # Force aspect ratio f.show_grayscale() f.hide_grayscale() f.ticks.set_color('black') f.axis_labels.set_xposition('top') f.axis_labels.set_yposition('right') f.axis_labels.set_font(size='medium', weight='medium', stretch='normal', style='normal') f.tick_labels.set_xformat('dd:mm:ss.ss') f.tick_labels.set_yformat('hh:mm:ss.ss') f.tick_labels.set_style('colons') f.ticks.set_xspacing(0.2) f.ticks.set_yspacing(0.2) f.ticks.set_minor_frequency(10) return f._figure # Test for showing colorscale @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=5) def test_show_colorbar_scalebar_beam(self): f = FITSFigure(self.filename_1, figsize=(7, 5)) f.ticks.set_color('black') f.show_colorscale(vmin=-0.1, vmax=0.1) f.add_colorbar() f.add_scalebar(7.5) f.add_beam(major=0.5, minor=0.2, angle=10.) f.tick_labels.hide() return f._figure # Test for overlaying shapes @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=1.5) def test_overlay_shapes(self): f = FITSFigure(self.filename_1, figsize=(7, 5)) # Force aspect ratio f.show_grayscale() f.hide_grayscale() f.ticks.set_color('black') # Markers f.show_markers([360., 350., 340.], [-61., -62., -63], color='cyan') f.show_markers([30, 40], [50, 70], coords_frame='pixel', edgecolor='blue') # Circles f.show_circles([360., 350., 340.], [-61., -62., -63], [0.5, 0.4, 0.3], edgecolor='purple') f.show_circles([30, 40], [50, 70], [10, 20], coords_frame='pixel', edgecolor='orange') # Ellipses f.show_ellipses(340., -66., 1.5, 2., 10., edgecolor='red') f.show_ellipses(120, 60, 20, 40, 20., coords_frame='pixel', edgecolor='green') # Rectangles f.show_rectangles([355., 350.], [-71, -72], [0.5, 1], [2, 1], angle=[20, 30], edgecolor='magenta') f.show_rectangles([66, 80], [20, 30], [10, 14], [20, 22], angle=[20, 30], coords_frame='pixel', edgecolor='yellow') # Arrows f.show_arrows([340., 360], [-72, -68], [2, -2], [2, 2]) # Polygons poly = np.array([[330, 340, 360], [-65, -61, -63]]) f.show_polygons([poly], edgecolor='0.3', zorder=10) # Lines f.show_lines([poly], zorder=9, lw=5, color='red', alpha=0.5) # Labels f.add_label(350., -66., 'text') f.add_label(0.4, 0.25, 'text', relative=True) f.frame.set_linewidth(1) # points f.frame.set_color('black') f.axis_labels.hide() return f._figure # Test for grid @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=7.5) def test_grid(self): f = FITSFigure(self.filename_1, figsize=(7, 5)) # Force aspect ratio f.show_grayscale() f.hide_grayscale() f.ticks.set_color('black') f.add_grid() f.grid.set_color('red') f.grid.set_alpha(0.8) f.grid.set_linestyle('solid') f.grid.set_xspacing('tick') f.grid.set_yspacing(3) return f._figure # Test recenter @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=1.5) def test_recenter(self): f = FITSFigure(self.filename_2, figsize=(7, 5)) # Force aspect ratio f.show_grayscale() f.hide_grayscale() f.ticks.set_color('black') f.recenter(266.5, -29.0, width=0.1, height=0.1) f.axis_labels.set_xpad(20) f.axis_labels.set_ypad(20) return f._figure # Test overlaying contours @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=5) def test_contours(self): data = np.arange(256).reshape((16, 16)) f = FITSFigure(data, figsize=(7, 5)) # Force aspect ratio f.show_grayscale() f.hide_grayscale() f.ticks.set_color('black') f.show_contour(data, levels=np.linspace(1., 254., 10), filled=False) return f._figure # Test cube slice @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=5) def test_cube_slice(self): f = FITSFigure(self.filename_3, dimensions=[2, 0], slices=[10], figsize=(7, 5), subplot=[0.25, 0.1, 0.7, 0.8]) f.ticks.set_color('black') f.add_grid() f.grid.set_color('black') f.grid.set_linestyle('solid') f.grid.set_xspacing(250) f.grid.set_yspacing(0.01) f.tick_labels.set_xformat('%g') f.tick_labels.set_yformat('dd:mm:ss.ss') return f._figure # Test for ds9 regions @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=5) def test_regions(self): f = FITSFigure(self.filename_2, figsize=(7, 5)) # Force aspect ratio f.show_grayscale() f.hide_grayscale() f.show_regions(os.path.join(DATADIR, 'shapes.reg')) f.axis_labels.hide() f.tick_labels.hide() f.ticks.hide() return f._figure @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=5) def test_north(self): f = FITSFigure(self.filename_4, figsize=(3, 3), north=True) f.show_grayscale(vmin=-1, vmax=1) f.axis_labels.hide() f.tick_labels.hide() f.ticks.hide() return f._figure @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=5) def test_downsample(self): data = np.arange(256).reshape((16, 16)) f = FITSFigure(data, downsample=2) f.show_grayscale() return f._figure @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=5) def test_set_nan_color(self): data = np.arange(56, dtype=float).reshape((8, 7)) data[3, :] = np.nan f = FITSFigure(data, figsize=(3, 3)) f.show_colorscale() f.axis_labels.hide() f.tick_labels.hide() f.ticks.hide() f.set_nan_color('black') return f._figure APLpy-2.0.3/aplpy/tests/test_init_cube.py0000644000077000000240000000751313432763221020271 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import pytest import numpy as np from astropy.io import fits from .helpers import generate_file, generate_hdu, generate_wcs from .. import FITSFigure # The tests in this file check that the initialization and basic plotting do # not crash for FITS files with 3+ dimensions. No reference images are # required here. ROOT = os.path.dirname(os.path.abspath(__file__)) HEADER_DIR = os.path.join(ROOT, 'data/3d_fits') HEADERS = [os.path.join(HEADER_DIR, 'cube.hdr')] REFERENCE = os.path.join(HEADER_DIR, 'cube.hdr') VALID_DIMENSIONS = [(0, 1), (1, 0), (0, 2), (2, 0), (1, 2), (2, 1)] INVALID_DIMENSIONS = [None, (1,), (0, 3), (-4, 2), (1, 1), (2, 2), (3, 3), (1, 2, 3), (3, 5, 3, 2)] # Test initialization through a filename def test_file_init(tmpdir): filename = generate_file(REFERENCE, str(tmpdir)) f = FITSFigure(filename, slices=[5]) f.show_grayscale() f.close() # Test initialization through an HDU object def test_hdu_init(): hdu = generate_hdu(REFERENCE) f = FITSFigure(hdu, slices=[5]) f.show_grayscale() f.close() # Test initialization through a WCS object def test_wcs_init(): wcs = generate_wcs(REFERENCE) with pytest.raises(ValueError) as exc: FITSFigure(wcs, slices=[5]) assert exc.value.args[0] == "FITSFigure initialization via WCS objects can only be done with 2-dimensional WCS objects" # Test initialization through an HDU object (no WCS) def test_hdu_nowcs_init(): data = np.zeros((16, 16, 16)) hdu = fits.PrimaryHDU(data) f = FITSFigure(hdu, slices=[5]) f.show_grayscale() f.close() # Test initalization through a Numpy array (no WCS) def test_numpy_nowcs_init(): data = np.zeros((16, 16, 16)) f = FITSFigure(data, slices=[5]) f.show_grayscale() f.close() # Test that initialization without specifying slices raises an exception for a # true 3D cube def test_hdu_noslices(): hdu = generate_hdu(REFERENCE) with pytest.raises(Exception): FITSFigure(hdu) # Test that initialization without specifying slices does *not* raise an # exception if the remaining dimensions have size 1. def test_hdu_noslices_2d(): data = np.zeros((1, 16, 16)) f = FITSFigure(data) f.show_grayscale() f.close() # Now check initialization with valid and invalid dimensions. We just need to # tes with HDU objects since we already tested that reading from files is ok. # Test initialization with valid dimensions @pytest.mark.parametrize(('dimensions'), VALID_DIMENSIONS) def test_init_dimensions_valid(dimensions): hdu = generate_hdu(REFERENCE) f = FITSFigure(hdu, dimensions=dimensions, slices=[5]) f.show_grayscale() f.close() # Test initialization with invalid dimensions @pytest.mark.parametrize(('dimensions'), INVALID_DIMENSIONS) def test_init_dimensions_invalid(dimensions): hdu = generate_hdu(REFERENCE) with pytest.raises(ValueError): FITSFigure(hdu, dimensions=dimensions, slices=[5]) # Now check initialization of different WCS projections, and we check only # valid dimensions valid_parameters = [] for h in HEADERS: for d in VALID_DIMENSIONS: valid_parameters.append((h, d)) @pytest.mark.parametrize(('header', 'dimensions'), valid_parameters) def test_init_extensive_wcs(tmpdir, header, dimensions): filename = generate_file(header, str(tmpdir)) f = FITSFigure(filename, dimensions=dimensions, slices=[5]) f.show_grayscale() f.close() # Test that recenter works for cube slices # TODO: remove xfail once pix2world transformations work for multidimensional # datasets @pytest.mark.xfail def test_recenter_cube_slices(): data = np.zeros((16, 16, 16)) hdu = fits.PrimaryHDU(data) f = FITSFigure(hdu, slices=[5]) f.show_grayscale() f.recenter(5., 5., width=3., height=3.) f.close() APLpy-2.0.3/aplpy/tests/test_init_image.py0000644000077000000240000001375413432763221020441 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import pytest import numpy as np from astropy.io import fits from astropy.wcs import WCS as AstropyWCS from .helpers import generate_file, generate_hdu, generate_wcs from .. import FITSFigure # The tests in this file check that the initialization and basic plotting do # not crash for FITS files with 2 dimensions. No reference images are # required here. header_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/2d_fits') HEADERS = [os.path.join(header_dir, '1904-66_AIR.hdr'), os.path.join(header_dir, '1904-66_AIT.hdr'), os.path.join(header_dir, '1904-66_ARC.hdr'), os.path.join(header_dir, '1904-66_AZP.hdr'), os.path.join(header_dir, '1904-66_BON.hdr'), os.path.join(header_dir, '1904-66_CAR.hdr'), os.path.join(header_dir, '1904-66_CEA.hdr'), os.path.join(header_dir, '1904-66_COD.hdr'), os.path.join(header_dir, '1904-66_COE.hdr'), os.path.join(header_dir, '1904-66_COO.hdr'), os.path.join(header_dir, '1904-66_COP.hdr'), os.path.join(header_dir, '1904-66_CSC.hdr'), os.path.join(header_dir, '1904-66_CYP.hdr'), os.path.join(header_dir, '1904-66_HPX.hdr'), os.path.join(header_dir, '1904-66_MER.hdr'), os.path.join(header_dir, '1904-66_MOL.hdr'), os.path.join(header_dir, '1904-66_NCP.hdr'), os.path.join(header_dir, '1904-66_PAR.hdr'), os.path.join(header_dir, '1904-66_PCO.hdr'), os.path.join(header_dir, '1904-66_QSC.hdr'), os.path.join(header_dir, '1904-66_SFL.hdr'), os.path.join(header_dir, '1904-66_SIN.hdr'), os.path.join(header_dir, '1904-66_STG.hdr'), os.path.join(header_dir, '1904-66_SZP.hdr'), os.path.join(header_dir, '1904-66_TAN.hdr'), os.path.join(header_dir, '1904-66_TSC.hdr'), os.path.join(header_dir, '1904-66_ZEA.hdr'), os.path.join(header_dir, '1904-66_ZPN.hdr')] REFERENCE = os.path.join(header_dir, '1904-66_TAN.hdr') CAR_REFERENCE = os.path.join(header_dir, '1904-66_CAR.hdr') VALID_DIMENSIONS = [(0, 1), (1, 0)] INVALID_DIMENSIONS = [None, (1,), (0, 2), (-4, 2), (1, 1), (2, 2), (1, 2, 3)] # Test initialization through a filename def test_file_init(tmpdir): filename = generate_file(REFERENCE, str(tmpdir)) f = FITSFigure(filename) f.show_grayscale() f.close() # Test initialization through an HDU object def test_hdu_init(): hdu = generate_hdu(REFERENCE) f = FITSFigure(hdu) f.show_grayscale() f.close() # Test initialization through a WCS object def test_wcs_init(): wcs = generate_wcs(REFERENCE) f = FITSFigure(wcs) f.show_grayscale() f.close() # Test initialization through a WCS object with wcs.to_header() as a go-between # specifically for testing the cd -> pc -> cd hack, and has particular importance # for AVM-generated headers def test_wcs_toheader_init(): wcs = generate_wcs(REFERENCE) header_ = fits.Header.fromtextfile(REFERENCE) header = wcs.to_header() wcs2 = AstropyWCS(header) wcs2.pixel_shape = wcs.pixel_shape = (header_['NAXIS1'], header_['NAXIS2']) f = FITSFigure(wcs2) f.show_grayscale() f.add_grid() f.close() # Test initialization through an HDU object (no WCS) def test_hdu_nowcs_init(): data = np.zeros((16, 16)) hdu = fits.PrimaryHDU(data) f = FITSFigure(hdu) f.show_grayscale() f.close() # Test initalization through a Numpy array (no WCS) def test_numpy_nowcs_init(): data = np.zeros((16, 16)) f = FITSFigure(data) f.show_grayscale() f.close() # Now check initialization with valid and invalid dimensions. We just need to # tes with HDU objects since we already tested that reading from files is ok. # Test initialization with valid dimensions @pytest.mark.parametrize(('dimensions'), VALID_DIMENSIONS) def test_init_dimensions_valid(dimensions): hdu = generate_hdu(REFERENCE) f = FITSFigure(hdu, dimensions=dimensions) f.show_grayscale() f.close() # Test initialization with invalid dimensions @pytest.mark.parametrize(('dimensions'), INVALID_DIMENSIONS) def test_init_dimensions_invalid(dimensions): hdu = generate_hdu(REFERENCE) with pytest.raises(ValueError): FITSFigure(hdu, dimensions=dimensions) # Now check initialization of different WCS projections, and we check only # valid dimensions valid_parameters = [] for h in HEADERS: for d in VALID_DIMENSIONS: valid_parameters.append((h, d)) @pytest.mark.parametrize(('header', 'dimensions'), valid_parameters) def test_init_extensive_wcs(header, dimensions): hdu = generate_hdu(header) if 'CAR' in header: f = FITSFigure(hdu, dimensions=dimensions, convention='calabretta') else: f = FITSFigure(hdu, dimensions=dimensions) f.show_grayscale() f.add_grid() f.close() # Check that for CAR projections, an exception is raised if no convention is specified @pytest.mark.parametrize(('dimensions'), VALID_DIMENSIONS) def test_init_car_invalid(dimensions): hdu = generate_hdu(CAR_REFERENCE) with pytest.raises(Exception): FITSFigure(hdu, dimensions=dimensions) # Check that images containing only NaN or Inf values don't crash FITSFigure def test_init_only_naninf(): data = np.ones((10, 10)) * np.nan data[::2, ::2] = np.inf f = FITSFigure(data) f.show_grayscale() f.show_colorscale() def test_init_single_pixel(): data = np.zeros((4, 4)) data[...] = np.nan data[2, 2] = 1 f = FITSFigure(data) f.show_grayscale() def test_not_first_hdu(tmpdir): # Test that data is fetched from the first compatible HDU with data filename = tmpdir.join('test.fits').strpath hdu0 = fits.PrimaryHDU() hdu1 = fits.BinTableHDU() hdu2 = fits.ImageHDU(np.zeros((12, 12))) hdulist = fits.HDUList([hdu0, hdu1, hdu2]) hdulist.writeto(filename) f = FITSFigure(filename) assert f._data.shape == (12, 12) APLpy-2.0.3/aplpy/tests/test_layers.py0000644000077000000240000001231613432763221017624 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import pytest import numpy as np from .. import FITSFigure def test_layers(capsys): f = FITSFigure(np.arange(256).reshape((16, 16))) capsys.readouterr() # No layers f.list_layers() captured = capsys.readouterr() assert captured.out.strip() == ('There are no layers in this figure') # Two layers f.show_markers([360., 350., 340.], [-61., -62., -63], color='cyan', layer='markers') f.show_markers([360., 350., 340.], [-61., -62., -63], color='cyan', layer='extra_markers') capsys.readouterr() f.list_layers() captured = capsys.readouterr() assert captured.out.strip() == ('There are 2 layers in this figure:\n\n' ' -> markers\n' ' -> extra_markers') # Check removing layers f.remove_layer('extra_markers') f.list_layers() captured = capsys.readouterr() assert captured.out.strip() == ('There is one layer in this figure:\n\n' ' -> markers') # Check all layer types and overwriting layers f.show_markers([30, 40], [50, 70], layer='markers') f.show_circles([360., 350., 340.], [-61., -62., -63], [0.5, 0.4, 0.3], layer='circles') f.show_circles([30, 40], [50, 70], [10, 20], layer='circles') f.show_ellipses(340., -66., 1.5, 2., 10., layer='ellipses') f.show_ellipses(120, 60, 20, 40, 20., layer='ellipses') f.show_rectangles([355., 350.], [-71, -72], [0.5, 1], [2, 1], angle=[20, 30], layer='rectangles') f.show_rectangles([66, 80], [20, 30], [10, 14], [20, 22], angle=[20, 30], layer='rectangles') f.show_arrows([340., 360], [-72, -68], [2, -2], [2, 2], layer='arrows') f.show_arrows([340., 360], [-72, -68], [2, -2], [2, 2], layer='arrows') poly = np.array([[330, 340, 360], [-65, -61, -63]]) f.show_polygons([poly], layer='polygons') f.show_polygons([poly], layer='polygons') f.show_lines([poly], layer='lines') f.show_lines([poly], layer='lines') f.add_label(350., -66., 'text', layer='label') f.add_label(0.4, 0.25, 'text', relative=True, layer='label') # FIXME: Uncomment the following once # https://github.com/astropy/astropy/pull/8321 is merged into Astropy and in # a bug fix release. # f.show_contour(layer='contours') f.list_layers() captured = capsys.readouterr() assert captured.out.strip() == ('There are 8 layers in this figure:\n\n' ' -> markers\n' ' -> circles\n' ' -> ellipses\n' ' -> rectangles\n' ' -> arrows\n' ' -> polygons\n' ' -> lines\n' ' -> label') # Hiding/showing layers f.hide_layer('ellipses') f.hide_layer('polygons') f.list_layers() captured = capsys.readouterr() assert captured.out.strip() == ('There are 8 layers in this figure:\n\n' ' -> markers\n' ' -> circles\n' ' -> ellipses (hidden)\n' ' -> rectangles\n' ' -> arrows\n' ' -> polygons (hidden)\n' ' -> lines\n' ' -> label') layer = f.get_layer('circles') assert layer.get_visible() layer = f.get_layer('ellipses') assert not layer.get_visible() f.show_layer('ellipses') f.list_layers() captured = capsys.readouterr() assert captured.out.strip() == ('There are 8 layers in this figure:\n\n' ' -> markers\n' ' -> circles\n' ' -> ellipses\n' ' -> rectangles\n' ' -> arrows\n' ' -> polygons (hidden)\n' ' -> lines\n' ' -> label') layer = f.get_layer('ellipses') assert layer.get_visible() def test_non_existent_layers(): # Handling non-existent layers f = FITSFigure(np.arange(256).reshape((16, 16))) with pytest.raises(Exception) as exc: f.get_layer('banana') assert exc.value.args[0] == 'Layer banana does not exist' assert f.get_layer('banana', raise_exception=False) is None with pytest.raises(Exception) as exc: f.show_layer('banana') assert exc.value.args[0] == 'Layer banana does not exist' f.show_layer('banana', raise_exception=False) with pytest.raises(Exception) as exc: f.hide_layer('banana') assert exc.value.args[0] == 'Layer banana does not exist' f.hide_layer('banana', raise_exception=False) with pytest.raises(Exception) as exc: f.remove_layer('banana') assert exc.value.args[0] == 'Layer banana does not exist' f.remove_layer('banana', raise_exception=False) APLpy-2.0.3/aplpy/tests/test_misc.py0000644000077000000240000000214213432765627017270 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from ..core import FITSFigure def test_nan_color_copy(): """ Regression test to ensure that NaN values set in one image don't affect global Matplotlib colormap. """ data = np.zeros((16, 16)) f1 = FITSFigure(data) f1.show_grayscale() f1.set_nan_color('blue') f2 = FITSFigure(data) f2.show_grayscale() f2.set_nan_color('red') assert f1.image.get_cmap()._rgba_bad == (0.0, 0.0, 1.0, 1.0) assert f2.image.get_cmap()._rgba_bad == (1.0, 0.0, 0.0, 1.0) def test_stretches(): # Regression test to make sure none of the stretches crash data = np.arange(256).reshape((16, 16)) f = FITSFigure(data) f.show_grayscale() f.show_grayscale(stretch='linear') f.show_grayscale(stretch='sqrt') f.show_grayscale(stretch='log') f.show_grayscale(stretch='arcsinh') f.show_grayscale(stretch='power') f.show_grayscale(stretch='log', vmid=-10) f.show_grayscale(stretch='arcsinh', vmid=10) f.show_grayscale(stretch='power', exponent=3.0) f.close() APLpy-2.0.3/aplpy/tests/test_pixworldmarkers.py0000644000077000000240000000356213432763221021565 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import pytest import numpy as np from astropy.table import Table from astropy.io import fits from .helpers import generate_wcs from .. import FITSFigure HEADER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/2d_fits', '1904-66_TAN.hdr') tab = Table({'RA': [347., 349.], 'DEC': [-68., -68]}) GOOD_INPUT = [[1, 2], [[1, 2], [3, 4]], [np.arange(2), np.arange(2)], [tab['RA'], tab['DEC']] ] BAD_INPUT = [[1, ['s', 'e']], [np.arange(2), np.sum], [tab['RA'], 'ewr'] ] @pytest.mark.parametrize(('inputval'), GOOD_INPUT) def test_pixel_coords(inputval): data = np.zeros((16, 16)) f = FITSFigure(data) f.show_markers(inputval[0], inputval[1]) f.close() @pytest.mark.parametrize(('inputval'), GOOD_INPUT) def test_wcs_coords(inputval): wcs = generate_wcs(HEADER) header = fits.Header.fromtextfile(HEADER) wcs.naxis1 = header['NAXIS1'] wcs.naxis2 = header['NAXIS2'] f = FITSFigure(wcs) f.show_markers(inputval[0], inputval[1]) f.close() @pytest.mark.parametrize(('inputval'), BAD_INPUT) def test_pixel_coords_bad(inputval): data = np.zeros((16, 16)) f = FITSFigure(data) with pytest.raises(Exception) as exc: f.show_markers(inputval[0], inputval[1]) assert exc.value.args[0] == "x and y must be the same size" f.close() @pytest.mark.parametrize(('inputval'), BAD_INPUT) def test_wcs_coords_bad(inputval): wcs = generate_wcs(HEADER) header = fits.Header.fromtextfile(HEADER) wcs.naxis1 = header['NAXIS1'] wcs.naxis2 = header['NAXIS2'] f = FITSFigure(wcs) with pytest.raises(Exception) as exc: f.show_markers(inputval[0], inputval[1]) f.close() assert exc.value.args[0] == "x and y must be the same size" APLpy-2.0.3/aplpy/tests/test_rgb.py0000644000077000000240000000762413432763221017105 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import warnings import pytest import numpy as np from astropy.io import fits from astropy.coordinates import Galactic from .. import FITSFigure from ..rgb import make_rgb_image, make_rgb_cube from .test_images import BaseImageTests from . import baseline_dir from .helpers import generate_header ROOT = os.path.dirname(os.path.abspath(__file__)) HEADER = os.path.join(ROOT, 'data/2d_fits', '1904-66_TAN.hdr') class TestRGB(BaseImageTests): @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=7.5, filename='test_rgb.png') @pytest.mark.parametrize('embed_avm_tags', (False, True)) def test_rgb(self, tmpdir, embed_avm_tags): # Regression test to check that RGB recenter works properly r_file = tmpdir.join('r.fits').strpath g_file = tmpdir.join('g.fits').strpath b_file = tmpdir.join('b.fits').strpath rgb_file = tmpdir.join('rgb.png').strpath np.random.seed(12345) header = fits.Header.fromtextfile(HEADER) r = fits.PrimaryHDU(np.random.random((12, 12)), header) r.writeto(r_file) g = fits.PrimaryHDU(np.random.random((12, 12)), header) g.writeto(g_file) b = fits.PrimaryHDU(np.random.random((12, 12)), header) b.writeto(b_file) make_rgb_image([r_file, g_file, b_file], rgb_file, embed_avm_tags=embed_avm_tags) if embed_avm_tags: f = FITSFigure(rgb_file, figsize=(7, 5)) else: f = FITSFigure(r_file, figsize=(7, 5)) with warnings.catch_warnings(): warnings.simplefilter("ignore") f.show_rgb(rgb_file) f.tick_labels.set_xformat('dd.d') f.tick_labels.set_yformat('dd.d') f.recenter(359.3, -72.1, radius=0.05) return f._figure @pytest.mark.remote_data @pytest.mark.parametrize('north', ['default', 'galactic', 'false']) @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=7.5) def test_make_rgb_cube(self, tmpdir, north): # Regression test to check that RGB recenter works properly header = generate_header(os.path.join(ROOT, 'data', '2d_fits', '2MASS_k_rot.hdr')) header['CRPIX1'] = 6.5 header['CRPIX2'] = 6.5 header_r = header.copy() header_r['CROTA2'] = 5 header_g = header.copy() header_g['CROTA2'] = 35 header_b = header.copy() header_b['CROTA2'] = 70 r_file = tmpdir.join('r.fits').strpath g_file = tmpdir.join('g.fits').strpath b_file = tmpdir.join('b.fits').strpath rgb_cube = tmpdir.join('rgb.fits').strpath rgb_file = tmpdir.join('rgb.png').strpath header = fits.Header.fromtextfile(HEADER) r = fits.PrimaryHDU(np.ones((128, 128)), header_r) r.writeto(r_file) g = fits.PrimaryHDU(np.ones((128, 128)), header_g) g.writeto(g_file) b = fits.PrimaryHDU(np.ones((128, 128)), header_b) b.writeto(b_file) if north == 'default': kwargs = {} elif north == 'galactic': kwargs = {'north': Galactic()} elif north == 'false': kwargs = {'north': False} make_rgb_cube([r_file, g_file, b_file], rgb_cube, **kwargs) make_rgb_image(rgb_cube, rgb_file, embed_avm_tags=True, vmin_r=0, vmax_r=1, vmin_g=0, vmax_g=1, vmin_b=0, vmax_b=1) f = FITSFigure(rgb_file, figsize=(3, 3)) with warnings.catch_warnings(): warnings.simplefilter("ignore") f.show_rgb(rgb_file) f.tick_labels.hide() f.axis_labels.hide() f.add_grid() return f._figure APLpy-2.0.3/aplpy/tests/test_save.py0000644000077000000240000000540013432763221017257 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import sys from io import BytesIO as StringIO import pytest import numpy as np from .. import FITSFigure FORMATS = [None, 'png', 'pdf', 'eps', 'ps', 'svg'] ARRAY = np.arange(256).reshape((16, 16)) def is_format(filename, format): if isinstance(filename, str): f = open(filename, 'rb') else: f = filename if format == 'png': return f.read(8) == b'\x89\x50\x4e\x47\x0d\x0a\x1a\x0a' elif format == 'pdf': return f.read(4) == b'\x25\x50\x44\x46' elif format == 'eps': return f.read(23) == b'%!PS-Adobe-3.0 EPSF-3.0' elif format == 'ps': return f.read(14) == b'%!PS-Adobe-3.0' elif format == 'svg': from xml.dom import minidom return minidom.parse(f).childNodes[2].attributes['xmlns'].value == 'http://www.w3.org/2000/svg' else: raise Exception("Unknown format: %s" % format) @pytest.mark.parametrize(('format'), FORMATS) def test_write_png(tmpdir, format): filename = os.path.join(str(tmpdir), 'test_output.png') f = FITSFigure(ARRAY) f.show_grayscale() try: f.save(filename, format=format) except TypeError: pytest.xfail() finally: f.close() if format is None: assert is_format(filename, 'png') else: assert is_format(filename, format) @pytest.mark.parametrize(('format'), FORMATS) def test_write_pdf(tmpdir, format): filename = os.path.join(str(tmpdir), 'test_output.pdf') f = FITSFigure(ARRAY) f.show_grayscale() try: f.save(filename, format=format) except TypeError: pytest.xfail() finally: f.close() if format is None: assert is_format(filename, 'pdf') else: assert is_format(filename, format) @pytest.mark.parametrize(('format'), FORMATS) def test_write_eps(tmpdir, format): filename = os.path.join(str(tmpdir), 'test_output.eps') f = FITSFigure(ARRAY) f.show_grayscale() try: f.save(filename, format=format) except TypeError: pytest.xfail() finally: f.close() if format is None: assert is_format(filename, 'eps') else: assert is_format(filename, format) @pytest.mark.parametrize(('format'), FORMATS) def test_write_stringio(tmpdir, format): s = StringIO() f = FITSFigure(ARRAY) f.show_grayscale() try: f.save(s, format=format) except TypeError: pytest.xfail() finally: f.close() try: s.seek(0) except ValueError: if format == 'svg' and sys.version_info[:2] >= (3, 3): pytest.xfail() else: raise if format is None: assert is_format(s, 'png') else: assert is_format(s, format) APLpy-2.0.3/aplpy/tests/test_scalebar.py0000644000077000000240000000535713432763221020110 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import pytest import numpy as np from astropy import units as u from astropy.io import fits from .. import FITSFigure ROOT = os.path.dirname(os.path.abspath(__file__)) HEADER_DIR = os.path.join(ROOT, 'data/2d_fits') HEADER = fits.Header.fromtextfile(os.path.join(HEADER_DIR, '1904-66_TAN.hdr')) HDU = fits.PrimaryHDU(np.zeros((16, 16)), HEADER) def test_scalebar_add_invalid(): f = FITSFigure(HDU) with pytest.raises(TypeError): f.add_scalebar() def test_scalebar_addremove(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.remove_scalebar() f.add_scalebar(0.1) f.close() def test_scalebar_showhide(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.scalebar.hide() f.scalebar.show(0.1) f.close() def test_scalebar_length(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.scalebar.set_length(0.01) f.scalebar.set_length(0.1) f.close() @pytest.mark.parametrize('quantity', [1 * u.arcsec, u.arcsec, 2 * u.degree, 5 * u.radian]) def test_scalebar_length_quantity(quantity): f = FITSFigure(HDU) f.add_scalebar(quantity) f.scalebar.set_length(quantity) f.close() def test_scalebar_label(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.scalebar.set_label('1 pc') f.scalebar.set_label('5 AU') f.scalebar.set_label('2"') f.close() def test_scalebar_corner(): f = FITSFigure(HDU) f.add_scalebar(0.1) for corner in ['top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right']: f.scalebar.set_corner(corner) f.close() def test_scalebar_frame(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.scalebar.set_frame(True) f.scalebar.set_frame(False) f.close() def test_scalebar_color(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.scalebar.set_color('black') f.scalebar.set_color('#003344') f.scalebar.set_color((1.0, 0.4, 0.3)) f.close() def test_scalebar_alpha(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.scalebar.set_alpha(0.1) f.scalebar.set_alpha(0.2) f.scalebar.set_alpha(0.5) f.close() def test_scalebar_font(): f = FITSFigure(HDU) f.add_scalebar(0.1) f.scalebar.set_font(size='small', weight='bold', stretch='normal', family='serif', style='normal', variant='normal') f.close() def test_regression_exception_type(): # In Matplotlib 1.5, the exception type changed for when a property doesn't # exist, so we need to catch both AttributeError and TypeError. f = FITSFigure(HDU) with pytest.warns(UserWarning, match='Scalebar does not have attribute family'): f.add_scalebar(0.1, family='serif') f.close() APLpy-2.0.3/aplpy/tests/test_subplot.py0000644000077000000240000000127513432763221020017 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import pytest import numpy as np from .. import FITSFigure def test_subplot_grid(): f = FITSFigure(np.zeros((10, 10)), subplot=(2, 2, 1)) f.show_grayscale() f.close() def test_subplot_box(): f = FITSFigure(np.zeros((10, 10)), subplot=[0.1, 0.1, 0.8, 0.8]) f.show_grayscale() f.close() @pytest.mark.parametrize('subplot', [(1, 2, 3, 4), [1, 2, 3], '111', 1.2]) def test_subplot_invalid(subplot): with pytest.raises(ValueError) as exc: FITSFigure(np.zeros((10, 10)), subplot=subplot) assert exc.value.args[0] == "subplot= should be either a tuple of three values, or a list of four values" APLpy-2.0.3/aplpy/tests/test_tick_labels.py0000644000077000000240000000357713432763221020612 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import os import pytest import numpy as np from .helpers import generate_hdu from .. import FITSFigure ROOT = os.path.dirname(os.path.abspath(__file__)) HEADER_DIR = os.path.join(ROOT, 'data/2d_fits') REFERENCE = os.path.join(HEADER_DIR, '1904-66_TAN.hdr') def test_tick_labels_show_hide(): data = np.zeros((16, 16)) f = FITSFigure(data) f.tick_labels.hide() f.tick_labels.show() f.tick_labels.hide_x() f.tick_labels.show_x() f.tick_labels.hide_y() f.tick_labels.show_y() f.close() def test_tick_labels_format_scalar(): data = np.zeros((16, 16)) f = FITSFigure(data) f.tick_labels.set_xformat('%i') f.tick_labels.set_yformat('%i') f.close() def test_tick_labels_position(): data = np.zeros((16, 16)) f = FITSFigure(data) f.tick_labels.set_xposition('top') f.tick_labels.set_xposition('bottom') f.tick_labels.set_yposition('right') f.tick_labels.set_yposition('left') f.close() def test_tick_labels_position_invalid(): data = np.zeros((16, 16)) f = FITSFigure(data) with pytest.raises(ValueError): f.tick_labels.set_xposition('right') with pytest.raises(ValueError): f.tick_labels.set_xposition('left') with pytest.raises(ValueError): f.tick_labels.set_yposition('top') with pytest.raises(ValueError): f.tick_labels.set_yposition('bottom') f.close() def test_tick_labels_font(): data = np.zeros((16, 16)) f = FITSFigure(data) f.tick_labels.set_font(size='small', weight='bold', stretch='normal', family='serif', style='normal', variant='normal') f.close() def test_single_d_format(): hdu = generate_hdu(REFERENCE) f = FITSFigure(hdu) f.show_grayscale(vmin=0, vmax=1) f.tick_labels.set_yformat('d.d') f.save('test_label_format.png') APLpy-2.0.3/aplpy/tests/test_ticks.py0000644000077000000240000000244713432763221017446 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import numpy as np from .. import FITSFigure def test_ticks_show_hide(): data = np.zeros((16, 16)) f = FITSFigure(data) f.ticks.hide() f.ticks.show() f.ticks.hide_x() f.ticks.show_x() f.ticks.hide_y() f.ticks.show_y() f.close() def test_ticks_spacing(): data = np.zeros((16, 16)) f = FITSFigure(data) f.ticks.set_xspacing(0.5) f.ticks.set_xspacing(1.) f.ticks.set_yspacing(0.5) f.ticks.set_yspacing(1.) f.close() def test_ticks_length(): data = np.zeros((16, 16)) f = FITSFigure(data) f.ticks.set_length(0) f.ticks.set_length(1) f.ticks.set_length(10) f.close() def test_ticks_color(): data = np.zeros((16, 16)) f = FITSFigure(data) f.ticks.set_color('black') f.ticks.set_color('#003344') f.ticks.set_color((1.0, 0.4, 0.3)) f.close() def test_ticks_linewidth(): data = np.zeros((16, 16)) f = FITSFigure(data) f.ticks.set_linewidth(1) f.ticks.set_linewidth(3) f.ticks.set_linewidth(10) f.close() def test_ticks_minor_frequency(): data = np.zeros((16, 16)) f = FITSFigure(data) f.ticks.set_minor_frequency(1) f.ticks.set_minor_frequency(5) f.ticks.set_minor_frequency(10) f.close() APLpy-2.0.3/aplpy/tests/test_vectors.py0000644000077000000240000000220713432763221020010 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division import pytest import numpy as np from ..core import FITSFigure from .test_images import BaseImageTests from . import baseline_dir x = np.linspace(-1., 1., 10) y = np.linspace(-1., 1., 10) X, Y = np.meshgrid(x, y) np.random.seed(12345) IMAGE = np.random.random((10, 10)) PDATA = np.arange(100).reshape((10, 10)) / 50. + 0.5 ADATA = np.degrees(np.arctan2(Y, X)) class TestVectors(BaseImageTests): @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=1.5) def test_default(self): f = FITSFigure(IMAGE, figsize=(4, 4)) f.show_grayscale() f.show_vectors(PDATA, ADATA, color='orange') return f._figure @pytest.mark.remote_data @pytest.mark.mpl_image_compare(style={}, savefig_kwargs={'adjust_bbox': False}, baseline_dir=baseline_dir, tolerance=1.5) def test_step_scale(self): f = FITSFigure(IMAGE, figsize=(4, 4)) f.show_grayscale() f.show_vectors(PDATA, ADATA, step=2, scale=0.8, color='orange') return f._figure APLpy-2.0.3/aplpy/tick_labels.py0000644000077000000240000001351113432763221016376 0ustar tomstaff00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, division, unicode_literals from .decorators import auto_refresh, fixdocstring __all__ = ['TickLabels'] class TickLabels(object): def __init__(self, parent): self._figure = parent._figure self._ax = parent.ax self._wcs = parent.ax.wcs self.x = parent.x self.y = parent.y self.set_style('plain') @auto_refresh def set_xformat(self, xformat): """ Set the format of the x-axis tick labels. If the x-axis type is ``longitude`` or ``latitude``, then the options are: * ``d.ddddd`` - decimal degrees, where the number of decimal places can be varied * ``hh`` or ``dd`` - hours (or degrees) * ``hh:mm`` or ``dd:mm`` - hours and minutes (or degrees and arcminutes) * ``hh:mm:ss`` or ``dd:mm:ss`` - hours, minutes, and seconds (or degrees, arcminutes, and arcseconds) * ``hh:mm:ss.ss`` or ``dd:mm:ss.ss`` - hours, minutes, and seconds (or degrees, arcminutes, and arcseconds), where the number of decimal places can be varied. If the x-axis type is ``scalar``, then the format should be a valid python string format beginning with a ``%``. If one of these arguments is not specified, the format for that axis is left unchanged. """ if 'dd.' in xformat: xformat = xformat.replace('ddd.', 'd.').replace('dd.', 'd.') self._ax.coords[self.x].set_major_formatter(xformat) @auto_refresh def set_yformat(self, yformat): """ Set the format of the y-axis tick labels. If the y-axis type is ``longitude`` or ``latitude``, then the options are: * ``d.ddddd`` - decimal degrees, where the number of decimal places can be varied * ``hh`` or ``dd`` - hours (or degrees) * ``hh:mm`` or ``dd:mm`` - hours and minutes (or degrees and arcminutes) * ``hh:mm:ss`` or ``dd:mm:ss`` - hours, minutes, and seconds (or degrees, arcminutes, and arcseconds) * ``hh:mm:ss.ss`` or ``dd:mm:ss.ss`` - hours, minutes, and seconds (or degrees, arcminutes, and arcseconds), where the number of decimal places can be varied. If the y-axis type is ``scalar``, then the format should be a valid python string format beginning with a ``%``. If one of these arguments is not specified, the format for that axis is left unchanged. """ if 'dd.' in yformat: yformat = yformat.replace('ddd.', 'd.').replace('dd.', 'd.') self._ax.coords[self.y].set_major_formatter(yformat) @auto_refresh def set_style(self, style): """ Set the format of the x-axis tick labels. This can be 'colons' or 'plain': * 'colons' uses colons as separators, for example 31:41:59.26 +27:18:28.1 * 'plain' uses letters and symbols as separators, for example 31h41m59.26s +27º18'28.1" """ if style not in ['colons', 'plain']: raise Exception("Label style should be one of colons/plain") self.style = style for coord in [self.x, self.y]: coord_type = self._ax.coords[coord].coord_type if coord_type in ['longitude', 'latitude']: if style == 'colons': sep = (':', ':', '') else: sep = None self._ax.coords[coord].set_separator(sep) @auto_refresh @fixdocstring def set_font(self, **kwargs): """ Set the font of the tick labels. Parameters ---------- common: family, style, variant, stretch, weight, size, fontproperties Notes ----- Default values are set by matplotlib or previously set values if set_font has already been called. Global default values can be set by editing the matplotlibrc file. """ self._ax.coords[self.x].set_ticklabel(**kwargs) self._ax.coords[self.y].set_ticklabel(**kwargs) @auto_refresh def show(self): """ Show the x- and y-axis tick labels. """ self.show_x() self.show_y() @auto_refresh def hide(self): """ Hide the x- and y-axis tick labels. """ self.hide_x() self.hide_y() @auto_refresh def show_x(self): """ Show the x-axis tick labels. """ self._ax.coords[self.x].set_ticklabel_visible(True) @auto_refresh def hide_x(self): """ Hide the x-axis tick labels. """ self._ax.coords[self.x].set_ticklabel_visible(False) @auto_refresh def show_y(self): """ Show the y-axis tick labels. """ self._ax.coords[self.y].set_ticklabel_visible(True) @auto_refresh def hide_y(self): """ Hide the y-axis tick labels. """ self._ax.coords[self.y].set_ticklabel_visible(False) @auto_refresh def set_xposition(self, position): """ Set the position of the x-axis tick labels ('top' or 'bottom') """ if position == 'bottom': self._ax.coords[self.x].set_ticklabel_position('b') elif position == 'top': self._ax.coords[self.x].set_ticklabel_position('t') else: raise ValueError("position should be one of 'top' or 'bottom'") @auto_refresh def set_yposition(self, position): """ Set the position of the y-axis tick labels ('left' or 'right') """ if position == 'left': self._ax.coords[self.y].set_ticklabel_position('l') elif position == 'right': self._ax.coords[self.y].set_ticklabel_position('r') else: raise ValueError("position should be one of 'left' or 'right'") APLpy-2.0.3/aplpy/ticks.py0000644000077000000240000000746713432763221015254 0ustar tomstaff00000000000000from __future__ import absolute_import, print_function, division from .decorators import auto_refresh class Ticks(object): @auto_refresh def __init__(self, parent): self._figure = parent._figure self._ax = parent.ax self.x = parent.x self.y = parent.y self._wcs = self._ax.wcs def set_tick_direction(self, direction): """ Set the direction of the ticks to be facing out of the axes (``out``) or into the axes (``in``). """ if direction in ('in', 'out'): self.ax.coords[self.x].ticks.set_tick_out(direction == 'out') self.ax.coords[self.y].ticks.set_tick_out(direction == 'out') else: raise ValueError("direction should be 'in' or 'out'") @auto_refresh def set_xspacing(self, spacing): """ Set the x-axis tick spacing, in degrees. To set the tick spacing to be automatically determined, set this to 'auto'. """ self._set_spacing(self.x, spacing) @auto_refresh def set_yspacing(self, spacing): """ Set the y-axis tick spacing, in degrees. To set the tick spacing to be automatically determined, set this to 'auto'. """ self._set_spacing(self.y, spacing) @auto_refresh def _set_spacing(self, coord, spacing): if spacing == 'auto': self._ax.coords[coord].set_ticks(spacing=None) else: coord_unit = self._wcs.wcs.cunit[coord] self._ax.coords[coord].set_ticks(spacing=spacing * coord_unit) @auto_refresh def set_color(self, color): """ Set the color of the ticks """ self._ax.coords[self.x].set_ticks(color=color) self._ax.coords[self.y].set_ticks(color=color) @auto_refresh def set_length(self, length, minor_factor=0.5): """ Set the length of the ticks (in points) """ # TODO: Can't set minor ticksize. Should we just remove that? # Not mentioned in the APLpy in docs either self._ax.coords[self.x].set_ticks(size=length) self._ax.coords[self.y].set_ticks(size=length) @auto_refresh def set_linewidth(self, linewidth): """ Set the linewidth of the ticks (in points) """ self._ax.coords[self.x].set_ticks(width=linewidth) self._ax.coords[self.y].set_ticks(width=linewidth) @auto_refresh def set_minor_frequency(self, xfrequency, yfrequency=None): ''' Set the number of subticks per major tick. Set to one to hide minor ticks. If not yfrequency given, frequency is the same in both axis. Otherwise, xfrequency represents the frequency in the xaxis and yfrequency the one in the yaxis. ''' if yfrequency is None: yfrequency = xfrequency self._ax.coords[self.x].set_minor_frequency(xfrequency) self._ax.coords[self.y].set_minor_frequency(yfrequency) @auto_refresh def show(self): """ Show the x- and y-axis ticks """ self.show_x() self.show_y() @auto_refresh def hide(self): """ Hide the x- and y-axis ticks """ self.hide_x() self.hide_y() @auto_refresh def show_x(self): """ Show the x-axis ticks """ self._ax.coords[self.x].set_ticks_visible(True) @auto_refresh def hide_x(self): """ Hide the x-axis ticks """ self._ax.coords[self.x].set_ticks_visible(False) @auto_refresh def show_y(self): """ Show the y-axis ticks """ self._ax.coords[self.y].set_ticks_visible(True) @auto_refresh def hide_y(self): """ Hide the y-axis ticks """ self._ax.coords[self.y].set_ticks_visible(False) APLpy-2.0.3/aplpy/version.py0000644000077000000240000001632113432765723015622 0ustar tomstaff00000000000000# Autogenerated by Astropy-affiliated package aplpy's setup.py on 2019-02-19 11:43:15 UTC from __future__ import unicode_literals import datetime import locale import os import subprocess import warnings def _decode_stdio(stream): try: stdio_encoding = locale.getdefaultlocale()[1] or 'utf-8' except ValueError: stdio_encoding = 'utf-8' try: text = stream.decode(stdio_encoding) except UnicodeDecodeError: # Final fallback text = stream.decode('latin1') return text def update_git_devstr(version, path=None): """ Updates the git revision string if and only if the path is being imported directly from a git working copy. This ensures that the revision number in the version string is accurate. """ try: # Quick way to determine if we're in git or not - returns '' if not devstr = get_git_devstr(sha=True, show_warning=False, path=path) except OSError: return version if not devstr: # Probably not in git so just pass silently return version if 'dev' in version: # update to the current git revision version_base = version.split('.dev', 1)[0] devstr = get_git_devstr(sha=False, show_warning=False, path=path) return version_base + '.dev' + devstr else: # otherwise it's already the true/release version return version def get_git_devstr(sha=False, show_warning=True, path=None): """ Determines the number of revisions in this repository. Parameters ---------- sha : bool If True, the full SHA1 hash will be returned. Otherwise, the total count of commits in the repository will be used as a "revision number". show_warning : bool If True, issue a warning if git returns an error code, otherwise errors pass silently. path : str or None If a string, specifies the directory to look in to find the git repository. If `None`, the current working directory is used, and must be the root of the git repository. If given a filename it uses the directory containing that file. Returns ------- devversion : str Either a string with the revision number (if `sha` is False), the SHA1 hash of the current commit (if `sha` is True), or an empty string if git version info could not be identified. """ if path is None: path = os.getcwd() if not os.path.isdir(path): path = os.path.abspath(os.path.dirname(path)) if sha: # Faster for getting just the hash of HEAD cmd = ['rev-parse', 'HEAD'] else: cmd = ['rev-list', '--count', 'HEAD'] def run_git(cmd): try: p = subprocess.Popen(['git'] + cmd, cwd=path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() except OSError as e: if show_warning: warnings.warn('Error running git: ' + str(e)) return (None, b'', b'') if p.returncode == 128: if show_warning: warnings.warn('No git repository present at {0!r}! Using ' 'default dev version.'.format(path)) return (p.returncode, b'', b'') if p.returncode == 129: if show_warning: warnings.warn('Your git looks old (does it support {0}?); ' 'consider upgrading to v1.7.2 or ' 'later.'.format(cmd[0])) return (p.returncode, stdout, stderr) elif p.returncode != 0: if show_warning: warnings.warn('Git failed while determining revision ' 'count: {0}'.format(_decode_stdio(stderr))) return (p.returncode, stdout, stderr) return p.returncode, stdout, stderr returncode, stdout, stderr = run_git(cmd) if not sha and returncode == 128: # git returns 128 if the command is not run from within a git # repository tree. In this case, a warning is produced above but we # return the default dev version of '0'. return '0' elif not sha and returncode == 129: # git returns 129 if a command option failed to parse; in # particular this could happen in git versions older than 1.7.2 # where the --count option is not supported # Also use --abbrev-commit and --abbrev=0 to display the minimum # number of characters needed per-commit (rather than the full hash) cmd = ['rev-list', '--abbrev-commit', '--abbrev=0', 'HEAD'] returncode, stdout, stderr = run_git(cmd) # Fall back on the old method of getting all revisions and counting # the lines if returncode == 0: return str(stdout.count(b'\n')) else: return '' elif sha: return _decode_stdio(stdout)[:40] else: return _decode_stdio(stdout).strip() # This function is tested but it is only ever executed within a subprocess when # creating a fake package, so it doesn't get picked up by coverage metrics. def _get_repo_path(pathname, levels=None): # pragma: no cover """ Given a file or directory name, determine the root of the git repository this path is under. If given, this won't look any higher than ``levels`` (that is, if ``levels=0`` then the given path must be the root of the git repository and is returned if so. Returns `None` if the given path could not be determined to belong to a git repo. """ if os.path.isfile(pathname): current_dir = os.path.abspath(os.path.dirname(pathname)) elif os.path.isdir(pathname): current_dir = os.path.abspath(pathname) else: return None current_level = 0 while levels is None or current_level <= levels: if os.path.exists(os.path.join(current_dir, '.git')): return current_dir current_level += 1 if current_dir == os.path.dirname(current_dir): break current_dir = os.path.dirname(current_dir) return None _packagename = "aplpy" _last_generated_version = "2.0.3" _last_githash = "70f1a5fedfc04f8d97ef71d2078c47cf5efec9b3" # Determine where the source code for this module # lives. If __file__ is not a filesystem path then # it is assumed not to live in a git repo at all. if _get_repo_path(__file__, levels=len(_packagename.split('.'))): version = update_git_devstr(_last_generated_version, path=__file__) githash = get_git_devstr(sha=True, show_warning=False, path=__file__) or _last_githash else: # The file does not appear to live in a git repo so don't bother # invoking git version = _last_generated_version githash = _last_githash major = 2 minor = 0 bugfix = 3 version_info = (major, minor, bugfix) release = True timestamp = datetime.datetime(2019, 2, 19, 11, 43, 15) debug = False astropy_helpers_version = "3.1" try: from ._compiler import compiler except ImportError: compiler = "unknown" try: from .cython_version import cython_version except ImportError: cython_version = "unknown" APLpy-2.0.3/astropy_helpers/0000755000077000000240000000000013432765724015657 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/.coveragerc0000644000077000000240000000124113404171254017762 0ustar tomstaff00000000000000[run] source = astropy_helpers omit = astropy_helpers/*/setup_package.py astropy_helpers/tests/* astropy_helpers/conftest.py [report] omit = astropy_helpers/*/setup_package.py astropy_helpers/tests/* astropy_helpers/conftest.py exclude_lines = # Have to re-enable the standard pragma pragma: no cover # Don't complain about packages we have installed except ImportError # Don't complain if tests don't hit assertions raise AssertionError raise NotImplementedError # Don't complain about script hooks def main\(.*\): # Ignore branches that don't pertain to this version of Python pragma: py{ignore_python_version} APLpy-2.0.3/astropy_helpers/.travis.yml0000644000077000000240000001020413404171254017751 0ustar tomstaff00000000000000# We set the language to c because python isn't supported on the MacOS X nodes # on Travis. However, the language ends up being irrelevant anyway, since we # install Python ourselves using conda. language: c os: - osx - linux # Setting sudo to false opts in to Travis-CI container-based builds. sudo: false env: matrix: - PYTHON_VERSION=3.5 - PYTHON_VERSION=3.6 - PYTHON_VERSION=3.7 SETUPTOOLS_VERSION=dev DEBUG=True CONDA_DEPENDENCIES='sphinx cython numpy pytest-cov' EVENT_TYPE='push pull_request cron' global: - CONDA_DEPENDENCIES="setuptools sphinx cython numpy pytest-cov" - PIP_DEPENDENCIES="codecov" - EVENT_TYPE='push pull_request' matrix: include: # Do one build with sphinx-astropy as one of the tests bypasses the auto- # installation but we want to make sure that test runs for coverage. - os: linux env: PYTHON_VERSION=3.6 PIP_DEPENDENCIES='codecov sphinx-astropy' - os: linux env: PYTHON_VERSION=3.6 SPHINX_VERSION='1.5' SETUPTOOLS_VERSION=27 - os: linux env: PYTHON_VERSION=3.5 SPHINX_VERSION='1.4' SETUPTOOLS_VERSION=27 - os: linux env: PYTHON_VERSION=3.6 PIP_DEPENDENCIES='git+https://github.com/sphinx-doc/sphinx.git#egg=sphinx codecov' CONDA_DEPENDENCIES="setuptools cython numpy pytest-cov" # Test without installing numpy beforehand to make sure everything works # without assuming numpy is already installed - os: linux env: PYTHON_VERSION=3.6 CONDA_DEPENDENCIES='sphinx cython pytest-cov' # Test conda's clang - os: osx env: - PYTHON_VERSION=3.5 - CONDA_DEPENDENCIES="setuptools sphinx cython numpy pytest-cov clang llvm-openmp" - OPENMP_EXPECTED=True - CCOMPILER=clang # Test gcc on OSX - os: osx env: - PYTHON_VERSION=3.5 - CONDA_DEPENDENCIES="setuptools sphinx cython numpy pytest-cov gcc" - OPENMP_EXPECTED=True - CCOMPILER=gcc # Uncomment the following if there are issues in setuptools that we # can't work around quickly - otherwise leave uncommented so that # we notice when things go wrong. # # allow_failures: # - env: PYTHON_VERSION=3.6 SETUPTOOLS_VERSION=dev DEBUG=True # CONDA_DEPENDENCIES='sphinx cython numpy pytest-cov' # EVENT_TYPE='push pull_request cron' before_install: # Test OSX without OpenMP support # Since the matrix OSX tests use the OS shipped version of clang, they double up # as exploratory tests for when the shipped version has automatic OpenMP support. # These tests will then fail and at such a time a new one should be added # to explicitly remove OpenMP support. - if [ -z $OPENMP_EXPECTED ]; then if [[ $TRAVIS_OS_NAME == osx ]]; then export OPENMP_EXPECTED=False; else export OPENMP_EXPECTED=True; fi fi # We need to use CCOMPILER otherwise Travis overwrites CC if we define it # in env: above. - if [ ! -z $CCOMPILER ]; then export CC=$CCOMPILER; fi # Check CC variable - echo $CC install: - git clone git://github.com/astropy/ci-helpers.git - source ci-helpers/travis/setup_conda.sh # We cannot install the developer version of setuptools using pip because # pip tries to remove the previous version of setuptools before the # installation is complete, which causes issues. Instead, we just install # setuptools manually. - if [[ $SETUPTOOLS_VERSION == dev ]]; then git clone http://github.com/pypa/setuptools.git; cd setuptools; python bootstrap.py; python setup.py install; cd ..; fi before_script: # Some of the tests use git commands that require a user to be configured - git config --global user.name "A U Thor" - git config --global user.email "author@example.com" script: - py.test --cov astropy_helpers astropy_helpers # In conftest.py we produce a .coverage.subprocess that contains coverage # statistics for sub-processes, so we combine it with the main one here. - mv .coverage .coverage.main - coverage combine .coverage.main .coverage.subprocess - coverage report after_success: - codecov APLpy-2.0.3/astropy_helpers/CHANGES.rst0000644000077000000240000004536613404171254017463 0ustar tomstaff00000000000000astropy-helpers Changelog ************************* 3.1 (2018-12-04) ---------------- - Added extensive documentation about astropy-helpers to the README.rst file. [#416] - Fixed the compatibility of the build_docs command with Sphinx 1.8 and above. [#413] - Removing deprecated test_helpers.py file. [#369] - Removing ez_setup.py file and requiring setuptools 1.0 or later. [#384] - Remove all sphinx components from ``astropy-helpers``. These are now replaced by the ``sphinx-astropy`` package in conjunction with the ``astropy-theme-sphinx``, ``sphinx-automodapi``, and ``numpydoc`` packages. [#368] - openmp_helpers.py: Make add_openmp_flags_if_available() work for clang. The necessary include, library, and runtime paths now get added to the C test code used to determine if openmp works. Autogenerator utility added ``openmp_enabled.is_openmp_enabled()`` which can be called post build to determine state of OpenMP support. [#382] - Add version_info tuple to autogenerated version.py. Allows for simple version checking, i.e. version_info > (2,0,1). [#385] 3.0.2 (2018-06-01) ------------------ - Nothing changed. 3.0.1 (2018-02-22) ------------------ - Nothing changed. 3.0 (2018-02-09) ---------------- - Removing Python 2 support, including 2to3. Packages wishing to keep Python 2 support should NOT update to this version. [#340] - Removing deprecated _test_compat making astropy a hard dependency for packages wishing to use the astropy tests machinery. [#314] - Removing unused 'register' command since packages should be uploaded with twine and get registered automatically. [#332] 2.0.8 (2018-12-04) ------------------ - Fixed compatibility with Sphinx 1.8+. [#428] - Fixed error that occurs when installing a package in an environment where ``numpy`` is not already installed. [#404] - Updated bundled version of sphinx-automodapi to v0.9. [#422] - Updated bundled version of numpydoc to v0.8.0. [#423] 2.0.7 (2018-06-01) ------------------ - Removing ez_setup.py file and requiring setuptools 1.0 or later. [#384] 2.0.6 (2018-02-24) ------------------ - Avoid deprecation warning due to ``exclude=`` keyword in ``setup.py``. [#379] 2.0.5 (2018-02-22) ------------------ - Fix segmentation faults that occurred when the astropy-helpers submodule was first initialized in packages that also contained Cython code. [#375] 2.0.4 (2018-02-09) ------------------ - Support dotted package names as namespace packages in generate_version_py. [#370] - Fix compatibility with setuptools 36.x and above. [#372] - Fix false negative in add_openmp_flags_if_available when measuring code coverage with gcc. [#374] 2.0.3 (2018-01-20) ------------------ - Make sure that astropy-helpers 3.x.x is not downloaded on Python 2. [#362, #363] - The bundled version of sphinx-automodapi has been updated to v0.7. [#365] - Add --auto-use and --no-auto-use command-line flags to match the ``auto_use`` configuration option, and add an alias ``--use-system-astropy-helpers`` for ``--no-auto-use``. [#366] 2.0.2 (2017-10-13) ------------------ - Added new helper function add_openmp_flags_if_available that can add OpenMP compilation flags to a C/Cython extension if needed. [#346] - Update numpydoc to v0.7. [#343] - The function ``get_git_devstr`` now returns ``'0'`` instead of ``None`` when no git repository is present. This allows generation of development version strings that are in a format that ``setuptools`` expects (e.g. "1.1.3.dev0" instead of "1.1.3.dev"). [#330] - It is now possible to override generated timestamps to make builds reproducible by setting the ``SOURCE_DATE_EPOCH`` environment variable [#341] - Mark Sphinx extensions as parallel-safe. [#344] - Switch to using mathjax instead of imgmath for local builds. [#342] - Deprecate ``exclude`` parameter of various functions in setup_helpers since it could not work as intended. Add new function ``add_exclude_packages`` to provide intended behavior. [#331] - Allow custom Sphinx doctest extension to recognize and process standard doctest directives ``testsetup`` and ``doctest``. [#335] 2.0.1 (2017-07-28) ------------------ - Fix compatibility with Sphinx <1.5. [#326] 2.0 (2017-07-06) ---------------- - Add support for package that lies in a subdirectory. [#249] - Removing ``compat.subprocess``. [#298] - Python 3.3 is no longer supported. [#300] - The 'automodapi' Sphinx extension (and associated dependencies) has now been moved to a standalone package which can be found at https://github.com/astropy/sphinx-automodapi - this is now bundled in astropy-helpers under astropy_helpers.extern.automodapi for convenience. Version shipped with astropy-helpers is v0.6. [#278, #303, #309, #323] - The ``numpydoc`` Sphinx extension has now been moved to ``astropy_helpers.extern``. [#278] - Fix ``build_docs`` error catching, so it doesn't hide Sphinx errors. [#292] - Fix compatibility with Sphinx 1.6. [#318] - Updating ez_setup.py to the last version before it's removal. [#321] 1.3.1 (2017-03-18) ------------------ - Fixed the missing button to hide output in documentation code blocks. [#287] - Fixed bug when ``build_docs`` when running with the clean (-l) option. [#289] - Add alternative location for various intersphinx inventories to fall back to. [#293] 1.3 (2016-12-16) ---------------- - ``build_sphinx`` has been deprecated in favor of the ``build_docs`` command. [#246] - Force the use of Cython's old ``build_ext`` command. A new ``build_ext`` command was added in Cython 0.25, but it does not work with astropy-helpers currently. [#261] 1.2 (2016-06-18) ---------------- - Added sphinx configuration value ``automodsumm_inherited_members``. If ``True`` this will include members that are inherited from a base class in the generated API docs. Defaults to ``False`` which matches the previous behavior. [#215] - Fixed ``build_sphinx`` to recognize builds that succeeded but have output *after* the "build succeeded." statement. This only applies when ``--warnings-returncode`` is given (which is primarily relevant for Travis documentation builds). [#223] - Fixed ``build_sphinx`` the sphinx extensions to not output a spurious warning for sphinx versions > 1.4. [#229] - Add Python version dependent local sphinx inventories that contain otherwise missing references. [#216] - ``astropy_helpers`` now require Sphinx 1.3 or later. [#226] 1.1.2 (2016-03-9) ----------------- - The CSS for the sphinx documentation was altered to prevent some text overflow problems. [#217] 1.1.1 (2015-12-23) ------------------ - Fixed crash in build with ``AttributeError: cython_create_listing`` with older versions of setuptools. [#209, #210] 1.1 (2015-12-10) ---------------- - The original ``AstropyTest`` class in ``astropy_helpers``, which implements the ``setup.py test`` command, is deprecated in favor of moving the implementation of that command closer to the actual Astropy test runner in ``astropy.tests``. Now a dummy ``test`` command is provided solely for informing users that they need ``astropy`` installed to run the tests (however, the previous, now deprecated implementation is still provided and continues to work with older versions of Astropy). See the related issue for more details. [#184] - Added a useful new utility function to ``astropy_helpers.utils`` called ``find_data_files``. This is similar to the ``find_packages`` function in setuptools in that it can be used to search a package for data files (matching a pattern) that can be passed to the ``package_data`` argument for ``setup()``. See the docstring to ``astropy_helpers.utils.find_data_files`` for more details. [#42] - The ``astropy_helpers`` module now sets the global ``_ASTROPY_SETUP_`` flag upon import (from within a ``setup.py``) script, so it's not necessary to have this in the ``setup.py`` script explicitly. If in doubt though, there's no harm in setting it twice. Putting it in ``astropy_helpers`` just ensures that any other imports that occur during build will have this flag set. [#191] - It is now possible to use Cython as a ``setup_requires`` build requirement, and still build Cython extensions even if Cython wasn't available at the beginning of the build processes (that is, is automatically downloaded via setuptools' processing of ``setup_requires``). [#185] - Moves the ``adjust_compiler`` check into the ``build_ext`` command itself, so it's only used when actually building extension modules. This also deprecates the stand-alone ``adjust_compiler`` function. [#76] - When running the ``build_sphinx`` / ``build_docs`` command with the ``-w`` option, the output from Sphinx is streamed as it runs instead of silently buffering until the doc build is complete. [#197] 1.0.7 (unreleased) ------------------ - Fix missing import in ``astropy_helpers/utils.py``. [#196] 1.0.6 (2015-12-04) ------------------ - Fixed bug where running ``./setup.py build_sphinx`` could return successfully even when the build was not successful (and should have returned a non-zero error code). [#199] 1.0.5 (2015-10-02) ------------------ - Fixed a regression in the ``./setup.py test`` command that was introduced in v1.0.4. 1.0.4 (2015-10-02) ------------------ - Fixed issue with the sphinx documentation css where the line numbers for code blocks were not aligned with the code. [#179, #180] - Fixed crash that could occur when trying to build Cython extension modules when Cython isn't installed. Normally this still results in a failed build, but was supposed to provide a useful error message rather than crash outright (this was a regression introduced in v1.0.3). [#181] - Fixed a crash that could occur on Python 3 when a working C compiler isn't found. [#182] - Quieted warnings about deprecated Numpy API in Cython extensions, when building Cython extensions against Numpy >= 1.7. [#183, #186] - Improved support for py.test >= 2.7--running the ``./setup.py test`` command now copies all doc pages into the temporary test directory as well, so that all test files have a "common root directory". [#189, #190] 1.0.3 (2015-07-22) ------------------ - Added workaround for sphinx-doc/sphinx#1843, a but in Sphinx which prevented descriptor classes with a custom metaclass from being documented correctly. [#158] - Added an alias for the ``./setup.py build_sphinx`` command as ``./setup.py build_docs`` which, to a new contributor, should hopefully be less cryptic. [#161] - The fonts in graphviz diagrams now match the font of the HTML content. [#169] - When the documentation is built on readthedocs.org, MathJax will be used for math rendering. When built elsewhere, the "pngmath" extension is still used for math rendering. [#170] - Fix crash when importing astropy_helpers when running with ``python -OO`` [#171] - The ``build`` and ``build_ext`` stages now correctly recognize the presence of C++ files in Cython extensions (previously only vanilla C worked). [#173] 1.0.2 (2015-04-02) ------------------ - Various fixes enabling the astropy-helpers Sphinx build command and Sphinx extensions to work with Sphinx 1.3. [#148] - More improvement to the ability to handle multiple versions of astropy-helpers being imported in the same Python interpreter session in the (somewhat rare) case of nested installs. [#147] - To better support high resolution displays, use SVG for the astropy logo and linkout image, falling back to PNGs for browsers that support it. [#150, #151] - Improve ``setup_helpers.get_compiler_version`` to work with more compilers, and to return more info. This will help fix builds of Astropy on less common compilers, like Sun C. [#153] 1.0.1 (2015-03-04) ------------------ - Released in concert with v0.4.8 to address the same issues. 0.4.8 (2015-03-04) ------------------ - Improved the ``ah_bootstrap`` script's ability to override existing installations of astropy-helpers with new versions in the context of installing multiple packages simultaneously within the same Python interpreter (e.g. when one package has in its ``setup_requires`` another package that uses a different version of astropy-helpers. [#144] - Added a workaround to an issue in matplotlib that can, in rare cases, lead to a crash when installing packages that import matplotlib at build time. [#144] 1.0 (2015-02-17) ---------------- - Added new pre-/post-command hook points for ``setup.py`` commands. Now any package can define code to run before and/or after any ``setup.py`` command without having to manually subclass that command by adding ``pre__hook`` and ``post__hook`` callables to the package's ``setup_package.py`` module. See the PR for more details. [#112] - The following objects in the ``astropy_helpers.setup_helpers`` module have been relocated: - ``get_dummy_distribution``, ``get_distutils_*``, ``get_compiler_option``, ``add_command_option``, ``is_distutils_display_option`` -> ``astropy_helpers.distutils_helpers`` - ``should_build_with_cython``, ``generate_build_ext_command`` -> ``astropy_helpers.commands.build_ext`` - ``AstropyBuildPy`` -> ``astropy_helpers.commands.build_py`` - ``AstropyBuildSphinx`` -> ``astropy_helpers.commands.build_sphinx`` - ``AstropyInstall`` -> ``astropy_helpers.commands.install`` - ``AstropyInstallLib`` -> ``astropy_helpers.commands.install_lib`` - ``AstropyRegister`` -> ``astropy_helpers.commands.register`` - ``get_pkg_version_module`` -> ``astropy_helpers.version_helpers`` - ``write_if_different``, ``import_file``, ``get_numpy_include_path`` -> ``astropy_helpers.utils`` All of these are "soft" deprecations in the sense that they are still importable from ``astropy_helpers.setup_helpers`` for now, and there is no (easy) way to produce deprecation warnings when importing these objects from ``setup_helpers`` rather than directly from the modules they are defined in. But please consider updating any imports to these objects. [#110] - Use of the ``astropy.sphinx.ext.astropyautosummary`` extension is deprecated for use with Sphinx < 1.2. Instead it should suffice to remove this extension for the ``extensions`` list in your ``conf.py`` and add the stock ``sphinx.ext.autosummary`` instead. [#131] 0.4.7 (2015-02-17) ------------------ - Fixed incorrect/missing git hash being added to the generated ``version.py`` when creating a release. [#141] 0.4.6 (2015-02-16) ------------------ - Fixed problems related to the automatically generated _compiler module not being created properly. [#139] 0.4.5 (2015-02-11) ------------------ - Fixed an issue where ah_bootstrap.py could blow up when astropy_helper's version number is 1.0. - Added a workaround for documentation of properties in the rare case where the class's metaclass has a property of the same name. [#130] - Fixed an issue on Python 3 where importing a package using astropy-helper's generated version.py module would crash when the current working directory is an empty git repository. [#114, #137] - Fixed an issue where the "revision count" appended to .dev versions by the generated version.py did not accurately reflect the revision count for the package it belongs to, and could be invalid if the current working directory is an unrelated git repository. [#107, #137] - Likewise, fixed a confusing warning message that could occur in the same circumstances as the above issue. [#121, #137] 0.4.4 (2014-12-31) ------------------ - More improvements for building the documentation using Python 3.x. [#100] - Additional minor fixes to Python 3 support. [#115] - Updates to support new test features in Astropy [#92, #106] 0.4.3 (2014-10-22) ------------------ - The generated ``version.py`` file now preserves the git hash of installed copies of the package as well as when building a source distribution. That is, the git hash of the changeset that was installed/released is preserved. [#87] - In smart resolver add resolution for class links when they exist in the intersphinx inventory, but not the mapping of the current package (e.g. when an affiliated package uses an astropy core class of which "actual" and "documented" location differs) [#88] - Fixed a bug that could occur when running ``setup.py`` for the first time in a repository that uses astropy-helpers as a submodule: ``AttributeError: 'NoneType' object has no attribute 'mkdtemp'`` [#89] - Fixed a bug where optional arguments to the ``doctest-skip`` Sphinx directive were sometimes being left in the generated documentation output. [#90] - Improved support for building the documentation using Python 3.x. [#96] - Avoid error message if .git directory is not present. [#91] 0.4.2 (2014-08-09) ------------------ - Fixed some CSS issues in generated API docs. [#69] - Fixed the warning message that could be displayed when generating a version number with some older versions of git. [#77] - Fixed automodsumm to work with new versions of Sphinx (>= 1.2.2). [#80] 0.4.1 (2014-08-08) ------------------ - Fixed git revision count on systems with git versions older than v1.7.2. [#70] - Fixed display of warning text when running a git command fails (previously the output of stderr was not being decoded properly). [#70] - The ``--offline`` flag to ``setup.py`` understood by ``ah_bootstrap.py`` now also prevents git from going online to fetch submodule updates. [#67] - The Sphinx extension for converting issue numbers to links in the changelog now supports working on arbitrary pages via a new ``conf.py`` setting: ``changelog_links_docpattern``. By default it affects the ``changelog`` and ``whatsnew`` pages in one's Sphinx docs. [#61] - Fixed crash that could result from users with missing/misconfigured locale settings. [#58] - The font used for code examples in the docs is now the system-defined ``monospace`` font, rather than ``Minaco``, which is not available on all platforms. [#50] 0.4 (2014-07-15) ---------------- - Initial release of astropy-helpers. See `APE4 `_ for details of the motivation and design of this package. - The ``astropy_helpers`` package replaces the following modules in the ``astropy`` package: - ``astropy.setup_helpers`` -> ``astropy_helpers.setup_helpers`` - ``astropy.version_helpers`` -> ``astropy_helpers.version_helpers`` - ``astropy.sphinx`` - > ``astropy_helpers.sphinx`` These modules should be considered deprecated in ``astropy``, and any new, non-critical changes to those modules will be made in ``astropy_helpers`` instead. Affiliated packages wishing to make use those modules (as in the Astropy package-template) should use the versions from ``astropy_helpers`` instead, and include the ``ah_bootstrap.py`` script in their project, for bootstrapping the ``astropy_helpers`` package in their setup.py script. APLpy-2.0.3/astropy_helpers/CONTRIBUTING.md0000644000077000000240000000216512361722142020077 0ustar tomstaff00000000000000Contributing to astropy-helpers =============================== The guidelines for contributing to ``astropy-helpers`` are generally the same as the [contributing guidelines for the astropy core package](http://github.com/astropy/astropy/blob/master/CONTRIBUTING.md). Basically, report relevant issues in the ``astropy-helpers`` issue tracker, and we welcome pull requests that broadly follow the [Astropy coding guidelines](http://docs.astropy.org/en/latest/development/codeguide.html). The key subtlety lies in understanding the relationship between ``astropy`` and ``astropy-helpers``. This package contains the build, installation, and documentation tools used by astropy. It also includes support for the ``setup.py test`` command, though Astropy is still required for this to function (it does not currently include the full Astropy test runner). So issues or improvements to that functionality should be addressed in this package. Any other aspect of the [astropy core package](http://github.com/astropy/astropy) (or any other package that uses ``astropy-helpers``) should be addressed in the github repository for that package. APLpy-2.0.3/astropy_helpers/LICENSE.rst0000644000077000000240000000272312361722142017462 0ustar tomstaff00000000000000Copyright (c) 2014, Astropy Developers 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 the Astropy Team 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. APLpy-2.0.3/astropy_helpers/MANIFEST.in0000644000077000000240000000025413404171254017402 0ustar tomstaff00000000000000include README.rst include CHANGES.rst include LICENSE.rst recursive-include licenses * include ah_bootstrap.py exclude *.pyc *.o prune build prune astropy_helpers/tests APLpy-2.0.3/astropy_helpers/README.rst0000644000077000000240000003357613404171254017350 0ustar tomstaff00000000000000astropy-helpers =============== .. image:: https://travis-ci.org/astropy/astropy-helpers.svg :target: https://travis-ci.org/astropy/astropy-helpers .. image:: https://ci.appveyor.com/api/projects/status/rt9161t9mhx02xp7/branch/master?svg=true :target: https://ci.appveyor.com/project/Astropy/astropy-helpers .. image:: https://codecov.io/gh/astropy/astropy-helpers/branch/master/graph/badge.svg :target: https://codecov.io/gh/astropy/astropy-helpers **Warning:** Please note that version ``v3.0`` and later of ``astropy-helpers`` requires Python 3.5 or later. If you wish to maintain Python 2 support for your package that uses ``astropy-helpers``, then do not upgrade the helpers to ``v3.0+``. We will still provide Python 2.7 compatible releases on the ``v2.0.x`` branch during the lifetime of the ``astropy`` core package LTS of ``v2.0.x``. About ----- This project provides a Python package, ``astropy_helpers``, which includes many build, installation, and documentation-related tools used by the Astropy project, but packaged separately for use by other projects that wish to leverage this work. The motivation behind this package and details of its implementation are in the accepted `Astropy Proposal for Enhancement (APE) 4 `_. ``astropy_helpers`` includes a special "bootstrap" module called ``ah_bootstrap.py`` which is intended to be used by a project's setup.py in order to ensure that the ``astropy_helpers`` package is available for build/installation. As described in `APE4 `_, the version numbers for ``astropy_helpers`` follow the corresponding major/minor version of the `astropy core package `_, but with an independent sequence of micro (bugfix) version numbers. Hence, the initial release is 0.4, in parallel with Astropy v0.4, which will be the first version of Astropy to use ``astropy-helpers``. For examples of how to implement ``astropy-helpers`` in a project, see the ``setup.py`` and ``setup.cfg`` files of the `Affiliated package template `_. What does astropy-helpers provide? ---------------------------------- Astropy-helpers' big-picture purpose is to provide customization to Python's packaging infrastructure process in ways that the Astropy Project has found to help simplifying the developint and releasing packages. This is primarily build around ``setup.py`` commands, as outlined below, as well as code to help manage version numbers and better control the build process of larger packages. Custom setup.py commands ^^^^^^^^^^^^^^^^^^^^^^^^ The main part of astropy-helpers is to provide customized setuptools commands. For example, in a package that uses astropy-helpers, the following command will be available:: python setup.py build_docs and this command is implemented in astropy-helpers. To use the custom commands described here, add:: from astropy_helpers.setup_helpers import register_commands to your ``setup.py`` file, then do:: cmdclassd = register_commands(NAME, VERSION, RELEASE) where ``NAME`` is the name of your package, ``VERSION`` is the full version string, and ``RELEASE`` is a boolean value indicating whether the version is a stable released version (``True``) or a developer version (``False``). Finally, pass ``cmdclassd`` to the ``setup`` function:: setup(..., cmdclass=cmdclassd) The commands we provide or customize are: **python setup.py test** This command will automatically build the package, install it to a temporary directory, and run the tests using `pytest `_ on this installed version. Note that the bulk of this command is actually defined in ``astropy.tests.command.AstropyTest``, because that allows the test machinery to operate outside a setuptools command. This, here we simply define the custom setuptools command. **python setup.py sdist** We redefine ``sdist`` to use the version from distutils rather than from setuptools, as the setuptools version requires duplication of information in ``MANIFEST.in``. **python setup.py build_docs** This command will automatically build the package, then run sphinx to build the documentation. This makes development much easier because it ensures sphinx extensions that use the package's code to make documentation are actually using the in-development version of the code. Sphinx itself provides a custom setuptools command, which we expand with the following options: * ``-w``: set the return code to 1 if there are any warnings during the build process. * ``-l``: completely clean previous builds, including files generated by the sphinx-automodapi package (which creates API pages for different functions/classes). * ``-n``: disable the intersphinx option. * ``-o``: open the documentation in a browser if a build finishes successfully. In addition, ``build_docs`` will automatically download and temporarily install sphinx-astropy (which is a meta-package that provides standardized configuration and documentation dependencies for astropy packages) if it isn't already installed. Temporary installation means that the package will be installed into an ``.eggs`` directory in the current working directory, and it will only be available for the duration of the call to ``build_docs``. **python setup.py build_ext** This is also used when running ``build`` or ``install``. We add several features compared to the default ``build_ext`` command: * For packages with C/Cython extensions, we create a ``packagename._compiler`` submodule that contains information about the compilers used. * Packages that need to build C extensions using the Numpy C API, we allow those packages to define the include path as ``'numpy'`` as opposed to having to import Numpy and call ``get_include``. The goal is to solve the issue that if one has to import Numpy to define extensions, then Numpy has to be installed/available before the package is installed, which means that one needs to install Numpy in a separate installation step. * We detect broken compilers and replace them with other compilers on-the-fly unless the compiler is explicitly specified with the ``CC`` environment variable. * If Cython is not installed, then we automatically check for generated C files (which are normally present in the stable releases) and give a nice error if these are not found. Version helpers ^^^^^^^^^^^^^^^^ Another piece of functionality we provide in astropy-helpers is the ability to generate a ``packagename.version`` file that includes functions that automatically set the version string for developer versions, to e.g. ``3.2.dev22213`` so that each developer version has a unique number (although note that branches an equal number of commits away from the master branch will share the same version number). To use this, import:: from astropy_helpers.git_helpers import get_git_devstr in your ``setup.py`` file, and you will then be able to use:: VERSION += get_git_devstr() where ``VERSION`` is a version string without any developer version suffix. We then also provide a function that generates a ``version.py`` file inside your package (which can then be imported as ``packagename.version``) that contains variables such as ``major``, ``minor``, and ``bugfix``, as well as ``version_info`` (a tuple of the previous three values), a ``release`` flag that indicates whether we are using a stable release, and several other complementary variables. To use this, import:: from astropy_helpers.version_helpers import generate_version_py in your ``setup.py`` file, and call:: generate_version_py(NAME, VERSION, RELEASE, uses_git=not RELEASE) where ``NAME`` is the name of your package, ``VERSION`` is the full version string (including any developer suffix), ``RELEASE`` indicates whether the version is a stable or developer version, and ``uses_git`` indicates whether we are in a git repository (using ``not RELEASE`` is sensible since git is not available in a stable release). Collecting package information ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``setup`` function from setuptools can take a number of options that indicate for example what extensions to build, and what package data to include. However, for large packages this can become cumbersome. We therefore provide a mechanism for defining extensions and package data inside individual sub-packages. To do this, you can create ``setup_package.py`` files anywhere in your package, and these files can include one or more of the following functions: * ``get_package_data``: This function, if defined, should return a dictionary mapping the name of the subpackage(s) that need package data to a list of data file paths (possibly including wildcards) relative to the path of the package's source code. e.g. if the source distribution has a needed data file ``astropy/wcs/tests/data/3d_cd.hdr``, this function should return ``{'astropy.wcs.tests':['data/3d_cd.hdr']}``. See the ``package_data`` option of the :func:`distutils.core.setup` function. It is recommended that all such data be in a directory named ``data`` inside the package within which it is supposed to be used. This package data should be accessed via the ``astropy.utils.data.get_pkg_data_filename`` and ``astropy.utils.data.get_pkg_data_fileobj`` functions. * ``get_extensions``: This provides information for building C or Cython extensions. If defined, it should return a list of ``distutils.core.Extension`` objects. * ``get_build_options``: This function allows a package to add extra build options. It should return a list of tuples, where each element has: - *name*: The name of the option as it would appear on the commandline or in the ``setup.cfg`` file. - *doc*: A short doc string for the option, displayed by ``setup.py build --help``. - *is_bool* (optional): When `True`, the option is a boolean option and doesn't have an associated value. Once an option has been added, its value can be looked up using ``astropy_helpers.setup_helpers.get_distutils_build_option``. * ``get_external_libraries``: This function declares that the package uses libraries that are included in the astropy distribution that may also be distributed elsewhere on the users system. It should return a list of library names. For each library, a new build option is created, ``'--use-system-X'`` which allows the user to request to use the system's copy of the library. The package would typically call ``astropy_helpers.setup_helpers.use_system_library`` from its ``get_extensions`` function to determine if the package should use the system library or the included one. * ``get_entry_points()``: This function can returns a dict formatted as required by the ``entry_points`` argument to ``setup()``. With these files in place, you can then add the following to your ``setup.py`` file:: from astropy_helpers.setup_helpers import get_package_info ... package_info = get_package_info() ... setup(..., **package_info) OpenMP helpers ^^^^^^^^^^^^^^ We provide a helper function ``add_openmp_flags_if_available`` that can be used to automatically add OpenMP flags for C/Cython extensions, based on whether OpenMP is available and produces executable code. To use this, edit the ``setup_package.py`` file where you define a C extension, import the helper function:: from astropy_helpers.openmp_helpers import add_openmp_flags_if_available then once you have defined the extension and before returning it, use it as:: extension = Extension(...) add_openmp_flags_if_available(extension) return [extension] Using astropy-helpers --------------------- The easiest way to get set up with astropy-helpers in a new package is to use the `package-template `_ that we provide. This template is specifically designed for use with the helpers, so using it avoids some of the tedium of setting up the heleprs. However, we now go through the steps of adding astropy-helpers as a submodule to a package in case you wish to do so manually. First, add astropy-helpers as a submodule at the root of your repository:: git submodule add git://github.com/astropy/astropy-helpers astropy_helpers Then go inside the submodule and check out a stable version of astropy-helpers. You can see the available versions by running:: $ cd astropy_helpers $ git tag ... v2.0.6 v2.0.7 ... v3.0.1 v3.0.2 If you want to support Python 2, pick the latest v2.0.x version (in the above case ``v2.0.7``) and if you don't need to support Python 2, just pick the latest stable version (in the above case ``v3.0.2``). Check out this version with e.g.:: $ git checkout v3.0.2 Then go back up to the root of your repository and copy the ``ah_bootstrap.py`` file from the submodule to the root of your repository:: $ cd .. $ cp astropy_helpers/ah_bootstrap.py . Finally, add:: import ah_bootstrap at the top of your ``setup.py`` file. This will ensure that ``astropy_helpers`` is now available to use in your ``setup.py`` file. Finally, add then commit your changes:: git add astropy_helpers ah_bootstrap.py setup.py git commit -m "Added astropy-helpers" Updating astropy-helpers ------------------------ If you would like the Astropy team to automatically open pull requests to update astropy-helpers in your package, then see the instructions `here `_. To instead update astropy-helpers manually, go inside the submodule and do:: cd astropy_helpers git fetch origin Then checkout the version you want to use, e.g.:: git checkout v3.0.3 Go back up to the root of the repository and update the ``ah_bootstap.py`` file too, then add your changes:: cp astropy_helpers/ah_bootstrap.py . git add astropy_helpers ah_bootstrap.py git commit ... APLpy-2.0.3/astropy_helpers/ah_bootstrap.py0000644000077000000240000010550613404171254020711 0ustar tomstaff00000000000000""" This bootstrap module contains code for ensuring that the astropy_helpers package will be importable by the time the setup.py script runs. It also includes some workarounds to ensure that a recent-enough version of setuptools is being used for the installation. This module should be the first thing imported in the setup.py of distributions that make use of the utilities in astropy_helpers. If the distribution ships with its own copy of astropy_helpers, this module will first attempt to import from the shipped copy. However, it will also check PyPI to see if there are any bug-fix releases on top of the current version that may be useful to get past platform-specific bugs that have been fixed. When running setup.py, use the ``--offline`` command-line option to disable the auto-upgrade checks. When this module is imported or otherwise executed it automatically calls a main function that attempts to read the project's setup.cfg file, which it checks for a configuration section called ``[ah_bootstrap]`` the presences of that section, and options therein, determine the next step taken: If it contains an option called ``auto_use`` with a value of ``True``, it will automatically call the main function of this module called `use_astropy_helpers` (see that function's docstring for full details). Otherwise no further action is taken and by default the system-installed version of astropy-helpers will be used (however, ``ah_bootstrap.use_astropy_helpers`` may be called manually from within the setup.py script). This behavior can also be controlled using the ``--auto-use`` and ``--no-auto-use`` command-line flags. For clarity, an alias for ``--no-auto-use`` is ``--use-system-astropy-helpers``, and we recommend using the latter if needed. Additional options in the ``[ah_boostrap]`` section of setup.cfg have the same names as the arguments to `use_astropy_helpers`, and can be used to configure the bootstrap script when ``auto_use = True``. See https://github.com/astropy/astropy-helpers for more details, and for the latest version of this module. """ import contextlib import errno import io import locale import os import re import subprocess as sp import sys __minimum_python_version__ = (3, 5) if sys.version_info < __minimum_python_version__: print("ERROR: Python {} or later is required by astropy-helpers".format( __minimum_python_version__)) sys.exit(1) try: from ConfigParser import ConfigParser, RawConfigParser except ImportError: from configparser import ConfigParser, RawConfigParser _str_types = (str, bytes) # What follows are several import statements meant to deal with install-time # issues with either missing or misbehaving pacakges (including making sure # setuptools itself is installed): # Check that setuptools 1.0 or later is present from distutils.version import LooseVersion try: import setuptools assert LooseVersion(setuptools.__version__) >= LooseVersion('1.0') except (ImportError, AssertionError): print("ERROR: setuptools 1.0 or later is required by astropy-helpers") sys.exit(1) # typing as a dependency for 1.6.1+ Sphinx causes issues when imported after # initializing submodule with ah_boostrap.py # See discussion and references in # https://github.com/astropy/astropy-helpers/issues/302 try: import typing # noqa except ImportError: pass # Note: The following import is required as a workaround to # https://github.com/astropy/astropy-helpers/issues/89; if we don't import this # module now, it will get cleaned up after `run_setup` is called, but that will # later cause the TemporaryDirectory class defined in it to stop working when # used later on by setuptools try: import setuptools.py31compat # noqa except ImportError: pass # matplotlib can cause problems if it is imported from within a call of # run_setup(), because in some circumstances it will try to write to the user's # home directory, resulting in a SandboxViolation. See # https://github.com/matplotlib/matplotlib/pull/4165 # Making sure matplotlib, if it is available, is imported early in the setup # process can mitigate this (note importing matplotlib.pyplot has the same # issue) try: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot except: # Ignore if this fails for *any* reason* pass # End compatibility imports... # In case it didn't successfully import before the ez_setup checks import pkg_resources from setuptools import Distribution from setuptools.package_index import PackageIndex from distutils import log from distutils.debug import DEBUG # TODO: Maybe enable checking for a specific version of astropy_helpers? DIST_NAME = 'astropy-helpers' PACKAGE_NAME = 'astropy_helpers' UPPER_VERSION_EXCLUSIVE = None # Defaults for other options DOWNLOAD_IF_NEEDED = True INDEX_URL = 'https://pypi.python.org/simple' USE_GIT = True OFFLINE = False AUTO_UPGRADE = True # A list of all the configuration options and their required types CFG_OPTIONS = [ ('auto_use', bool), ('path', str), ('download_if_needed', bool), ('index_url', str), ('use_git', bool), ('offline', bool), ('auto_upgrade', bool) ] class _Bootstrapper(object): """ Bootstrapper implementation. See ``use_astropy_helpers`` for parameter documentation. """ def __init__(self, path=None, index_url=None, use_git=None, offline=None, download_if_needed=None, auto_upgrade=None): if path is None: path = PACKAGE_NAME if not (isinstance(path, _str_types) or path is False): raise TypeError('path must be a string or False') if not isinstance(path, str): fs_encoding = sys.getfilesystemencoding() path = path.decode(fs_encoding) # path to unicode self.path = path # Set other option attributes, using defaults where necessary self.index_url = index_url if index_url is not None else INDEX_URL self.offline = offline if offline is not None else OFFLINE # If offline=True, override download and auto-upgrade if self.offline: download_if_needed = False auto_upgrade = False self.download = (download_if_needed if download_if_needed is not None else DOWNLOAD_IF_NEEDED) self.auto_upgrade = (auto_upgrade if auto_upgrade is not None else AUTO_UPGRADE) # If this is a release then the .git directory will not exist so we # should not use git. git_dir_exists = os.path.exists(os.path.join(os.path.dirname(__file__), '.git')) if use_git is None and not git_dir_exists: use_git = False self.use_git = use_git if use_git is not None else USE_GIT # Declared as False by default--later we check if astropy-helpers can be # upgraded from PyPI, but only if not using a source distribution (as in # the case of import from a git submodule) self.is_submodule = False @classmethod def main(cls, argv=None): if argv is None: argv = sys.argv config = cls.parse_config() config.update(cls.parse_command_line(argv)) auto_use = config.pop('auto_use', False) bootstrapper = cls(**config) if auto_use: # Run the bootstrapper, otherwise the setup.py is using the old # use_astropy_helpers() interface, in which case it will run the # bootstrapper manually after reconfiguring it. bootstrapper.run() return bootstrapper @classmethod def parse_config(cls): if not os.path.exists('setup.cfg'): return {} cfg = ConfigParser() try: cfg.read('setup.cfg') except Exception as e: if DEBUG: raise log.error( "Error reading setup.cfg: {0!r}\n{1} will not be " "automatically bootstrapped and package installation may fail." "\n{2}".format(e, PACKAGE_NAME, _err_help_msg)) return {} if not cfg.has_section('ah_bootstrap'): return {} config = {} for option, type_ in CFG_OPTIONS: if not cfg.has_option('ah_bootstrap', option): continue if type_ is bool: value = cfg.getboolean('ah_bootstrap', option) else: value = cfg.get('ah_bootstrap', option) config[option] = value return config @classmethod def parse_command_line(cls, argv=None): if argv is None: argv = sys.argv config = {} # For now we just pop recognized ah_bootstrap options out of the # arg list. This is imperfect; in the unlikely case that a setup.py # custom command or even custom Distribution class defines an argument # of the same name then we will break that. However there's a catch22 # here that we can't just do full argument parsing right here, because # we don't yet know *how* to parse all possible command-line arguments. if '--no-git' in argv: config['use_git'] = False argv.remove('--no-git') if '--offline' in argv: config['offline'] = True argv.remove('--offline') if '--auto-use' in argv: config['auto_use'] = True argv.remove('--auto-use') if '--no-auto-use' in argv: config['auto_use'] = False argv.remove('--no-auto-use') if '--use-system-astropy-helpers' in argv: config['auto_use'] = False argv.remove('--use-system-astropy-helpers') return config def run(self): strategies = ['local_directory', 'local_file', 'index'] dist = None # First, remove any previously imported versions of astropy_helpers; # this is necessary for nested installs where one package's installer # is installing another package via setuptools.sandbox.run_setup, as in # the case of setup_requires for key in list(sys.modules): try: if key == PACKAGE_NAME or key.startswith(PACKAGE_NAME + '.'): del sys.modules[key] except AttributeError: # Sometimes mysterious non-string things can turn up in # sys.modules continue # Check to see if the path is a submodule self.is_submodule = self._check_submodule() for strategy in strategies: method = getattr(self, 'get_{0}_dist'.format(strategy)) dist = method() if dist is not None: break else: raise _AHBootstrapSystemExit( "No source found for the {0!r} package; {0} must be " "available and importable as a prerequisite to building " "or installing this package.".format(PACKAGE_NAME)) # This is a bit hacky, but if astropy_helpers was loaded from a # directory/submodule its Distribution object gets a "precedence" of # "DEVELOP_DIST". However, in other cases it gets a precedence of # "EGG_DIST". However, when activing the distribution it will only be # placed early on sys.path if it is treated as an EGG_DIST, so always # do that dist = dist.clone(precedence=pkg_resources.EGG_DIST) # Otherwise we found a version of astropy-helpers, so we're done # Just active the found distribution on sys.path--if we did a # download this usually happens automatically but it doesn't hurt to # do it again # Note: Adding the dist to the global working set also activates it # (makes it importable on sys.path) by default. try: pkg_resources.working_set.add(dist, replace=True) except TypeError: # Some (much) older versions of setuptools do not have the # replace=True option here. These versions are old enough that all # bets may be off anyways, but it's easy enough to work around just # in case... if dist.key in pkg_resources.working_set.by_key: del pkg_resources.working_set.by_key[dist.key] pkg_resources.working_set.add(dist) @property def config(self): """ A `dict` containing the options this `_Bootstrapper` was configured with. """ return dict((optname, getattr(self, optname)) for optname, _ in CFG_OPTIONS if hasattr(self, optname)) def get_local_directory_dist(self): """ Handle importing a vendored package from a subdirectory of the source distribution. """ if not os.path.isdir(self.path): return log.info('Attempting to import astropy_helpers from {0} {1!r}'.format( 'submodule' if self.is_submodule else 'directory', self.path)) dist = self._directory_import() if dist is None: log.warn( 'The requested path {0!r} for importing {1} does not ' 'exist, or does not contain a copy of the {1} ' 'package.'.format(self.path, PACKAGE_NAME)) elif self.auto_upgrade and not self.is_submodule: # A version of astropy-helpers was found on the available path, but # check to see if a bugfix release is available on PyPI upgrade = self._do_upgrade(dist) if upgrade is not None: dist = upgrade return dist def get_local_file_dist(self): """ Handle importing from a source archive; this also uses setup_requires but points easy_install directly to the source archive. """ if not os.path.isfile(self.path): return log.info('Attempting to unpack and import astropy_helpers from ' '{0!r}'.format(self.path)) try: dist = self._do_download(find_links=[self.path]) except Exception as e: if DEBUG: raise log.warn( 'Failed to import {0} from the specified archive {1!r}: ' '{2}'.format(PACKAGE_NAME, self.path, str(e))) dist = None if dist is not None and self.auto_upgrade: # A version of astropy-helpers was found on the available path, but # check to see if a bugfix release is available on PyPI upgrade = self._do_upgrade(dist) if upgrade is not None: dist = upgrade return dist def get_index_dist(self): if not self.download: log.warn('Downloading {0!r} disabled.'.format(DIST_NAME)) return None log.warn( "Downloading {0!r}; run setup.py with the --offline option to " "force offline installation.".format(DIST_NAME)) try: dist = self._do_download() except Exception as e: if DEBUG: raise log.warn( 'Failed to download and/or install {0!r} from {1!r}:\n' '{2}'.format(DIST_NAME, self.index_url, str(e))) dist = None # No need to run auto-upgrade here since we've already presumably # gotten the most up-to-date version from the package index return dist def _directory_import(self): """ Import astropy_helpers from the given path, which will be added to sys.path. Must return True if the import succeeded, and False otherwise. """ # Return True on success, False on failure but download is allowed, and # otherwise raise SystemExit path = os.path.abspath(self.path) # Use an empty WorkingSet rather than the man # pkg_resources.working_set, since on older versions of setuptools this # will invoke a VersionConflict when trying to install an upgrade ws = pkg_resources.WorkingSet([]) ws.add_entry(path) dist = ws.by_key.get(DIST_NAME) if dist is None: # We didn't find an egg-info/dist-info in the given path, but if a # setup.py exists we can generate it setup_py = os.path.join(path, 'setup.py') if os.path.isfile(setup_py): # We use subprocess instead of run_setup from setuptools to # avoid segmentation faults - see the following for more details: # https://github.com/cython/cython/issues/2104 sp.check_output([sys.executable, 'setup.py', 'egg_info'], cwd=path) for dist in pkg_resources.find_distributions(path, True): # There should be only one... return dist return dist def _do_download(self, version='', find_links=None): if find_links: allow_hosts = '' index_url = None else: allow_hosts = None index_url = self.index_url # Annoyingly, setuptools will not handle other arguments to # Distribution (such as options) before handling setup_requires, so it # is not straightforward to programmatically augment the arguments which # are passed to easy_install class _Distribution(Distribution): def get_option_dict(self, command_name): opts = Distribution.get_option_dict(self, command_name) if command_name == 'easy_install': if find_links is not None: opts['find_links'] = ('setup script', find_links) if index_url is not None: opts['index_url'] = ('setup script', index_url) if allow_hosts is not None: opts['allow_hosts'] = ('setup script', allow_hosts) return opts if version: req = '{0}=={1}'.format(DIST_NAME, version) else: if UPPER_VERSION_EXCLUSIVE is None: req = DIST_NAME else: req = '{0}<{1}'.format(DIST_NAME, UPPER_VERSION_EXCLUSIVE) attrs = {'setup_requires': [req]} # NOTE: we need to parse the config file (e.g. setup.cfg) to make sure # it honours the options set in the [easy_install] section, and we need # to explicitly fetch the requirement eggs as setup_requires does not # get honored in recent versions of setuptools: # https://github.com/pypa/setuptools/issues/1273 try: context = _verbose if DEBUG else _silence with context(): dist = _Distribution(attrs=attrs) try: dist.parse_config_files(ignore_option_errors=True) dist.fetch_build_eggs(req) except TypeError: # On older versions of setuptools, ignore_option_errors # doesn't exist, and the above two lines are not needed # so we can just continue pass # If the setup_requires succeeded it will have added the new dist to # the main working_set return pkg_resources.working_set.by_key.get(DIST_NAME) except Exception as e: if DEBUG: raise msg = 'Error retrieving {0} from {1}:\n{2}' if find_links: source = find_links[0] elif index_url != INDEX_URL: source = index_url else: source = 'PyPI' raise Exception(msg.format(DIST_NAME, source, repr(e))) def _do_upgrade(self, dist): # Build up a requirement for a higher bugfix release but a lower minor # release (so API compatibility is guaranteed) next_version = _next_version(dist.parsed_version) req = pkg_resources.Requirement.parse( '{0}>{1},<{2}'.format(DIST_NAME, dist.version, next_version)) package_index = PackageIndex(index_url=self.index_url) upgrade = package_index.obtain(req) if upgrade is not None: return self._do_download(version=upgrade.version) def _check_submodule(self): """ Check if the given path is a git submodule. See the docstrings for ``_check_submodule_using_git`` and ``_check_submodule_no_git`` for further details. """ if (self.path is None or (os.path.exists(self.path) and not os.path.isdir(self.path))): return False if self.use_git: return self._check_submodule_using_git() else: return self._check_submodule_no_git() def _check_submodule_using_git(self): """ Check if the given path is a git submodule. If so, attempt to initialize and/or update the submodule if needed. This function makes calls to the ``git`` command in subprocesses. The ``_check_submodule_no_git`` option uses pure Python to check if the given path looks like a git submodule, but it cannot perform updates. """ cmd = ['git', 'submodule', 'status', '--', self.path] try: log.info('Running `{0}`; use the --no-git option to disable git ' 'commands'.format(' '.join(cmd))) returncode, stdout, stderr = run_cmd(cmd) except _CommandNotFound: # The git command simply wasn't found; this is most likely the # case on user systems that don't have git and are simply # trying to install the package from PyPI or a source # distribution. Silently ignore this case and simply don't try # to use submodules return False stderr = stderr.strip() if returncode != 0 and stderr: # Unfortunately the return code alone cannot be relied on, as # earlier versions of git returned 0 even if the requested submodule # does not exist # This is a warning that occurs in perl (from running git submodule) # which only occurs with a malformatted locale setting which can # happen sometimes on OSX. See again # https://github.com/astropy/astropy/issues/2749 perl_warning = ('perl: warning: Falling back to the standard locale ' '("C").') if not stderr.strip().endswith(perl_warning): # Some other unknown error condition occurred log.warn('git submodule command failed ' 'unexpectedly:\n{0}'.format(stderr)) return False # Output of `git submodule status` is as follows: # # 1: Status indicator: '-' for submodule is uninitialized, '+' if # submodule is initialized but is not at the commit currently indicated # in .gitmodules (and thus needs to be updated), or 'U' if the # submodule is in an unstable state (i.e. has merge conflicts) # # 2. SHA-1 hash of the current commit of the submodule (we don't really # need this information but it's useful for checking that the output is # correct) # # 3. The output of `git describe` for the submodule's current commit # hash (this includes for example what branches the commit is on) but # only if the submodule is initialized. We ignore this information for # now _git_submodule_status_re = re.compile( '^(?P[+-U ])(?P[0-9a-f]{40}) ' '(?P\S+)( .*)?$') # The stdout should only contain one line--the status of the # requested submodule m = _git_submodule_status_re.match(stdout) if m: # Yes, the path *is* a git submodule self._update_submodule(m.group('submodule'), m.group('status')) return True else: log.warn( 'Unexpected output from `git submodule status`:\n{0}\n' 'Will attempt import from {1!r} regardless.'.format( stdout, self.path)) return False def _check_submodule_no_git(self): """ Like ``_check_submodule_using_git``, but simply parses the .gitmodules file to determine if the supplied path is a git submodule, and does not exec any subprocesses. This can only determine if a path is a submodule--it does not perform updates, etc. This function may need to be updated if the format of the .gitmodules file is changed between git versions. """ gitmodules_path = os.path.abspath('.gitmodules') if not os.path.isfile(gitmodules_path): return False # This is a minimal reader for gitconfig-style files. It handles a few of # the quirks that make gitconfig files incompatible with ConfigParser-style # files, but does not support the full gitconfig syntax (just enough # needed to read a .gitmodules file). gitmodules_fileobj = io.StringIO() # Must use io.open for cross-Python-compatible behavior wrt unicode with io.open(gitmodules_path) as f: for line in f: # gitconfig files are more flexible with leading whitespace; just # go ahead and remove it line = line.lstrip() # comments can start with either # or ; if line and line[0] in (':', ';'): continue gitmodules_fileobj.write(line) gitmodules_fileobj.seek(0) cfg = RawConfigParser() try: cfg.readfp(gitmodules_fileobj) except Exception as exc: log.warn('Malformatted .gitmodules file: {0}\n' '{1} cannot be assumed to be a git submodule.'.format( exc, self.path)) return False for section in cfg.sections(): if not cfg.has_option(section, 'path'): continue submodule_path = cfg.get(section, 'path').rstrip(os.sep) if submodule_path == self.path.rstrip(os.sep): return True return False def _update_submodule(self, submodule, status): if status == ' ': # The submodule is up to date; no action necessary return elif status == '-': if self.offline: raise _AHBootstrapSystemExit( "Cannot initialize the {0} submodule in --offline mode; " "this requires being able to clone the submodule from an " "online repository.".format(submodule)) cmd = ['update', '--init'] action = 'Initializing' elif status == '+': cmd = ['update'] action = 'Updating' if self.offline: cmd.append('--no-fetch') elif status == 'U': raise _AHBootstrapSystemExit( 'Error: Submodule {0} contains unresolved merge conflicts. ' 'Please complete or abandon any changes in the submodule so that ' 'it is in a usable state, then try again.'.format(submodule)) else: log.warn('Unknown status {0!r} for git submodule {1!r}. Will ' 'attempt to use the submodule as-is, but try to ensure ' 'that the submodule is in a clean state and contains no ' 'conflicts or errors.\n{2}'.format(status, submodule, _err_help_msg)) return err_msg = None cmd = ['git', 'submodule'] + cmd + ['--', submodule] log.warn('{0} {1} submodule with: `{2}`'.format( action, submodule, ' '.join(cmd))) try: log.info('Running `{0}`; use the --no-git option to disable git ' 'commands'.format(' '.join(cmd))) returncode, stdout, stderr = run_cmd(cmd) except OSError as e: err_msg = str(e) else: if returncode != 0: err_msg = stderr if err_msg is not None: log.warn('An unexpected error occurred updating the git submodule ' '{0!r}:\n{1}\n{2}'.format(submodule, err_msg, _err_help_msg)) class _CommandNotFound(OSError): """ An exception raised when a command run with run_cmd is not found on the system. """ def run_cmd(cmd): """ Run a command in a subprocess, given as a list of command-line arguments. Returns a ``(returncode, stdout, stderr)`` tuple. """ try: p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE) # XXX: May block if either stdout or stderr fill their buffers; # however for the commands this is currently used for that is # unlikely (they should have very brief output) stdout, stderr = p.communicate() except OSError as e: if DEBUG: raise if e.errno == errno.ENOENT: msg = 'Command not found: `{0}`'.format(' '.join(cmd)) raise _CommandNotFound(msg, cmd) else: raise _AHBootstrapSystemExit( 'An unexpected error occurred when running the ' '`{0}` command:\n{1}'.format(' '.join(cmd), str(e))) # Can fail of the default locale is not configured properly. See # https://github.com/astropy/astropy/issues/2749. For the purposes under # consideration 'latin1' is an acceptable fallback. try: stdio_encoding = locale.getdefaultlocale()[1] or 'latin1' except ValueError: # Due to an OSX oddity locale.getdefaultlocale() can also crash # depending on the user's locale/language settings. See: # http://bugs.python.org/issue18378 stdio_encoding = 'latin1' # Unlikely to fail at this point but even then let's be flexible if not isinstance(stdout, str): stdout = stdout.decode(stdio_encoding, 'replace') if not isinstance(stderr, str): stderr = stderr.decode(stdio_encoding, 'replace') return (p.returncode, stdout, stderr) def _next_version(version): """ Given a parsed version from pkg_resources.parse_version, returns a new version string with the next minor version. Examples ======== >>> _next_version(pkg_resources.parse_version('1.2.3')) '1.3.0' """ if hasattr(version, 'base_version'): # New version parsing from setuptools >= 8.0 if version.base_version: parts = version.base_version.split('.') else: parts = [] else: parts = [] for part in version: if part.startswith('*'): break parts.append(part) parts = [int(p) for p in parts] if len(parts) < 3: parts += [0] * (3 - len(parts)) major, minor, micro = parts[:3] return '{0}.{1}.{2}'.format(major, minor + 1, 0) class _DummyFile(object): """A noop writeable object.""" errors = '' # Required for Python 3.x encoding = 'utf-8' def write(self, s): pass def flush(self): pass @contextlib.contextmanager def _verbose(): yield @contextlib.contextmanager def _silence(): """A context manager that silences sys.stdout and sys.stderr.""" old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = _DummyFile() sys.stderr = _DummyFile() exception_occurred = False try: yield except: exception_occurred = True # Go ahead and clean up so that exception handling can work normally sys.stdout = old_stdout sys.stderr = old_stderr raise if not exception_occurred: sys.stdout = old_stdout sys.stderr = old_stderr _err_help_msg = """ If the problem persists consider installing astropy_helpers manually using pip (`pip install astropy_helpers`) or by manually downloading the source archive, extracting it, and installing by running `python setup.py install` from the root of the extracted source code. """ class _AHBootstrapSystemExit(SystemExit): def __init__(self, *args): if not args: msg = 'An unknown problem occurred bootstrapping astropy_helpers.' else: msg = args[0] msg += '\n' + _err_help_msg super(_AHBootstrapSystemExit, self).__init__(msg, *args[1:]) BOOTSTRAPPER = _Bootstrapper.main() def use_astropy_helpers(**kwargs): """ Ensure that the `astropy_helpers` module is available and is importable. This supports automatic submodule initialization if astropy_helpers is included in a project as a git submodule, or will download it from PyPI if necessary. Parameters ---------- path : str or None, optional A filesystem path relative to the root of the project's source code that should be added to `sys.path` so that `astropy_helpers` can be imported from that path. If the path is a git submodule it will automatically be initialized and/or updated. The path may also be to a ``.tar.gz`` archive of the astropy_helpers source distribution. In this case the archive is automatically unpacked and made temporarily available on `sys.path` as a ``.egg`` archive. If `None` skip straight to downloading. download_if_needed : bool, optional If the provided filesystem path is not found an attempt will be made to download astropy_helpers from PyPI. It will then be made temporarily available on `sys.path` as a ``.egg`` archive (using the ``setup_requires`` feature of setuptools. If the ``--offline`` option is given at the command line the value of this argument is overridden to `False`. index_url : str, optional If provided, use a different URL for the Python package index than the main PyPI server. use_git : bool, optional If `False` no git commands will be used--this effectively disables support for git submodules. If the ``--no-git`` option is given at the command line the value of this argument is overridden to `False`. auto_upgrade : bool, optional By default, when installing a package from a non-development source distribution ah_boostrap will try to automatically check for patch releases to astropy-helpers on PyPI and use the patched version over any bundled versions. Setting this to `False` will disable that functionality. If the ``--offline`` option is given at the command line the value of this argument is overridden to `False`. offline : bool, optional If `False` disable all actions that require an internet connection, including downloading packages from the package index and fetching updates to any git submodule. Defaults to `True`. """ global BOOTSTRAPPER config = BOOTSTRAPPER.config config.update(**kwargs) # Create a new bootstrapper with the updated configuration and run it BOOTSTRAPPER = _Bootstrapper(**config) BOOTSTRAPPER.run() APLpy-2.0.3/astropy_helpers/appveyor.yml0000644000077000000240000000303513404171254020234 0ustar tomstaff00000000000000# AppVeyor.com is a Continuous Integration service to build and run tests under # Windows environment: global: PYTHON: "C:\\conda" MINICONDA_VERSION: "latest" OPENMP_EXPECTED: "True" CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci-helpers\\appveyor\\windows_sdk.cmd" PYTHON_ARCH: "64" # needs to be set for CMD_IN_ENV to succeed. If a mix # of 32 bit and 64 bit builds are needed, move this # to the matrix section. # babel 2.0 is known to break on Windows: # https://github.com/python-babel/babel/issues/174 CONDA_DEPENDENCIES: "numpy Cython sphinx pytest babel!=2.0 setuptools pytest-cov" PIP_DEPENDENCIES: "codecov" matrix: - PYTHON_VERSION: "3.5" - PYTHON_VERSION: "3.6" - PYTHON_VERSION: "3.7" platform: -x64 install: # Set up ci-helpers - "git clone git://github.com/astropy/ci-helpers.git" - "powershell ci-helpers/appveyor/install-miniconda.ps1" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - "activate test" # Some of the tests use git commands that require a user to be configured - git config --global user.name "A U Thor" - git config --global user.email "author@example.com" # Not a .NET project, we build the package in the install step instead build: false test_script: # Specify basetemp explicitly otherwise some of the filenames exceed # 260 characters when fetch_build_eggs runs. - "%CMD_IN_ENV% py.test --cov --basetemp=\\pytest-tmp astropy_helpers" - "%CMD_IN_ENV% codecov" APLpy-2.0.3/astropy_helpers/astropy_helpers/0000755000077000000240000000000013432765724021102 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers/__init__.py0000644000077000000240000000331213404171254023176 0ustar tomstaff00000000000000try: from .version import version as __version__ from .version import githash as __githash__ except ImportError: __version__ = '' __githash__ = '' # If we've made it as far as importing astropy_helpers, we don't need # ah_bootstrap in sys.modules anymore. Getting rid of it is actually necessary # if the package we're installing has a setup_requires of another package that # uses astropy_helpers (and possibly a different version at that) # See https://github.com/astropy/astropy/issues/3541 import sys if 'ah_bootstrap' in sys.modules: del sys.modules['ah_bootstrap'] # Note, this is repeated from ah_bootstrap.py, but is here too in case this # astropy-helpers was upgraded to from an older version that did not have this # check in its ah_bootstrap. # matplotlib can cause problems if it is imported from within a call of # run_setup(), because in some circumstances it will try to write to the user's # home directory, resulting in a SandboxViolation. See # https://github.com/matplotlib/matplotlib/pull/4165 # Making sure matplotlib, if it is available, is imported early in the setup # process can mitigate this (note importing matplotlib.pyplot has the same # issue) try: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot except: # Ignore if this fails for *any* reason* pass import os # Ensure that all module-level code in astropy or other packages know that # we're in setup mode: if ('__main__' in sys.modules and hasattr(sys.modules['__main__'], '__file__')): filename = os.path.basename(sys.modules['__main__'].__file__) if filename.rstrip('co') == 'setup.py': import builtins builtins._ASTROPY_SETUP_ = True del filename APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/0000755000077000000240000000000013432765724022703 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/__init__.py0000644000077000000240000000000012476604504024775 0ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/_dummy.py0000644000077000000240000000526213404171254024540 0ustar tomstaff00000000000000""" Provides a base class for a 'dummy' setup.py command that has no functionality (probably due to a missing requirement). This dummy command can raise an exception when it is run, explaining to the user what dependencies must be met to use this command. The reason this is at all tricky is that we want the command to be able to provide this message even when the user passes arguments to the command. If we don't know ahead of time what arguments the command can take, this is difficult, because distutils does not allow unknown arguments to be passed to a setup.py command. This hacks around that restriction to provide a useful error message even when a user passes arguments to the dummy implementation of a command. Use this like: try: from some_dependency import SetupCommand except ImportError: from ._dummy import _DummyCommand class SetupCommand(_DummyCommand): description = \ 'Implementation of SetupCommand from some_dependency; ' 'some_dependency must be installed to run this command' # This is the message that will be raised when a user tries to # run this command--define it as a class attribute. error_msg = \ "The 'setup_command' command requires the some_dependency " "package to be installed and importable." """ import sys from setuptools import Command from distutils.errors import DistutilsArgError from textwrap import dedent class _DummyCommandMeta(type): """ Causes an exception to be raised on accessing attributes of a command class so that if ``./setup.py command_name`` is run with additional command-line options we can provide a useful error message instead of the default that tells users the options are unrecognized. """ def __init__(cls, name, bases, members): if bases == (Command, object): # This is the _DummyCommand base class, presumably return if not hasattr(cls, 'description'): raise TypeError( "_DummyCommand subclass must have a 'description' " "attribute.") if not hasattr(cls, 'error_msg'): raise TypeError( "_DummyCommand subclass must have an 'error_msg' " "attribute.") def __getattribute__(cls, attr): if attr in ('description', 'error_msg'): # Allow cls.description to work so that `./setup.py # --help-commands` still works return super(_DummyCommandMeta, cls).__getattribute__(attr) raise DistutilsArgError(cls.error_msg) class _DummyCommand(Command, object, metaclass=_DummyCommandMeta): pass APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/build_ext.py0000644000077000000240000004655513404171254025237 0ustar tomstaff00000000000000import errno import os import re import shlex import shutil import subprocess import sys import textwrap from distutils import log, ccompiler, sysconfig from distutils.core import Extension from distutils.ccompiler import get_default_compiler from importlib import invalidate_caches from setuptools.command.build_ext import build_ext as SetuptoolsBuildExt from setuptools.command import build_py from ..utils import get_numpy_include_path, classproperty from ..version_helpers import get_pkg_version_module def should_build_with_cython(package, release=None): """Returns the previously used Cython version (or 'unknown' if not previously built) if Cython should be used to build extension modules from pyx files. If the ``release`` parameter is not specified an attempt is made to determine the release flag from `astropy.version`. """ try: version_module = __import__(package + '.cython_version', fromlist=['release', 'cython_version']) except ImportError: version_module = None if release is None and version_module is not None: try: release = version_module.release except AttributeError: pass try: cython_version = version_module.cython_version except AttributeError: cython_version = 'unknown' # Only build with Cython if, of course, Cython is installed, we're in a # development version (i.e. not release) or the Cython-generated source # files haven't been created yet (cython_version == 'unknown'). The latter # case can happen even when release is True if checking out a release tag # from the repository have_cython = False try: import Cython # noqa have_cython = True except ImportError: pass if have_cython and (not release or cython_version == 'unknown'): return cython_version else: return False _compiler_versions = {} def get_compiler_version(compiler): if compiler in _compiler_versions: return _compiler_versions[compiler] # Different flags to try to get the compiler version # TODO: It might be worth making this configurable to support # arbitrary odd compilers; though all bets may be off in such # cases anyway flags = ['--version', '--Version', '-version', '-Version', '-v', '-V'] def try_get_version(flag): process = subprocess.Popen( shlex.split(compiler, posix=('win' not in sys.platform)) + [flag], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if process.returncode != 0: return 'unknown' output = stdout.strip().decode('latin-1') # Safest bet if not output: # Some compilers return their version info on stderr output = stderr.strip().decode('latin-1') if not output: output = 'unknown' return output for flag in flags: version = try_get_version(flag) if version != 'unknown': break # Cache results to speed up future calls _compiler_versions[compiler] = version return version # TODO: I think this can be reworked without having to create the class # programmatically. def generate_build_ext_command(packagename, release): """ Creates a custom 'build_ext' command that allows for manipulating some of the C extension options at build time. We use a function to build the class since the base class for build_ext may be different depending on certain build-time parameters (for example, we may use Cython's build_ext instead of the default version in distutils). Uses the default distutils.command.build_ext by default. """ class build_ext(SetuptoolsBuildExt, object): package_name = packagename is_release = release _user_options = SetuptoolsBuildExt.user_options[:] _boolean_options = SetuptoolsBuildExt.boolean_options[:] _help_options = SetuptoolsBuildExt.help_options[:] force_rebuild = False _broken_compiler_mapping = [ ('i686-apple-darwin[0-9]*-llvm-gcc-4.2', 'clang') ] # Warning: Spaghetti code ahead. # During setup.py, the setup_helpers module needs the ability to add # items to a command's user_options list. At this stage we don't know # whether or not we can build with Cython, and so don't know for sure # what base class will be used for build_ext; nevertheless we want to # be able to provide a list to add options into. # # Later, once setup() has been called we should have all build # dependencies included via setup_requires available. distutils needs # to be able to access the user_options as a *class* attribute before # the class has been initialized, but we do need to be able to # enumerate the options for the correct base class at that point @classproperty def user_options(cls): from distutils import core if core._setup_distribution is None: # We haven't gotten into setup() yet, and the Distribution has # not yet been initialized return cls._user_options return cls._final_class.user_options @classproperty def boolean_options(cls): # Similar to user_options above from distutils import core if core._setup_distribution is None: # We haven't gotten into setup() yet, and the Distribution has # not yet been initialized return cls._boolean_options return cls._final_class.boolean_options @classproperty def help_options(cls): # Similar to user_options above from distutils import core if core._setup_distribution is None: # We haven't gotten into setup() yet, and the Distribution has # not yet been initialized return cls._help_options return cls._final_class.help_options @classproperty(lazy=True) def _final_class(cls): """ Late determination of what the build_ext base class should be, depending on whether or not Cython is available. """ uses_cython = should_build_with_cython(cls.package_name, cls.is_release) if uses_cython: # We need to decide late on whether or not to use Cython's # build_ext (since Cython may not be available earlier in the # setup.py if it was brought in via setup_requires) try: from Cython.Distutils.old_build_ext import old_build_ext as base_cls except ImportError: from Cython.Distutils import build_ext as base_cls else: base_cls = SetuptoolsBuildExt # Create and return an instance of a new class based on this class # using one of the above possible base classes def merge_options(attr): base = getattr(base_cls, attr) ours = getattr(cls, '_' + attr) all_base = set(opt[0] for opt in base) return base + [opt for opt in ours if opt[0] not in all_base] boolean_options = (base_cls.boolean_options + [opt for opt in cls._boolean_options if opt not in base_cls.boolean_options]) members = dict(cls.__dict__) members.update({ 'user_options': merge_options('user_options'), 'help_options': merge_options('help_options'), 'boolean_options': boolean_options, 'uses_cython': uses_cython, }) # Update the base class for the original build_ext command build_ext.__bases__ = (base_cls, object) # Create a new class for the existing class, but now with the # appropriate base class depending on whether or not to use Cython. # Ensure that object is one of the bases to make a new-style class. return type(cls.__name__, (build_ext,), members) def __new__(cls, *args, **kwargs): # By the time the command is actually instantialized, the # Distribution instance for the build has been instantiated, which # means setup_requires has been processed--now we can determine # what base class we can use for the actual build, and return an # instance of a build_ext command that uses that base class (right # now the options being Cython.Distutils.build_ext, or the stock # setuptools build_ext) new_cls = super(build_ext, cls._final_class).__new__(cls._final_class) # Since the new cls is not a subclass of the original cls, we must # manually call its __init__ new_cls.__init__(*args, **kwargs) return new_cls def finalize_options(self): # Add a copy of the _compiler.so module as well, but only if there # are in fact C modules to compile (otherwise there's no reason to # include a record of the compiler used) # Note, self.extensions may not be set yet, but # self.distribution.ext_modules is where any extension modules # passed to setup() can be found self._adjust_compiler() extensions = self.distribution.ext_modules if extensions: build_py = self.get_finalized_command('build_py') package_dir = build_py.get_package_dir(packagename) src_path = os.path.relpath( os.path.join(os.path.dirname(__file__), 'src')) shutil.copy(os.path.join(src_path, 'compiler.c'), os.path.join(package_dir, '_compiler.c')) ext = Extension(self.package_name + '._compiler', [os.path.join(package_dir, '_compiler.c')]) extensions.insert(0, ext) super(build_ext, self).finalize_options() # Generate if self.uses_cython: try: from Cython import __version__ as cython_version except ImportError: # This shouldn't happen if we made it this far cython_version = None if (cython_version is not None and cython_version != self.uses_cython): self.force_rebuild = True # Update the used cython version self.uses_cython = cython_version # Regardless of the value of the '--force' option, force a rebuild # if the debug flag changed from the last build if self.force_rebuild: self.force = True def run(self): # For extensions that require 'numpy' in their include dirs, # replace 'numpy' with the actual paths np_include = None for extension in self.extensions: if 'numpy' in extension.include_dirs: if np_include is None: np_include = get_numpy_include_path() idx = extension.include_dirs.index('numpy') extension.include_dirs.insert(idx, np_include) extension.include_dirs.remove('numpy') self._check_cython_sources(extension) super(build_ext, self).run() # Update cython_version.py if building with Cython try: cython_version = get_pkg_version_module( packagename, fromlist=['cython_version'])[0] except (AttributeError, ImportError): cython_version = 'unknown' if self.uses_cython and self.uses_cython != cython_version: build_py = self.get_finalized_command('build_py') package_dir = build_py.get_package_dir(packagename) cython_py = os.path.join(package_dir, 'cython_version.py') with open(cython_py, 'w') as f: f.write('# Generated file; do not modify\n') f.write('cython_version = {0!r}\n'.format(self.uses_cython)) if os.path.isdir(self.build_lib): # The build/lib directory may not exist if the build_py # command was not previously run, which may sometimes be # the case self.copy_file(cython_py, os.path.join(self.build_lib, cython_py), preserve_mode=False) invalidate_caches() def _adjust_compiler(self): """ This function detects broken compilers and switches to another. If the environment variable CC is explicitly set, or a compiler is specified on the commandline, no override is performed -- the purpose here is to only override a default compiler. The specific compilers with problems are: * The default compiler in XCode-4.2, llvm-gcc-4.2, segfaults when compiling wcslib. The set of broken compilers can be updated by changing the compiler_mapping variable. It is a list of 2-tuples where the first in the pair is a regular expression matching the version of the broken compiler, and the second is the compiler to change to. """ if 'CC' in os.environ: # Check that CC is not set to llvm-gcc-4.2 c_compiler = os.environ['CC'] try: version = get_compiler_version(c_compiler) except OSError: msg = textwrap.dedent( """ The C compiler set by the CC environment variable: {compiler:s} cannot be found or executed. """.format(compiler=c_compiler)) log.warn(msg) sys.exit(1) for broken, fixed in self._broken_compiler_mapping: if re.match(broken, version): msg = textwrap.dedent( """Compiler specified by CC environment variable ({compiler:s}:{version:s}) will fail to compile {pkg:s}. Please set CC={fixed:s} and try again. You can do this, for example, by running: CC={fixed:s} python setup.py where is the command you ran. """.format(compiler=c_compiler, version=version, pkg=self.package_name, fixed=fixed)) log.warn(msg) sys.exit(1) # If C compiler is set via CC, and isn't broken, we are good to go. We # should definitely not try accessing the compiler specified by # ``sysconfig.get_config_var('CC')`` lower down, because this may fail # if the compiler used to compile Python is missing (and maybe this is # why the user is setting CC). For example, the official Python 2.7.3 # MacOS X binary was compiled with gcc-4.2, which is no longer available # in XCode 4. return if self.compiler is not None: # At this point, self.compiler will be set only if a compiler # was specified in the command-line or via setup.cfg, in which # case we don't do anything return compiler_type = ccompiler.get_default_compiler() if compiler_type == 'unix': # We have to get the compiler this way, as this is the one that is # used if os.environ['CC'] is not set. It is actually read in from # the Python Makefile. Note that this is not necessarily the same # compiler as returned by ccompiler.new_compiler() c_compiler = sysconfig.get_config_var('CC') try: version = get_compiler_version(c_compiler) except OSError: msg = textwrap.dedent( """ The C compiler used to compile Python {compiler:s}, and which is normally used to compile C extensions, is not available. You can explicitly specify which compiler to use by setting the CC environment variable, for example: CC=gcc python setup.py or if you are using MacOS X, you can try: CC=clang python setup.py """.format(compiler=c_compiler)) log.warn(msg) sys.exit(1) for broken, fixed in self._broken_compiler_mapping: if re.match(broken, version): os.environ['CC'] = fixed break def _check_cython_sources(self, extension): """ Where relevant, make sure that the .c files associated with .pyx modules are present (if building without Cython installed). """ # Determine the compiler we'll be using if self.compiler is None: compiler = get_default_compiler() else: compiler = self.compiler # Replace .pyx with C-equivalents, unless c files are missing for jdx, src in enumerate(extension.sources): base, ext = os.path.splitext(src) pyxfn = base + '.pyx' cfn = base + '.c' cppfn = base + '.cpp' if not os.path.isfile(pyxfn): continue if self.uses_cython: extension.sources[jdx] = pyxfn else: if os.path.isfile(cfn): extension.sources[jdx] = cfn elif os.path.isfile(cppfn): extension.sources[jdx] = cppfn else: msg = ( 'Could not find C/C++ file {0}.(c/cpp) for Cython ' 'file {1} when building extension {2}. Cython ' 'must be installed to build from a git ' 'checkout.'.format(base, pyxfn, extension.name)) raise IOError(errno.ENOENT, msg, cfn) # Current versions of Cython use deprecated Numpy API features # the use of which produces a few warnings when compiling. # These additional flags should squelch those warnings. # TODO: Feel free to remove this if/when a Cython update # removes use of the deprecated Numpy API if compiler == 'unix': extension.extra_compile_args.extend([ '-Wp,-w', '-Wno-unused-function']) return build_ext APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/build_sphinx.py0000644000077000000240000002353013404171254025734 0ustar tomstaff00000000000000from __future__ import print_function import os import pkgutil import re import shutil import subprocess import sys import glob import warnings from distutils.version import LooseVersion from distutils import log from sphinx import __version__ as sphinx_version from sphinx.setup_command import BuildDoc as SphinxBuildDoc from ..utils import AstropyDeprecationWarning SPHINX_LT_17 = LooseVersion(sphinx_version) < LooseVersion('1.7') SUBPROCESS_TEMPLATE = """ import os import sys {build_main} os.chdir({srcdir!r}) {sys_path_inserts} for builder in {builders!r}: retcode = build_main(argv={argv!r} + ['-b', builder, '.', os.path.join({output_dir!r}, builder)]) if retcode != 0: sys.exit(retcode) """ def ensure_sphinx_astropy_installed(): """ Make sure that sphinx-astropy is available, installing it temporarily if not. This returns the available version of sphinx-astropy as well as any paths that should be added to sys.path for sphinx-astropy to be available. """ # We've split out the Sphinx part of astropy-helpers into sphinx-astropy # but we want it to be auto-installed seamlessly for anyone using # build_docs. We check if it's already installed, and if not, we install # it to a local .eggs directory and add the eggs to the path (these # have to each be added to the path, we can't add them by simply adding # .eggs to the path) sys_path_inserts = [] sphinx_astropy_version = None try: from sphinx_astropy import __version__ as sphinx_astropy_version # noqa except ImportError: from setuptools import Distribution dist = Distribution() eggs = dist.fetch_build_eggs('sphinx-astropy') # Find out the version of sphinx-astropy if possible. For some old # setuptools version, eggs will be None even if sphinx-astropy was # successfully installed. if eggs is not None: for egg in eggs: if egg.project_name == 'sphinx-astropy': sphinx_astropy_version = egg.parsed_version.public break eggs_path = os.path.abspath('.eggs') for egg in glob.glob(os.path.join(eggs_path, '*.egg')): sys_path_inserts.append(egg) return sphinx_astropy_version, sys_path_inserts class AstropyBuildDocs(SphinxBuildDoc): """ A version of the ``build_docs`` command that uses the version of Astropy that is built by the setup ``build`` command, rather than whatever is installed on the system. To build docs against the installed version, run ``make html`` in the ``astropy/docs`` directory. """ description = 'Build Sphinx documentation for Astropy environment' user_options = SphinxBuildDoc.user_options[:] user_options.append( ('warnings-returncode', 'w', 'Parses the sphinx output and sets the return code to 1 if there ' 'are any warnings. Note that this will cause the sphinx log to ' 'only update when it completes, rather than continuously as is ' 'normally the case.')) user_options.append( ('clean-docs', 'l', 'Completely clean previous builds, including ' 'automodapi-generated files before building new ones')) user_options.append( ('no-intersphinx', 'n', 'Skip intersphinx, even if conf.py says to use it')) user_options.append( ('open-docs-in-browser', 'o', 'Open the docs in a browser (using the webbrowser module) if the ' 'build finishes successfully.')) boolean_options = SphinxBuildDoc.boolean_options[:] boolean_options.append('warnings-returncode') boolean_options.append('clean-docs') boolean_options.append('no-intersphinx') boolean_options.append('open-docs-in-browser') _self_iden_rex = re.compile(r"self\.([^\d\W][\w]+)", re.UNICODE) def initialize_options(self): SphinxBuildDoc.initialize_options(self) self.clean_docs = False self.no_intersphinx = False self.open_docs_in_browser = False self.warnings_returncode = False self.traceback = False def finalize_options(self): # This has to happen before we call the parent class's finalize_options if self.build_dir is None: self.build_dir = 'docs/_build' SphinxBuildDoc.finalize_options(self) # Clear out previous sphinx builds, if requested if self.clean_docs: dirstorm = [os.path.join(self.source_dir, 'api'), os.path.join(self.source_dir, 'generated')] dirstorm.append(self.build_dir) for d in dirstorm: if os.path.isdir(d): log.info('Cleaning directory ' + d) shutil.rmtree(d) else: log.info('Not cleaning directory ' + d + ' because ' 'not present or not a directory') def run(self): # TODO: Break this method up into a few more subroutines and # document them better import webbrowser from urllib.request import pathname2url # This is used at the very end of `run` to decide if sys.exit should # be called. If it's None, it won't be. retcode = None # Now make sure Astropy is built and determine where it was built build_cmd = self.reinitialize_command('build') build_cmd.inplace = 0 self.run_command('build') build_cmd = self.get_finalized_command('build') build_cmd_path = os.path.abspath(build_cmd.build_lib) ah_importer = pkgutil.get_importer('astropy_helpers') if ah_importer is None: ah_path = '.' else: ah_path = os.path.abspath(ah_importer.path) if SPHINX_LT_17: build_main = 'from sphinx import build_main' else: build_main = 'from sphinx.cmd.build import build_main' # We need to make sure sphinx-astropy is installed and install it # temporarily if not sphinx_astropy_version, extra_paths = ensure_sphinx_astropy_installed() sys_path_inserts = [build_cmd_path, ah_path] + extra_paths sys_path_inserts = os.linesep.join(['sys.path.insert(0, {0!r})'.format(path) for path in sys_path_inserts]) argv = [] if self.warnings_returncode: argv.append('-W') if self.no_intersphinx: # Note, if sphinx_astropy_version is None, this could indicate an # old version of setuptools, but sphinx-astropy is likely ok, so # we can proceed. if sphinx_astropy_version is None or LooseVersion(sphinx_astropy_version) >= LooseVersion('1.1'): argv.extend(['-D', 'disable_intersphinx=1']) else: log.warn('The -n option to disable intersphinx requires ' 'sphinx-astropy>=1.1. Ignoring.') # We now need to adjust the flags based on the parent class's options if self.fresh_env: argv.append('-E') if self.all_files: argv.append('-a') if getattr(self, 'pdb', False): argv.append('-P') if getattr(self, 'nitpicky', False): argv.append('-n') if self.traceback: argv.append('-T') # The default verbosity level is 1, so in that case we just don't add a flag if self.verbose == 0: argv.append('-q') elif self.verbose > 1: argv.append('-v') if SPHINX_LT_17: argv.insert(0, 'sphinx-build') if isinstance(self.builder, str): builders = [self.builder] else: builders = self.builder subproccode = SUBPROCESS_TEMPLATE.format(build_main=build_main, srcdir=self.source_dir, sys_path_inserts=sys_path_inserts, builders=builders, argv=argv, output_dir=os.path.abspath(self.build_dir)) log.debug('Starting subprocess of {0} with python code:\n{1}\n' '[CODE END])'.format(sys.executable, subproccode)) proc = subprocess.Popen([sys.executable], stdin=subprocess.PIPE) proc.communicate(subproccode.encode('utf-8')) if proc.returncode != 0: retcode = proc.returncode if retcode is None: if self.open_docs_in_browser: if self.builder == 'html': absdir = os.path.abspath(self.builder_target_dir) index_path = os.path.join(absdir, 'index.html') fileurl = 'file://' + pathname2url(index_path) webbrowser.open(fileurl) else: log.warn('open-docs-in-browser option was given, but ' 'the builder is not html! Ignoring.') # Here we explicitly check proc.returncode since we only want to output # this for cases where the return code really wasn't 0. if proc.returncode: log.warn('Sphinx Documentation subprocess failed with return ' 'code ' + str(proc.returncode)) if retcode is not None: # this is potentially dangerous in that there might be something # after the call to `setup` in `setup.py`, and exiting here will # prevent that from running. But there's no other apparent way # to signal what the return code should be. sys.exit(retcode) class AstropyBuildSphinx(AstropyBuildDocs): # pragma: no cover description = 'deprecated alias to the build_docs command' def run(self): warnings.warn( 'The "build_sphinx" command is now deprecated. Use' '"build_docs" instead.', AstropyDeprecationWarning) AstropyBuildDocs.run(self) APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/setup_package.py0000644000077000000240000000017012770325077026063 0ustar tomstaff00000000000000from os.path import join def get_package_data(): return {'astropy_helpers.commands': [join('src', 'compiler.c')]} APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/src/0000755000077000000240000000000013432765724023472 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/src/compiler.c0000644000077000000240000000573112476604504025451 0ustar tomstaff00000000000000#include /*************************************************************************** * Macros for determining the compiler version. * * These are borrowed from boost, and majorly abridged to include only * the compilers we care about. ***************************************************************************/ #ifndef PY3K #if PY_MAJOR_VERSION >= 3 #define PY3K 1 #else #define PY3K 0 #endif #endif #define STRINGIZE(X) DO_STRINGIZE(X) #define DO_STRINGIZE(X) #X #if defined __clang__ /* Clang C++ emulates GCC, so it has to appear early. */ # define COMPILER "Clang version " __clang_version__ #elif defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC) /* Intel */ # if defined(__INTEL_COMPILER) # define INTEL_VERSION __INTEL_COMPILER # elif defined(__ICL) # define INTEL_VERSION __ICL # elif defined(__ICC) # define INTEL_VERSION __ICC # elif defined(__ECC) # define INTEL_VERSION __ECC # endif # define COMPILER "Intel C compiler version " STRINGIZE(INTEL_VERSION) #elif defined(__GNUC__) /* gcc */ # define COMPILER "GCC version " __VERSION__ #elif defined(__SUNPRO_CC) /* Sun Workshop Compiler */ # define COMPILER "Sun compiler version " STRINGIZE(__SUNPRO_CC) #elif defined(_MSC_VER) /* Microsoft Visual C/C++ Must be last since other compilers define _MSC_VER for compatibility as well */ # if _MSC_VER < 1200 # define COMPILER_VERSION 5.0 # elif _MSC_VER < 1300 # define COMPILER_VERSION 6.0 # elif _MSC_VER == 1300 # define COMPILER_VERSION 7.0 # elif _MSC_VER == 1310 # define COMPILER_VERSION 7.1 # elif _MSC_VER == 1400 # define COMPILER_VERSION 8.0 # elif _MSC_VER == 1500 # define COMPILER_VERSION 9.0 # elif _MSC_VER == 1600 # define COMPILER_VERSION 10.0 # else # define COMPILER_VERSION _MSC_VER # endif # define COMPILER "Microsoft Visual C++ version " STRINGIZE(COMPILER_VERSION) #else /* Fallback */ # define COMPILER "Unknown compiler" #endif /*************************************************************************** * Module-level ***************************************************************************/ struct module_state { /* The Sun compiler can't handle empty structs */ #if defined(__SUNPRO_C) || defined(_MSC_VER) int _dummy; #endif }; #if PY3K static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_compiler", NULL, sizeof(struct module_state), NULL, NULL, NULL, NULL, NULL }; #define INITERROR return NULL PyMODINIT_FUNC PyInit__compiler(void) #else #define INITERROR return PyMODINIT_FUNC init_compiler(void) #endif { PyObject* m; #if PY3K m = PyModule_Create(&moduledef); #else m = Py_InitModule3("_compiler", NULL, NULL); #endif if (m == NULL) INITERROR; PyModule_AddStringConstant(m, "compiler", COMPILER); #if PY3K return m; #endif } APLpy-2.0.3/astropy_helpers/astropy_helpers/commands/test.py0000644000077000000240000000240313404171254024217 0ustar tomstaff00000000000000""" Different implementations of the ``./setup.py test`` command depending on what's locally available. If Astropy v1.1.0.dev or later is available it should be possible to import AstropyTest from ``astropy.tests.command``. If ``astropy`` can be imported but not ``astropy.tests.command`` (i.e. an older version of Astropy), we can use the backwards-compat implementation of the command. If Astropy can't be imported at all then there is a skeleton implementation that allows users to at least discover the ``./setup.py test`` command and learn that they need Astropy to run it. """ # Previously these except statements caught only ImportErrors, but there are # some other obscure exceptional conditions that can occur when importing # astropy.tests (at least on older versions) that can cause these imports to # fail try: import astropy # noqa from astropy.tests.command import AstropyTest except Exception: # No astropy at all--provide the dummy implementation from ._dummy import _DummyCommand class AstropyTest(_DummyCommand): command_name = 'test' description = 'Run the tests for this package' error_msg = ( "The 'test' command requires the astropy package to be " "installed and importable.") APLpy-2.0.3/astropy_helpers/astropy_helpers/conftest.py0000644000077000000240000000361213404171254023267 0ustar tomstaff00000000000000# This file contains settings for pytest that are specific to astropy-helpers. # Since we run many of the tests in sub-processes, we need to collect coverage # data inside each subprocess and then combine it into a single .coverage file. # To do this we set up a list which run_setup appends coverage objects to. # This is not intended to be used by packages other than astropy-helpers. import os import glob try: from coverage import CoverageData except ImportError: HAS_COVERAGE = False else: HAS_COVERAGE = True if HAS_COVERAGE: SUBPROCESS_COVERAGE = [] def pytest_configure(config): if HAS_COVERAGE: SUBPROCESS_COVERAGE.clear() def pytest_unconfigure(config): if HAS_COVERAGE: # We create an empty coverage data object combined_cdata = CoverageData() # Add all files from astropy_helpers to make sure we compute the total # coverage, not just the coverage of the files that have non-zero # coverage. lines = {} for filename in glob.glob(os.path.join('astropy_helpers', '**', '*.py'), recursive=True): lines[os.path.abspath(filename)] = [] for cdata in SUBPROCESS_COVERAGE: # For each CoverageData object, we go through all the files and # change the filename from one which might be a temporary path # to the local filename. We then only keep files that actually # exist. for filename in cdata.measured_files(): try: pos = filename.rindex('astropy_helpers') except ValueError: continue short_filename = filename[pos:] if os.path.exists(short_filename): lines[os.path.abspath(short_filename)].extend(cdata.lines(filename)) combined_cdata.add_lines(lines) combined_cdata.write_file('.coverage.subprocess') APLpy-2.0.3/astropy_helpers/astropy_helpers/distutils_helpers.py0000644000077000000240000001736213137061426025221 0ustar tomstaff00000000000000""" This module contains various utilities for introspecting the distutils module and the setup process. Some of these utilities require the `astropy_helpers.setup_helpers.register_commands` function to be called first, as it will affect introspection of setuptools command-line arguments. Other utilities in this module do not have that restriction. """ import os import sys from distutils import ccompiler, log from distutils.dist import Distribution from distutils.errors import DistutilsError from .utils import silence # This function, and any functions that call it, require the setup in # `astropy_helpers.setup_helpers.register_commands` to be run first. def get_dummy_distribution(): """ Returns a distutils Distribution object used to instrument the setup environment before calling the actual setup() function. """ from .setup_helpers import _module_state if _module_state['registered_commands'] is None: raise RuntimeError( 'astropy_helpers.setup_helpers.register_commands() must be ' 'called before using ' 'astropy_helpers.setup_helpers.get_dummy_distribution()') # Pre-parse the Distutils command-line options and config files to if # the option is set. dist = Distribution({'script_name': os.path.basename(sys.argv[0]), 'script_args': sys.argv[1:]}) dist.cmdclass.update(_module_state['registered_commands']) with silence(): try: dist.parse_config_files() dist.parse_command_line() except (DistutilsError, AttributeError, SystemExit): # Let distutils handle DistutilsErrors itself AttributeErrors can # get raise for ./setup.py --help SystemExit can be raised if a # display option was used, for example pass return dist def get_distutils_option(option, commands): """ Returns the value of the given distutils option. Parameters ---------- option : str The name of the option commands : list of str The list of commands on which this option is available Returns ------- val : str or None the value of the given distutils option. If the option is not set, returns None. """ dist = get_dummy_distribution() for cmd in commands: cmd_opts = dist.command_options.get(cmd) if cmd_opts is not None and option in cmd_opts: return cmd_opts[option][1] else: return None def get_distutils_build_option(option): """ Returns the value of the given distutils build option. Parameters ---------- option : str The name of the option Returns ------- val : str or None The value of the given distutils build option. If the option is not set, returns None. """ return get_distutils_option(option, ['build', 'build_ext', 'build_clib']) def get_distutils_install_option(option): """ Returns the value of the given distutils install option. Parameters ---------- option : str The name of the option Returns ------- val : str or None The value of the given distutils build option. If the option is not set, returns None. """ return get_distutils_option(option, ['install']) def get_distutils_build_or_install_option(option): """ Returns the value of the given distutils build or install option. Parameters ---------- option : str The name of the option Returns ------- val : str or None The value of the given distutils build or install option. If the option is not set, returns None. """ return get_distutils_option(option, ['build', 'build_ext', 'build_clib', 'install']) def get_compiler_option(): """ Determines the compiler that will be used to build extension modules. Returns ------- compiler : str The compiler option specified for the build, build_ext, or build_clib command; or the default compiler for the platform if none was specified. """ compiler = get_distutils_build_option('compiler') if compiler is None: return ccompiler.get_default_compiler() return compiler def add_command_option(command, name, doc, is_bool=False): """ Add a custom option to a setup command. Issues a warning if the option already exists on that command. Parameters ---------- command : str The name of the command as given on the command line name : str The name of the build option doc : str A short description of the option, for the `--help` message is_bool : bool, optional When `True`, the option is a boolean option and doesn't require an associated value. """ dist = get_dummy_distribution() cmdcls = dist.get_command_class(command) if (hasattr(cmdcls, '_astropy_helpers_options') and name in cmdcls._astropy_helpers_options): return attr = name.replace('-', '_') if hasattr(cmdcls, attr): raise RuntimeError( '{0!r} already has a {1!r} class attribute, barring {2!r} from ' 'being usable as a custom option name.'.format(cmdcls, attr, name)) for idx, cmd in enumerate(cmdcls.user_options): if cmd[0] == name: log.warn('Overriding existing {0!r} option ' '{1!r}'.format(command, name)) del cmdcls.user_options[idx] if name in cmdcls.boolean_options: cmdcls.boolean_options.remove(name) break cmdcls.user_options.append((name, None, doc)) if is_bool: cmdcls.boolean_options.append(name) # Distutils' command parsing requires that a command object have an # attribute with the same name as the option (with '-' replaced with '_') # in order for that option to be recognized as valid setattr(cmdcls, attr, None) # This caches the options added through add_command_option so that if it is # run multiple times in the same interpreter repeated adds are ignored # (this way we can still raise a RuntimeError if a custom option overrides # a built-in option) if not hasattr(cmdcls, '_astropy_helpers_options'): cmdcls._astropy_helpers_options = set([name]) else: cmdcls._astropy_helpers_options.add(name) def get_distutils_display_options(): """ Returns a set of all the distutils display options in their long and short forms. These are the setup.py arguments such as --name or --version which print the project's metadata and then exit. Returns ------- opts : set The long and short form display option arguments, including the - or -- """ short_display_opts = set('-' + o[1] for o in Distribution.display_options if o[1]) long_display_opts = set('--' + o[0] for o in Distribution.display_options) # Include -h and --help which are not explicitly listed in # Distribution.display_options (as they are handled by optparse) short_display_opts.add('-h') long_display_opts.add('--help') # This isn't the greatest approach to hardcode these commands. # However, there doesn't seem to be a good way to determine # whether build *will be* run as part of the command at this # phase. display_commands = set([ 'clean', 'register', 'setopt', 'saveopts', 'egg_info', 'alias']) return short_display_opts.union(long_display_opts.union(display_commands)) def is_distutils_display_option(): """ Returns True if sys.argv contains any of the distutils display options such as --version or --name. """ display_options = get_distutils_display_options() return bool(set(sys.argv[1:]).intersection(display_options)) APLpy-2.0.3/astropy_helpers/astropy_helpers/git_helpers.py0000644000077000000240000001450113404171254023746 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst """ Utilities for retrieving revision information from a project's git repository. """ # Do not remove the following comment; it is used by # astropy_helpers.version_helpers to determine the beginning of the code in # this module # BEGIN import locale import os import subprocess import warnings def _decode_stdio(stream): try: stdio_encoding = locale.getdefaultlocale()[1] or 'utf-8' except ValueError: stdio_encoding = 'utf-8' try: text = stream.decode(stdio_encoding) except UnicodeDecodeError: # Final fallback text = stream.decode('latin1') return text def update_git_devstr(version, path=None): """ Updates the git revision string if and only if the path is being imported directly from a git working copy. This ensures that the revision number in the version string is accurate. """ try: # Quick way to determine if we're in git or not - returns '' if not devstr = get_git_devstr(sha=True, show_warning=False, path=path) except OSError: return version if not devstr: # Probably not in git so just pass silently return version if 'dev' in version: # update to the current git revision version_base = version.split('.dev', 1)[0] devstr = get_git_devstr(sha=False, show_warning=False, path=path) return version_base + '.dev' + devstr else: # otherwise it's already the true/release version return version def get_git_devstr(sha=False, show_warning=True, path=None): """ Determines the number of revisions in this repository. Parameters ---------- sha : bool If True, the full SHA1 hash will be returned. Otherwise, the total count of commits in the repository will be used as a "revision number". show_warning : bool If True, issue a warning if git returns an error code, otherwise errors pass silently. path : str or None If a string, specifies the directory to look in to find the git repository. If `None`, the current working directory is used, and must be the root of the git repository. If given a filename it uses the directory containing that file. Returns ------- devversion : str Either a string with the revision number (if `sha` is False), the SHA1 hash of the current commit (if `sha` is True), or an empty string if git version info could not be identified. """ if path is None: path = os.getcwd() if not os.path.isdir(path): path = os.path.abspath(os.path.dirname(path)) if sha: # Faster for getting just the hash of HEAD cmd = ['rev-parse', 'HEAD'] else: cmd = ['rev-list', '--count', 'HEAD'] def run_git(cmd): try: p = subprocess.Popen(['git'] + cmd, cwd=path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() except OSError as e: if show_warning: warnings.warn('Error running git: ' + str(e)) return (None, b'', b'') if p.returncode == 128: if show_warning: warnings.warn('No git repository present at {0!r}! Using ' 'default dev version.'.format(path)) return (p.returncode, b'', b'') if p.returncode == 129: if show_warning: warnings.warn('Your git looks old (does it support {0}?); ' 'consider upgrading to v1.7.2 or ' 'later.'.format(cmd[0])) return (p.returncode, stdout, stderr) elif p.returncode != 0: if show_warning: warnings.warn('Git failed while determining revision ' 'count: {0}'.format(_decode_stdio(stderr))) return (p.returncode, stdout, stderr) return p.returncode, stdout, stderr returncode, stdout, stderr = run_git(cmd) if not sha and returncode == 128: # git returns 128 if the command is not run from within a git # repository tree. In this case, a warning is produced above but we # return the default dev version of '0'. return '0' elif not sha and returncode == 129: # git returns 129 if a command option failed to parse; in # particular this could happen in git versions older than 1.7.2 # where the --count option is not supported # Also use --abbrev-commit and --abbrev=0 to display the minimum # number of characters needed per-commit (rather than the full hash) cmd = ['rev-list', '--abbrev-commit', '--abbrev=0', 'HEAD'] returncode, stdout, stderr = run_git(cmd) # Fall back on the old method of getting all revisions and counting # the lines if returncode == 0: return str(stdout.count(b'\n')) else: return '' elif sha: return _decode_stdio(stdout)[:40] else: return _decode_stdio(stdout).strip() # This function is tested but it is only ever executed within a subprocess when # creating a fake package, so it doesn't get picked up by coverage metrics. def _get_repo_path(pathname, levels=None): # pragma: no cover """ Given a file or directory name, determine the root of the git repository this path is under. If given, this won't look any higher than ``levels`` (that is, if ``levels=0`` then the given path must be the root of the git repository and is returned if so. Returns `None` if the given path could not be determined to belong to a git repo. """ if os.path.isfile(pathname): current_dir = os.path.abspath(os.path.dirname(pathname)) elif os.path.isdir(pathname): current_dir = os.path.abspath(pathname) else: return None current_level = 0 while levels is None or current_level <= levels: if os.path.exists(os.path.join(current_dir, '.git')): return current_dir current_level += 1 if current_dir == os.path.dirname(current_dir): break current_dir = os.path.dirname(current_dir) return None APLpy-2.0.3/astropy_helpers/astropy_helpers/openmp_helpers.py0000644000077000000240000002224513404171254024465 0ustar tomstaff00000000000000# This module defines functions that can be used to check whether OpenMP is # available and if so what flags to use. To use this, import the # add_openmp_flags_if_available function in a setup_package.py file where you # are defining your extensions: # # from astropy_helpers.openmp_helpers import add_openmp_flags_if_available # # then call it with a single extension as the only argument: # # add_openmp_flags_if_available(extension) # # this will add the OpenMP flags if available. from __future__ import absolute_import, print_function import os import sys import glob import time import datetime import tempfile import subprocess from distutils import log from distutils.ccompiler import new_compiler from distutils.sysconfig import customize_compiler, get_config_var from distutils.errors import CompileError, LinkError from .setup_helpers import get_compiler_option __all__ = ['add_openmp_flags_if_available'] try: # Check if this has already been instantiated, only set the default once. _ASTROPY_DISABLE_SETUP_WITH_OPENMP_ except NameError: import builtins # It hasn't, so do so. builtins._ASTROPY_DISABLE_SETUP_WITH_OPENMP_ = False CCODE = """ #include #include int main(void) { #pragma omp parallel printf("nthreads=%d\\n", omp_get_num_threads()); return 0; } """ def _get_flag_value_from_var(flag, var, delim=' '): """ Extract flags from an environment variable. Parameters ---------- flag : str The flag to extract, for example '-I' or '-L' var : str The environment variable to extract the flag from, e.g. CFLAGS or LDFLAGS. delim : str, optional The delimiter separating flags inside the environment variable Examples -------- Let's assume the LDFLAGS is set to '-L/usr/local/include -customflag'. This function will then return the following: >>> _get_flag_value_from_var('-L', 'LDFLAGS') '/usr/local/include' Notes ----- Environment variables are first checked in ``os.environ[var]``, then in ``distutils.sysconfig.get_config_var(var)``. This function is not supported on Windows. """ if sys.platform.startswith('win'): return None # Simple input validation if not var or not flag: return None flag_length = len(flag) if not flag_length: return None # Look for var in os.eviron then in get_config_var if var in os.environ: flags = os.environ[var] else: try: flags = get_config_var(var) except KeyError: return None # Extract flag from {var:value} if flags: for item in flags.split(delim): if item.startswith(flag): return item[flag_length:] def get_openmp_flags(): """ Utility for returning compiler and linker flags possibly needed for OpenMP support. Returns ------- result : `{'compiler_flags':, 'linker_flags':}` Notes ----- The flags returned are not tested for validity, use `check_openmp_support(openmp_flags=get_openmp_flags())` to do so. """ compile_flags = [] link_flags = [] if get_compiler_option() == 'msvc': compile_flags.append('-openmp') else: include_path = _get_flag_value_from_var('-I', 'CFLAGS') if include_path: compile_flags.append('-I' + include_path) lib_path = _get_flag_value_from_var('-L', 'LDFLAGS') if lib_path: link_flags.append('-L' + lib_path) link_flags.append('-Wl,-rpath,' + lib_path) compile_flags.append('-fopenmp') link_flags.append('-fopenmp') return {'compiler_flags': compile_flags, 'linker_flags': link_flags} def check_openmp_support(openmp_flags=None): """ Check whether OpenMP test code can be compiled and run. Parameters ---------- openmp_flags : dict, optional This should be a dictionary with keys ``compiler_flags`` and ``linker_flags`` giving the compiliation and linking flags respectively. These are passed as `extra_postargs` to `compile()` and `link_executable()` respectively. If this is not set, the flags will be automatically determined using environment variables. Returns ------- result : bool `True` if the test passed, `False` otherwise. """ ccompiler = new_compiler() customize_compiler(ccompiler) if not openmp_flags: # customize_compiler() extracts info from os.environ. If certain keys # exist it uses these plus those from sysconfig.get_config_vars(). # If the key is missing in os.environ it is not extracted from # sysconfig.get_config_var(). E.g. 'LDFLAGS' get left out, preventing # clang from finding libomp.dylib because -L is not passed to # linker. Call get_openmp_flags() to get flags missed by # customize_compiler(). openmp_flags = get_openmp_flags() compile_flags = openmp_flags.get('compiler_flags') link_flags = openmp_flags.get('linker_flags') tmp_dir = tempfile.mkdtemp() start_dir = os.path.abspath('.') try: os.chdir(tmp_dir) # Write test program with open('test_openmp.c', 'w') as f: f.write(CCODE) os.mkdir('objects') # Compile, test program ccompiler.compile(['test_openmp.c'], output_dir='objects', extra_postargs=compile_flags) # Link test program objects = glob.glob(os.path.join('objects', '*' + ccompiler.obj_extension)) ccompiler.link_executable(objects, 'test_openmp', extra_postargs=link_flags) # Run test program output = subprocess.check_output('./test_openmp') output = output.decode(sys.stdout.encoding or 'utf-8').splitlines() if 'nthreads=' in output[0]: nthreads = int(output[0].strip().split('=')[1]) if len(output) == nthreads: is_openmp_supported = True else: log.warn("Unexpected number of lines from output of test OpenMP " "program (output was {0})".format(output)) is_openmp_supported = False else: log.warn("Unexpected output from test OpenMP " "program (output was {0})".format(output)) is_openmp_supported = False except (CompileError, LinkError, subprocess.CalledProcessError): is_openmp_supported = False finally: os.chdir(start_dir) return is_openmp_supported def is_openmp_supported(): """ Determine whether the build compiler has OpenMP support. """ log_threshold = log.set_threshold(log.FATAL) ret = check_openmp_support() log.set_threshold(log_threshold) return ret def add_openmp_flags_if_available(extension): """ Add OpenMP compilation flags, if supported (if not a warning will be printed to the console and no flags will be added.) Returns `True` if the flags were added, `False` otherwise. """ if _ASTROPY_DISABLE_SETUP_WITH_OPENMP_: log.info("OpenMP support has been explicitly disabled.") return False openmp_flags = get_openmp_flags() using_openmp = check_openmp_support(openmp_flags=openmp_flags) if using_openmp: compile_flags = openmp_flags.get('compiler_flags') link_flags = openmp_flags.get('linker_flags') log.info("Compiling Cython/C/C++ extension with OpenMP support") extension.extra_compile_args.extend(compile_flags) extension.extra_link_args.extend(link_flags) else: log.warn("Cannot compile Cython/C/C++ extension with OpenMP, reverting " "to non-parallel code") return using_openmp _IS_OPENMP_ENABLED_SRC = """ # Autogenerated by {packagetitle}'s setup.py on {timestamp!s} def is_openmp_enabled(): \"\"\" Determine whether this package was built with OpenMP support. \"\"\" return {return_bool} """[1:] def generate_openmp_enabled_py(packagename, srcdir='.', disable_openmp=None): """ Generate ``package.openmp_enabled.is_openmp_enabled``, which can then be used to determine, post build, whether the package was built with or without OpenMP support. """ if packagename.lower() == 'astropy': packagetitle = 'Astropy' else: packagetitle = packagename epoch = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) timestamp = datetime.datetime.utcfromtimestamp(epoch) if disable_openmp is not None: import builtins builtins._ASTROPY_DISABLE_SETUP_WITH_OPENMP_ = disable_openmp if _ASTROPY_DISABLE_SETUP_WITH_OPENMP_: log.info("OpenMP support has been explicitly disabled.") openmp_support = False if _ASTROPY_DISABLE_SETUP_WITH_OPENMP_ else is_openmp_supported() src = _IS_OPENMP_ENABLED_SRC.format(packagetitle=packagetitle, timestamp=timestamp, return_bool=openmp_support) package_srcdir = os.path.join(srcdir, *packagename.split('.')) is_openmp_enabled_py = os.path.join(package_srcdir, 'openmp_enabled.py') with open(is_openmp_enabled_py, 'w') as f: f.write(src) APLpy-2.0.3/astropy_helpers/astropy_helpers/setup_helpers.py0000644000077000000240000006324613404171254024335 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst """ This module contains a number of utilities for use during setup/build/packaging that are useful to astropy as a whole. """ from __future__ import absolute_import, print_function import collections import os import re import subprocess import sys import traceback import warnings from distutils import log from distutils.errors import DistutilsOptionError, DistutilsModuleError from distutils.core import Extension from distutils.core import Command from distutils.command.sdist import sdist as DistutilsSdist from setuptools import find_packages as _find_packages from .distutils_helpers import (add_command_option, get_compiler_option, get_dummy_distribution, get_distutils_build_option, get_distutils_build_or_install_option) from .version_helpers import get_pkg_version_module from .utils import (walk_skip_hidden, import_file, extends_doc, resolve_name, AstropyDeprecationWarning) from .commands.build_ext import generate_build_ext_command from .commands.test import AstropyTest # These imports are not used in this module, but are included for backwards # compat with older versions of this module from .utils import get_numpy_include_path, write_if_different # noqa from .commands.build_ext import should_build_with_cython, get_compiler_version # noqa _module_state = {'registered_commands': None, 'have_sphinx': False, 'package_cache': None, 'exclude_packages': set(), 'excludes_too_late': False} try: import sphinx # noqa _module_state['have_sphinx'] = True except ValueError as e: # This can occur deep in the bowels of Sphinx's imports by way of docutils # and an occurrence of this bug: http://bugs.python.org/issue18378 # In this case sphinx is effectively unusable if 'unknown locale' in e.args[0]: log.warn( "Possible misconfiguration of one of the environment variables " "LC_ALL, LC_CTYPES, LANG, or LANGUAGE. For an example of how to " "configure your system's language environment on OSX see " "http://blog.remibergsma.com/2012/07/10/" "setting-locales-correctly-on-mac-osx-terminal-application/") except ImportError: pass except SyntaxError: # occurs if markupsafe is recent version, which doesn't support Python 3.2 pass def adjust_compiler(package): """ This function detects broken compilers and switches to another. If the environment variable CC is explicitly set, or a compiler is specified on the commandline, no override is performed -- the purpose here is to only override a default compiler. The specific compilers with problems are: * The default compiler in XCode-4.2, llvm-gcc-4.2, segfaults when compiling wcslib. The set of broken compilers can be updated by changing the compiler_mapping variable. It is a list of 2-tuples where the first in the pair is a regular expression matching the version of the broken compiler, and the second is the compiler to change to. """ warnings.warn( 'Direct use of the adjust_compiler function in setup.py is ' 'deprecated and can be removed from your setup.py. This ' 'functionality is now incorporated directly into the build_ext ' 'command.', AstropyDeprecationWarning) def get_debug_option(packagename): """ Determines if the build is in debug mode. Returns ------- debug : bool True if the current build was started with the debug option, False otherwise. """ try: current_debug = get_pkg_version_module(packagename, fromlist=['debug'])[0] except (ImportError, AttributeError): current_debug = None # Only modify the debug flag if one of the build commands was explicitly # run (i.e. not as a sub-command of something else) dist = get_dummy_distribution() if any(cmd in dist.commands for cmd in ['build', 'build_ext']): debug = bool(get_distutils_build_option('debug')) else: debug = bool(current_debug) if current_debug is not None and current_debug != debug: build_ext_cmd = dist.get_command_class('build_ext') build_ext_cmd.force_rebuild = True return debug def add_exclude_packages(excludes): if _module_state['excludes_too_late']: raise RuntimeError( "add_package_excludes must be called before all other setup helper " "functions in order to properly handle excluded packages") _module_state['exclude_packages'].update(set(excludes)) def register_commands(package, version, release, srcdir='.'): if _module_state['registered_commands'] is not None: return _module_state['registered_commands'] if _module_state['have_sphinx']: try: from .commands.build_sphinx import (AstropyBuildSphinx, AstropyBuildDocs) except ImportError: AstropyBuildSphinx = AstropyBuildDocs = FakeBuildSphinx else: AstropyBuildSphinx = AstropyBuildDocs = FakeBuildSphinx _module_state['registered_commands'] = registered_commands = { 'test': generate_test_command(package), # Use distutils' sdist because it respects package_data. # setuptools/distributes sdist requires duplication of information in # MANIFEST.in 'sdist': DistutilsSdist, # The exact form of the build_ext command depends on whether or not # we're building a release version 'build_ext': generate_build_ext_command(package, release), 'build_sphinx': AstropyBuildSphinx, 'build_docs': AstropyBuildDocs } # Need to override the __name__ here so that the commandline options are # presented as being related to the "build" command, for example; normally # this wouldn't be necessary since commands also have a command_name # attribute, but there is a bug in distutils' help display code that it # uses __name__ instead of command_name. Yay distutils! for name, cls in registered_commands.items(): cls.__name__ = name # Add a few custom options; more of these can be added by specific packages # later for option in [ ('use-system-libraries', "Use system libraries whenever possible", True)]: add_command_option('build', *option) add_command_option('install', *option) add_command_hooks(registered_commands, srcdir=srcdir) return registered_commands def add_command_hooks(commands, srcdir='.'): """ Look through setup_package.py modules for functions with names like ``pre__hook`` and ``post__hook`` where ```` is the name of a ``setup.py`` command (e.g. build_ext). If either hook is present this adds a wrapped version of that command to the passed in ``commands`` `dict`. ``commands`` may be pre-populated with other custom distutils command classes that should be wrapped if there are hooks for them (e.g. `AstropyBuildPy`). """ hook_re = re.compile(r'^(pre|post)_(.+)_hook$') # Distutils commands have a method of the same name, but it is not a # *classmethod* (which probably didn't exist when distutils was first # written) def get_command_name(cmdcls): if hasattr(cmdcls, 'command_name'): return cmdcls.command_name else: return cmdcls.__name__ packages = find_packages(srcdir) dist = get_dummy_distribution() hooks = collections.defaultdict(dict) for setuppkg in iter_setup_packages(srcdir, packages): for name, obj in vars(setuppkg).items(): match = hook_re.match(name) if not match: continue hook_type = match.group(1) cmd_name = match.group(2) if hook_type not in hooks[cmd_name]: hooks[cmd_name][hook_type] = [] hooks[cmd_name][hook_type].append((setuppkg.__name__, obj)) for cmd_name, cmd_hooks in hooks.items(): commands[cmd_name] = generate_hooked_command( cmd_name, dist.get_command_class(cmd_name), cmd_hooks) def generate_hooked_command(cmd_name, cmd_cls, hooks): """ Returns a generated subclass of ``cmd_cls`` that runs the pre- and post-command hooks for that command before and after the ``cmd_cls.run`` method. """ def run(self, orig_run=cmd_cls.run): self.run_command_hooks('pre_hooks') orig_run(self) self.run_command_hooks('post_hooks') return type(cmd_name, (cmd_cls, object), {'run': run, 'run_command_hooks': run_command_hooks, 'pre_hooks': hooks.get('pre', []), 'post_hooks': hooks.get('post', [])}) def run_command_hooks(cmd_obj, hook_kind): """Run hooks registered for that command and phase. *cmd_obj* is a finalized command object; *hook_kind* is either 'pre_hook' or 'post_hook'. """ hooks = getattr(cmd_obj, hook_kind, None) if not hooks: return for modname, hook in hooks: if isinstance(hook, str): try: hook_obj = resolve_name(hook) except ImportError as exc: raise DistutilsModuleError( 'cannot find hook {0}: {1}'.format(hook, exc)) else: hook_obj = hook if not callable(hook_obj): raise DistutilsOptionError('hook {0!r} is not callable' % hook) log.info('running {0} from {1} for {2} command'.format( hook_kind.rstrip('s'), modname, cmd_obj.get_command_name())) try: hook_obj(cmd_obj) except Exception: log.error('{0} command hook {1} raised an exception: %s\n'.format( hook_obj.__name__, cmd_obj.get_command_name())) log.error(traceback.format_exc()) sys.exit(1) def generate_test_command(package_name): """ Creates a custom 'test' command for the given package which sets the command's ``package_name`` class attribute to the name of the package being tested. """ return type(package_name.title() + 'Test', (AstropyTest,), {'package_name': package_name}) def update_package_files(srcdir, extensions, package_data, packagenames, package_dirs): """ This function is deprecated and maintained for backward compatibility with affiliated packages. Affiliated packages should update their setup.py to use `get_package_info` instead. """ info = get_package_info(srcdir) extensions.extend(info['ext_modules']) package_data.update(info['package_data']) packagenames = list(set(packagenames + info['packages'])) package_dirs.update(info['package_dir']) def get_package_info(srcdir='.', exclude=()): """ Collates all of the information for building all subpackages and returns a dictionary of keyword arguments that can be passed directly to `distutils.setup`. The purpose of this function is to allow subpackages to update the arguments to the package's ``setup()`` function in its setup.py script, rather than having to specify all extensions/package data directly in the ``setup.py``. See Astropy's own ``setup.py`` for example usage and the Astropy development docs for more details. This function obtains that information by iterating through all packages in ``srcdir`` and locating a ``setup_package.py`` module. This module can contain the following functions: ``get_extensions()``, ``get_package_data()``, ``get_build_options()``, and ``get_external_libraries()``. Each of those functions take no arguments. - ``get_extensions`` returns a list of `distutils.extension.Extension` objects. - ``get_package_data()`` returns a dict formatted as required by the ``package_data`` argument to ``setup()``. - ``get_build_options()`` returns a list of tuples describing the extra build options to add. - ``get_external_libraries()`` returns a list of libraries that can optionally be built using external dependencies. - ``get_entry_points()`` returns a dict formatted as required by the ``entry_points`` argument to ``setup()``. """ ext_modules = [] packages = [] package_data = {} package_dir = {} if exclude: warnings.warn( "Use of the exclude parameter is no longer supported since it does " "not work as expected. Use add_exclude_packages instead. Note that " "it must be called prior to any other calls from setup helpers.", AstropyDeprecationWarning) # Use the find_packages tool to locate all packages and modules packages = find_packages(srcdir, exclude=exclude) # Update package_dir if the package lies in a subdirectory if srcdir != '.': package_dir[''] = srcdir # For each of the setup_package.py modules, extract any # information that is needed to install them. The build options # are extracted first, so that their values will be available in # subsequent calls to `get_extensions`, etc. for setuppkg in iter_setup_packages(srcdir, packages): if hasattr(setuppkg, 'get_build_options'): options = setuppkg.get_build_options() for option in options: add_command_option('build', *option) if hasattr(setuppkg, 'get_external_libraries'): libraries = setuppkg.get_external_libraries() for library in libraries: add_external_library(library) for setuppkg in iter_setup_packages(srcdir, packages): # get_extensions must include any Cython extensions by their .pyx # filename. if hasattr(setuppkg, 'get_extensions'): ext_modules.extend(setuppkg.get_extensions()) if hasattr(setuppkg, 'get_package_data'): package_data.update(setuppkg.get_package_data()) # Locate any .pyx files not already specified, and add their extensions in. # The default include dirs include numpy to facilitate numerical work. ext_modules.extend(get_cython_extensions(srcdir, packages, ext_modules, ['numpy'])) # Now remove extensions that have the special name 'skip_cython', as they # exist Only to indicate that the cython extensions shouldn't be built for i, ext in reversed(list(enumerate(ext_modules))): if ext.name == 'skip_cython': del ext_modules[i] # On Microsoft compilers, we need to pass the '/MANIFEST' # commandline argument. This was the default on MSVC 9.0, but is # now required on MSVC 10.0, but it doesn't seem to hurt to add # it unconditionally. if get_compiler_option() == 'msvc': for ext in ext_modules: ext.extra_link_args.append('/MANIFEST') return { 'ext_modules': ext_modules, 'packages': packages, 'package_dir': package_dir, 'package_data': package_data, } def iter_setup_packages(srcdir, packages): """ A generator that finds and imports all of the ``setup_package.py`` modules in the source packages. Returns ------- modgen : generator A generator that yields (modname, mod), where `mod` is the module and `modname` is the module name for the ``setup_package.py`` modules. """ for packagename in packages: package_parts = packagename.split('.') package_path = os.path.join(srcdir, *package_parts) setup_package = os.path.relpath( os.path.join(package_path, 'setup_package.py')) if os.path.isfile(setup_package): module = import_file(setup_package, name=packagename + '.setup_package') yield module def iter_pyx_files(package_dir, package_name): """ A generator that yields Cython source files (ending in '.pyx') in the source packages. Returns ------- pyxgen : generator A generator that yields (extmod, fullfn) where `extmod` is the full name of the module that the .pyx file would live in based on the source directory structure, and `fullfn` is the path to the .pyx file. """ for dirpath, dirnames, filenames in walk_skip_hidden(package_dir): for fn in filenames: if fn.endswith('.pyx'): fullfn = os.path.relpath(os.path.join(dirpath, fn)) # Package must match file name extmod = '.'.join([package_name, fn[:-4]]) yield (extmod, fullfn) break # Don't recurse into subdirectories def get_cython_extensions(srcdir, packages, prevextensions=tuple(), extincludedirs=None): """ Looks for Cython files and generates Extensions if needed. Parameters ---------- srcdir : str Path to the root of the source directory to search. prevextensions : list of `~distutils.core.Extension` objects The extensions that are already defined. Any .pyx files already here will be ignored. extincludedirs : list of str or None Directories to include as the `include_dirs` argument to the generated `~distutils.core.Extension` objects. Returns ------- exts : list of `~distutils.core.Extension` objects The new extensions that are needed to compile all .pyx files (does not include any already in `prevextensions`). """ # Vanilla setuptools and old versions of distribute include Cython files # as .c files in the sources, not .pyx, so we cannot simply look for # existing .pyx sources in the previous sources, but we should also check # for .c files with the same remaining filename. So we look for .pyx and # .c files, and we strip the extension. prevsourcepaths = [] ext_modules = [] for ext in prevextensions: for s in ext.sources: if s.endswith(('.pyx', '.c', '.cpp')): sourcepath = os.path.realpath(os.path.splitext(s)[0]) prevsourcepaths.append(sourcepath) for package_name in packages: package_parts = package_name.split('.') package_path = os.path.join(srcdir, *package_parts) for extmod, pyxfn in iter_pyx_files(package_path, package_name): sourcepath = os.path.realpath(os.path.splitext(pyxfn)[0]) if sourcepath not in prevsourcepaths: ext_modules.append(Extension(extmod, [pyxfn], include_dirs=extincludedirs)) return ext_modules class DistutilsExtensionArgs(collections.defaultdict): """ A special dictionary whose default values are the empty list. This is useful for building up a set of arguments for `distutils.Extension` without worrying whether the entry is already present. """ def __init__(self, *args, **kwargs): def default_factory(): return [] super(DistutilsExtensionArgs, self).__init__( default_factory, *args, **kwargs) def update(self, other): for key, val in other.items(): self[key].extend(val) def pkg_config(packages, default_libraries, executable='pkg-config'): """ Uses pkg-config to update a set of distutils Extension arguments to include the flags necessary to link against the given packages. If the pkg-config lookup fails, default_libraries is applied to libraries. Parameters ---------- packages : list of str A list of pkg-config packages to look up. default_libraries : list of str A list of library names to use if the pkg-config lookup fails. Returns ------- config : dict A dictionary containing keyword arguments to `distutils.Extension`. These entries include: - ``include_dirs``: A list of include directories - ``library_dirs``: A list of library directories - ``libraries``: A list of libraries - ``define_macros``: A list of macro defines - ``undef_macros``: A list of macros to undefine - ``extra_compile_args``: A list of extra arguments to pass to the compiler """ flag_map = {'-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries', '-D': 'define_macros', '-U': 'undef_macros'} command = "{0} --libs --cflags {1}".format(executable, ' '.join(packages)), result = DistutilsExtensionArgs() try: pipe = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) output = pipe.communicate()[0].strip() except subprocess.CalledProcessError as e: lines = [ ("{0} failed. This may cause the build to fail below." .format(executable)), " command: {0}".format(e.cmd), " returncode: {0}".format(e.returncode), " output: {0}".format(e.output) ] log.warn('\n'.join(lines)) result['libraries'].extend(default_libraries) else: if pipe.returncode != 0: lines = [ "pkg-config could not lookup up package(s) {0}.".format( ", ".join(packages)), "This may cause the build to fail below." ] log.warn('\n'.join(lines)) result['libraries'].extend(default_libraries) else: for token in output.split(): # It's not clear what encoding the output of # pkg-config will come to us in. It will probably be # some combination of pure ASCII (for the compiler # flags) and the filesystem encoding (for any argument # that includes directories or filenames), but this is # just conjecture, as the pkg-config documentation # doesn't seem to address it. arg = token[:2].decode('ascii') value = token[2:].decode(sys.getfilesystemencoding()) if arg in flag_map: if arg == '-D': value = tuple(value.split('=', 1)) result[flag_map[arg]].append(value) else: result['extra_compile_args'].append(value) return result def add_external_library(library): """ Add a build option for selecting the internal or system copy of a library. Parameters ---------- library : str The name of the library. If the library is `foo`, the build option will be called `--use-system-foo`. """ for command in ['build', 'build_ext', 'install']: add_command_option(command, str('use-system-' + library), 'Use the system {0} library'.format(library), is_bool=True) def use_system_library(library): """ Returns `True` if the build configuration indicates that the given library should use the system copy of the library rather than the internal one. For the given library `foo`, this will be `True` if `--use-system-foo` or `--use-system-libraries` was provided at the commandline or in `setup.cfg`. Parameters ---------- library : str The name of the library Returns ------- use_system : bool `True` if the build should use the system copy of the library. """ return ( get_distutils_build_or_install_option('use_system_{0}'.format(library)) or get_distutils_build_or_install_option('use_system_libraries')) @extends_doc(_find_packages) def find_packages(where='.', exclude=(), invalidate_cache=False): """ This version of ``find_packages`` caches previous results to speed up subsequent calls. Use ``invalide_cache=True`` to ignore cached results from previous ``find_packages`` calls, and repeat the package search. """ if exclude: warnings.warn( "Use of the exclude parameter is no longer supported since it does " "not work as expected. Use add_exclude_packages instead. Note that " "it must be called prior to any other calls from setup helpers.", AstropyDeprecationWarning) # Calling add_exclude_packages after this point will have no effect _module_state['excludes_too_late'] = True if not invalidate_cache and _module_state['package_cache'] is not None: return _module_state['package_cache'] packages = _find_packages( where=where, exclude=list(_module_state['exclude_packages'])) _module_state['package_cache'] = packages return packages class FakeBuildSphinx(Command): """ A dummy build_sphinx command that is called if Sphinx is not installed and displays a relevant error message """ # user options inherited from sphinx.setup_command.BuildDoc user_options = [ ('fresh-env', 'E', ''), ('all-files', 'a', ''), ('source-dir=', 's', ''), ('build-dir=', None, ''), ('config-dir=', 'c', ''), ('builder=', 'b', ''), ('project=', None, ''), ('version=', None, ''), ('release=', None, ''), ('today=', None, ''), ('link-index', 'i', '')] # user options appended in astropy.setup_helpers.AstropyBuildSphinx user_options.append(('warnings-returncode', 'w', '')) user_options.append(('clean-docs', 'l', '')) user_options.append(('no-intersphinx', 'n', '')) user_options.append(('open-docs-in-browser', 'o', '')) def initialize_options(self): try: raise RuntimeError("Sphinx and its dependencies must be installed " "for build_docs.") except: log.error('error: Sphinx and its dependencies must be installed ' 'for build_docs.') sys.exit(1) APLpy-2.0.3/astropy_helpers/astropy_helpers/sphinx/0000755000077000000240000000000013432765724022413 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers/sphinx/__init__.py0000644000077000000240000000000013404171254024476 0ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers/sphinx/conf.py0000644000077000000240000000023413404171254023675 0ustar tomstaff00000000000000import warnings from sphinx_astropy.conf import * warnings.warn("Note that astropy_helpers.sphinx.conf is deprecated - use sphinx_astropy.conf instead") APLpy-2.0.3/astropy_helpers/astropy_helpers/tests/0000755000077000000240000000000013432765724022244 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers/tests/__init__.py0000644000077000000240000001215713404171254024347 0ustar tomstaff00000000000000import os import subprocess as sp import sys import pytest try: from coverage import CoverageData except ImportError: HAS_COVERAGE = False else: HAS_COVERAGE = True from ..conftest import SUBPROCESS_COVERAGE PACKAGE_DIR = os.path.dirname(__file__) def run_cmd(cmd, args, path=None, raise_error=True): """ Runs a shell command with the given argument list. Changes directory to ``path`` if given, otherwise runs the command in the current directory. Returns a 3-tuple of (stdout, stderr, exit code) If ``raise_error=True`` raise an exception on non-zero exit codes. """ if path is not None: # Transparently support py.path objects path = str(path) p = sp.Popen([cmd] + list(args), stdout=sp.PIPE, stderr=sp.PIPE, cwd=path) streams = tuple(s.decode('latin1').strip() for s in p.communicate()) return_code = p.returncode if raise_error and return_code != 0: raise RuntimeError( "The command `{0}` with args {1!r} exited with code {2}.\n" "Stdout:\n\n{3}\n\nStderr:\n\n{4}".format( cmd, list(args), return_code, streams[0], streams[1])) return streams + (return_code,) def run_setup(setup_script, args): # This used to call setuptools.sandbox's run_setup, but due to issues with # this and Cython (which caused segmentation faults), we now use subprocess. setup_script = os.path.abspath(setup_script) path = os.path.dirname(setup_script) setup_script = os.path.basename(setup_script) if HAS_COVERAGE: # In this case, we run the command using the coverage command and we # then collect the coverage data into a SUBPROCESS_COVERAGE list which # is set up at the start of the testing process and is then combined # into a single .coverage file at the end of the testing process. p = sp.Popen(['coverage', 'run', setup_script] + list(args), cwd=path, stdout=sp.PIPE, stderr=sp.PIPE) stdout, stderr = p.communicate() cdata = CoverageData() cdata.read_file(os.path.join(path, '.coverage')) SUBPROCESS_COVERAGE.append(cdata) else: # Otherwise we just run the tests with Python p = sp.Popen([sys.executable, setup_script] + list(args), cwd=path, stdout=sp.PIPE, stderr=sp.PIPE) stdout, stderr = p.communicate() sys.stdout.write(stdout.decode('utf-8')) sys.stderr.write(stderr.decode('utf-8')) if p.returncode != 0: raise SystemExit(p.returncode) @pytest.fixture(scope='function', autouse=True) def reset_setup_helpers(request): """ Saves and restores the global state of the astropy_helpers.setup_helpers module between tests. """ mod = __import__('astropy_helpers.setup_helpers', fromlist=['']) old_state = mod._module_state.copy() def finalizer(old_state=old_state): mod = sys.modules.get('astropy_helpers.setup_helpers') if mod is not None: mod._module_state.update(old_state) request.addfinalizer(finalizer) @pytest.fixture(scope='function', autouse=True) def reset_distutils_log(): """ This is a setup/teardown fixture that ensures the log-level of the distutils log is always set to a default of WARN, since different settings could affect tests that check the contents of stdout. """ from distutils import log log.set_threshold(log.WARN) TEST_PACKAGE_SETUP_PY = """\ #!/usr/bin/env python from setuptools import setup NAME = 'astropy-helpers-test' VERSION = {version!r} setup(name=NAME, version=VERSION, packages=['_astropy_helpers_test_'], zip_safe=False) """ def create_testpackage(tmpdir, version='0.1'): source = tmpdir.mkdir('testpkg') with source.as_cwd(): source.mkdir('_astropy_helpers_test_') init = source.join('_astropy_helpers_test_', '__init__.py') init.write('__version__ = {0!r}'.format(version)) setup_py = TEST_PACKAGE_SETUP_PY.format(version=version) source.join('setup.py').write(setup_py) # Make the new test package into a git repo run_cmd('git', ['init']) run_cmd('git', ['add', '--all']) run_cmd('git', ['commit', '-m', 'test package']) return source @pytest.fixture def testpackage(tmpdir, version='0.1'): """ This fixture creates a simplified package called _astropy_helpers_test_ used primarily for testing ah_boostrap, but without using the astropy_helpers package directly and getting it confused with the astropy_helpers package already under test. """ return create_testpackage(tmpdir, version=version) def cleanup_import(package_name): """Remove all references to package_name from sys.modules""" for k in list(sys.modules): if not isinstance(k, str): # Some things will actually do this =_= continue elif k.startswith('astropy_helpers.tests'): # Don't delete imported test modules or else the tests will break, # badly continue if k == package_name or k.startswith(package_name + '.'): del sys.modules[k] APLpy-2.0.3/astropy_helpers/astropy_helpers/tests/test_ah_bootstrap.py0000644000077000000240000003535213404171254026336 0ustar tomstaff00000000000000# -*- coding: utf-8 -*- import glob import os import json import textwrap from distutils.version import LooseVersion import setuptools import pytest from . import reset_setup_helpers, reset_distutils_log # noqa from . import run_cmd, run_setup, testpackage, create_testpackage from ..utils import silence TEST_SETUP_PY = """\ #!/usr/bin/env python from __future__ import print_function import os import sys # This import is not the real run of ah_bootstrap for the purposes of the test, # so we need to preserve the command-line arguments otherwise these get eaten # up by this import args = sys.argv[:] import ah_bootstrap sys.argv = args {extra} # reset the name of the package installed by ah_boostrap to # _astropy_helpers_test_--this will prevent any confusion by pkg_resources with # any already installed packages named astropy_helpers # We also disable auto-upgrade by default ah_bootstrap.DIST_NAME = 'astropy-helpers-test' ah_bootstrap.PACKAGE_NAME = '_astropy_helpers_test_' ah_bootstrap.AUTO_UPGRADE = False ah_bootstrap.DOWNLOAD_IF_NEEDED = False try: ah_bootstrap.BOOTSTRAPPER = ah_bootstrap._Bootstrapper.main() ah_bootstrap.use_astropy_helpers({args}) finally: ah_bootstrap.DIST_NAME = 'astropy-helpers' ah_bootstrap.PACKAGE_NAME = 'astropy_helpers' ah_bootstrap.AUTO_UPGRADE = True ah_bootstrap.DOWNLOAD_IF_NEEDED = True # Kind of a hacky way to do this, but this assertion is specifically # for test_check_submodule_no_git # TODO: Rework the tests in this module so that it's easier to test specific # behaviors of ah_bootstrap for each test assert '--no-git' not in sys.argv import _astropy_helpers_test_ filename = os.path.abspath(_astropy_helpers_test_.__file__) filename = filename.replace('.pyc', '.py') # More consistent this way # We print out variables that are needed in tests below in JSON import json data = {{}} data['filename'] = filename data['ah_bootstrap.BOOTSTRAPPER.use_git'] = ah_bootstrap.BOOTSTRAPPER.use_git print(json.dumps(data)) """ AH_BOOTSTRAP_FILE = os.path.join(os.path.dirname(__file__), '..', '..', 'ah_bootstrap.py') with open(AH_BOOTSTRAP_FILE) as f: AH_BOOTSTRAP = f.read() # The behavior checked in some of the tests depends on the version of # setuptools try: # We need to use LooseVersion here instead of StrictVersion since developer # versions of setuptools ('35.0.2.post20170530') don't satisfy the # StrictVersion criteria even though they satisfy PEP440 SETUPTOOLS_VERSION = LooseVersion(setuptools.__version__).version except: # Broken setuptools? ¯\_(ツ)_/¯ SETUPTOOLS_VERSION = (0, 0, 0) def test_bootstrap_from_submodule(tmpdir, testpackage, capsys): """ Tests importing _astropy_helpers_test_ from a submodule in a git repository. This tests actually performing a fresh clone of the repository without the submodule initialized, and that importing astropy_helpers in that context works transparently after calling `ah_boostrap.use_astropy_helpers`. """ orig_repo = tmpdir.mkdir('orig') with orig_repo.as_cwd(): run_cmd('git', ['init']) orig_repo.join('ah_bootstrap.py').write(AH_BOOTSTRAP) run_cmd('git', ['add', 'ah_bootstrap.py']) # Write a test setup.py that uses ah_bootstrap; it also ensures that # any previous reference to astropy_helpers is first wiped from # sys.modules orig_repo.join('setup.py').write(TEST_SETUP_PY.format(args='', extra='')) run_cmd('git', ['add', 'setup.py']) # Add our own clone of the astropy_helpers repo as a submodule named # astropy_helpers run_cmd('git', ['submodule', 'add', str(testpackage), '_astropy_helpers_test_']) run_cmd('git', ['commit', '-m', 'test repository']) os.chdir(str(tmpdir)) # Creates a clone of our test repo in the directory 'clone' run_cmd('git', ['clone', 'orig', 'clone']) os.chdir('clone') run_setup('setup.py', []) stdout, stderr = capsys.readouterr() path = json.loads(stdout.strip())['filename'] # Ensure that the astropy_helpers used by the setup.py is the one that # was imported from git submodule a = os.path.normcase(path) b = os.path.normcase(str(tmpdir.join('clone', '_astropy_helpers_test_', '_astropy_helpers_test_', '__init__.py'))) assert a == b def test_bootstrap_from_submodule_no_locale(tmpdir, testpackage, capsys, monkeypatch): """ Regression test for https://github.com/astropy/astropy/issues/2749 Runs test_bootstrap_from_submodule but with missing locale/language settings. """ for varname in ('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE'): monkeypatch.delenv(varname, raising=False) test_bootstrap_from_submodule(tmpdir, testpackage, capsys) def test_bootstrap_from_submodule_bad_locale(tmpdir, testpackage, capsys, monkeypatch): """ Additional regression test for https://github.com/astropy/astropy/issues/2749 """ for varname in ('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE'): monkeypatch.delenv(varname, raising=False) # Test also with bad LC_CTYPE a la http://bugs.python.org/issue18378 monkeypatch.setenv('LC_CTYPE', 'UTF-8') test_bootstrap_from_submodule(tmpdir, testpackage, capsys) UPDATE_ERROR_PATCH = """ class UpgradeError(Exception): pass def _do_upgrade(*args, **kwargs): raise UpgradeError() ah_bootstrap._Bootstrapper._do_upgrade = _do_upgrade """ def test_check_submodule_no_git(capsys, tmpdir, testpackage): """ Tests that when importing astropy_helpers from a submodule, it is still recognized as a submodule even when using the --no-git option. In particular this ensures that the auto-upgrade feature is not activated. """ orig_repo = tmpdir.mkdir('orig') with orig_repo.as_cwd(): orig_repo.join('ah_bootstrap.py').write(AH_BOOTSTRAP) run_cmd('git', ['init']) # Write a test setup.py that uses ah_bootstrap; it also ensures that # any previous reference to astropy_helpers is first wiped from # sys.modules args = 'auto_upgrade=True' orig_repo.join('setup.py').write(TEST_SETUP_PY.format(args=args, extra=UPDATE_ERROR_PATCH)) run_cmd('git', ['add', 'setup.py']) # Add our own clone of the astropy_helpers repo as a submodule named # astropy_helpers run_cmd('git', ['submodule', 'add', str(testpackage), '_astropy_helpers_test_']) run_cmd('git', ['commit', '-m', 'test repository']) run_setup('setup.py', ['--no-git']) stdout, stderr = capsys.readouterr() use_git = bool(json.loads(stdout.strip())['ah_bootstrap.BOOTSTRAPPER.use_git']) if 'UpgradeError' in stderr: pytest.fail('Attempted to run auto-upgrade despite importing ' '_astropy_helpers_test_ from a git submodule') # Ensure that the no-git option was in fact set assert not use_git def test_bootstrap_from_directory(tmpdir, testpackage, capsys): """ Tests simply bundling a copy of the astropy_helpers source code in its entirety bundled directly in the source package and not in an archive. """ source = tmpdir.mkdir('source') testpackage.copy(source.join('_astropy_helpers_test_')) with source.as_cwd(): source.join('ah_bootstrap.py').write(AH_BOOTSTRAP) source.join('setup.py').write(TEST_SETUP_PY.format(args='', extra='')) run_setup('setup.py', []) stdout, stderr = capsys.readouterr() path = json.loads(stdout.strip())['filename'] # Ensure that the astropy_helpers used by the setup.py is the one that # was imported from git submodule a = os.path.normcase(path) b = os.path.normcase(str(source.join('_astropy_helpers_test_', '_astropy_helpers_test_', '__init__.py'))) assert a == b def test_bootstrap_from_archive(tmpdir, testpackage, capsys): """ Tests importing _astropy_helpers_test_ from a .tar.gz source archive shipped alongside the package that uses it. """ orig_repo = tmpdir.mkdir('orig') # Make a source distribution of the test package with silence(): run_setup(str(testpackage.join('setup.py')), ['sdist', '--dist-dir=dist', '--formats=gztar']) dist_dir = testpackage.join('dist') for dist_file in dist_dir.visit('*.tar.gz'): dist_file.copy(orig_repo) with orig_repo.as_cwd(): orig_repo.join('ah_bootstrap.py').write(AH_BOOTSTRAP) # Write a test setup.py that uses ah_bootstrap; it also ensures that # any previous reference to astropy_helpers is first wiped from # sys.modules args = 'path={0!r}'.format(os.path.basename(str(dist_file))) orig_repo.join('setup.py').write(TEST_SETUP_PY.format(args=args, extra='')) run_setup('setup.py', []) stdout, stderr = capsys.readouterr() path = json.loads(stdout.strip())['filename'] # Installation from the .tar.gz should have resulted in a .egg # directory that the _astropy_helpers_test_ package was imported from eggs = _get_local_eggs() assert eggs egg = orig_repo.join(eggs[0]) assert os.path.isdir(str(egg)) a = os.path.normcase(path) b = os.path.normcase(str(egg.join('_astropy_helpers_test_', '__init__.py'))) assert a == b def test_download_if_needed(tmpdir, testpackage, capsys): """ Tests the case where astropy_helpers was not actually included in a package, or is otherwise missing, and we need to "download" it. This does not test actually downloading from the internet--this is normally done through setuptools' easy_install command which can also install from a source archive. From the point of view of ah_boostrap the two actions are equivalent, so we can just as easily simulate this by providing a setup.cfg giving the path to a source archive to "download" (as though it were a URL). """ source = tmpdir.mkdir('source') # Ensure ah_bootstrap is imported from the local directory import ah_bootstrap # noqa # Make a source distribution of the test package with silence(): run_setup(str(testpackage.join('setup.py')), ['sdist', '--dist-dir=dist', '--formats=gztar']) dist_dir = testpackage.join('dist') with source.as_cwd(): source.join('ah_bootstrap.py').write(AH_BOOTSTRAP) source.join('setup.py').write(TEST_SETUP_PY.format( args='download_if_needed=True', extra='')) source.join('setup.cfg').write(textwrap.dedent("""\ [easy_install] find_links = {find_links} """.format(find_links=str(dist_dir)))) run_setup('setup.py', []) stdout, stderr = capsys.readouterr() path = json.loads(stdout.strip())['filename'] # easy_install should have worked by 'installing' astropy_helpers as a # .egg in the current directory eggs = _get_local_eggs() assert eggs egg = source.join(eggs[0]) assert os.path.isdir(str(egg)) a = os.path.normcase(path) b = os.path.normcase(str(egg.join('_astropy_helpers_test_', '__init__.py'))) assert a == b EXTRA_PACKAGE_INDEX = """ from setuptools.package_index import PackageIndex class FakePackageIndex(PackageIndex): def __init__(self, *args, **kwargs): PackageIndex.__init__(self, *args, **kwargs) self.to_scan = {dists} def find_packages(self, requirement): # no-op pass ah_bootstrap.PackageIndex = FakePackageIndex """ def test_upgrade(tmpdir, capsys): orig_dir = create_testpackage(tmpdir.mkdir('orig')) # Make a test package that uses _astropy_helpers_test_ source = tmpdir.mkdir('source') dist_dir = source.mkdir('dists') orig_dir.copy(source.join('_astropy_helpers_test_')) with source.as_cwd(): source.join('ah_bootstrap.py').write(AH_BOOTSTRAP) setup_py = TEST_SETUP_PY.format(args='auto_upgrade=True', extra='') source.join('setup.py').write(setup_py) # This will be used to later to fake downloading the upgrade package source.join('setup.cfg').write(textwrap.dedent("""\ [easy_install] find_links = {find_links} """.format(find_links=str(dist_dir)))) # Make additional "upgrade" versions of the _astropy_helpers_test_ # package--one of them is version 0.2 and the other is version 0.1.1. The # auto-upgrade should ignore version 0.2 but use version 0.1.1. upgrade_dir_1 = create_testpackage(tmpdir.mkdir('upgrade_1'), version='0.2') upgrade_dir_2 = create_testpackage(tmpdir.mkdir('upgrade_2'), version='0.1.1') dists = [] # For each upgrade package go ahead and build a source distribution of it # and copy that source distribution to a dist directory we'll use later to # simulate a 'download' for upgrade_dir in [upgrade_dir_1, upgrade_dir_2]: with silence(): run_setup(str(upgrade_dir.join('setup.py')), ['sdist', '--dist-dir=dist', '--formats=gztar']) dists.append(str(upgrade_dir.join('dist'))) for dist_file in upgrade_dir.visit('*.tar.gz'): dist_file.copy(source.join('dists')) with source.as_cwd(): setup_py = TEST_SETUP_PY.format(args='auto_upgrade=True', extra=EXTRA_PACKAGE_INDEX.format(dists=dists)) source.join('setup.py').write(setup_py) # Now run the source setup.py; this test is similar to # test_download_if_needed, but we explicitly check that the correct # *version* of _astropy_helpers_test_ was used run_setup('setup.py', []) stdout, stderr = capsys.readouterr() path = json.loads(stdout.strip())['filename'] eggs = _get_local_eggs() assert eggs egg = source.join(eggs[0]) assert os.path.isdir(str(egg)) a = os.path.normcase(path) b = os.path.normcase(str(egg.join('_astropy_helpers_test_', '__init__.py'))) assert a == b assert 'astropy_helpers_test-0.1.1-' in str(egg) def _get_local_eggs(path='.'): """ Helper utility used by some tests to get the list of egg archive files in a local directory. """ if SETUPTOOLS_VERSION[0] >= 7: eggs = glob.glob(os.path.join(path, '.eggs', '*.egg')) else: eggs = glob.glob('*.egg') return eggs APLpy-2.0.3/astropy_helpers/astropy_helpers/tests/test_git_helpers.py0000644000077000000240000001775413404171254026164 0ustar tomstaff00000000000000import glob import imp import os import pkgutil import re import sys import tarfile import pytest from warnings import catch_warnings from . import reset_setup_helpers, reset_distutils_log # noqa from . import run_cmd, run_setup, cleanup_import from astropy_helpers.git_helpers import get_git_devstr _DEV_VERSION_RE = re.compile(r'\d+\.\d+(?:\.\d+)?\.dev(\d+)') ASTROPY_HELPERS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) TEST_VERSION_SETUP_PY = """\ #!/usr/bin/env python import sys from setuptools import setup NAME = 'apyhtest_eva' VERSION = {version!r} RELEASE = 'dev' not in VERSION sys.path.insert(0, r'{astropy_helpers_path}') from astropy_helpers.git_helpers import get_git_devstr from astropy_helpers.version_helpers import generate_version_py if not RELEASE: VERSION += get_git_devstr(False) generate_version_py(NAME, VERSION, RELEASE, False, uses_git=not RELEASE) setup(name=NAME, version=VERSION, packages=['apyhtest_eva']) """ TEST_VERSION_INIT = """\ try: from .version import version as __version__ from .version import githash as __githash__ except ImportError: __version__ = __githash__ = '' """ @pytest.fixture def version_test_package(tmpdir, request): def make_test_package(version='42.42.dev'): test_package = tmpdir.mkdir('test_package') test_package.join('setup.py').write( TEST_VERSION_SETUP_PY.format(version=version, astropy_helpers_path=ASTROPY_HELPERS_PATH)) test_package.mkdir('apyhtest_eva').join('__init__.py').write(TEST_VERSION_INIT) with test_package.as_cwd(): run_cmd('git', ['init']) run_cmd('git', ['add', '--all']) run_cmd('git', ['commit', '-m', 'test package']) if '' in sys.path: sys.path.remove('') sys.path.insert(0, '') def finalize(): cleanup_import('apyhtest_eva') request.addfinalizer(finalize) return test_package return make_test_package def test_update_git_devstr(version_test_package, capsys): """Tests that the commit number in the package's version string updates after git commits even without re-running setup.py. """ # We have to call version_test_package to actually create the package test_pkg = version_test_package() with test_pkg.as_cwd(): run_setup('setup.py', ['--version']) stdout, stderr = capsys.readouterr() version = stdout.strip() m = _DEV_VERSION_RE.match(version) assert m, ( "Stdout did not match the version string pattern:" "\n\n{0}\n\nStderr:\n\n{1}".format(stdout, stderr)) revcount = int(m.group(1)) import apyhtest_eva assert apyhtest_eva.__version__ == version # Make a silly git commit with open('.test', 'w'): pass run_cmd('git', ['add', '.test']) run_cmd('git', ['commit', '-m', 'test']) import apyhtest_eva.version imp.reload(apyhtest_eva.version) # Previously this checked packagename.__version__, but in order for that to # be updated we also have to re-import _astropy_init which could be tricky. # Checking directly that the packagename.version module was updated is # sufficient: m = _DEV_VERSION_RE.match(apyhtest_eva.version.version) assert m assert int(m.group(1)) == revcount + 1 # This doesn't test astropy_helpers.get_helpers.update_git_devstr directly # since a copy of that function is made in packagename.version (so that it # can work without astropy_helpers installed). In order to get test # coverage on the actual astropy_helpers copy of that function just call it # directly and compare to the value in packagename from astropy_helpers.git_helpers import update_git_devstr newversion = update_git_devstr(version, path=str(test_pkg)) assert newversion == apyhtest_eva.version.version def test_version_update_in_other_repos(version_test_package, tmpdir): """ Regression test for https://github.com/astropy/astropy-helpers/issues/114 and for https://github.com/astropy/astropy-helpers/issues/107 """ test_pkg = version_test_package() with test_pkg.as_cwd(): run_setup('setup.py', ['build']) # Add the path to the test package to sys.path for now sys.path.insert(0, str(test_pkg)) try: import apyhtest_eva m = _DEV_VERSION_RE.match(apyhtest_eva.__version__) assert m correct_revcount = int(m.group(1)) with tmpdir.as_cwd(): testrepo = tmpdir.mkdir('testrepo') testrepo.chdir() # Create an empty git repo run_cmd('git', ['init']) import apyhtest_eva.version imp.reload(apyhtest_eva.version) m = _DEV_VERSION_RE.match(apyhtest_eva.version.version) assert m assert int(m.group(1)) == correct_revcount correct_revcount = int(m.group(1)) # Add several commits--more than the revcount for the apyhtest_eva package for idx in range(correct_revcount + 5): test_filename = '.test' + str(idx) testrepo.ensure(test_filename) run_cmd('git', ['add', test_filename]) run_cmd('git', ['commit', '-m', 'A message']) import apyhtest_eva.version imp.reload(apyhtest_eva.version) m = _DEV_VERSION_RE.match(apyhtest_eva.version.version) assert m assert int(m.group(1)) == correct_revcount correct_revcount = int(m.group(1)) finally: sys.path.remove(str(test_pkg)) @pytest.mark.parametrize('version', ['1.0.dev', '1.0']) def test_installed_git_version(version_test_package, version, tmpdir, capsys): """ Test for https://github.com/astropy/astropy-helpers/issues/87 Ensures that packages installed with astropy_helpers have a correct copy of the git hash of the installed commit. """ # To test this, it should suffice to build a source dist, unpack it # somewhere outside the git repository, and then do a build and import # from the build directory--no need to "install" as such test_pkg = version_test_package(version) with test_pkg.as_cwd(): run_setup('setup.py', ['build']) try: import apyhtest_eva githash = apyhtest_eva.__githash__ assert githash and isinstance(githash, str) # Ensure that it does in fact look like a git hash and not some # other arbitrary string assert re.match(r'[0-9a-f]{40}', githash) finally: cleanup_import('apyhtest_eva') run_setup('setup.py', ['sdist', '--dist-dir=dist', '--formats=gztar']) tgzs = glob.glob(os.path.join('dist', '*.tar.gz')) assert len(tgzs) == 1 tgz = test_pkg.join(tgzs[0]) build_dir = tmpdir.mkdir('build_dir') tf = tarfile.open(str(tgz), mode='r:gz') tf.extractall(str(build_dir)) with build_dir.as_cwd(): pkg_dir = glob.glob('apyhtest_eva-*')[0] os.chdir(pkg_dir) with catch_warnings(record=True) as w: run_setup('setup.py', ['build']) try: import apyhtest_eva loader = pkgutil.get_loader('apyhtest_eva') # Ensure we are importing the 'packagename' that was just unpacked # into the build_dir assert loader.get_filename().startswith(str(build_dir)) assert apyhtest_eva.__githash__ == githash finally: cleanup_import('apyhtest_eva') def test_get_git_devstr(tmpdir): dirpath = str(tmpdir) warn_msg = "No git repository present at" # Verify as much as possible, but avoid dealing with paths on windows if not sys.platform.startswith('win'): warn_msg += " '{}'".format(dirpath) with catch_warnings(record=True) as w: devstr = get_git_devstr(path=dirpath) assert devstr == '0' assert len(w) == 1 assert str(w[0].message).startswith(warn_msg) APLpy-2.0.3/astropy_helpers/astropy_helpers/tests/test_openmp_helpers.py0000644000077000000240000000432713404171254026667 0ustar tomstaff00000000000000import os import sys import types from copy import deepcopy from importlib import machinery from distutils.core import Extension from ..openmp_helpers import add_openmp_flags_if_available, generate_openmp_enabled_py from ..setup_helpers import _module_state, register_commands IS_TRAVIS_LINUX = os.environ.get('TRAVIS_OS_NAME', None) == 'linux' IS_TRAVIS_OSX = os.environ.get('TRAVIS_OS_NAME', None) == 'osx' IS_APPVEYOR = os.environ.get('APPVEYOR', None) == 'True' PY3_LT_35 = sys.version_info[0] == 3 and sys.version_info[1] < 5 _state = None try: OPENMP_EXPECTED = 'True' == os.environ['OPENMP_EXPECTED'] except KeyError: raise Exception("The OPENMP_EXPECTED environment variable should be set to " "True or False and should indicate whether OpenMP should " "work on your platform.") def setup_function(function): global state state = deepcopy(_module_state) def teardown_function(function): _module_state.clear() _module_state.update(state) def test_add_openmp_flags_if_available(): register_commands('openmp_testing', '0.0', False) using_openmp = add_openmp_flags_if_available(Extension('test', [])) # Make sure that on Travis (Linux) and AppVeyor OpenMP does get used (for # MacOS X usually it will not work but this will depend on the compiler). # Having this is useful because we'll find out if OpenMP no longer works # for any reason on platforms on which it does work at the time of writing. if OPENMP_EXPECTED: assert using_openmp else: assert not using_openmp def test_generate_openmp_enabled_py(): register_commands('openmp_autogeneration_testing', '0.0', False) # Test file generation generate_openmp_enabled_py('') assert os.path.isfile('openmp_enabled.py') # Load openmp_enabled file as a module to check the result loader = machinery.SourceFileLoader('openmp_enabled', 'openmp_enabled.py') mod = types.ModuleType(loader.name) loader.exec_module(mod) is_openmp_enabled = mod.is_openmp_enabled() # Test is_openmp_enabled() assert isinstance(is_openmp_enabled, bool) if OPENMP_EXPECTED: assert is_openmp_enabled else: assert not is_openmp_enabled APLpy-2.0.3/astropy_helpers/astropy_helpers/tests/test_setup_helpers.py0000644000077000000240000004337213404171254026534 0ustar tomstaff00000000000000import os import sys import stat import shutil import importlib import contextlib import pytest from textwrap import dedent from setuptools import Distribution from ..setup_helpers import get_package_info, register_commands from ..commands import build_ext from . import reset_setup_helpers, reset_distutils_log # noqa from . import run_setup, cleanup_import ASTROPY_HELPERS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) def _extension_test_package(tmpdir, request, extension_type='c', include_numpy=False): """Creates a simple test package with an extension module.""" test_pkg = tmpdir.mkdir('test_pkg') test_pkg.mkdir('apyhtest_eva').ensure('__init__.py') # TODO: It might be later worth making this particular test package into a # reusable fixture for other build_ext tests if extension_type in ('c', 'both'): # A minimal C extension for testing test_pkg.join('apyhtest_eva', 'unit01.c').write(dedent("""\ #include #ifndef PY3K #if PY_MAJOR_VERSION >= 3 #define PY3K 1 #else #define PY3K 0 #endif #endif #if PY3K static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "unit01", NULL, -1, NULL }; PyMODINIT_FUNC PyInit_unit01(void) { return PyModule_Create(&moduledef); } #else PyMODINIT_FUNC initunit01(void) { Py_InitModule3("unit01", NULL, NULL); } #endif """)) if extension_type in ('pyx', 'both'): # A minimal Cython extension for testing test_pkg.join('apyhtest_eva', 'unit02.pyx').write(dedent("""\ print("Hello cruel angel.") """)) if extension_type == 'c': extensions = ['unit01.c'] elif extension_type == 'pyx': extensions = ['unit02.pyx'] elif extension_type == 'both': extensions = ['unit01.c', 'unit02.pyx'] include_dirs = ['numpy'] if include_numpy else [] extensions_list = [ "Extension('apyhtest_eva.{0}', [join('apyhtest_eva', '{1}')], include_dirs={2})".format( os.path.splitext(extension)[0], extension, include_dirs) for extension in extensions] test_pkg.join('apyhtest_eva', 'setup_package.py').write(dedent("""\ from setuptools import Extension from os.path import join def get_extensions(): return [{0}] """.format(', '.join(extensions_list)))) test_pkg.join('setup.py').write(dedent("""\ import sys from os.path import join from setuptools import setup sys.path.insert(0, r'{astropy_helpers_path}') from astropy_helpers.setup_helpers import register_commands from astropy_helpers.setup_helpers import get_package_info from astropy_helpers.version_helpers import generate_version_py if '--no-cython' in sys.argv: from astropy_helpers.commands import build_ext build_ext.should_build_with_cython = lambda *args: False sys.argv.remove('--no-cython') NAME = 'apyhtest_eva' VERSION = '0.1' RELEASE = True cmdclassd = register_commands(NAME, VERSION, RELEASE) generate_version_py(NAME, VERSION, RELEASE, False, False) package_info = get_package_info() setup( name=NAME, version=VERSION, cmdclass=cmdclassd, **package_info ) """.format(astropy_helpers_path=ASTROPY_HELPERS_PATH))) if '' in sys.path: sys.path.remove('') sys.path.insert(0, '') def finalize(): cleanup_import('apyhtest_eva') request.addfinalizer(finalize) return test_pkg @pytest.fixture def extension_test_package(tmpdir, request): return _extension_test_package(tmpdir, request, extension_type='both') @pytest.fixture def c_extension_test_package(tmpdir, request): # Check whether numpy is installed in the test environment has_numpy = bool(importlib.util.find_spec('numpy')) return _extension_test_package(tmpdir, request, extension_type='c', include_numpy=has_numpy) @pytest.fixture def pyx_extension_test_package(tmpdir, request): return _extension_test_package(tmpdir, request, extension_type='pyx') def test_cython_autoextensions(tmpdir): """ Regression test for https://github.com/astropy/astropy-helpers/pull/19 Ensures that Cython extensions in sub-packages are discovered and built only once. """ # Make a simple test package test_pkg = tmpdir.mkdir('test_pkg') test_pkg.mkdir('yoda').mkdir('luke') test_pkg.ensure('yoda', '__init__.py') test_pkg.ensure('yoda', 'luke', '__init__.py') test_pkg.join('yoda', 'luke', 'dagobah.pyx').write( """def testfunc(): pass""") # Required, currently, for get_package_info to work register_commands('yoda', '0.0', False, srcdir=str(test_pkg)) package_info = get_package_info(str(test_pkg)) assert len(package_info['ext_modules']) == 1 assert package_info['ext_modules'][0].name == 'yoda.luke.dagobah' def test_compiler_module(capsys, c_extension_test_package): """ Test ensuring that the compiler module is built and installed for packages that have extension modules. """ test_pkg = c_extension_test_package install_temp = test_pkg.mkdir('install_temp') with test_pkg.as_cwd(): # This is one of the simplest ways to install just a package into a # test directory run_setup('setup.py', ['install', '--single-version-externally-managed', '--install-lib={0}'.format(install_temp), '--record={0}'.format(install_temp.join('record.txt'))]) stdout, stderr = capsys.readouterr() assert "No git repository present at" in stderr with install_temp.as_cwd(): import apyhtest_eva # Make sure we imported the apyhtest_eva package from the correct place dirname = os.path.abspath(os.path.dirname(apyhtest_eva.__file__)) assert dirname == str(install_temp.join('apyhtest_eva')) import apyhtest_eva._compiler import apyhtest_eva.version assert apyhtest_eva.version.compiler == apyhtest_eva._compiler.compiler assert apyhtest_eva.version.compiler != 'unknown' def test_no_cython_buildext(capsys, c_extension_test_package, monkeypatch): """ Regression test for https://github.com/astropy/astropy-helpers/pull/35 This tests the custom build_ext command installed by astropy_helpers when used with a project that has no Cython extensions (but does have one or more normal C extensions). """ test_pkg = c_extension_test_package with test_pkg.as_cwd(): run_setup('setup.py', ['build_ext', '--inplace', '--no-cython']) stdout, stderr = capsys.readouterr() assert "No git repository present at" in stderr sys.path.insert(0, str(test_pkg)) try: import apyhtest_eva.unit01 dirname = os.path.abspath(os.path.dirname(apyhtest_eva.unit01.__file__)) assert dirname == str(test_pkg.join('apyhtest_eva')) finally: sys.path.remove(str(test_pkg)) def test_missing_cython_c_files(capsys, pyx_extension_test_package, monkeypatch): """ Regression test for https://github.com/astropy/astropy-helpers/pull/181 Test failure mode when building a package that has Cython modules, but where Cython is not installed and the generated C files are missing. """ test_pkg = pyx_extension_test_package with test_pkg.as_cwd(): with pytest.raises(SystemExit): run_setup('setup.py', ['build_ext', '--inplace', '--no-cython']) stdout, stderr = capsys.readouterr() assert "No git repository present at" in stderr msg = ('Could not find C/C++ file ' '{0}.(c/cpp)'.format('apyhtest_eva/unit02'.replace('/', os.sep))) assert msg in stderr @pytest.mark.parametrize('mode', ['cli', 'cli-w', 'deprecated', 'cli-l']) def test_build_docs(capsys, tmpdir, mode): """ Test for build_docs """ test_pkg = tmpdir.mkdir('test_pkg') test_pkg.mkdir('mypackage') test_pkg.join('mypackage').join('__init__.py').write(dedent("""\ def test_function(): pass class A(): pass class B(A): pass """)) test_pkg.mkdir('docs') docs_dir = test_pkg.join('docs') docs_dir.join('conf.py').write(dedent("""\ import warnings with warnings.catch_warnings(): # ignore matplotlib warning warnings.simplefilter("ignore") from sphinx_astropy.conf import * exclude_patterns.append('_templates') suppress_warnings = ['app.add_directive', 'app.add_node', 'app.add_role'] """)) docs_dir.join('index.rst').write(dedent("""\ .. automodapi:: mypackage :no-inheritance-diagram: """)) test_pkg.join('setup.py').write(dedent("""\ import sys sys.path.insert(0, r'{astropy_helpers_path}') from os.path import join from setuptools import setup, Extension from astropy_helpers.setup_helpers import register_commands, get_package_info NAME = 'mypackage' VERSION = 0.1 RELEASE = True cmdclassd = register_commands(NAME, VERSION, RELEASE) setup( name=NAME, version=VERSION, cmdclass=cmdclassd, **get_package_info() ) """.format(astropy_helpers_path=ASTROPY_HELPERS_PATH))) with test_pkg.as_cwd(): if mode == 'cli': run_setup('setup.py', ['build_docs']) elif mode == 'cli-w': run_setup('setup.py', ['build_docs', '-w']) elif mode == 'cli-l': run_setup('setup.py', ['build_docs', '-l']) elif mode == 'deprecated': run_setup('setup.py', ['build_sphinx']) stdout, stderr = capsys.readouterr() assert 'AstropyDeprecationWarning' in stderr assert os.path.exists(docs_dir.join('_build', 'html', 'index.html').strpath) def test_command_hooks(tmpdir, capsys): """A basic test for pre- and post-command hooks.""" test_pkg = tmpdir.mkdir('test_pkg') test_pkg.mkdir('_welltall_') test_pkg.join('_welltall_', '__init__.py').ensure() # Create a setup_package module with a couple of command hooks in it test_pkg.join('_welltall_', 'setup_package.py').write(dedent("""\ def pre_build_hook(cmd_obj): print('Hello build!') def post_build_hook(cmd_obj): print('Goodbye build!') """)) # A simple setup.py for the test package--running register_commands should # discover and enable the command hooks test_pkg.join('setup.py').write(dedent("""\ import sys from os.path import join from setuptools import setup, Extension sys.path.insert(0, r'{astropy_helpers_path}') from astropy_helpers.setup_helpers import register_commands, get_package_info NAME = '_welltall_' VERSION = 0.1 RELEASE = True cmdclassd = register_commands(NAME, VERSION, RELEASE) setup( name=NAME, version=VERSION, cmdclass=cmdclassd ) """.format(astropy_helpers_path=ASTROPY_HELPERS_PATH))) with test_pkg.as_cwd(): try: run_setup('setup.py', ['build']) finally: cleanup_import('_welltall_') stdout, stderr = capsys.readouterr() want = dedent("""\ running build running pre_hook from _welltall_.setup_package for build command Hello build! running post_hook from _welltall_.setup_package for build command Goodbye build! """).strip() assert want in stdout.replace('\r\n', '\n').replace('\r', '\n') def test_adjust_compiler(monkeypatch, tmpdir): """ Regression test for https://github.com/astropy/astropy-helpers/issues/182 """ from distutils import ccompiler, sysconfig class MockLog(object): def __init__(self): self.messages = [] def warn(self, message): self.messages.append(message) good = tmpdir.join('gcc-good') good.write(dedent("""\ #!{python} import sys print('gcc 4.10') sys.exit(0) """.format(python=sys.executable))) good.chmod(stat.S_IRUSR | stat.S_IEXEC) # A "compiler" that reports itself to be a version of Apple's llvm-gcc # which is broken bad = tmpdir.join('gcc-bad') bad.write(dedent("""\ #!{python} import sys print('i686-apple-darwin-llvm-gcc-4.2') sys.exit(0) """.format(python=sys.executable))) bad.chmod(stat.S_IRUSR | stat.S_IEXEC) # A "compiler" that doesn't even know its identity (this reproduces the bug # in #182) ugly = tmpdir.join('gcc-ugly') ugly.write(dedent("""\ #!{python} import sys sys.exit(1) """.format(python=sys.executable))) ugly.chmod(stat.S_IRUSR | stat.S_IEXEC) # Scripts with shebang lines don't work implicitly in Windows when passed # to subprocess.Popen, so... if 'win' in sys.platform: good = ' '.join((sys.executable, str(good))) bad = ' '.join((sys.executable, str(bad))) ugly = ' '.join((sys.executable, str(ugly))) dist = Distribution({}) cmd_cls = build_ext.generate_build_ext_command('astropy', False) cmd = cmd_cls(dist) adjust_compiler = cmd._adjust_compiler @contextlib.contextmanager def test_setup(): log = MockLog() monkeypatch.setattr(build_ext, 'log', log) yield log monkeypatch.undo() @contextlib.contextmanager def compiler_setter_with_environ(compiler): monkeypatch.setenv('CC', compiler) with test_setup() as log: yield log monkeypatch.undo() @contextlib.contextmanager def compiler_setter_with_sysconfig(compiler): monkeypatch.setattr(ccompiler, 'get_default_compiler', lambda: 'unix') monkeypatch.setattr(sysconfig, 'get_config_var', lambda v: compiler) old_cc = os.environ.get('CC') if old_cc is not None: del os.environ['CC'] with test_setup() as log: yield log monkeypatch.undo() monkeypatch.undo() monkeypatch.undo() if old_cc is not None: os.environ['CC'] = old_cc compiler_setters = (compiler_setter_with_environ, compiler_setter_with_sysconfig) for compiler_setter in compiler_setters: with compiler_setter(str(good)): # Should have no side-effects adjust_compiler() with compiler_setter(str(ugly)): # Should just pass without complaint, since we can't determine # anything about the compiler anyways adjust_compiler() # In the following tests we check the log messages just to ensure that the # failures occur on the correct code paths for these cases with compiler_setter_with_environ(str(bad)) as log: with pytest.raises(SystemExit): adjust_compiler() assert len(log.messages) == 1 assert 'will fail to compile' in log.messages[0] with compiler_setter_with_sysconfig(str(bad)): adjust_compiler() assert 'CC' in os.environ and os.environ['CC'] == 'clang' with compiler_setter_with_environ('bogus') as log: with pytest.raises(SystemExit): # Missing compiler? adjust_compiler() assert len(log.messages) == 1 assert 'cannot be found or executed' in log.messages[0] with compiler_setter_with_sysconfig('bogus') as log: with pytest.raises(SystemExit): # Missing compiler? adjust_compiler() assert len(log.messages) == 1 assert 'The C compiler used to compile Python' in log.messages[0] def test_invalid_package_exclusion(tmpdir, capsys): module_name = 'foobar' setup_header = dedent("""\ import sys from os.path import join from setuptools import setup, Extension sys.path.insert(0, r'{astropy_helpers_path}') from astropy_helpers.setup_helpers import register_commands, \\ get_package_info, add_exclude_packages NAME = {module_name!r} VERSION = 0.1 RELEASE = True """.format(module_name=module_name, astropy_helpers_path=ASTROPY_HELPERS_PATH)) setup_footer = dedent("""\ setup( name=NAME, version=VERSION, cmdclass=cmdclassd, **package_info ) """) # Test error when using add_package_excludes out of order error_commands = dedent("""\ cmdclassd = register_commands(NAME, VERSION, RELEASE) package_info = get_package_info() add_exclude_packages(['tests*']) """) error_pkg = tmpdir.mkdir('error_pkg') error_pkg.join('setup.py').write( setup_header + error_commands + setup_footer) with error_pkg.as_cwd(): with pytest.raises(SystemExit): run_setup('setup.py', ['build']) stdout, stderr = capsys.readouterr() assert "RuntimeError" in stderr # Test warning when using deprecated exclude parameter warn_commands = dedent("""\ cmdclassd = register_commands(NAME, VERSION, RELEASE) package_info = get_package_info(exclude=['test*']) """) warn_pkg = tmpdir.mkdir('warn_pkg') warn_pkg.join('setup.py').write( setup_header + warn_commands + setup_footer) with warn_pkg.as_cwd(): run_setup('setup.py', ['build']) stdout, stderr = capsys.readouterr() assert 'AstropyDeprecationWarning' in stderr APLpy-2.0.3/astropy_helpers/astropy_helpers/tests/test_utils.py0000644000077000000240000000135712703324024025003 0ustar tomstaff00000000000000import os from ..utils import find_data_files def test_find_data_files(tmpdir): data = tmpdir.mkdir('data') sub1 = data.mkdir('sub1') sub2 = data.mkdir('sub2') sub3 = sub1.mkdir('sub3') for directory in (data, sub1, sub2, sub3): filename = directory.join('data.dat').strpath with open(filename, 'w') as f: f.write('test') filenames = find_data_files(data.strpath, '**/*.dat') filenames = sorted(os.path.relpath(x, data.strpath) for x in filenames) assert filenames[0] == os.path.join('data.dat') assert filenames[1] == os.path.join('sub1', 'data.dat') assert filenames[2] == os.path.join('sub1', 'sub3', 'data.dat') assert filenames[3] == os.path.join('sub2', 'data.dat') APLpy-2.0.3/astropy_helpers/astropy_helpers/utils.py0000644000077000000240000006030513404171254022604 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst from __future__ import absolute_import, unicode_literals import contextlib import functools import imp import inspect import os import sys import glob import textwrap import types import warnings from importlib import machinery as import_machinery # Note: The following Warning subclasses are simply copies of the Warnings in # Astropy of the same names. class AstropyWarning(Warning): """ The base warning class from which all Astropy warnings should inherit. Any warning inheriting from this class is handled by the Astropy logger. """ class AstropyDeprecationWarning(AstropyWarning): """ A warning class to indicate a deprecated feature. """ class AstropyPendingDeprecationWarning(PendingDeprecationWarning, AstropyWarning): """ A warning class to indicate a soon-to-be deprecated feature. """ def _get_platlib_dir(cmd): """ Given a build command, return the name of the appropriate platform-specific build subdirectory directory (e.g. build/lib.linux-x86_64-2.7) """ plat_specifier = '.{0}-{1}'.format(cmd.plat_name, sys.version[0:3]) return os.path.join(cmd.build_base, 'lib' + plat_specifier) def get_numpy_include_path(): """ Gets the path to the numpy headers. """ # We need to go through this nonsense in case setuptools # downloaded and installed Numpy for us as part of the build or # install, since Numpy may still think it's in "setup mode", when # in fact we're ready to use it to build astropy now. import builtins if hasattr(builtins, '__NUMPY_SETUP__'): del builtins.__NUMPY_SETUP__ import imp import numpy imp.reload(numpy) try: numpy_include = numpy.get_include() except AttributeError: numpy_include = numpy.get_numpy_include() return numpy_include class _DummyFile(object): """A noop writeable object.""" errors = '' def write(self, s): pass def flush(self): pass @contextlib.contextmanager def silence(): """A context manager that silences sys.stdout and sys.stderr.""" old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = _DummyFile() sys.stderr = _DummyFile() exception_occurred = False try: yield except: exception_occurred = True # Go ahead and clean up so that exception handling can work normally sys.stdout = old_stdout sys.stderr = old_stderr raise if not exception_occurred: sys.stdout = old_stdout sys.stderr = old_stderr if sys.platform == 'win32': import ctypes def _has_hidden_attribute(filepath): """ Returns True if the given filepath has the hidden attribute on MS-Windows. Based on a post here: http://stackoverflow.com/questions/284115/cross-platform-hidden-file-detection """ if isinstance(filepath, bytes): filepath = filepath.decode(sys.getfilesystemencoding()) try: attrs = ctypes.windll.kernel32.GetFileAttributesW(filepath) assert attrs != -1 result = bool(attrs & 2) except (AttributeError, AssertionError): result = False return result else: def _has_hidden_attribute(filepath): return False def is_path_hidden(filepath): """ Determines if a given file or directory is hidden. Parameters ---------- filepath : str The path to a file or directory Returns ------- hidden : bool Returns `True` if the file is hidden """ name = os.path.basename(os.path.abspath(filepath)) if isinstance(name, bytes): is_dotted = name.startswith(b'.') else: is_dotted = name.startswith('.') return is_dotted or _has_hidden_attribute(filepath) def walk_skip_hidden(top, onerror=None, followlinks=False): """ A wrapper for `os.walk` that skips hidden files and directories. This function does not have the parameter `topdown` from `os.walk`: the directories must always be recursed top-down when using this function. See also -------- os.walk : For a description of the parameters """ for root, dirs, files in os.walk( top, topdown=True, onerror=onerror, followlinks=followlinks): # These lists must be updated in-place so os.walk will skip # hidden directories dirs[:] = [d for d in dirs if not is_path_hidden(d)] files[:] = [f for f in files if not is_path_hidden(f)] yield root, dirs, files def write_if_different(filename, data): """Write `data` to `filename`, if the content of the file is different. Parameters ---------- filename : str The file name to be written to. data : bytes The data to be written to `filename`. """ assert isinstance(data, bytes) if os.path.exists(filename): with open(filename, 'rb') as fd: original_data = fd.read() else: original_data = None if original_data != data: with open(filename, 'wb') as fd: fd.write(data) def import_file(filename, name=None): """ Imports a module from a single file as if it doesn't belong to a particular package. The returned module will have the optional ``name`` if given, or else a name generated from the filename. """ # Specifying a traditional dot-separated fully qualified name here # results in a number of "Parent module 'astropy' not found while # handling absolute import" warnings. Using the same name, the # namespaces of the modules get merged together. So, this # generates an underscore-separated name which is more likely to # be unique, and it doesn't really matter because the name isn't # used directly here anyway. mode = 'r' if name is None: basename = os.path.splitext(filename)[0] name = '_'.join(os.path.relpath(basename).split(os.sep)[1:]) if import_machinery: loader = import_machinery.SourceFileLoader(name, filename) mod = loader.load_module() else: with open(filename, mode) as fd: mod = imp.load_module(name, fd, filename, ('.py', mode, 1)) return mod def resolve_name(name): """Resolve a name like ``module.object`` to an object and return it. Raise `ImportError` if the module or name is not found. """ parts = name.split('.') cursor = len(parts) - 1 module_name = parts[:cursor] attr_name = parts[-1] while cursor > 0: try: ret = __import__('.'.join(module_name), fromlist=[attr_name]) break except ImportError: if cursor == 0: raise cursor -= 1 module_name = parts[:cursor] attr_name = parts[cursor] ret = '' for part in parts[cursor:]: try: ret = getattr(ret, part) except AttributeError: raise ImportError(name) return ret def extends_doc(extended_func): """ A function decorator for use when wrapping an existing function but adding additional functionality. This copies the docstring from the original function, and appends to it (along with a newline) the docstring of the wrapper function. Examples -------- >>> def foo(): ... '''Hello.''' ... >>> @extends_doc(foo) ... def bar(): ... '''Goodbye.''' ... >>> print(bar.__doc__) Hello. Goodbye. """ def decorator(func): if not (extended_func.__doc__ is None or func.__doc__ is None): func.__doc__ = '\n\n'.join([extended_func.__doc__.rstrip('\n'), func.__doc__.lstrip('\n')]) return func return decorator # Duplicated from astropy.utils.decorators.deprecated # When fixing issues in this function fix them in astropy first, then # port the fixes over to astropy-helpers def deprecated(since, message='', name='', alternative='', pending=False, obj_type=None): """ Used to mark a function or class as deprecated. To mark an attribute as deprecated, use `deprecated_attribute`. Parameters ---------- since : str The release at which this API became deprecated. This is required. message : str, optional Override the default deprecation message. The format specifier ``func`` may be used for the name of the function, and ``alternative`` may be used in the deprecation message to insert the name of an alternative to the deprecated function. ``obj_type`` may be used to insert a friendly name for the type of object being deprecated. name : str, optional The name of the deprecated function or class; if not provided the name is automatically determined from the passed in function or class, though this is useful in the case of renamed functions, where the new function is just assigned to the name of the deprecated function. For example:: def new_function(): ... oldFunction = new_function alternative : str, optional An alternative function or class name that the user may use in place of the deprecated object. The deprecation warning will tell the user about this alternative if provided. pending : bool, optional If True, uses a AstropyPendingDeprecationWarning instead of a AstropyDeprecationWarning. obj_type : str, optional The type of this object, if the automatically determined one needs to be overridden. """ method_types = (classmethod, staticmethod, types.MethodType) def deprecate_doc(old_doc, message): """ Returns a given docstring with a deprecation message prepended to it. """ if not old_doc: old_doc = '' old_doc = textwrap.dedent(old_doc).strip('\n') new_doc = (('\n.. deprecated:: {since}' '\n {message}\n\n'.format( **{'since': since, 'message': message.strip()})) + old_doc) if not old_doc: # This is to prevent a spurious 'unexpected unindent' warning from # docutils when the original docstring was blank. new_doc += r'\ ' return new_doc def get_function(func): """ Given a function or classmethod (or other function wrapper type), get the function object. """ if isinstance(func, method_types): func = func.__func__ return func def deprecate_function(func, message): """ Returns a wrapped function that displays an ``AstropyDeprecationWarning`` when it is called. """ if isinstance(func, method_types): func_wrapper = type(func) else: func_wrapper = lambda f: f func = get_function(func) def deprecated_func(*args, **kwargs): if pending: category = AstropyPendingDeprecationWarning else: category = AstropyDeprecationWarning warnings.warn(message, category, stacklevel=2) return func(*args, **kwargs) # If this is an extension function, we can't call # functools.wraps on it, but we normally don't care. # This crazy way to get the type of a wrapper descriptor is # straight out of the Python 3.3 inspect module docs. if type(func) is not type(str.__dict__['__add__']): # nopep8 deprecated_func = functools.wraps(func)(deprecated_func) deprecated_func.__doc__ = deprecate_doc( deprecated_func.__doc__, message) return func_wrapper(deprecated_func) def deprecate_class(cls, message): """ Update the docstring and wrap the ``__init__`` in-place (or ``__new__`` if the class or any of the bases overrides ``__new__``) so it will give a deprecation warning when an instance is created. This won't work for extension classes because these can't be modified in-place and the alternatives don't work in the general case: - Using a new class that looks and behaves like the original doesn't work because the __new__ method of extension types usually makes sure that it's the same class or a subclass. - Subclassing the class and return the subclass can lead to problems with pickle and will look weird in the Sphinx docs. """ cls.__doc__ = deprecate_doc(cls.__doc__, message) if cls.__new__ is object.__new__: cls.__init__ = deprecate_function(get_function(cls.__init__), message) else: cls.__new__ = deprecate_function(get_function(cls.__new__), message) return cls def deprecate(obj, message=message, name=name, alternative=alternative, pending=pending): if obj_type is None: if isinstance(obj, type): obj_type_name = 'class' elif inspect.isfunction(obj): obj_type_name = 'function' elif inspect.ismethod(obj) or isinstance(obj, method_types): obj_type_name = 'method' else: obj_type_name = 'object' else: obj_type_name = obj_type if not name: name = get_function(obj).__name__ altmessage = '' if not message or type(message) is type(deprecate): if pending: message = ('The {func} {obj_type} will be deprecated in a ' 'future version.') else: message = ('The {func} {obj_type} is deprecated and may ' 'be removed in a future version.') if alternative: altmessage = '\n Use {} instead.'.format(alternative) message = ((message.format(**{ 'func': name, 'name': name, 'alternative': alternative, 'obj_type': obj_type_name})) + altmessage) if isinstance(obj, type): return deprecate_class(obj, message) else: return deprecate_function(obj, message) if type(message) is type(deprecate): return deprecate(message) return deprecate def deprecated_attribute(name, since, message=None, alternative=None, pending=False): """ Used to mark a public attribute as deprecated. This creates a property that will warn when the given attribute name is accessed. To prevent the warning (i.e. for internal code), use the private name for the attribute by prepending an underscore (i.e. ``self._name``). Parameters ---------- name : str The name of the deprecated attribute. since : str The release at which this API became deprecated. This is required. message : str, optional Override the default deprecation message. The format specifier ``name`` may be used for the name of the attribute, and ``alternative`` may be used in the deprecation message to insert the name of an alternative to the deprecated function. alternative : str, optional An alternative attribute that the user may use in place of the deprecated attribute. The deprecation warning will tell the user about this alternative if provided. pending : bool, optional If True, uses a AstropyPendingDeprecationWarning instead of a AstropyDeprecationWarning. Examples -------- :: class MyClass: # Mark the old_name as deprecated old_name = misc.deprecated_attribute('old_name', '0.1') def method(self): self._old_name = 42 """ private_name = '_' + name @deprecated(since, name=name, obj_type='attribute') def get(self): return getattr(self, private_name) @deprecated(since, name=name, obj_type='attribute') def set(self, val): setattr(self, private_name, val) @deprecated(since, name=name, obj_type='attribute') def delete(self): delattr(self, private_name) return property(get, set, delete) def minversion(module, version, inclusive=True, version_path='__version__'): """ Returns `True` if the specified Python module satisfies a minimum version requirement, and `False` if not. By default this uses `pkg_resources.parse_version` to do the version comparison if available. Otherwise it falls back on `distutils.version.LooseVersion`. Parameters ---------- module : module or `str` An imported module of which to check the version, or the name of that module (in which case an import of that module is attempted-- if this fails `False` is returned). version : `str` The version as a string that this module must have at a minimum (e.g. ``'0.12'``). inclusive : `bool` The specified version meets the requirement inclusively (i.e. ``>=``) as opposed to strictly greater than (default: `True`). version_path : `str` A dotted attribute path to follow in the module for the version. Defaults to just ``'__version__'``, which should work for most Python modules. Examples -------- >>> import astropy >>> minversion(astropy, '0.4.4') True """ if isinstance(module, types.ModuleType): module_name = module.__name__ elif isinstance(module, str): module_name = module try: module = resolve_name(module_name) except ImportError: return False else: raise ValueError('module argument must be an actual imported ' 'module, or the import name of the module; ' 'got {0!r}'.format(module)) if '.' not in version_path: have_version = getattr(module, version_path) else: have_version = resolve_name('.'.join([module.__name__, version_path])) try: from pkg_resources import parse_version except ImportError: from distutils.version import LooseVersion as parse_version if inclusive: return parse_version(have_version) >= parse_version(version) else: return parse_version(have_version) > parse_version(version) # Copy of the classproperty decorator from astropy.utils.decorators class classproperty(property): """ Similar to `property`, but allows class-level properties. That is, a property whose getter is like a `classmethod`. The wrapped method may explicitly use the `classmethod` decorator (which must become before this decorator), or the `classmethod` may be omitted (it is implicit through use of this decorator). .. note:: classproperty only works for *read-only* properties. It does not currently allow writeable/deleteable properties, due to subtleties of how Python descriptors work. In order to implement such properties on a class a metaclass for that class must be implemented. Parameters ---------- fget : callable The function that computes the value of this property (in particular, the function when this is used as a decorator) a la `property`. doc : str, optional The docstring for the property--by default inherited from the getter function. lazy : bool, optional If True, caches the value returned by the first call to the getter function, so that it is only called once (used for lazy evaluation of an attribute). This is analogous to `lazyproperty`. The ``lazy`` argument can also be used when `classproperty` is used as a decorator (see the third example below). When used in the decorator syntax this *must* be passed in as a keyword argument. Examples -------- :: >>> class Foo: ... _bar_internal = 1 ... @classproperty ... def bar(cls): ... return cls._bar_internal + 1 ... >>> Foo.bar 2 >>> foo_instance = Foo() >>> foo_instance.bar 2 >>> foo_instance._bar_internal = 2 >>> foo_instance.bar # Ignores instance attributes 2 As previously noted, a `classproperty` is limited to implementing read-only attributes:: >>> class Foo: ... _bar_internal = 1 ... @classproperty ... def bar(cls): ... return cls._bar_internal ... @bar.setter ... def bar(cls, value): ... cls._bar_internal = value ... Traceback (most recent call last): ... NotImplementedError: classproperty can only be read-only; use a metaclass to implement modifiable class-level properties When the ``lazy`` option is used, the getter is only called once:: >>> class Foo: ... @classproperty(lazy=True) ... def bar(cls): ... print("Performing complicated calculation") ... return 1 ... >>> Foo.bar Performing complicated calculation 1 >>> Foo.bar 1 If a subclass inherits a lazy `classproperty` the property is still re-evaluated for the subclass:: >>> class FooSub(Foo): ... pass ... >>> FooSub.bar Performing complicated calculation 1 >>> FooSub.bar 1 """ def __new__(cls, fget=None, doc=None, lazy=False): if fget is None: # Being used as a decorator--return a wrapper that implements # decorator syntax def wrapper(func): return cls(func, lazy=lazy) return wrapper return super().__new__(cls) def __init__(self, fget, doc=None, lazy=False): self._lazy = lazy if lazy: self._cache = {} fget = self._wrap_fget(fget) super().__init__(fget=fget, doc=doc) # There is a buglet in Python where self.__doc__ doesn't # get set properly on instances of property subclasses if # the doc argument was used rather than taking the docstring # from fget # Related Python issue: https://bugs.python.org/issue24766 if doc is not None: self.__doc__ = doc def __get__(self, obj, objtype): if self._lazy and objtype in self._cache: return self._cache[objtype] # The base property.__get__ will just return self here; # instead we pass objtype through to the original wrapped # function (which takes the class as its sole argument) val = self.fget.__wrapped__(objtype) if self._lazy: self._cache[objtype] = val return val def getter(self, fget): return super().getter(self._wrap_fget(fget)) def setter(self, fset): raise NotImplementedError( "classproperty can only be read-only; use a metaclass to " "implement modifiable class-level properties") def deleter(self, fdel): raise NotImplementedError( "classproperty can only be read-only; use a metaclass to " "implement modifiable class-level properties") @staticmethod def _wrap_fget(orig_fget): if isinstance(orig_fget, classmethod): orig_fget = orig_fget.__func__ # Using stock functools.wraps instead of the fancier version # found later in this module, which is overkill for this purpose @functools.wraps(orig_fget) def fget(obj): return orig_fget(obj.__class__) return fget def find_data_files(package, pattern): """ Include files matching ``pattern`` inside ``package``. Parameters ---------- package : str The package inside which to look for data files pattern : str Pattern (glob-style) to match for the data files (e.g. ``*.dat``). This supports the``**``recursive syntax. For example, ``**/*.fits`` matches all files ending with ``.fits`` recursively. Only one instance of ``**`` can be included in the pattern. """ return glob.glob(os.path.join(package, pattern), recursive=True) APLpy-2.0.3/astropy_helpers/astropy_helpers/version.py0000644000077000000240000000113413432245133023123 0ustar tomstaff00000000000000# Autogenerated by Astropy-affiliated package astropy_helpers's setup.py on 2019-02-17 11:49:47 UTC from __future__ import unicode_literals import datetime version = "3.1" githash = "9f82aac6c2141b425e2d639560f7260189d90b54" major = 3 minor = 1 bugfix = 0 version_info = (major, minor, bugfix) release = True timestamp = datetime.datetime(2019, 2, 17, 11, 49, 47) debug = False astropy_helpers_version = "" try: from ._compiler import compiler except ImportError: compiler = "unknown" try: from .cython_version import cython_version except ImportError: cython_version = "unknown" APLpy-2.0.3/astropy_helpers/astropy_helpers/version_helpers.py0000644000077000000240000002300013404171254024642 0ustar tomstaff00000000000000# Licensed under a 3-clause BSD style license - see LICENSE.rst """ Utilities for generating the version string for Astropy (or an affiliated package) and the version.py module, which contains version info for the package. Within the generated astropy.version module, the `major`, `minor`, and `bugfix` variables hold the respective parts of the version number (bugfix is '0' if absent). The `release` variable is True if this is a release, and False if this is a development version of astropy. For the actual version string, use:: from astropy.version import version or:: from astropy import __version__ """ from __future__ import division import datetime import imp import os import pkgutil import sys import time from distutils import log from importlib import invalidate_caches import pkg_resources from . import git_helpers from .distutils_helpers import is_distutils_display_option def _version_split(version): """ Split a version string into major, minor, and bugfix numbers. If any of those numbers are missing the default is zero. Any pre/post release modifiers are ignored. Examples ======== >>> _version_split('1.2.3') (1, 2, 3) >>> _version_split('1.2') (1, 2, 0) >>> _version_split('1.2rc1') (1, 2, 0) >>> _version_split('1') (1, 0, 0) >>> _version_split('') (0, 0, 0) """ parsed_version = pkg_resources.parse_version(version) if hasattr(parsed_version, 'base_version'): # New version parsing for setuptools >= 8.0 if parsed_version.base_version: parts = [int(part) for part in parsed_version.base_version.split('.')] else: parts = [] else: parts = [] for part in parsed_version: if part.startswith('*'): # Ignore any .dev, a, b, rc, etc. break parts.append(int(part)) if len(parts) < 3: parts += [0] * (3 - len(parts)) # In principle a version could have more parts (like 1.2.3.4) but we only # support .. return tuple(parts[:3]) # This is used by setup.py to create a new version.py - see that file for # details. Note that the imports have to be absolute, since this is also used # by affiliated packages. _FROZEN_VERSION_PY_TEMPLATE = """ # Autogenerated by {packagetitle}'s setup.py on {timestamp!s} UTC from __future__ import unicode_literals import datetime {header} major = {major} minor = {minor} bugfix = {bugfix} version_info = (major, minor, bugfix) release = {rel} timestamp = {timestamp!r} debug = {debug} astropy_helpers_version = "{ahver}" try: from ._compiler import compiler except ImportError: compiler = "unknown" try: from .cython_version import cython_version except ImportError: cython_version = "unknown" """[1:] _FROZEN_VERSION_PY_WITH_GIT_HEADER = """ {git_helpers} _packagename = "{packagename}" _last_generated_version = "{verstr}" _last_githash = "{githash}" # Determine where the source code for this module # lives. If __file__ is not a filesystem path then # it is assumed not to live in a git repo at all. if _get_repo_path(__file__, levels=len(_packagename.split('.'))): version = update_git_devstr(_last_generated_version, path=__file__) githash = get_git_devstr(sha=True, show_warning=False, path=__file__) or _last_githash else: # The file does not appear to live in a git repo so don't bother # invoking git version = _last_generated_version githash = _last_githash """[1:] _FROZEN_VERSION_PY_STATIC_HEADER = """ version = "{verstr}" githash = "{githash}" """[1:] def _get_version_py_str(packagename, version, githash, release, debug, uses_git=True): try: from astropy_helpers import __version__ as ahver except ImportError: ahver = "unknown" epoch = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) timestamp = datetime.datetime.utcfromtimestamp(epoch) major, minor, bugfix = _version_split(version) if packagename.lower() == 'astropy': packagetitle = 'Astropy' else: packagetitle = 'Astropy-affiliated package ' + packagename header = '' if uses_git: header = _generate_git_header(packagename, version, githash) elif not githash: # _generate_git_header will already generate a new git has for us, but # for creating a new version.py for a release (even if uses_git=False) # we still need to get the githash to include in the version.py # See https://github.com/astropy/astropy-helpers/issues/141 githash = git_helpers.get_git_devstr(sha=True, show_warning=True) if not header: # If _generate_git_header fails it returns an empty string header = _FROZEN_VERSION_PY_STATIC_HEADER.format(verstr=version, githash=githash) return _FROZEN_VERSION_PY_TEMPLATE.format(packagetitle=packagetitle, timestamp=timestamp, header=header, major=major, minor=minor, bugfix=bugfix, ahver=ahver, rel=release, debug=debug) def _generate_git_header(packagename, version, githash): """ Generates a header to the version.py module that includes utilities for probing the git repository for updates (to the current git hash, etc.) These utilities should only be available in development versions, and not in release builds. If this fails for any reason an empty string is returned. """ loader = pkgutil.get_loader(git_helpers) source = loader.get_source(git_helpers.__name__) or '' source_lines = source.splitlines() if not source_lines: log.warn('Cannot get source code for astropy_helpers.git_helpers; ' 'git support disabled.') return '' idx = 0 for idx, line in enumerate(source_lines): if line.startswith('# BEGIN'): break git_helpers_py = '\n'.join(source_lines[idx + 1:]) verstr = version new_githash = git_helpers.get_git_devstr(sha=True, show_warning=False) if new_githash: githash = new_githash return _FROZEN_VERSION_PY_WITH_GIT_HEADER.format( git_helpers=git_helpers_py, packagename=packagename, verstr=verstr, githash=githash) def generate_version_py(packagename, version, release=None, debug=None, uses_git=True, srcdir='.'): """Regenerate the version.py module if necessary.""" try: version_module = get_pkg_version_module(packagename) try: last_generated_version = version_module._last_generated_version except AttributeError: last_generated_version = version_module.version try: last_githash = version_module._last_githash except AttributeError: last_githash = version_module.githash current_release = version_module.release current_debug = version_module.debug except ImportError: version_module = None last_generated_version = None last_githash = None current_release = None current_debug = None if release is None: # Keep whatever the current value is, if it exists release = bool(current_release) if debug is None: # Likewise, keep whatever the current value is, if it exists debug = bool(current_debug) package_srcdir = os.path.join(srcdir, *packagename.split('.')) version_py = os.path.join(package_srcdir, 'version.py') if (last_generated_version != version or current_release != release or current_debug != debug): if '-q' not in sys.argv and '--quiet' not in sys.argv: log.set_threshold(log.INFO) if is_distutils_display_option(): # Always silence unnecessary log messages when display options are # being used log.set_threshold(log.WARN) log.info('Freezing version number to {0}'.format(version_py)) with open(version_py, 'w') as f: # This overwrites the actual version.py f.write(_get_version_py_str(packagename, version, last_githash, release, debug, uses_git=uses_git)) invalidate_caches() if version_module: imp.reload(version_module) def get_pkg_version_module(packagename, fromlist=None): """Returns the package's .version module generated by `astropy_helpers.version_helpers.generate_version_py`. Raises an ImportError if the version module is not found. If ``fromlist`` is an iterable, return a tuple of the members of the version module corresponding to the member names given in ``fromlist``. Raises an `AttributeError` if any of these module members are not found. """ if not fromlist: # Due to a historical quirk of Python's import implementation, # __import__ will not return submodules of a package if 'fromlist' is # empty. # TODO: For Python 3.1 and up it may be preferable to use importlib # instead of the __import__ builtin return __import__(packagename + '.version', fromlist=['']) else: mod = __import__(packagename + '.version', fromlist=fromlist) return tuple(getattr(mod, member) for member in fromlist) APLpy-2.0.3/astropy_helpers/astropy_helpers.egg-info/0000755000077000000240000000000013432765724022574 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/astropy_helpers.egg-info/PKG-INFO0000644000077000000240000004305113432245133023657 0ustar tomstaff00000000000000Metadata-Version: 1.2 Name: astropy-helpers Version: 3.1 Summary: Utilities for building and installing Astropy, Astropy affiliated packages, and their respective documentation. Home-page: https://github.com/astropy/astropy-helpers Author: The Astropy Developers Author-email: astropy.team@gmail.com License: BSD Description: astropy-helpers =============== .. image:: https://travis-ci.org/astropy/astropy-helpers.svg :target: https://travis-ci.org/astropy/astropy-helpers .. image:: https://ci.appveyor.com/api/projects/status/rt9161t9mhx02xp7/branch/master?svg=true :target: https://ci.appveyor.com/project/Astropy/astropy-helpers .. image:: https://codecov.io/gh/astropy/astropy-helpers/branch/master/graph/badge.svg :target: https://codecov.io/gh/astropy/astropy-helpers **Warning:** Please note that version ``v3.0`` and later of ``astropy-helpers`` requires Python 3.5 or later. If you wish to maintain Python 2 support for your package that uses ``astropy-helpers``, then do not upgrade the helpers to ``v3.0+``. We will still provide Python 2.7 compatible releases on the ``v2.0.x`` branch during the lifetime of the ``astropy`` core package LTS of ``v2.0.x``. About ----- This project provides a Python package, ``astropy_helpers``, which includes many build, installation, and documentation-related tools used by the Astropy project, but packaged separately for use by other projects that wish to leverage this work. The motivation behind this package and details of its implementation are in the accepted `Astropy Proposal for Enhancement (APE) 4 `_. ``astropy_helpers`` includes a special "bootstrap" module called ``ah_bootstrap.py`` which is intended to be used by a project's setup.py in order to ensure that the ``astropy_helpers`` package is available for build/installation. As described in `APE4 `_, the version numbers for ``astropy_helpers`` follow the corresponding major/minor version of the `astropy core package `_, but with an independent sequence of micro (bugfix) version numbers. Hence, the initial release is 0.4, in parallel with Astropy v0.4, which will be the first version of Astropy to use ``astropy-helpers``. For examples of how to implement ``astropy-helpers`` in a project, see the ``setup.py`` and ``setup.cfg`` files of the `Affiliated package template `_. What does astropy-helpers provide? ---------------------------------- Astropy-helpers' big-picture purpose is to provide customization to Python's packaging infrastructure process in ways that the Astropy Project has found to help simplifying the developint and releasing packages. This is primarily build around ``setup.py`` commands, as outlined below, as well as code to help manage version numbers and better control the build process of larger packages. Custom setup.py commands ^^^^^^^^^^^^^^^^^^^^^^^^ The main part of astropy-helpers is to provide customized setuptools commands. For example, in a package that uses astropy-helpers, the following command will be available:: python setup.py build_docs and this command is implemented in astropy-helpers. To use the custom commands described here, add:: from astropy_helpers.setup_helpers import register_commands to your ``setup.py`` file, then do:: cmdclassd = register_commands(NAME, VERSION, RELEASE) where ``NAME`` is the name of your package, ``VERSION`` is the full version string, and ``RELEASE`` is a boolean value indicating whether the version is a stable released version (``True``) or a developer version (``False``). Finally, pass ``cmdclassd`` to the ``setup`` function:: setup(..., cmdclass=cmdclassd) The commands we provide or customize are: **python setup.py test** This command will automatically build the package, install it to a temporary directory, and run the tests using `pytest `_ on this installed version. Note that the bulk of this command is actually defined in ``astropy.tests.command.AstropyTest``, because that allows the test machinery to operate outside a setuptools command. This, here we simply define the custom setuptools command. **python setup.py sdist** We redefine ``sdist`` to use the version from distutils rather than from setuptools, as the setuptools version requires duplication of information in ``MANIFEST.in``. **python setup.py build_docs** This command will automatically build the package, then run sphinx to build the documentation. This makes development much easier because it ensures sphinx extensions that use the package's code to make documentation are actually using the in-development version of the code. Sphinx itself provides a custom setuptools command, which we expand with the following options: * ``-w``: set the return code to 1 if there are any warnings during the build process. * ``-l``: completely clean previous builds, including files generated by the sphinx-automodapi package (which creates API pages for different functions/classes). * ``-n``: disable the intersphinx option. * ``-o``: open the documentation in a browser if a build finishes successfully. In addition, ``build_docs`` will automatically download and temporarily install sphinx-astropy (which is a meta-package that provides standardized configuration and documentation dependencies for astropy packages) if it isn't already installed. Temporary installation means that the package will be installed into an ``.eggs`` directory in the current working directory, and it will only be available for the duration of the call to ``build_docs``. **python setup.py build_ext** This is also used when running ``build`` or ``install``. We add several features compared to the default ``build_ext`` command: * For packages with C/Cython extensions, we create a ``packagename._compiler`` submodule that contains information about the compilers used. * Packages that need to build C extensions using the Numpy C API, we allow those packages to define the include path as ``'numpy'`` as opposed to having to import Numpy and call ``get_include``. The goal is to solve the issue that if one has to import Numpy to define extensions, then Numpy has to be installed/available before the package is installed, which means that one needs to install Numpy in a separate installation step. * We detect broken compilers and replace them with other compilers on-the-fly unless the compiler is explicitly specified with the ``CC`` environment variable. * If Cython is not installed, then we automatically check for generated C files (which are normally present in the stable releases) and give a nice error if these are not found. Version helpers ^^^^^^^^^^^^^^^^ Another piece of functionality we provide in astropy-helpers is the ability to generate a ``packagename.version`` file that includes functions that automatically set the version string for developer versions, to e.g. ``3.2.dev22213`` so that each developer version has a unique number (although note that branches an equal number of commits away from the master branch will share the same version number). To use this, import:: from astropy_helpers.git_helpers import get_git_devstr in your ``setup.py`` file, and you will then be able to use:: VERSION += get_git_devstr() where ``VERSION`` is a version string without any developer version suffix. We then also provide a function that generates a ``version.py`` file inside your package (which can then be imported as ``packagename.version``) that contains variables such as ``major``, ``minor``, and ``bugfix``, as well as ``version_info`` (a tuple of the previous three values), a ``release`` flag that indicates whether we are using a stable release, and several other complementary variables. To use this, import:: from astropy_helpers.version_helpers import generate_version_py in your ``setup.py`` file, and call:: generate_version_py(NAME, VERSION, RELEASE, uses_git=not RELEASE) where ``NAME`` is the name of your package, ``VERSION`` is the full version string (including any developer suffix), ``RELEASE`` indicates whether the version is a stable or developer version, and ``uses_git`` indicates whether we are in a git repository (using ``not RELEASE`` is sensible since git is not available in a stable release). Collecting package information ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``setup`` function from setuptools can take a number of options that indicate for example what extensions to build, and what package data to include. However, for large packages this can become cumbersome. We therefore provide a mechanism for defining extensions and package data inside individual sub-packages. To do this, you can create ``setup_package.py`` files anywhere in your package, and these files can include one or more of the following functions: * ``get_package_data``: This function, if defined, should return a dictionary mapping the name of the subpackage(s) that need package data to a list of data file paths (possibly including wildcards) relative to the path of the package's source code. e.g. if the source distribution has a needed data file ``astropy/wcs/tests/data/3d_cd.hdr``, this function should return ``{'astropy.wcs.tests':['data/3d_cd.hdr']}``. See the ``package_data`` option of the :func:`distutils.core.setup` function. It is recommended that all such data be in a directory named ``data`` inside the package within which it is supposed to be used. This package data should be accessed via the ``astropy.utils.data.get_pkg_data_filename`` and ``astropy.utils.data.get_pkg_data_fileobj`` functions. * ``get_extensions``: This provides information for building C or Cython extensions. If defined, it should return a list of ``distutils.core.Extension`` objects. * ``get_build_options``: This function allows a package to add extra build options. It should return a list of tuples, where each element has: - *name*: The name of the option as it would appear on the commandline or in the ``setup.cfg`` file. - *doc*: A short doc string for the option, displayed by ``setup.py build --help``. - *is_bool* (optional): When `True`, the option is a boolean option and doesn't have an associated value. Once an option has been added, its value can be looked up using ``astropy_helpers.setup_helpers.get_distutils_build_option``. * ``get_external_libraries``: This function declares that the package uses libraries that are included in the astropy distribution that may also be distributed elsewhere on the users system. It should return a list of library names. For each library, a new build option is created, ``'--use-system-X'`` which allows the user to request to use the system's copy of the library. The package would typically call ``astropy_helpers.setup_helpers.use_system_library`` from its ``get_extensions`` function to determine if the package should use the system library or the included one. * ``get_entry_points()``: This function can returns a dict formatted as required by the ``entry_points`` argument to ``setup()``. With these files in place, you can then add the following to your ``setup.py`` file:: from astropy_helpers.setup_helpers import get_package_info ... package_info = get_package_info() ... setup(..., **package_info) OpenMP helpers ^^^^^^^^^^^^^^ We provide a helper function ``add_openmp_flags_if_available`` that can be used to automatically add OpenMP flags for C/Cython extensions, based on whether OpenMP is available and produces executable code. To use this, edit the ``setup_package.py`` file where you define a C extension, import the helper function:: from astropy_helpers.openmp_helpers import add_openmp_flags_if_available then once you have defined the extension and before returning it, use it as:: extension = Extension(...) add_openmp_flags_if_available(extension) return [extension] Using astropy-helpers --------------------- The easiest way to get set up with astropy-helpers in a new package is to use the `package-template `_ that we provide. This template is specifically designed for use with the helpers, so using it avoids some of the tedium of setting up the heleprs. However, we now go through the steps of adding astropy-helpers as a submodule to a package in case you wish to do so manually. First, add astropy-helpers as a submodule at the root of your repository:: git submodule add git://github.com/astropy/astropy-helpers astropy_helpers Then go inside the submodule and check out a stable version of astropy-helpers. You can see the available versions by running:: $ cd astropy_helpers $ git tag ... v2.0.6 v2.0.7 ... v3.0.1 v3.0.2 If you want to support Python 2, pick the latest v2.0.x version (in the above case ``v2.0.7``) and if you don't need to support Python 2, just pick the latest stable version (in the above case ``v3.0.2``). Check out this version with e.g.:: $ git checkout v3.0.2 Then go back up to the root of your repository and copy the ``ah_bootstrap.py`` file from the submodule to the root of your repository:: $ cd .. $ cp astropy_helpers/ah_bootstrap.py . Finally, add:: import ah_bootstrap at the top of your ``setup.py`` file. This will ensure that ``astropy_helpers`` is now available to use in your ``setup.py`` file. Finally, add then commit your changes:: git add astropy_helpers ah_bootstrap.py setup.py git commit -m "Added astropy-helpers" Updating astropy-helpers ------------------------ If you would like the Astropy team to automatically open pull requests to update astropy-helpers in your package, then see the instructions `here `_. To instead update astropy-helpers manually, go inside the submodule and do:: cd astropy_helpers git fetch origin Then checkout the version you want to use, e.g.:: git checkout v3.0.3 Go back up to the root of the repository and update the ``ah_bootstap.py`` file too, then add your changes:: cp astropy_helpers/ah_bootstrap.py . git add astropy_helpers ah_bootstrap.py git commit ... Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Framework :: Setuptools Plugin Classifier: Framework :: Sphinx :: Extension Classifier: Framework :: Sphinx :: Theme Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Build Tools Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Archiving :: Packaging Requires-Python: >=3.5 APLpy-2.0.3/astropy_helpers/astropy_helpers.egg-info/SOURCES.txt0000644000077000000240000000162713432245133024451 0ustar tomstaff00000000000000CHANGES.rst LICENSE.rst MANIFEST.in README.rst ah_bootstrap.py setup.cfg setup.py astropy_helpers/__init__.py astropy_helpers/conftest.py astropy_helpers/distutils_helpers.py astropy_helpers/git_helpers.py astropy_helpers/openmp_helpers.py astropy_helpers/setup_helpers.py astropy_helpers/utils.py astropy_helpers/version.py astropy_helpers/version_helpers.py astropy_helpers.egg-info/PKG-INFO astropy_helpers.egg-info/SOURCES.txt astropy_helpers.egg-info/dependency_links.txt astropy_helpers.egg-info/not-zip-safe astropy_helpers.egg-info/top_level.txt astropy_helpers/commands/__init__.py astropy_helpers/commands/_dummy.py astropy_helpers/commands/build_ext.py astropy_helpers/commands/build_sphinx.py astropy_helpers/commands/setup_package.py astropy_helpers/commands/test.py astropy_helpers/commands/src/compiler.c astropy_helpers/sphinx/__init__.py astropy_helpers/sphinx/conf.py licenses/LICENSE_ASTROSCRAPPY.rstAPLpy-2.0.3/astropy_helpers/astropy_helpers.egg-info/dependency_links.txt0000644000077000000240000000000113432245133026625 0ustar tomstaff00000000000000 APLpy-2.0.3/astropy_helpers/astropy_helpers.egg-info/not-zip-safe0000644000077000000240000000000113432245133025005 0ustar tomstaff00000000000000 APLpy-2.0.3/astropy_helpers/astropy_helpers.egg-info/top_level.txt0000644000077000000240000000002013432245133025301 0ustar tomstaff00000000000000astropy_helpers APLpy-2.0.3/astropy_helpers/licenses/0000755000077000000240000000000013432765724017464 5ustar tomstaff00000000000000APLpy-2.0.3/astropy_helpers/licenses/LICENSE_ASTROSCRAPPY.rst0000644000077000000240000000315413404171254023301 0ustar tomstaff00000000000000# The OpenMP helpers include code heavily adapted from astroscrappy, released # under the following license: # # Copyright (c) 2015, Curtis McCully # 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 the Astropy Team 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. APLpy-2.0.3/astropy_helpers/setup.cfg0000644000077000000240000000015313103641505017460 0ustar tomstaff00000000000000[tool:pytest] norecursedirs = .tox astropy_helpers/tests/package_template python_functions = test_ APLpy-2.0.3/astropy_helpers/setup.py0000755000077000000240000000367313404171254017371 0ustar tomstaff00000000000000#!/usr/bin/env python # Licensed under a 3-clause BSD style license - see LICENSE.rst import ah_bootstrap import pkg_resources from setuptools import setup from astropy_helpers.setup_helpers import (register_commands, get_package_info, add_exclude_packages) from astropy_helpers.version_helpers import generate_version_py NAME = 'astropy_helpers' VERSION = '3.1' RELEASE = 'dev' not in VERSION generate_version_py(NAME, VERSION, RELEASE, False, uses_git=not RELEASE) # Use the updated version including the git rev count from astropy_helpers.version import version as VERSION add_exclude_packages(['astropy_helpers.tests']) cmdclass = register_commands(NAME, VERSION, RELEASE) # This package actually doesn't use the Astropy test command del cmdclass['test'] setup( name=pkg_resources.safe_name(NAME), # astropy_helpers -> astropy-helpers version=VERSION, description='Utilities for building and installing Astropy, Astropy ' 'affiliated packages, and their respective documentation.', author='The Astropy Developers', author_email='astropy.team@gmail.com', license='BSD', url=' https://github.com/astropy/astropy-helpers', long_description=open('README.rst').read(), classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Framework :: Setuptools Plugin', 'Framework :: Sphinx :: Extension', 'Framework :: Sphinx :: Theme', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Build Tools', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: System :: Archiving :: Packaging' ], cmdclass=cmdclass, python_requires='>=3.5', zip_safe=False, **get_package_info() ) APLpy-2.0.3/conftest.py0000644000077000000240000000005013432763221014614 0ustar tomstaff00000000000000import matplotlib matplotlib.use('Agg') APLpy-2.0.3/docs/0000755000077000000240000000000013432765724013364 5ustar tomstaff00000000000000APLpy-2.0.3/docs/Makefile0000644000077000000240000001116412536551502015016 0ustar tomstaff00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest #This is needed with git because git doesn't create a dir if it's empty $(shell [ -d "_static" ] || mkdir -p _static) help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR) -rm -rf api html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Astropy.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Astropy.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Astropy" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Astropy" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." APLpy-2.0.3/docs/_templates/0000755000077000000240000000000013432765723015520 5ustar tomstaff00000000000000APLpy-2.0.3/docs/_templates/autosummary/0000755000077000000240000000000013432765724020107 5ustar tomstaff00000000000000APLpy-2.0.3/docs/_templates/autosummary/base.rst0000644000077000000240000000037212536551502021544 0ustar tomstaff00000000000000{% extends "autosummary_core/base.rst" %} {# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #}APLpy-2.0.3/docs/_templates/autosummary/class.rst0000644000077000000240000000037312536551502021740 0ustar tomstaff00000000000000{% extends "autosummary_core/class.rst" %} {# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #}APLpy-2.0.3/docs/_templates/autosummary/module.rst0000644000077000000240000000037412536551502022121 0ustar tomstaff00000000000000{% extends "autosummary_core/module.rst" %} {# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #}APLpy-2.0.3/docs/aplpy_logo.png0000644000077000000240000001256212536551502016234 0ustar tomstaff00000000000000PNG  IHDRi1 HiCCPPhotoshop ICC profileHǝwTTϽwz0zm轃* C`T,(ED 0Ċ(*j@QDE%3V{>k]H>\^,@:OvGұ}xf0Yٙa^@$_Owz ^HmL+;7֔P!{I2`[9,8-W)ϊ2U0J|Q"sg6]NE,9s9"FD\5ӄ\ǦsHbJIPw;#%}+`'O >{F*>7)Y@elmtNnG 0 fR|6=#=[3tQl̍;(.C{^|DW~u0Dme5M <4$ v&&\X\xC$2in !dqFyr9|O)2./In+f\j >ϵHo nRs/@Q/} G͋R<pMNg 9H**@#`l=ppVHrA>(EA 8Ah'A;8.+AX Q yH҂ s9AP @ PăP> *ʡ} .Bנ~4MCB`&TXֆM` r8 ΂WÅv mE<9 D!FqGX$#bCN"3[EAQF({*Be֡JQ5c6T76j 5&h;/:E+GЭA5at06L &Sهi\c1sX,VkuaX[==N`8U9 6*qs$n/l*|߉/ :GB8!P@"4.^Du-1%n VOLjoI2$};)$$m'%] #$dr,Y@Nn _"?"HKJ%KJI HꬬlllYQBӦhe!ڻ%K\pl[Ҽd`ɼGXEnP<]S>U~|CBB~ 3TE{EbIJRJJs*ʙʗgTh*.*)**TU)N\ OtWzMUSRQRS[PQPߨޢPHԨҘT lҼbh%kњюޢݮ=#㫳ZI.YY7KNFO>o_6637D HFF9FMFc4M4MbMv|42M37113hi9˼bE KK~˻V@-V]Vm66 6{mTF0qmf[;k;I_St8LCNtNjL:..l#.z)]Z׺_@<==X= z}&$86IYh~hO%,>1u[xYHn0+R22.!r>#T/e^쫪'n+.ۿchcwjWWZe===UU՚;$ ֺնUڻm>.((9 Cއ*c~RY5# GJ|8;:z,XwMCCRcY$l>w7t45j''~I]no+ j[6۞>tW}g=vٲssϯ>?w!Ť]]#/+z\{_uzݵoXhm>뾶67;nw?7}/.FNXˣ,_u=zzacoo{E\}}_ACG ѹbKGD pHYs  tIME3^ IDATx]W眙͚4iMmjjk) BETAOB>('̃6Im@XC՘lVC_6;?o313ԗ|￟$kj#m;5o 箮3ь[zDRN*f2w^e`c>ČP)VEQiEQiEQFQTEQiEQEQFQTEQiEQEQ%1S+jNw~MuxǞBSV4)c;Hb'vFGFkvp4LMNWi~b>i4ƀ]g,pd}f/UE) )rnLkJp+vP)ǧ&'4Jx+v|x@\.(R|g35=V C3F*>6_(re#lX^Ri 'oNcg/jz&'PPk]H?-Ʀ%>w/t@-{;YI4wB>|,qU4>33/4ʲ ,>][ \ "rFBq6>om)ap ҷuALnn 0 YTBԑ 3 8XesG1 8)4 Apx.*pp>9^Q{gXg]QZţ+Ϸ ApXQVGzgW4ah 1JNk҉0d:|:?kuB0|ʀ9e _{i̿q23xy-BߌZ7+\]h`m,""q &ǶIDGɏoFiX\4/H<ɑY+"3gL:dNlK$ɰ 3S0՟txB$M)CC6첈v콞;@/EȶqWz(; bPi^8 ܒ!ဥ٧(+,B[R>h!^ }ϔN-{_w}L%}-@_Y0-Wֲ@: n1huD_Qin9PO01OrkzcKn|VQ٪;TWk ApIb_!%jCG4jյSQV>Ĭ4zul( (J(*4X+Yk,VlCG@"4r3bk0:oKSj",QFFfgb$" 4$<ѣgzRety#,֪DQSDc+DlF?X/q|55Fgz#65cһӤi$\'8IHd'xOr#aKvJ+]u(J(*4(J(J(*4(J(J(*4(J(C%5%e:Í[ 1=[}Iveyg=9 8 LF%{#Uq#0;!\97⻱”I_ltW׈4e7-YQ򈿓?t/cIENDB`APLpy-2.0.3/docs/conf.py0000644000077000000240000001373313432763221014660 0ustar tomstaff00000000000000# -*- coding: utf-8 -*- # Licensed under a 3-clause BSD style license - see LICENSE.rst # # Astropy documentation build configuration file. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this file. # # All configuration values have a default. Some values are defined in # the global Astropy configuration which is loaded here before anything else. # See astropy.sphinx.conf for which values are set there. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('..')) # IMPORTANT: the above commented section was generated by sphinx-quickstart, but # is *NOT* appropriate for astropy or Astropy affiliated packages. It is left # commented out with this explanation to make it clear why this should not be # done. If the sys.path entry above is added, when the astropy.sphinx.conf # import occurs, it will import the *source* version of astropy instead of the # version installed (if invoked as "make html" or directly with sphinx), or the # version in the build directory (if "python setup.py build_sphinx" is used). # Thus, any C-extensions that are needed to build the documentation will *not* # be accessible, and the documentation will not build correctly. import datetime import os import sys try: from sphinx_astropy.conf.v1 import * # noqa except ImportError: print('ERROR: the documentation requires the sphinx-astropy package to be installed') sys.exit(1) # Get configuration information from setup.cfg try: from ConfigParser import ConfigParser except ImportError: from configparser import ConfigParser conf = ConfigParser() conf.read([os.path.join(os.path.dirname(__file__), '..', 'setup.cfg')]) setup_cfg = dict(conf.items('metadata')) # -- General configuration ---------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.1' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns.append('_templates') # This is added to the end of RST files - a good place to put substitutions to # be used globally. rst_epilog += """ """ # -- Project information ------------------------------------------------------ # This does not *have* to match the package name, but typically does project = setup_cfg['package_name'] author = setup_cfg['author'] copyright = '{0}, {1}'.format( datetime.datetime.now().year, setup_cfg['author']) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. __import__(setup_cfg['package_name']) package = sys.modules[setup_cfg['package_name']] # The short X.Y version. version = package.__version__.split('-', 1)[0] # The full version, including alpha/beta/rc tags. release = package.__version__ # -- Options for HTML output --------------------------------------------------- # A NOTE ON HTML THEMES # The global astropy configuration uses a custom theme, 'bootstrap-astropy', # which is installed along with astropy. A different theme can be used or # the options for this theme can be modified by overriding some of the # variables set in the global configuration. The variables set in the # global configuration are listed below, commented out. # Add any paths that contain custom themes here, relative to this directory. # To use a different custom theme, add the directory containing the theme. #html_theme_path = [] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. To override the custom theme, set this to the # name of a builtin theme or the name of a custom theme in html_theme_path. html_theme = 'alabaster' # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = '' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = '{0} v{1}'.format(project, release) # Output file base name for HTML help builder. htmlhelp_basename = project + 'doc' html_logo = 'aplpy_logo.png' # -- Options for LaTeX output -------------------------------------------------- # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [('index', project + '.tex', project + u' Documentation', author, 'manual')] # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [('index', project.lower(), project + u' Documentation', [author], 1)] ## -- Options for the edit_on_github extension ---------------------------------------- if eval(setup_cfg.get('edit_on_github')): extensions += ['astropy.sphinx.ext.edit_on_github'] versionmod = __import__(setup_cfg['package_name'] + '.version') edit_on_github_project = setup_cfg['github_project'] if versionmod.version.release: edit_on_github_branch = "v" + versionmod.version.version else: edit_on_github_branch = "master" edit_on_github_source_root = "" edit_on_github_doc_root = "docs" # Use nitpicky mode to avoid broken links in docs nitpicky = True nitpick_ignore = [('py:class', 'aplpy.layers.Layers'), ('py:class', 'aplpy.regions.Regions')] APLpy-2.0.3/docs/fitsfigure/0000755000077000000240000000000013432765724015533 5ustar tomstaff00000000000000APLpy-2.0.3/docs/fitsfigure/arbitrary_coordinate_systems.rst0000644000077000000240000000527113432763221024255 0ustar tomstaff00000000000000.. _arbitrary: Arbitrary coordinate systems ============================ Coordinate type --------------- In addition to standard longitude/latitude coordinates, APLpy supports any valid quantities for coordinates (e.g. velocity, frequency, ...) as long as the WCS header information is valid. To differentiate between longitudes, latitudes, and arbitrary scalar values, APLpy keeps track of the axis coordinate 'type' for each axis, and will try and guess these based on the header. However, it is possible to explicitly specify the coordinate type with the :meth:`~aplpy.FITSFigure.set_xaxis_coord_type` and :meth:`~aplpy.FITSFigure.set_yaxis_coord_type` methods in the :class:`~aplpy.FITSFigure` object:: f = FITSFigure('2MASS_k.fits') f.set_xaxis_coord_type('scalar') f.set_xaxis_coord_type('latitude') Valid coordinate types are ``longitude``, ``latitude``, and ``scalar``. Longitudes are forced to be in the 0 to 360 degree range, latitudes are forced to be in the -90 to 90 degree range, and scalars are not constrained. Label formatting ---------------- How label formats are specified depends on the coordinate type. If the coordinate is a longitude or latitude, then the label format is specified using a special syntax which describes whether the label should be decimal or sexagesimal, in hours or degrees, and indicates the number of decimal places. For example: * ``ddd.ddddd`` means decimal degrees, where the number of decimal places can be varied * ``hh`` or ``dd`` means hours (or degrees) * ``hh:mm`` or ``dd:mm`` means hours and minutes (or degrees and arcminutes) * ``hh:mm:ss`` or ``dd:mm:ss`` means hours, minutes, and seconds (or degrees, arcminutes, and arcseconds) * ``hh:mm:ss.ss`` or ``dd:mm:ss.ss`` means hours, minutes, and seconds (or degrees, arcminutes, and arcseconds), where the number of decimal places can be varied. If the coordinate type is scalar, then the format should be specified as a valid Python format. For example, ``%g`` is the default Python format, ``%10.3f`` means decimal notation with three decimal places, etc. For more information, see `String Formatting Operations `_. In both cases, the default label format can be overridden:: f.tick_labels.set_xformat('dd.ddddd') f.tick_labels.set_yformat('%11.3f') Aspect ratio ------------ When plotting images in sky coordinates, APLpy makes pixel square by default, but it is possible to change this, which can be useful for non-sky coordinates. When calling :meth:`~aplpy.FITSFigure.show_grayscale` or :meth:`~aplpy.FITSFigure.show_colorscale`, simply add ``aspect='auto'`` which will override the ``aspect='equal'`` default. APLpy-2.0.3/docs/fitsfigure/buttons.png0000644000077000000240000002220613432763221017727 0ustar tomstaff00000000000000PNG  IHDRX iCCPICC ProfilexWgP>.i9A$$ iɒ\E $#(QEP$J wǭvթLOwyv , s$b/i!~ք[ ~yIB;%$V!nJ| 85 /&_  c +0YYƔ^q+Ń"N p xm¹0N \ K ﰹK#/0&?>!]w`??? b)'K 6<~GQ:P  GC뿿209E@ !BfDz(Wt<YFʖm(1C8*K> ;=W8w.O+ ^WP_W8M]8$NR,8^E\e>U=2}IS 36>0a7U1;kiQ`n5koa{6оa鄳Kk۶;gW(TiPᅍ:![4"pïD޸x-z|tdLXw x7KBRXSn5^KI x0fSmMw\ JKOї,hLww^}ځzF#L[e=ƶ=A>yݖ~)gWԺAwwO\q]߻ʁ j/_{YڐћX>O\Ԙ"zSoZyxfj]<煶%,wdXY=X{)3WǾooNo᷵w$U縯qk 1|LԈ@f1!?"im4((KcU40)nw뼥|}+h!aa}@LVeIJ)Eiw[r[ JOPW?as_ި!ڈC[S_KVm>!8:^?Wwzk}>ů?tB/0!=_Ppe+WY讑^;3W|#1eB"SnDrMJ-T4LjzgF^&.,["~{(Nj^HCNXc1xdܿBrnr=?tO74g4>Ll6+`Z?j~|\mi3/; 5{{z .hy}Hcn9z~lpy`2f[i.ws I<>8,[I|7"6Swndury/w^l @ P=B#¢Ѣ$,dq 1J~*ZYz(oa1J3n250Hl6r@C9\R]逞tuYvT~\4D<|bybM\̏&_+~}M@+pVXHo@/(R25/H[?8 o!_(5Ba w$R鋬DyTQqQ4;F!>GH"q i$%!u%m#'@6L.JO1TQRQLQRP RPS'DF]1131V22u3[2` e%g-cSa` (rsg7=@PH(h8/ЕXLѕ-D|eE/%se5U jF.•i" N34a1u33?4*޵5+?{`XvvvyFsT ɰ+Ȓ(kK q$&]LHK8Țy[V`[$]BRX\y=ͽ[=yབྷC# 'Og΍/l.,}^3,޾᰹vO_Fn{m*oN+A)how@; A=G)̿5" QA"ՐF Q0Q :FGKGC_𒄓Ɠ.irWn&EaGCDH%LUAG]JCSA+L[O@IoL?1 WVal)pXp|L c AP!~qHQYx19%sd:ɩ?+)v((䪦LWTרl^E\:Ue|LɪgVMY^fC']d 7{'z4?@ʠ[80|WjFM\}x:~7$4V]KkXvm;"ҕ*Pk, |Z,?s~o@WaISUomg0O\PuK$r=leq=ە?w?8: |w,B$,%AO ? QGF!ԉP-_&v&^ q!Y"" 'Gb1 :KTzTԭ4r?_ea`ff`1f`ųco(6Q@ ~,(2/VlR|LbTr\jBzEHN) I J#۪'Ψhiiuk3l5f,r$tʜ2 ]~GsN]\Jڞc8_O=fpYf .; JcVS.ڥKgFrsm )KYoV޼Y|l-CBC&EkjSgϳl{{g=^ 1>44;m l|"+ט?i~vrkz7ƹM-ߋmw(w3ӯ]݂=-~73<;p<<8T< =::B8r?<99=6=8<~}|[#I%~2@@^Z!m疕V:ds pHYs  IDATx[ |Tչ?w=%3d!E"žV|b]?'T6[SWk=VdE L&eę$AOmn&s9wwsؽ{7z[,ߪ UvkHQVty<Ќk yy禹2(H2 0 Y"$yR`NyK孇[nQX<s 'm˷i]\'t{^ӔʎD"19VF\!(*Koi*!HH9pÖjkm3 auv?U%=z:sO_yUV+Y^Ď;<ɧ_}̝/*`ߟCSx+#^EO_#Q4Rl^@|H,2Gt+xboO{C~r|S[4ٗN)\ ۺu1{IBژDjjjN^ٹN%IʀՄ54W lPCGSl Rimh E:@M@J2D"e6ёޑ'v7v?dW{ؠR':1[K& $ r^w;+I@ٽ{$6x@{o[BhSYiGyD _R6o|gVamOEfg:.Y.dQE]=6Lڸ*vfٌT4i $"G8qeT`t,gh >(E { ʼ' ݿdok;{ Vrg)(X Y."TdӦI# L!1eH P(wN]D)Z .&wF,G qUAтDŽf9?koђI=0 eus >uQ6Lɭ8qb I($@}u!JI7\ļK̘y2@Ҽum#Zzw{':<0"ʐ΀r5Yqӡee9 6DAo=^=[QVD3+AaڃZ-ZT\$dm쮏ͽeϟ~I}ݺu}u.xP+V޳w=ܬoy*Dan|" ?|  N Y8"aq3!oՂƄĐ. 5{zѾ-q-U| aPL6oA],Ʀ40YXVڕ'~ҊYjRZߒ2Ю]ݦ%;\PH/I::8^*H:IJ6$qLb%] b$u=$d˄.^+E,E |GDaWm'n;餄g/t49?v N.Pmx(ĒbD0 eŐ /˛L 9s,>%e6goo>4((.xC-AJp %(IY0H#Ac^J7p*'k3{ 8 CbCY5r53M#FmԽ ~BB\NSھ[" 3Dd3 4 _jE@cQ+@܍%a0:P2o[DQ·,aN"w`"8@@"l7a}^DPiisZow]K~u9rd4= 1ɛVDN:Ԭ&@a0CDR<+an:IP$mi5^Fk^6H& 38!orWl2|?Ki4`HEd8]ma-,Q<\ AX3t0KACxN' ^_0ecC3 \?2#ƅ3Zqrppu]ƭȬ,%/|vuVmtU0+ 9bi.(5Q}K z6R;:: hۿW]pX!}%2[4uɁHC #EX^57=8Ti(עni(Xqi)q?UvU^,0k% A$=ƒ9\mH"; qRZ0IR,HA0QA+xPi}pk,]WF|G7UWQ^q0ib% e&Zx?zAUnjcv5pT&2qoT&aR&]ѵX %I"~YxUN'`!9 T d*NDX5TlZE7 +x)M}&dgZD4[LL1*Uc~^j\E˟xիW'פ2lDqcOfϞ]QQ5,.M|:Vixm%X|J%u1c ej2u^TfZmSeiKAuqBa"<^/Ư?fDKR%ųꞔ`zꩡ9xw[Ч{ %lR"/&%G8b3 ς+f8=&X`:o`F[atO.O:>l0 6zY:vz1]Y 5UJ**IENDB`APLpy-2.0.3/docs/fitsfigure/howto_avm.rst0000644000077000000240000000272413432763221020263 0ustar tomstaff00000000000000.. _howto-avm: AVM tagging =========== The latest developer version of APLpy has support for reading/writing AVM tags from/to RGB images (via `PyAVM `_). To make a plot with an AVM-tagged RGB image, say 'example.jpg', you can use:: import aplpy f = aplpy.FITSFigure('example.jpg') f.show_rgb() Note that no filename is required for :meth:`~aplpy.FITSFigure.show_rgb` in this case. If PyAVM is installed, :func:`~aplpy.make_rgb_image` can embed AVM meta-data into RGB images it creates, although only JPEG and PNG files support this:: import aplpy aplpy.make_rgb_image('2mass_cube.fits', '2mass_rgb.jpg') If PyAVM 0.9.1 or later is installed, the above file ``2mass_rgb.jpg`` will include AVM meta-data and can then be plotted with:: import aplpy f = aplpy.FITSFigure('2mass_rgb.jpg') f.show_rgb() In other words, this means that when creating an RGB image with APLpy, it is no longer necessary to initialize :class:`~aplpy.FITSFigure` with a FITS file and then use :meth:`~aplpy.FITSFigure.show_rgb` with the RGB image filename - instead, :class:`~aplpy.FITSFigure` can be directly initialized with the AVM-tagged image. To disable the embedding of AVM tags, you can use the ``embed_avm_tags=False`` option for :func:`~aplpy.make_rgb_image`. These features require `PyAVM 0.9.1 `_ or later. Please report any issues you encounter `here `_. APLpy-2.0.3/docs/fitsfigure/howto_noninteractive.rst0000644000077000000240000000474413432763221022534 0ustar tomstaff00000000000000APLpy in non-interactive mode ----------------------------- While APLpy can be easily used to interactively make plots, it is also possible to make plots without opening up a display. This can be useful to run APLpy remotely, or to write non-interactive scripts to plot one or many FITS files. Running APLpy in non-interactive mode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To run APLpy in non-interactive mode, you will need to change the 'backend' used by matplotlib from an interactive (e.g. WxAgg, TkAgg, MacOS X) to a non-interactive (e.g. Agg, Cairo, PS, PDF) backend. The default backend is typically set in your ``.matplotlibrc`` file (or if you do not have such a file, an interactive backend is usually chosen by default). The easiest way to change the backend temporarily is to use the ``matplotlib.use()`` function:: import matplotlib matplotlib.use('Agg') It is important to change the backend via ``matplotlib.use`` before the ``aplpy`` module is imported. Once the backend has been changed, any call to ``FITSFigure()`` will no longer make a figure window appear. The following script can be used to make a PNG plot:: import matplotlib matplotlib.use('Agg') import aplpy f = aplpy.FITSFigure('mips_24micron.fits') f.show_grayscale() f.save('mips_24.png') Pan/Zoom in non-interactive mode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ One of the advantages of using APLpy in interactive mode is the ability to zoom in on a given region of interest. To replicate this functionality in non-interactive mode, the ``FITSFigure.recenter()`` method can be used. This method takes a central position, and either a radius (to make a square plot) or a width/height (to make a rectangular plot). This is illustrated in the following example:: import matplotlib matplotlib.use('Agg') import aplpy f = aplpy.FITSFigure('mips_24micron.fits') f.show_grayscale() f.recenter(266.2142,-29.1832,width=0.5,height=0.3) f.save('mips_24_zoomin.png') Batch scripting ^^^^^^^^^^^^^^^ Using APLpy non-interactively can be useful for making plots of many FITS files. Given a directory ``fits/`` containing FITS files, the following code will generate on plot for each ``.fits`` file:: import matplotlib matplotlib.use('Agg') import aplpy import glob import os for fits_file in glob.glob(os.path.join('fits/','*.fits')): f = aplpy.FITSFigure(fits_file) f.show_grayscale() f.save(fits_file.replace('.fits','.png')) f.close() APLpy-2.0.3/docs/fitsfigure/howto_subplot.rst0000644000077000000240000000543413432763221021171 0ustar tomstaff00000000000000Creating subplots ----------------- By default, :class:`~aplpy.FITSFigure` creates a figure with a single subplot that occupies the entire figure. However, APLpy can be used to place a subplot in an existing matplotlib figure instance. To do this, :class:`~aplpy.FITSFigure` should be called with the ``figure=`` argument as follows:: import aplpy import matplotlib.pyplot as mpl fig = mpl.figure() f = aplpy.FITSFigure('some_image.fits', figure=fig) The above will place a subplot inside the ``fig`` figure instance. The ``f`` object can be used as normal to control the FITS figure inside the subplot. The above however is not very interesting compared to just creating a FITSFigure instance from scratch. What this is useful for is only using sub-regions of the figure to display the FITS data, to leave place for other subplots, whether histograms, scatter, or other matplotlib plots, or another FITS Figure. This can be done using the ``subplot`` argument. From the docstring for FITSFigure:: *subplot*: [ list of four floats ] If specified, a subplot will be added at this position. The list should contain [xmin, ymin, dx, dy] where xmin and ymin are the position of the bottom left corner of the subplot, and dx and dy are the width and height of the subplot respectively. These should all be given in units of the figure width and height. For example, [0.1, 0.1, 0.8, 0.8] will almost fill the entire figure, leaving a 10 percent margin on all sides. The following code outline illustrates how to create a rectangular figure with two FITS images:: import aplpy import matplotlib.pyplot as mpl fig = mpl.figure(figsize=(15, 7)) f1 = aplpy.FITSFigure('image_1.fits', figure=fig, subplot=[0.1,0.1,0.35,0.8]) f1.set_tick_labels_font(size='x-small') f1.set_axis_labels_font(size='small') f1.show_grayscale() f2 = aplpy.FITSFigure('image_2.fits', figure=fig, subplot=[0.5,0.1,0.35,0.8]) f2.set_tick_labels_font(size='x-small') f2.set_axis_labels_font(size='small') f2.show_grayscale() f2.hide_yaxis_label() f2.hide_ytick_labels() fig.canvas.draw() The ``hide`` methods shown above are especially useful when working with subplots, as in some cases there is no need to repeat the tick labels. Alternatively figures can be constructed from both APLpy figures and normal matplotlib axes:: import aplpy import matplotlib.pyplot as mpl fig = mpl.figure(figsize=(15, 7)) f1 = aplpy.FITSFigure('image_1.fits', figure=fig, subplot=[0.1,0.1,0.35,0.8]) f1.set_tick_labels_font(size='x-small') f1.set_axis_labels_font(size='small') f1.show_grayscale() ax2 = fig.add_axes([0.5,0.1,0.35,0.8]) # some code here with ax2 fig.canvas.draw() APLpy-2.0.3/docs/fitsfigure/myfirstplot.png0000644000077000000240000451234513432763221020641 0ustar tomstaff00000000000000PNG  IHDRjiZfsBIT|d pHYsaa?i9tEXtSoftwarematplotlib version 3.0.2, http://matplotlib.org/8; IDATxiU˳[YJU%K,ƃAFn  &i0A730̀if0v ۲dkJZ3+w{{7/n1KUe~eCc>~eCe}GL_5yӬr_pW]u/_= p%;9~~g3\rCqYN<ÙĄ'cwKzl}^Rg_y?~a?oY%y{Oks~߽o׋wK~ߙm`_pdee%}}_vv/_9wܾE1_{ŗԮŋ~O/=ϵ~|}_{ܹ~oagϞ~ڦ&>1N8A[?# vs/s^[[{_Oޯ9vvq677_2i9?loo'?_Ν{eaaoܤgk}aL0L0L0{;''N`B"̴4EP8Xgx13Fa,RA)J1u:I,QH442ح J+@PJEZDDSBp|CΥk% =x Gd-Gܟ<$e1vp͂a0x{2Ј@F+6>l"8l*! X٭' bbf`6qU6Z| y+XΣ CSb0cMt-d5Zc.wxPR8+ljcfx_0p 1njC“hѸFk! DA(F@D+J/hCV{RRsMه(*U\H)>[.:Ӕ92kŐf"5`l*0%Ӊ!ъ Z!H' FDZ[hkrxg.V h'S8DQ;R,Υ'Be-x (quu= cFc$"0,^ ZkkHZ]co~ vF?~h hz:TQ{^=`X ihga0N #4>RF[Q8?%Z(~}hY ^q S<Ԁku:VƤV|ldB/l8&ke)Q`ua-m "ɧ)W:/cFC@kSK YjmP|h '{Z+\!n ײ G *|0MҲ<ܐa(\Nc9{n6 XcQ:Boc?<gܐ(Pʑw:lFk.B@xIk}6&eб0ע(,B`cwMb@48Y<إJieN;A }^MϮ1;:mKQ:BNqnu5\RMæ y kkǟZ8;8K}ƥcksLR(s./hwVlN<ϟe}2pp*z CGy!JiMkfl45g;%8w yi3WJ;O ys4Iڦ0F3DK<7o⡏}_71"ONp*4hc҂`nXa& 6MJ4S|❣ʤ(I29(<3c}y'FYJlX8z ;?~m|COQT ƇV0)=|(A"vEvlO$Z!*&heJgHAi":7ߑ3kFfJ[2d (\0FtbH C@֚AIm,<©ok.3NN:|ZU|>78n1 V V V5G(VеqZyϲѼ6f+  m)xeSR{sW{\ͧGyj$u§LuX7l4QU*ffkZ|8FB bSy*ċW']D+XB B+тF!x0M!@JwUi1 GCZiV(W; Rc80p[EXJx(/\/pZ k^q2ceEckNne 05=hAr ՚Jf TV߸;rT/fV( QU߸ \s"/qM`f&ob{sȵgxo/?s[o1pBtzn"O8%p/2M'̚Wy>U|N) ;+_uV0Fx!1QBU B Jf]/G7slk:Edi"[&JYտx-GG\Yۜ04vYw?cyOU+_uݾop~K+CeѨ<dy"o/Й1ZRֻ\=y3=7ΎՊٔVyf ^8ɥmW]+W4UCov 0}p0DTrt(.jvJ9;:&)ijhw2uiGGg|?yLDL~$$FNFu9}q> ̑rF 1A7V+8~Aj?|<[5A|a`D9&I(Gc4M7S v@)4;Baz~VM9i Z1kД(r~<|YAA 1DJoytҚ_!n:|a~~lLTx196m\j<r‰jD5 JA+U4 ZF hP*LH<(U|MepʊKbZxb(v "0al=[@kpۋlQq̊[Fqfx@l1G)x^wc-9SRrwxt(ÑT*J | 4%ׅ@ߢy>hDI T혀&aGZD9j! sD879*֥8gC>T~E@111)J'nJԯ&j:Q1Tl?h#FYnfOvKfubpnMDF*2 J(}ʺ6$6'f\\!%<*P ixh B>0G9.`bZE0INsoJ&AI ^p-έ{v0)S ɦXNpuE#6<$GxCjkjS ę;|GSmo8P a4dfg}` NՂV5׈T->mחY*YjP ic_~~GiRӻgFΟou 1nYMiZVS9()ӆ/=KTN4̷-Hlmfc|cg*UK↧wtZ4MR8|SzC>J(:t|Uej3ʠT[ʪbqZN=ɱ7~7ߢ0 ^0l2FNx˽K+v !ͨaTX(Q!daTJ)BÙ;d8XIy9| ZQY斦*A" B30xOXqmĂiec _ k2-( =1*ݳ ?cas`{bcb}K,D(!j4Ӹd(T/?Sr:j&n[$ll89e{Dy~Nmv O?SOQ >:dVS ƣ !vY?u SWϮ0;fj6SP K$x2k9p돳yA|]r;8^{gR9\ezp@c{`Ռw6Ib\΁@]{`f'-SS9"$MhjT^6rwKOpv)Iaw.QVlo9eǂ尜cJXڽ.ոƑ9qón pf(G#6,?ճi6a;)kl2=~!֐)pLS9|ƒ[!G9jZ$=xOޓysW-{_ӿF-턙.}lk'[<:Kf8|K]q?v/=I2Rdӝ'W0J0ڒm&fN6a}dXZ٤6 eP@BDMltHiyhN7e>K; u5kzlI A*T&̴5FIyAy$+z֤ybN_FG>dNAQK,B 9N8'gCV7 NB2-藞{/iK}@f ;6c]7GpIjY}TJqN k*pA×Zύw(O+s+(BC(ͧr%(!\jtREFl>&+ *D^L IDATUiðRn :`T`LX, P{c&l3lnx,(f  #O[[Qij DI 7h/uPeIk@amNgj )N B4R o͸ @w\hpA3T\ӕg'?h\QO Z%ͧh !lU(quXhKJM9eE1bgE +;vqo:#)7=!^q95NBb0Z2-bfW|PZ0<\S5B70&W8=os?NbT @*OUrCxRkxkˇl70f`\ʞ :f(MkfFYƎvnh[  W'r,KZ ],pռp*:buHdR0lx i+O++gn㜝bmxuM;WԍaP/DO*y㳡Pv2;RXvHbWz8j'eMSK+7HKv#nn\d8Ϲ\ĤUw#n G\á#T.G+!p:g>yw˟~c@UULO/s<Ń@C o82qkN;#>6I&^J|Edne,NnK[,^ڀ |ԦUl XeO[O MZ(a\)l"weSsEJ S|STF=`;6sz8836÷|A.5ǖ ιMD 8Wq2ib@P@8XbݞcJp>:(.%זK_ 4n&姎嫗Xц^ʇFUXur WK4 Lbɲ"E7C?3Kn0ɰD_yNo~˔g6Xhd6^ĊP/xx9RѰdzBxgqVR髏xdmFC\pA[nzNe0(ZmQ$I%suCSO=.&J{13f*A3|gEV|Y . n [mvs$ t >P yI2Rd"KܷfaiҪ#MLGSf55D\q{REbX6c.^PZ3)NLX 8/;ot 3W!<FuC Wv\(t׏o[\YY(;N)2ťD40|P` Й74 Q&LRr 'z<5bLa孧O (H[-T=5&lkWoq0v(m:Q@,sqËp^x2e$ W0E5Uw1Ҍ| OY;5Q/l4\Ѹb`0hp4嚖᙭֔"!{o2 h"{'jUsDHDyvI$ZÔ1$6R!:(Mړ3U]ca04<6R 9qTKYp"3z@Q!H WN >k^U~VGP9UQ_Q&4. 퐤 ,0jh{땔O=V#B\u/&>6 s9^B+t;ƿأh(JG Lʇe·W(g\6=A"(/lO'%ΜP7¡yx?d|AдO~SK\^5ɓ=UlnZqrU#t3C)K-EA ;!10l՞C,!4Z-C5EX=E`X >xLApTUEYyzS:a⯺q~b?|g]{{n[JU*R 2`Y M3L70c,%K݄a0zD(*I( a3 є"Ͼ c|D9>H?z&B2-4?NQ 'V{ |k)*==A&-LU+WHeM+AYZ͘z3;k "Nbc%vHH\"~g>>~gs&!a SBbR)ǀ@II&:*mW&H%apv3d3W<44sehXp+ws4(k)dxHϮ&I]D/wzpT!Q:VVZRK MF-z.NJFG s T}vDVW1\6[)iQ.i^R/$xӼ j/I"^PD!㱦N%(`PѕE*R45J8uaa{ٙKsvzr,q.Țz#,Y&R2y{HyV6PQf6TXy|`ig2ı-N Фt[ qQz`(xۇOG?.Ӓ|smy5Le1ֱgѧhٱkArrkK0<صƈ|Z6S\s :[:Ŋ{_P%6*R{#: ]FZ= fbZh7Xcɇ * ~/ޗ_é>(? .pod+7TyIˁc6?8b`9̍X~q_D@g*ks{@zϢ$*hW"iy1JXg(Jx1I#ʐR\ј :j?#(=vT6LP$$0)-G{m͏plu_÷]8rrlr'=, X p!2DҡfqG+PH*}2ケ.9#w_op٘Z"IU;OɵN9t~s\p84$cp'boGqJ9TX 8S 2EX,]OQzjg>xJ*gٷC❞=i$ɒ(y\ h$_Ay{d,lUA*R0=YsJ^|K#Lc Ք]mI=]Ш dhtU润ш>4 z8ǟ=i"7ع$B k _D!)φ>L]Әf#LDQDJ4 K=id e`4єeBZI,^pf8w3@ ~Vm(Jdžm"_M{DIč7B xj0֡agT$5z*m#0Fm6MN ~~=Yl3ioOEZ*"-׿478Ya}}J-,-d\LٵTySg) igFLSuU2׊wM1"S^%2N Db`rx6ap'"ׂ#V2FS7Qg @"n88$ri+*i{Z=FHHӈV+AWk;X qt;/A^mg|Kġ1JǓ5h#õΓz= ͬsRy.> ęQFwG(E$KQ1ںH18  ,MIQKg6)e)Ϝfߵ0n@v[!JH"mRӊSm#%49*debJ!!# j\CZ@ػ˯''Uqe~3x18񍋡a.J+[W?D, N?_9F̈$ ܿGN lډSy)5wu84mxB]g.zI-Q1g8Y?.Kl9aI  y7귘%[1s>x'ʿCr #Ic旻ı{<.o&ڍv{\ XliÎytP]1JŜ7W-@ +)ekj)'{F ³!3Vn@O6IeEc.f*fd6l LG` w8ɓң\B3O|īpԄJtR1T$qW)e4λPj)r,x޺๱#/4=sL߻?%Hy 1D`TKXɝ'L E0%BXK-h牢 ܃ЃpDonpfg8]1yT8T2Ky?k4j Yr(%B&mAs3B0.zƙĘPuj ޙbfn%/qBcú{y`lqL0B <@tc/Jk˨t?Bpw)C Oy3zs,ĵQh<>SQǎb͡?ul7OX i̱%cC.YS"y=K+HU<# MNCaMni)Ku mbAos]c K֨.xS䕣V9Hhg$26ykl)u~,UذMyaMt[ t76<ۨ/cfPJys拟?b \RO =60yIέh5̻^cG  8bSἥU'MDrwrt|E *g] ۞RVbZ1ў`JMg-/Zͳ~a2"FUBіfi IDAT9Fknlmn4)&k|3hmαcWƈބ?4eiHF3cOfuut(#eDkʛ<$(ao$AH*+{)SF1^(ZY7.02C* 5&~?+yaV|c?p7ވZ-?yo ZO xtB%9 |_sRKcwo]Qq8p?dNf"3^MOguĝ[uSe$S=簳7s%_&( lz6\ϴ{+ p$"g|xQ($#a VGA֐*8ly & yŠ83fZy~򞌵_C_@GQ:13:58$*FF):"%HҞ%F.?Q\^Zրp.b}\6?[Q/ }$ku֕BR Y($*V#e L8{,|vM(%J"Is06'O0bdD;q=j Lu+lSlj>̉4#RGHG^1+;,ƘOғtT/0de,HLA9 FE̯>n&kG&8 A`j)fڥ[VRnYbE߫|A^ f]| KZ8Zଥ*G%*f DVtx3,wB DH% <2x]˜<3fZHR7tt4qSv}-,Vq `đ?1 IUN8r"׮d G8i幰{R:q֢ S,$ B~pF!okؽAfaC)|B"qe"d<6(HXl`@ZTʄ `+ڸ EiIcpֱԍ܇mG<{:gc~HPU9W8* Q0t"`T =<އc-Ui“$"ES[p³kH$3pB[$]Գ@az 9v:EO5/qkM65!Ҥd/QQJN=ӊ$i9Duky_^%-AFz,x};ܗdB`ՒP8"a3pM*5! @*#[$ILEX5S&0t;)zGnQhh4|Ri&N K5=ʸjbuN۞ɫ08ťxԀTԣZ= Tmxц)24_s84D"xޘ>n~33QgDQޫ( C* U6x .]/˅ }ƣ2LKÁF̷c>9 k-B➛aL2U',6!Y:BUjjó8X\([l;k[[يWq_VI* VJw{?u2Iɛ&~^a41 teq08kC\V(Sx tE* 3BH~.R|: Ay MeACScgOącZ:Z$}-ABbT6(tc)ؚPє/`ZxnNi(;5Hhd )k;LZ9w;v.Xh)z#MoxnN Aj0./ԅŶŞ4>όƱ FCk9%C9fOڽ EB8 064 h UH;2hpj1RhO#S$`3Y,yGx8GRAoxMM-vh ,L*΅q*eZm4;offo1%7E5bG3LrB#L~)h)lZ9S萯`\شtH MI=/hAEe}d-\BhkREYyu|`bqQo+$t{nƹ !³#:*GkGQ93R:Z rdCBn[rCi=S9Rac5ِ!Pdm78$GqHTQ}iR)JqǏmqmֶ4ڂ󒕮`1q?ΌN xP2VA^d>ڣ76LsKq=񭰅N1Z3id\-t)0L[B,cڜ0"7l!}9=ZGO|.4Ibl(K|(uE,'&Ng6uNI2\-[&xoU؀\&j9mitn/lU)knFˆD 3O?6A\,-ձꍘI *3ݦ֨o8D- JZy队3g/ ǟ^Co{nt%7>B֩cYx! ?a*k$iF*<+;j<%d4K6)\=WC TAJ ڌc&gYٓRkld4c:ZEx4^ 3a?wsm|Oajy^D2!BZuӡ*ra7E`t"™c J YqKgGCZovH@xOUh*ßo{76x2A^zZW?xsM7 oxF8j&浯}-<YF6pGcэ؄3@xC,YOb^$"KAQB) %-RY7&V o bTPTЪ ThwFu6i.3% g΅@*xuFガ a|BιA(n:9ǖ'ϳufPtnآ)"9+"> hЏ<)J @eb&ݍhyg9vfUH<%cG+8̥D:WQ,eIfw㠓ӛMH#M&T2(/Oo2*w.(kiGN*xs9+/I ( ;1zK;b j(*S0.,0Gsm}ԩ:ϝ iBd4ue2%qHsm:PdƉ5z ljTH>XOJ~/aL@H@*,1Zdiʒ%)h/)Р2q(~C{ &Z"MϽA)(f$b)=KbXxJPT757l>wvD=͹9&mqA _2y4ͮ<T$4RE'33:N6B4BgIK&V,^qN3 7߸ẕ =ґD6b^~Gn;kS 3:4=Jxrwbf֥*6'֗gsӁ.-`}L}Z:Yfm;s!thcqzu2zH?48]QU0,?#l\<]]/KG>=Jol5*Ë )Ñ#HS]SMn>əLB5_7h|,!GkOpqHARkD7m?GC6 mL0KOG(%7SXq {y;8rt$H' b6e V|;$\_3<7z e1 u>pSÂ38K;A`ЮʊZ-FfQْq$p('eԓpO5RnzmU,VKc\y6*N:& zSV/q&x D1O9waĹ=ڜ;r(r[nS'3gO 5a?}${vхa嚫LdD{N+w<a=`RmPPSSn^F ۏ zN*-sb& e!}\u;$Vsc+GzSC/zxS9J gk F x ȄȉܩրKE$8$/iHǶsN"Kk"6X3%y9DbLtI"%I<3RW14Hh\)QZB$ iU ^vMgݿo\_bewƉSSH$|are8س= )KvʸZɰη6LxG+:-4wLsCU9(\хHɽ;V4,' ^[9[En3"=:*D&g, V:ISM{+$Qq%pC,MzL9^`}$"e=wlx+gr={/fҥ$YK-,^hL5ct' _7xꈋ%'F1Iq0rr(eBU-suژ)u*f ` }x}I dp$Zf g,iSdTQ\ %<[9s ;M7>AQU<a]g:r*=2ns->S\Y'LF%70υS5*(rrϧ\Fƶ&K5*[!`245&RVB5R_yJ36k#Npi#'bm~#z YC|4s)SaX($M"ytpwcX㮽;zѰm )鎹q13T1%%J)-ny'8h5(4d8do(IWDqx6jgh#1U688t.bd[匶/)N&`\ȩ d!B.T1%+]. 2j`!N>*l68Ӥi >07Rk՘s(ܧ;vc  C (Dv;VgCChkcXўY3g&zkfIos2څકEf=ƅYN>3cK[iu/GU~̧?2Zo|DW%nǛ~~}c:te?882yJ'acHjHo1 lbgM0.($$TiOО+)ipb}6up [% d/cMoX?LV"$N,E+̯1L ָ=vN'TK3xg^pqџzױ'x'>ET߇.{HogG-^s<փJ@d83Шy)R/..p MKNJ&R|4e)YC> ϶,- XPGro$7{ȫ>jWߒpbh= h_B!,UJ/HTLc k9ԧ7t_g3.5 )[0L ΄FӞ҇| k*|㠧_%"\i&<L[`4"awrgnHwg(kLv&p(Ü+(ii&i5#A+!.Qݓ VM"U.s^~S[ZݦBIA&<\ͦH}]IZ&B\fy&|Xɳ4 ,cK)+C$aRą: -GΑ k[ XH1CFÓ5$&/>I@zBR,χLW3g *s5ItyThFް^S(<1±Xұ1u!3,x-NNI஽1G.qJ`]H[fjw>3.-ޖa7Yٽs`w~ fP%waW rfvɋ%Ҳ33 sd0&xe킪$IDz=^Pi֑F\ow@š)JMfĴp0`b7Մ"7hO~};8# IDATM8Vj$r 䥒hF$I$G {:QhjY ': '&!1뵔!IWhޑbg(JGܼSs"|BW%Y&ʂ8A(QPtDIDSz&%.c,Tse[#&%b<-R _ |V~]Ka9ې=Qkdl "I z5)+ώ=+;8v\Ik4Qpnc1R,.uj8;Bd8k8IiJlS H*.y3O𵯜M1|LI4Ain%<< s|<.,Hg4(KPr`B&^71-"#/4ۙ"oB0({أ8ff「,2gFJ_NdJJނL3 @7EzC 0#!T J2Rʬ>qqþiO:/V>D܈87,@p WŻ<) y憍eZy&=N] MBЌ I؇dqK&WD^HI0`'ԁ=Z{K\>}k Eeh [H ]M28TŐ(Fu(` Q xM1E 6lKB;iL-C=of(` Sa%f[ x-ܶ:GrϝyQ(ɴ2YiPн8FhGDh'} _~ckD.Qh&y=_E+<` MTC,axRnU|{=)>x FH)!jҳ3e} ½WHἤ)낇&U]IHbEI>Ou x}@(K)7~uiX{TmI**P~Oş}]DOJ< y}h"9Ioe49ʇ~| Fp*9@<O)Ξ;E9-hw qŴF*wA}W06 }O_{|#CՁ!kIx /]䣿x}G?.eBxLQNsf#C{rk|? Q K OY5 BhpW)μtk YI8]#*#ʙV3_LJRp`kCj-AII/I;Y"Iz{UR|VSݷ2e! 'Ib?:eqc,I"vƎg·QID˭)eJ,Jӳ-}0hh7$Xd0u&岖^w6 AbG ٟNꋖscKCg`d}^ u9$b'C,3$8p7l6AլX^mo 8= B3d,Ce-^*\JƛO~o IڦA;O1gsnzud`4NTu"$$=NyBz&ޅ|3 -#EhPip{8B;4)eBO^Pj|lȈ4 c7]!χa?/8ft#r3 x'A b*G1 a+LC^?&NC9׷\XT8&ڂvSb<}b$4Rɛx?@)őGX;k7k5AHqct_OO),]/ؙ8vAk1o\{>+L0.kF?$~ -sЉ{qKsW ݡ*n'b[͐'1s?q4'Xl+ sӞ ŞJcut-2`SKag%cM?vȨC$,J)*9Q)ɾ=M* IIR$ *H"9Jds f,^Hک a^Ϧǒecٙ:d?1Pc Z3ԱXeOŒU=\چB"Mwxlh2Ԛ8 ^0ٞTZ qZ{zM"Y[hrrN$K~.'DB-f:S5?ѧssMT_8kasfZaUk1ep!ﴷ"/hf澛ggPso>'RV[<Qȵ&sf?=D b`"4֜0e/ٻe ]maËXH%Y{bytY×|ik V3z*)wlpy<ˇ:~8RhTu@6Sͷ蓼;xKChK>*$҉ ,,.5L*F: SU߻O4"/4I4S?k["iϙt+ eUY(ːB+7 Iv1Y# $ֆ@Z|.~s/\fר(f/>pt)qdna?(;g?itgO5*2&(Ix_8k"BkK]k|/bAYjƣXvgzuk@Km1UI Xz_?_cV(S4 wFh-Lr\PB)WvҘb2t){y^ӏ`>vV5.&o{V3yh&"I$K8mC!s sǾ0g&same3#j "qb%$T9ui tGRie@>lN+ k!'@*+E-* ƅi]GtR+'&#Iel8iɐl̺&pMKU?JxBHW癌&!',[`jTFApƅ"\fA?HKbH 2 ; fdg@ * 6,]xr̴М{,8Mn2Teؼ P MqSڽNhR"i,.g)F[4H:;}[?ukTa6=yk|Fg[ncLe4TF@!$8vUa|T1{+@"FHEc0,F;qNRST$H oFz aoGngG\YωcPghk8t븁DibK4w5a0BW/Q*4!83L9yd-m\ Z&IQʔI= g F$8Y8rv0AZ9%FxVf]$J oi)4`Yѐ[*)$/(GΖl̯!Z4C#"$ŗ JV]_1kyQg).жz[LqVc1HPaRk5M8a, yԨ}GifG bDsӡ;2*D*"Qۚ-x Œ> (%zVxlh5SRWc)2 d_3dۊʄdi!f%ZF1ŞPی.}1(K&eW d߼鋆_,wߙ".k($_8s1۬$͘J߰43jR [Sxo(Iګ83k`i{1bZM$vs2HX*j%Ux՝{x(IbS/Ly$RPh)JZ qZͫ=O] #w3Z.mT[NBat˾Ga#'V{LSIQYbNL2M%R)!p,n3qj˚D͐d.NL5Umu"jHHeŰahe[)wk`7C,DYw ,vDR$aRZqԘN0i`g_ {RlB1e:Y[ qX|yQ3nE|}#ӄA=|2$iH. Mg$?bRԕuo< cjI"`b8 MM1-25)]ر"FEiuAiYwۏ/{y {)/kN"Bю}$_ mVڄU>)IҘ4֪LpsT~}|sk!bv-gLr]؋pu$o&\8W嬭Lr k7$id[VJ-83;H%s6*ڙt |M?gMҠgk][,U=؇n#8Ӽ`w*RVqV3KP2V"TdZ3)=uɁ%A353!@/buᆵ5åu/gg{G]-=tb>l5lJ) dAƝPXz2lBTII**R@9S9("b\'fmՌxٝ8.5oxYB*c]ycr!ΞR8*/Gpy:д4uŋ.(g$x oڅZik6)ImJfRИm8^|iCQ+P+-~֎Wݽ©;tzY,Ev֐6qBbq,E9 %䓒"4B*N5J*Z;By`"y6r"kCʼ=UIL <:Zw3@T.Z Q+W'\~k̬Ipf2.n|3SUGdfTAyaeąsC.]瑯a2Ѽ=yIIX<.3<<*a"|F,#M`qɵN\yʓ!]u03{Lc]$ZMD C]6j2FZ`sPac2uLʀ+sc4,B0ܬ;wf4:$9>4OU[=w'>ֆo>u}0ǿkp<vu@ ֒8U#əg/#UQ5-c* !f4&0uMU:).]EIJvYC<*㴞y4@0xGID5cޛ={ab6B^H!5q\:N6c}S "f.xϝ+yK8h!`b0h qܐFdi3ء.ya_lOV!C%i58\7WRcB ]gHUs1)|y{Z_<o>'No|ǝEӜ3VHv6qD]o<;v/~JZx%ix:!E^EEB LR#GbRٽ{#܋Ӎ2`g kfX;|>8G1)iu-v )`8ҙos}\0=?pPf+Yje#te$=L2CR)vuGSn-<{D)h+8!Z9Xh("B[@H Aݞv+J4" 0kEaB[S, t$طKb)(xbb.1gv>j?sWK.m86`|/銅BɰK&戭eKAIL>B`”ArtWN#Bp Dc3j'F & s:&[ܼqn+y;ÒWMňzESWǶL.A@q,xyխqqSӝ? /XZ=E#sxjY՚-*Rxfs+'m)umiܔ( !47IQ兘iu3nbEeYPE,a~1;>Ε|ɸ,'^p?mL, ~Bp=CMIЦfo7bk n:HcMl ^wgQūiVϗ"V>*(k6a8[lGT&4~yί ]B B'(o?#7q!yRnG]a,-P8nx& ܰUxgWhj& P $(I BIMiG7mrM)e"ڎa01 9!u%/ EU= Uk@rVAAHMQ@^gTf3Wfڔc]<{b@&Ӂ'HNb#K-i! E hd0aՈJRJ:Y C&RR֒F!d[1E&Ab$>OnkϜ$I#a/$KX7A8?I-cV:5EnH7Sv58I$BĔ AUy_bH Y*).t3iHj lةe27,.d$ PjteXZn4!*Mo_%P_l}:l}I]UdYaۗxO5351k-uU@a$Y38Vʭ~FN'?UҚkO|~% _yq`y#<y^!UD炏CJEGlo`LȏF5;#K{b 3OY;ΟBAy+@|E] c_daAU.א~npEs.Br騠is D늺 ԧQN5LcI}F~e8xv&N.Bڀ鸤ʃQ>N2ѻn&M=ݴc?LEk`tTx,ũ"e`'*WyJJ>׳^ dь~>HbLCϔ B<=[y+Z""/)B zfsH!8+fwoSI,s+%Ea%8[9[5:&r;f ˒~V8q8G; !YW,+Z݈Iɠ?>Koy,R=L1ռ@5(,*huD8(ZQw"EH/yb(AHOgsOlQi 8r(=Ba9^ӎ-ǭw+&;c.Ae(~62v7(jC$ X|H$e8m MֱUhTyFgmI"KYlAlbyJ2JrXv텆8W6YWg5 -OqM<0ZN_դ Z_]w,t|0;^skվ!âlv3Oni$Tڑ1[We@8w(/-h{;iI"0`u9K=.]Sih5ct=a;v K4bu鱱U1D Vzr&UA7=K)y|_=0oKoqŨ:G5)2Pum=S# JQdKac'5^J+_ȸ<8pX!6 I$9Mm-7ϣ. ox=XL2Nop^X&w. -AQ A(km][,1ñ?}Ӱ)p>Ղ@$k8bkZ3F*x.o[\ :lf}`r51'iؠFI-}0.;7z >2ZjW￉5Bx镮5:SLKt'<`=<6G0ֳLRww!I ut bՈps7s7D*wrP8BJ7EۘN3&k7{omu>sο[^ڻRI*VkK2ba0!!.&!HO !@!L njUW;sI#;gF*Zs~>=JbJ U%/=Gs}G&yW38xp8vki챴:3:DHq,A|"*&n;tpHjE\ G[ϷNᰤߟS7576&%+=X?03V0[@}:} KO,?DS`;hmJRk2E4BEX/K@hmX8RRJgf6 &p*ƛ _ڵx0R౗_B7 Q){|2E$R*[jz3OoE$aN1dQ8EEI0/bvJz-ng[A)8,/zaŃm.jff8u.&mH)@<4$ d1+6a3 sԥf&*Rm <}&&0N; ~DkS] D1(&52N9|.cI2h˱c ηX=Y"hޓuZHN}8q۹^m&g;| f#%Q!˲0e3%/a"ESu^ӊYIV(434ˇ/?/hT%$!KH Eչ^;,&q8Goq'ϗqq۠ 1X&>XɈ+5U]Srw02ںJ@[G" Y)9l 󴔡tIԞWۭj Ykޅ(F|_`\Τt -s.9ڶha:+V)ĉl= o16H!"F`s4:#7F(Ϡ55̢7fl̵ x#ss7OP2n'\5mkVf=v GgY7?e}p0DJZHYZ\1|n9K9;+$dϏË+T;;V7tXZ%hCR^~X o&c0ogo34yjAmBZ˽!z԰1Oh|-7[O TF+q:'f3f$y(7oEPi+7ta\ROKeh4ǎ,RNR{sGm_`$'!r`>^̗7s"%HɬoYbO8 ^hTAZ*Ux6JA\ hG(ׯ 4Zi٣kKU s?QνF$qOGJ0?QUlݛWMx|ݚKn;;3@b)Ejܳ NBn7tW_!WIbŤ|]&k5o׸|esO 4&Vq+$";PNex sǎҞce9a4'~GyKs'.cmC9p`[!N{;# cGY(]v4M އ5.M$iژ:|~%lSP7RJ 1&66L%RJ{ӷ}D+M[jf3*()o|^S150ʦh/XOcwWS_A K=wײᠭ4/ Ġۻ;TI7)54(V N&VnpӮHld) _xvrJ,hy=ډ]C]=C2pzqlIEXX4VN=$ m@'t=w_,?~SH[ڕ۸T0<[#u,gr͉c342E ; ,Bbxơeu)[E3ܧ*,.89CPv Kϳ#E6~6o(J{Yp8A^[nlfcfreT'۾m5 E.NKRl,(gl̋s0h8wSюc}ym7YsH |0vޛDX4v)3=c>b2d1:1׷ju4IE\/BҞY*L ^Hٗwaga&L>3JK$5X]awcBec_Q}:VA<1p(mN5T6$U {M*9z4em8Qt;^CA$c:s\X\[3;>7/ Rre/f,hϞe8gT9ŭH@{+|ce9, ?=wImm, 9]QiV&88Т?4QKIҘ C%%R) Jc"Qhjb/S9?Z_$%diM]^k~5awu a}_D* GN^:A1L!†TwcI. =£8Χ?>D R8:~^x]|/smw}}huT*E48_bgΆ֎v'{ɑC?ϭ1S"d@[?kx~{\SW I!))IK?~+O2WPgэsz=x^6:G>(&`hg.o\1aXmi8EWԟס&e联ECXz]3שj#8qg!`! :>/@[B "^"ɖBg35C,EȈC68'?21:HZ?Ysʢ d~ƍ!+ٺwweް=AKSi|Y,um$KƓ-݌+Nq=Z֢TD<~|o|SM_ߡe(apIy汗x]Oט\55G|y>c,9HwC=KQl39Owv|^&ѰY9~րq%7V.e1؆陱.|{ ^|KrAJLњCJC,eQO}3"pM,'A<,`,a#1߅np_<ԎOwy򘼬" Hx B?˔,v!4׋煵an$Pi,IP qR[2vQ)J]q*\I"aBc{찻ođdqET`并Q'Ԣ)c~zٳ˴|M;;n؝8ds蹞{e 8rQO{'0m[Q]|~Dx{օ?J@X)#"z"O ?#?©S6׮`8P4@[A%߹C!{e~a hSÆܱ?eL+呻2JcK/V+Fk@ |Rvk?T[ǝ-ϵqe=1[! Ág4T>ľX dR%uTF|&J>Bf \~tYbcMS+[oMd\j՘k ۾ ,=vMNi\Jz]p" &|L' ~=ކG=:O(pDخ0qВ#9}#>ɔ- 1ֆOxz}F1aC3;ljgZlBr < wFo;Go 8ҸƷEIY֜:!oyM|WI*f JTFRU-`: ?/ 3)Γd1/BQwB&f4ʆ/=.pk7(&;4hTQb)4j2衲!:kg(]'^|<3y]n\z )@!ʓ_O'aVs/mFFxH҈٘(8$JJ{勏]63XKU?498KgEU՜c<^bjMo1wq6_F7/#,ԥ;OۢktŸ"M"DPMƕMFp$M1a<yIJ9q,еNKC7èhؼε-K>8vzv]=zɛ\/r~ҺD;0HbI3$빧2c=*u=!N;tU\' V^Ξi,NM!ꪙjayVƂ2ST +iGxB>8Kcypxֳr~JGd].1ZSul.=q~'$LRFGɐtzP/[yplI:{nΠDN`h갮?Ԇ9Qq݀I.:^aHNؼKxϤԤ1!m҄`&i*Y:Vt^;bɛP-#mȕ$s3 sboś_;ϰ3-$Ӌioos'_ʧZHyw[!n>}yn_sBFH7;dYIO^?^O|>>҃%m&6,\7ְv!mE4. E= qKw8vRsij[JS՚68|v&}`M!exT_gok?Ju흂CzKڝ8lf_üݷhS݀t)@rAzGcҳ:CQזqe^e{e_#hi'"$nJETE\ 2&\@LnebBx6t1\^භ¹2TtSOX~32溎8>-zT  wT8ˈ\=Fmq4|‡4I5݇9a1]T/$iH[-tP/p.s w~y Ù,J6(!N;G~[Gq8Z1u D]bɛVi)t5BuH?$*1MʱeVpo8):tQ ѳ&Dx˗Yg4غg?BŒC?|  G>{7>UiWeJ@7.ۊF:Y]cuC<qP^Xs{}N {=f0 yDQ3Hop"&K30S"d.mxJx%^|e̤DiBz+cK2 LOL4Sv6E:0#:kh&@q _$h;9u9ް@|PU)y)*Ce?] ydnl1΅iduQ $cV"ƅF\y[gȯ_᪴dK3gЀ-{b[Ӝu5L/""mOdQwS2׀*ۿ;ڷ?sa{1R1L/ g$qq{0Ӓ)2P}-1`$XLk#TfwlhzM#|&G;#9"#YVXhI}*K07JI YO)rCw6!$K {M-=Ii]ذ?44qy۱="Z`wlyRX߳T&8ޯ0/_n $euM{aՕô_]ʢrc7pMA/8VtےW^w c^4ҵĢ]ehk Wv,4Rh0;fp #Ia,;R0,q&+$o"A1 +N--gZGH`߀<@<7 'Aɛ܎c H#ţ&\4Drױo>z,<_И3o⌺)or'R7(RtZVi:Q WxE#Q`|8G  BHfggy!4 gsF[ Aэ$ND,׽LF#nlXQj/gC$:jf#:xZ.pxٙt ZQ#܈C1G\ ,i$ H7ęGojK+ ϔG4|)_Fv0%Aʐ?qz/Spo IDAT/yubei!c2ip1U籒 =٠=.9R,m78)KKCn Mc4 րֆnfX=jM]wi&!UgmlE0{U}Ma3~w߽BQqC+-y^& ΐO[Q sM7tq?\XRWu^Яs6hqaLB^iƹŻ0xyu"BΈnA2ֶ yɄ;'Ѹ!prΓ%HxlC1k:ZL#DN+匏~I QѨ"NRuʼYVWqud<(cq ƘlcԟНil(1uG>[m|4$NS,jzI!A6K4Nu4E58o [cJ% 0Mxw<ms2|vg~bYrZl,l8tJ4R0^L*ς\A'vvyv5}ʼ jCg-rPj%`XfԺ 6eёc˫Ɔ%{$7-!#QkEcgx} )pyO%B!>d(2pˆ ӎX zsF[Ii\H s,&C*+. v Nt.b)lLB\~8t|yw<<ā>/dq] p x}ڇk"IPW Q(P:`\$ΨEbg4O>IĠsv1Duz߉֚wsw/Oh%pOOk (),i${Ë6M]Q/3Ӯ2eP &ypJC^Zp\[l(YSO 8)=3$-Ck4/ q3$m@f,K1QkR7Ͱ6sFF1*j|)+y oDRA+(gX{v*9yjɸfCk%އ1BuyŴ(@8x#.W. 1:|I)`vvkh$e{K Fև5Y!`{{RƝBH]wy~wO,= N.X> Pd.x" 8^BZac~ε>)g- +s\7favu$&NbtU!m%[7 9~i&^\QR2|XYo?'h-aLQW5_m~y38ij]KkFc )%NJ؛p KavYFH YvLa:jYfڤ "W(v#dp&˄_mN}拿 ̵tq8h38!IXbTj@3&0"Zrґ Jz|&ۃ"kH&L02bTokЇnuWOȋjm)*?2xfH6Yy$A@E4;CFco~P[g4! }Y*˸?^xo4bRolh_.n']VKwETlG1(bm|^ ;gZȌ ҔVQ5q(H"IU;ڂwʚ_c7t{=P^;?LSgbA7Η_3a6tE<ݝVRGK60ē%u^'dcIoQ{#ғڭ#Ɯ_-8u%'P] ~L4a6Q*юv;-X4aS8okvHV0"À6#y/ũ[uKK=ŝm|1p4WV36a*/|8=6~U;SFm@[//ee8xGnM@!CqbmQ(CI{ڕujgh&ZFU6GV\{ƑGzBO$bx%FrUFB4P0kG?UA@6α0$}vmfӳ] 8?R8DQ QaQ=A8V0КZ$]y>+!N{9 c(9:f;mغ|]vYh$uP3]03"q;1hfgL9}r7X;9Gi7W.mSs:ywu~{_ϧi !JIд',g%B i35󕕜Υ1i8`smͯ.rtdHY;ruhȍǡCHGm= 'hjMSm:p;T@)ȰvUO=LY9Z@TRbNdh i }7Ⱥ$y (ߒ023sDj ᰤj&(]Ɩn ө/?o} NH9Pc /4c~]oeaiڇQ(!pym4ԇs̶tTN{W2e?jcBF0)@p4ڛ Ǵzc2ꚗiN:k9kW^^0t3Q0awkW&n~gwQAp@p)UJ pҢEJvGW4>R'Εsoo/㙯QVYԎ| 4u)qwqڷqs5GD;vb}Q{L/<9Ҏ|x/^} ؋A"Àk ͎i3=2*`sظ0"U$ w2,9B #ͿGn25z” w;9qf١ y 3WƚAǿ2 I/y;t+w]?΍2qP՚󂅩3іzCzḢ{kaHj0kÞm}O`%4zsٞ"QıhmHI)=lemlkxoVRP Y7ܰ#`-iE>%!rPBppJNHkOf H#۞?sn#W3fYZIX:cɠt}cXV3*|_!q{?1z x7s16㱧 kak.Ĉ.*Yj&RY|^XJp~^@Ct I*bjy; %I4`khqxyY=l$,g]j7r0%.]\4"Hm_(|_d%7rۍ=b\i_jƱbz3mb~>E)}CN[e響nL]yھ=t]zh]ׄfZJ`eXst;Z,$Lw-KKj1'geaP1;vM_| |Ntv?N0m%$1G;_=A K!i!Jr`smD QJѳ2갸WZ?rȰ뻓_OM&;!SKHv17>e 'YlSJҝb8Bk!@s힐͡?;WuX((cJFc֎G8 9ك*PvzBO hP& H9d4S8,^gC!3=_1RI>T06`;oop=,c3j4O\٤6 jK͔\Xc$ԨXƕ*G|G/F|% Bké0Z.}m9~: XtIBi_(5LuCnpu NS'$i(PU$T35MH*'RH+49oEsI]EFXK`IјD8M,t c"H~RRh&]tܹ{ZqbA qx_ȇ>1;|??OyJB%$.wGsw⍴"ɧq/v`{"ze׽|yesL);sdy3WOԹm/Wt8Ee3滆q6@ hqj3qegFQh@| 53_?vf*(4ogzyz QOgv@FSV9FU`{'f #S1 Z;үc<*F9q$vns@hH ,'dtJYM'0LuC\">1.'(jQvRz٤n,y/d3!  1XTND5qs7AFޥ i;O1αԡ) QҩaN6.=:8P< }"NߣѾ >*bj[~xқ-Y\l3yu>kZT8+*p>F;^/ffq*s.yuٟ=@T(Qӏ]f~+Hlyow.w4gD, S$ѨdO7a/)<tڔYy3 Z5[{_$-5~)CPQrtRϲt \=Oc6W0YGgax|.3oT11je9.ɲC-yZh1Vֻo=_= 䜃Ƒk(a?YYÉ8Mhł}(|RDt*D8i\f^z-q;^AԜXHPXQaG+qD8~2nƅ!/z?bD] ;F9_5)kM 5 uX>ȉ m`7ĉ1eX9Nyeq"dPQ0MB`~g I%ܐ)_K<wŸZ IK3ٛ\쓍rT3 +zoU 7!"\ž+/+ |3ۍq˜:5BJaѾp|Ƶ]1ǎm|cgN;a|)BEՈץȡ(J9OŹP1LZѯ=7ȍ|w@z$ B~ U =;X,AF{h02Bk\h\žQbe}dy͟}'g15Ԇ҄Q$Q =iy>T9):KYOe0444&Jc?4 sm'Ʊ/pe_d[ǵT&ꥁ/,%xܰoY6=ǯ&1KCIF n 4`uCh$EJ?qFj3g?ӻ!Zkw3 W]zYOIS["Xǎ!3-A#eChXx"4sEȏe@uC!.;ϴ)ع]IHtg@ ,(dPOQRjtMSgh iJeCf0:BʈU |5_]>Xm,4iPMNJVu%`PjRF"]o\ͮYf]K֜3cT[{S׌6Nc%j<$,%F$8bL ` {o@)h@ @n|ϑoRe}fprXO: 4e,v Kp$8^Eh&9 5ښbqlyI87B9㋊65$`yU|k)2l _?@8A8  @C."*me(LYif$eY$a{y~霣כⱣv8ʬ}!O^i!^ Vs qpNվ[CK/ssы Ú WJ6TefR C KT9p3썱~ {sP:-oQO|?kf[} 9 zbp =GS;ַEbm1(ְA~zk) A(IKÚf2%T94')[^E̷> X8`RcXi鋃ߦ(XY>'&ODqz1w^=<*b<*=YsbuDk( I)&k?ZMmK^ܹ1a"b4*,(A -N84wA`w`Y Y` 6Jo.SJ1&'`Ld_em0ΛU ZYi RjANI.n uXՖ(%+{ky _Saڧ^_\SKa|߫ne܀S7F^ Oc2̈́ LQ:榣)@ oBFh]S Ƶʶ!c&&TG 'MOi_Oy$}[J0?xctac%) TG1,|G ^qUeA JԆ,k|`P ; RPKZkL07M>O0?%ًlm5)k=# nh/s~]ln&b4jpi|~cvퟂF05ۢi, I"D[taș3 G 㼦trpwJmJƀ_Ws֐Z1[x'nTe!AњvO/+leUnj֮8ezөt ~m>ߧ,Nq˟W} MU= $8Yr+ Y^?bT11HXNK#!b<# $[F)ÀTZ"ZaD^"Ў;{څZ38F&RyݠaWKDfeH .6c@7%-"1"T .pw0j'άJBE^pbdHgKq.ElpGIAހ 8yGUT,Mnknm _l"KДTԍ_#3RPXȬ}Z*!L*\^gKQ8v,oyǯ:ss`oor_ 7ϿɷWI;]Z94Mo6|{./z,:˿yO4F7|a*Q=p $FL My (tTء1 BIjI^ʣFzp`7ξv>KүteF/r1%i*8IQ>=v$t닩F7X'!^'=s70so3s;Ǐ$>sZ32H)٣(w_(Ѹ&Ja~ZUL )N* B[񺻧y2\Z-2C;4@Cmv 4U\Tޑ! :''2D #Jp9au1DY C;X]&s Ry]1y Y-O ֆ}_|;ǟ YPq@Kƹ8wLI. -b}=|sWHf?Q`Df)*$`iZ$rvaO-kc$Fu$>e=y'+,z,l*6af&TVW2AQpD0&I#?qd5qM'VbjlTng-׏_J ~A> ɯ6ũb4vGƁntkl WP׆Q+BBL~~*;TAl7[hXs:y^E! ñ/J Yi&;F'|}юAbiƣ]mVL]8ޝ-au5gygV'* /sH1DqDQ)#ާx<L.R,n7u|W<ΥDiy/%}3? Bɸ?񫀛 i%YFJh|0 +iF]3_F!~asw__=~;/LBk9 ^Td=nri6`02#RwWc<%GH{o:_~NhW<|@wIO!V>p=i<22{![m$bVoOyĦ&n3rp1C)ng$,zOs[I9Y\3IKv[4lٙYVkUk2]$"֟Sr$ID׼6U{!xUpF8@ &XU0) [{ph|!5 K?{'\t/{ر0O~G<~/}ˈ8}ǽ`f6Yy*;ݻVN"Ӷ7΂VH*AR{$-cy.5?v]eߎ꘯axtK2'B;4Yo1Zi EHxO?{[ M?B#b-X t$aGMZH.o7Ji>iLV(W1alҎNIb/LxR}}Cg+c/wqq2sVDQi22 VPwΣ}|}o/IZ"`;O"/JH%gF>Gxm'/cȧKGNTXQ* v> McA N+fm+GJAӋ4toA |ӛፄaʏeRB 3hq= ZC2w͉+ưg6!Q^ '$+h\B fRʴ&Tq\fw3qX|~ ‚qa&ӆ^',==5e;Edk[ ~s b-Va@IA*{ S>e+vu*\șފ;30kZ`{ؠLyہcdo:9zbH"]xefibD;ʉ9,P[Xkػ6-$S^vMƊ!eY? 58{Ϲu/޿N$ľ] aLľC̢ Afdd‹Xk AV&&~7(%p4ReQ$'LŴ23C^iƆ}@؎vMќ8NH9 L֤Sm8:c%No*8} Gcj2۱,ezXFY6bisj>Z1Uɀfذ*?ɡ%^:/n*Oc9= k Rvn-gZf1Ş#s߿}^VP <+,G%vs 50Olfi& \qlr'f0Ľ), #Œt]ؕlHdQg&I JϓdqAc1uFe|eٺqɉY "4< N8e=;gй;TqİB=PW1Q'5c'ݵ:<<#YGx+7O^Z^8|JX9tI<$D,ɨ+Q rlO>}a)B \Ն'z$HH<͉%#<#3$ێt f.ҍsDEUlMapOBP,,O ATg&HDS._|jB7N %G2>.&") aXň7;o˖2h$ՔGN" (,}|m< I G(kD’wqL ri!9Y/qG)zcH| \rN8 ?B Ǿou|PQeo^tw+j]I%㵗cys9J[d|ǽl~¿)&~yؑ\W3~'>'ss}"qqRQG3o]`1 rfv.q+ذi! G$i,$W (rwIT80|-8&extfX]嬖 ~u^pƉtowYG€,}:ͅ6L[C =Q226BuǏjm]o~-dH}|p2oz|c IIu7zϸ "r5L@epN'KݶKDyN=d~0Ȉi͉]̱ >8s/3KH)(E>O:m!-kpŪQN;<7s3̈́}3h&i&[,AC)ę2aҜm߂"'3Tpz/ ֙nnJͮ!bUĠP,i^`pCk'^㬗RSPIb,'KǠ55YH7).zuT2ۉEFa a,=ʵ!J)E T.-_H3'I:"$ispqU/3LHz BT%5VKQOTkiF90<˼̄H,.1u5oZ IgXj·S䄧Ź_x^4R㒗{&J^ȕo%|?ZH)ٰiađs>?z^Yn}>qB?4Yae9m&΢ũYhcRx™OpǏ򑄮"bmк`b̒aٰG! # W&J9Xb@>K`lܧٱVe\ i+>|>Iwy~äqAThv4i^\ƾ0E6i'~|u%gބ#f4rH WW<_Zv 88щsrZъM5RsƆVbISHGIc[uRÑR9sSflrE/n{URR;e٠Di(nb8yij'3Mژ~_;du~!]'ٹ P*rCh}Q D8OIpKn v~k>I-53Z<,׳TWyTcUtfÞsK9'Z$ӴV$qʎ2V,z+ֺ׵{q[j;.?9"͂饜n;F/ֺKћ~Iޝi]>s<ܡἓk^b3EJABy<y- P)d4e汝輠NIs@(_ZM\9 ,x+6pH\p+B^x:?fhn j/I2E^ ^{ 4u4[i29gcwBv^kIP#z%IчIHBzvY t6O]B%c3Cs%~cs} y>Hk ARӟ2|1Z=I3K ݅=hy f&۩+t ([ &M.(Xz`\-ɾIhA^dRJkq˯A} VPΘGU4;^/aqbi8}-f\4[=(aP"O RNW<ݎ9:$f$R%blF $6N?LuN+f~fVǺT(E8m\qǯvR FetZKi"nP8"CIZsARKss&R VNvE|*y͍tSH;#ĭSX}*&ĝ9\1&ZSK,0j,c36 JIFj ^X-H_\3A *l\L3`gj56oW?|3Y;pW-(' ioxY3|xq35|}}'p⏍y绩kl=}w~_7x%䬳ar2YuDz}!:w|yɉ7ɴf蜤Ě$sz="(UQ ݖNy\ 'q.j/n<+W rGHDRm@Bʑd*S=^p7H C13c D%^8n`?1H1:Sd$qRۣt?mj=GrA衔 a !%Ր3'\nH+\qfHE[=տHX|? * M61ڒzma-/\~ZtxeK㼋7$NnkT+t#]=||?`X]/c.('t)<v,̷Iӂj,ǚ('I՗Z֯aC ۠ 9^UF^DY!VbO`=aQ|Ev~_j%`vѩRhz ))% u嗘9/Ɔˮ$ ݞ[']ʕA82)zs$"+][v TXJT#MAut% A*rGBaSزL`qNd~ϼ`%9V;?@#ژ Oj!?!rCK9AQtX /L!ַy{=~~h48s+ڏ}c<\uU|ӟ C/277G/|!yk~sQַ={;*}‰MGgê J8uv;:S& q.X~uOz\{7ɭEں2ĀTEm4 k^bVH:YA/IPUe ylYGNydB7αE1 =juXR)5Xd'@d᱙ѡ3Uy|.=~Yڝ$,G: T'f2ٲuTЉ5NA7tPR)Kg Ccz䉸gȠ[q~+',2A/%Ry~z,?!tre:{[V\IZ9anbt3='ՓBR)Ƕr7HRo?M*TUUzw` I:EѥDxe%M+CvS =m `r]{z>B wW~RM4]˪=ɉ џreN^h<ʻ' k3/ =g|ɍu `}'RJW]P^i@ ;OTaI.} ^AW`eD _Nr~:.jY-)K?k7,%Ez vPOT@r~6Hk(WY=h9" NC l=_rXg1y=Cp4+]FO~YnF!BxY* iCz˱[cX>Qfb\D,ϙ |R52^fx(m"+}WF/EkaQtw,йF -~7d- cnj{bBX.Ec }G{YZbҐfLbfӺ.xSK|9c_3|I}Dd[PET%t^h!!XBsJBy"3VTtG}!Z&cX"KmN6&ƖV_iOTy)ع{n!~.Ɨw{E7W?mGR/\ƾ7lexlusz3$RJ&&&1pYgqw~!drr}c}kUz{ezz /ccc^?y{W\g?Y6mʕ+ٽ{7 .\~ɘcCE=܋6>͐/8z !$Z0PvyNKCzh8僕[P:ں;uk4\SIvyPUGe XsEy?K},hZ)Ht0ެ <G?NQE ׂZw1BZJbx;O2PPc;MFZrJ=(.0de fu_JiX[:Pܤ`Q*I۞n()(Wk•KM5]:0S~ /B!3Ǧ׾ȇzp>w_ε_ů+W+:GX7VblF<`]$s^ck%,wҺóYe@[6-ht*)Oy _?&'Xh9PUrQ D) $j$em:Q{rqx5}ӗ"ڠq$NU6br]2M!4WirҢ;-{5qTeFق'bZNX8C,j͟_zsմn07ߥ;sY=15|$F9rpARY=Ǐ}*)Ri/.20TyRGzN) Yvuelrcxƅ](*m:FG@z0 y,͉; a?-^^7x)na:_ywqf 7w/yswr zE)?yo|/͎;yG'LEmo~7LOOsr pI'h׽k^LZ8}Xm VHݏ[Ǚe&$4Z#+Oj=C;~7 u-#Ʒ9y*2sҤ]LeOsʆD^XnY'vf1R!9BrccQαc8Y'E1k םϳ6Hraw 0l:]Dަ49ɋ/K^h+M/;[mƎW+(uu򕏼}_MK_{3mKUؼuQ*w@IN YQ V*%+8uxB#PqH$Xux[xWV<**A`6,FsNDy"]J④4B;WPqrw`ZJC%I+9p:L ,vbLP34eD~IZX]ΑY)y./˫h^282%IT2dpZ9hWLP5ߟ8UWO7DƐx퇱X^Pʺ1ZYЊ5D!Go(x|7?`#+<(t(5JӿTKݶ6v;OI#,fxpFa&yP +$8iӋ3-8y3p. Oh|9<ӡ1/+}w&4(k; $犳.aLJp( iƆȃJE2Ҿ_<sGcytλ#T.Q+),Fn8o8Q{8%0\S(a{()Hz gFNd! %nZ,ó(Rp~MsEn4QTPH`={%vI)-I l;$] ) . |zFu2A.VnC{JWt{d+>ң^/cr  (ruk\ ^Z5@>m%׍q7z|+B&WU)=FǫVퟟ45ϻl4Bebڭ4v pzH)ЅmR# Nx%ï~p;-}NjYj$||;uNw_{_f^P_?^~Ꙧ]?Fq`jXIHxfh"8.yk_sGn"ə#U:"izȨw Z݂s6Y0TC+KS@qF3 ߁W}F<.YqxZj^ ɕ;"2öq R59( i#콤JL-圜(KRyKmT/Vȓ:&gUtÑ5Vgʦ>Rbݚ33bfKHmA]);{vcl;uC)SsM%B(ḶT᫉ٸ.<8E8yو6Vy.2q5j\fQNZ;]5$#miڙD^ةS U@Yfud) op90*ﲪ(G]m: $Lfd۵&Wm ‘Q ⋥Tm@GlS #>%HjIC}<ČsaVluhgT#;h\.yȗԛioq}ɚc#&9Jiё2FB) Z\OXgD)R?L6o}k^ٻciI;uy6{ Nr1\rab:04w mEM#ˬJEA]>W_+p xnfuăi7Sx'`qݻ[ngr7p뭷'J%nv>|5{xӛ^sNZ^G?Sjxx^o$ImZǏ;yx bR(*fVF/#lwӫ>7An0a}y~ʵQNnm =K+g s 8~ק-)I^r~m,sC'+heGH; va0,sgt[3Єʹn^Ig"O `݀; }wyε?kXQ M'7p1O"WZX\Y4@(i~jN\P+>Ҷ澥vWHswNrivmj9Uk Mxv=/~v馊8մ18RktHk{|4/%&Rj%5k8d.Ce8p)eKnhu]k3\P6[瓞9|S,ͧL/Ĺ@羰Z *4 EL K۸C+r]Z{ۚW㺒 $5jָqc)~u' +YXUśK<~"auR! t;6SHMu*Np]R= y6 t˴u`ͺa.޽`aztpv=BŘb<(q=.$q'o|A%d,M4fyf!~ɠD܉ɓPVH!|"k#R<_'M2rdɉ9*WE`frn'ϡS+;)Aseq=jJ%c%@tM7ni|ӟS뮻Ds)Ⱦ;.ˍLͧV),J`E`ڕlt;Imeґ\*$ $ \6\?i֬]ʕϟTB}?xQ/5z>>98r#pQV[;:xٙi}FLOM^\<1!g]xzx쑇z 7sՔe=ʗ>Y.{yGD!tIF:x>/cW2XdͼSGenT7BkL+\3ӌ˱;ĀDJWSAa@j>qfclD;I|#c=ʩ|֍z\BYMdJҀT)2ex΀kK=X'WR\A=d|#ɬٻyp6Cɇ@B(=pWD)R) gcVKCg6HR)Uk!H?kA 8]$J@J͟JI$#}Mϸ'>BJ9( ҕTJ X2,mY:qZ?,3T"^2x-*&) Uњl9#%T!xi tA)񣝞1WB wbbQ 0\<7nkr``TLzL,(:f߃ytL38 Bt30 y`YFWT8pƆ驴ֆeE/eCpY"kx.5>6`!v"NJ"@R63bGys^ BXXNPձa|RXӴ#28QxZغ6$֒/C`YH3MK?NqlCkXh@)ŵW22a+zHDZ>EaFQΏ;?qHR"O+_=A-@ib++\q6YlgZ_z8MM6XaB[ARwAJ"p%.XY5/\HGZS-053aq!aAJKzy|86|Gwg}\x3 BCPsi7# ]))7!zדk f8KT Bυ7 Qf\&kCX!_7L!>*i o2W Qfm$NTUvc?ku֬ZYc\ "+D.׵ ?t:h'* 0PylǏk;Z!P#S7]cϼ xrјB.^iQ 7+cddwwZ/??cӦMϾ/};3q>Oя~۷vUW]E|k_N}wsAor_-[^3??C;x 7x##"%rn7Nsո#lᬌLYG)8wTB TMF[tZvQ sp"1$ )p8Į C7-cS+Fr`u@&5K5oP!ʑ(-j*#% 8R UJbY{38?$sYXx`uzY!Cv<>4̲q%_Z~sdA%rh%.3Z=JWS喀tFm3\rKR׾Wa0?7ˮɵ ^{=z?›s)!JPZg;^7! sgfO}ʑCw4X=ckm42 a힄>| '&bN)`"9TP\ ԗ3Z} zZQ\Vo)#&rZax#n.g͍{5H2E9VԑI|TV$WNOUs FLAk 5n{^=ʷ~ęE^=_q8+B+K2MɞǾ9Ұj4R,62\G}S'N)Wm!P*6MR;ܢzY! v?#ԗc%+1E\U⎢ي7BQ&@@/uYhw"Ksdﬔ7𫟟E H xɭy/lR1HapLk\c3d?7)r8d*$):'پm!Vykre\Vn@& qb&GHۈyNB\R CA+M}\OP- l_.y/'(1Ʊt"6nz{[.*ωJVYXYZN;y->83:h.@K+\~oJld†ʨe$]4ni}(A@ûLsψE cӅ<:Kll Xq"^ "fv2;9 Ej_DP.)J)PBiǕ7pUxN6Z[w~y[@g`oS9nu\k_]P)rEաPCC5^`1)Z,p=IOḽݦ"WVJ+J55.L;v<$| z_ ~;r r ^{-^z)gΜo WWٳgy{^>O._җXٛH_{? oxxK Ð!n~,({®qA;Ag-u|n n$yYJ Y e" 4T3q=K3ւ/SHIYQ !H (JG3EVKq6h*/ FE*OUWmtHSBhxE!z A#|Oe5A#I R4E I$ il)%BHBa%eF#~^o8;n-LNLrW{~SSF áO> L/w MOYj4W/﹛W\x^VE/y)׽╬:֮'_OЁ'x_OT,'9#.cz< 0t]clZx=̮mІ]JҚb[uc0<W?zgN)F ²"QVK@FRq 8QTNjU}~9åg0ӄVf5\T YX)#Ss 'S\O244@9Z Cvӂ:vģk:cNw%K9[l N)L,i ta4[P UF +J<]|W06gRd2#}gO7 C74ڬԛ9Bd$4bUMcLOIR;VzoqTB!ND &vK'ڜkTGᯖ񄽟mGj c.qfǿ;'frn[+6 ~u)p)B8{bc<D vz<}zYLeJCX;1,F!x'>Kǹ{gORe#;w&+ۊȷ4TC7ӔsK.G4Yl,/,'Jm52-bniK4}}I'ginزi?zN\~dYqߓjJHaQ| 6aΩz9ϱF A+ \l#s:\Qhc'B7':R`K 9TS vFD:)J@)m`$~ody&H!Hk@\]5 <~[_*;n{rN;K$-x*x0Zd\ͻfWSJʫVTkWѠ'={x艣Z>ފCn m,J8VR[Y!\p6qǩA7Q\7qo1XR4l1DZOAH ߁#M-$ l4))lfyk "DbE*GjYNo\p\'A{Esm8RS }YnvY10S/Vcߑ+B{¥e6(3J/3 9VF>ķ|cƧ$ ͐ [TL4FJpD>:I;E'4 @вYCA)Hsógq)gߓ-aP+1{W 6963c/GjqɶhxR+kX! Ynl~ W{"XlI5њRQPqKx 67\w?A'85./K 늫X*?O焁 !e\[PB#E%XR Sf,=E[~~R٧p\1a౼&|Րf#%M2 $Up\A"2*i!u-%kc>V!ٲDpXJ+^5eDi-V)%MWSyh%wsnK; Ͷm=n/~wc;?i-/sϵ(( FfS \}3xsIN<ճUG3$VitW164[Cc,܏ðjmrؓXֆL63ɲO p Ol@ ,o_QJ|Gl+V$cWl4e7vlm.iCU}\ܿG2&ROv 0k:ˉ||4:[?g0۩0L,5BCV6{D~Om \)/$4J[Պѐ"[!7p99er>'f az9e3ֱc P X\V A}n<˨sVúLbK"V_g06d2ƪ2|H^ ǚ폠jBOrɆK9ѥΙKhrqދ;;Ɇ5eiH6(4!'/KQR-y/ sIV03C5t!'9͖Ů6)=JnRY^PE!(TvFt(4 r׾"3EHBpݕ㜚ฒZ1>nev3_lY?yf+4F+Zݴȡ9n݈9~|93]?ȆpXY"W.aPcyeL$9oxWزm9z,a)q=feٺgա Ng9_ .ęq<(GkW,H]5IΝ:Hմ׊'|<3LYRfu3߸貵ĝ:uO_’knbs& #PxA"씨H15IqK#xNT-?iFXb )zG05(m`$jӕρ( X{F]u}?y7[ruUWuuMt# 8(8x=8"" %6dιrxs w.Yg?U{{?~ׅ#͵BɨHCM,D ,Z`tV(%;b4 rxG*=yIY+VJ@RV w_[' H' aN &D Hfkyo~'j\!ZMvBksg`ML>NmC*𯿵Ǟ~{ϻxOyCloy юAokDX"c)yLih*(?w8?*TY9o}ff6|;Es5~o'2 +@X6{xLxֶEay2ͩ|֗-#w=JAe:F3ܨ 1diPuJhC3 k_Z.ٔsAXEġz_<~AQiKJ<|̺C Ii"k댏O2 9y3LL$DQ2C:Hd\V2ъo|u^V,̤k{N@3w]a$OfBI 4$IPrBr-f!wQPvMU2$q/\XU*ʼZv-7LA@F`@S+!K"X.F)Ys[h|oU9f*WT ]|9kڹiɹUX̅!"knW4ঀ.Zp#/>gC=d8w8!I@381#6?l)'"|BF`[ |cJճ zc*-hPhk8wNTpr_Sg>"mE_X_4& O%!W<8gLCEocɔqDxÒ~&{8zǝymM7.Ǐkʫ9z>kCq+#_3 4A (C: _'膀ZXQ_AJF_I3CJ_|5Q_uz$A@J~+%_ڐB\yIۋF3"9Vp8TZ(`XZJXA!Ƙ[bO *!583ebXH4DF4倻$L Z[ 2],FadqJ bkzݾ=cXakϐk߉) x[rS Œnnxt=c= | ɥk Gk-S5\s [8wey ~x ~AhM)*39zV Ϟgn1.U؇';H]·R ~a4"n9:ƃORޭ`S {}#y$Juh3+ ]Te+ɩF2em)J3ӌ0Ja? NfY{Jy<AAgyM;QEkq,Ҭ ^᯻ԭ8U )bDm F3$S/7~ qb Y-,p V+TbniVИC?}&IH'( (ywK"5C-2YqGm!`pBJEXԙJ)ܗ}SpֳصtsX;#$1 s,()(HC_.= N$(TNH_JL`9XS9+GOH?TVF8G#( | t;5%Hʘ^*EXcbw|xiTV|$yҴ*Ócܡ,5˹ d9G1V,б+{>9 6oⱲY ^"ooy wȏ{nɟ gz.2X$*_Ûz# HJp '6^3O1yNi"Kuw/]R`p$(Nb4k@`d 5V 5mSlp( )  ؑ͒%pv.ŏzD76Pp%EM {F{[ʹEYfP@eE.@Q*n;Xc֘9a(iNlawqpajIw`ɀS4wj*?TTE:X&ϼaoXXtBY_Hz9^wJyP)JG-KwBJ ::á E\8u书(}9R(*vV;1^ jO+rʱׂ֩Q\G2"%O?lf"|채0\qt gwm(JSjPc]zx䌺nJ&K$ya d, (|FnsoP"V#`c&>#c+-+)O2dՂɀնFiCg}HQY( 6ow4vJ%?*j X%Ao@>ׁ!VN8 K_`J$!(Ur+ c8JN- .Ue/2duyUYnHfҫR/vW0`q`8>GxicC}ԾaW\>EqCf3%BV쾤ŁC3:33{ Nj鯿OofX.;k!#m~`$t3ڧ8qT>ڐ(6Ը⺍< F),bm%H(+pt/=B!i1Zl$.*`CAcEjq0ZGQz gIBTD]*d{n'Y8(ȺEAY"F P;CV k9Y ȇzcPk6N$CNsV^/Mmo%x#?抛o<>c PJ&v~,kt [6J>P @Hc vs֩g)ͩ!p1l=KOzK7xa(XJY*W,Y#J2ʢmN[ع Aah9طo#uϯSIr8wf k57493ub =?+b׾YPr$|7;4N{mX#Fk`~yx&]7QTd6O0T|&3oW~O8"lmvs|gdhr4J#%kl";[,H5ÊJ dkݱ^ZkF7 Pf "̰"ȚPXc81b(7!9_<8sRRRU"҄B29Co5xC|C s_X0Y *m8JK{%%mLS/XϮVԎ0"!a_R4`Je7h ˑԅJADg}O|\wMl߱|#߷?}nld'W\}-?Y-qTc/A Z(KhI3_3P^R(i,AƁ>[$--R mSB8Z *+JK<̞--Xm]/pL5I,QHM<{≧; !Iv/sxG(tE\-d۶INU󊟹/~s c *NmܗS AF~g7ı>_~L[O1R=s K30Tʡm@cbzXVB JSJ0ޒC:=C=Vz&xɦ+Ful^u~#%È S135 sC?cmmHwh20-4 ضIo`Y]+`- Ih !۰ sy7_{ <0b5SZ:N{1c.ޭHjIG8rBSg<3B6L1iaTITǶSZ>>NYJr;V9'E8r,?OciMX]Ļ?*t(J1y*8N0*q{.qL%t, {8kPnfo#!21O>=4&2liRTπ|W"QU^"s>:|}INC c 7ܶ'RR253ъB>p g2++=X噧Α $VDIBdyvCnO=zrX045 }B,{n.hN6)~1jL]뢵1beͭ$TU~K,3-Q,t KZVڭ]3;9i#E@ Qtuyv>6z.A^$&pШG,-) \޳L0ox010A e2c1pNQKËd7ktP:9"r8u ox9/H䖄  yv4cHgdȨm2ZÕ/@ 4D0vH%8LU#XʱNw-A-HxRNF3,#* ٝ8} i2jȉ#~m^T^N-f&`8ZϤ~pyfN/\ʁ P ! B#d҈0) >$Yw+esh#Y)*iƵ}[_|7S3鮯d5n|Kw'ٽg// TYaKYZ=RQ4~[9}C̨4"JpM%eepOjr׎Û$_>UFF=tKAhfw}_>Y^,Oj2am$ gRX0|x`|fDqZK'[ga`Ɛ-MOUl=ըkhRę L1Fȋ_y#woei_BU, Vć_#|DUj6%wx`QoD[K6>˶ >hAvo &k풳.IX[ pƻ?z3L(J#\u %4V(JCvlJ9Td €vo@Ճ^ f8%&[AU2đLO$G=?qy^v$O9j" "15EH2~ĒR^o>bj@rHѪ~ JYJ a$ʜքfRxt^!hC{[!Zw8җumMX8")*G{s@!~$I" t)OJyڟu8d@>ҁ-)Z[}@J&J67C DdrLRgjrv4Z"'Jӯn5VV8gV%=:V/ro\0at1y ]Vٳ%?Udd!_ya{`(;zƆ/_a})pid!{ EX] 2(Cez_$%I$go奯}HXga SCPqV})ѣlrDqs]wjr$AEG6ǯf8vvZ)j WË,<)2"v4:2U iMhB+| Μ+4v_3(XoF\kYgy{(KqfV{AV( ґgN8}3q n?ɅO2W ybc]Hd" P%A1^M&@{߰9mp~nq=Z-f7Hh w(~WGO8Fϙ2IIZ5:DqJKD8?#&nws4OxlZsBfugO}"BgrBWa[<8s~Fk$jJU.'LJ a\8ƣm ÈpHVoW.f>n=~$nHB0ԾSi5TGCjJ>h㥈cx3B+E<`QA:CVkȥ|pgpG /Vk1L5$JHۚ8_H$dF#F!EigJ;vNG!pϜDAjEEc2#q|{{}ɺ'. O4$hWNY)Owi Q-v#yK" J2(0>$Vo$㚷Rwnw_a瞭|Q&D8zd=@YXh HEonY`e,8WG-p^JDV#1:QP<7^J)/h%&d|,TmYX)AHjG{.t2Is(LB,M`ZhdGl^2wBb\fXh0,,a"Y/* Dblt3ЎS %8ؿ5f2Pt %A)&湎ż8ł g`%x(k ٿpL6)ALAPz\.!Y** [',#  &k q3?E7#alL?z^$ކm|D6 Ms.,^^#\Iy/d3;Wl!ZDL]2]p1Z'!Uo7\~~04ĉ#XzRi)K/#t^S^ʒF!wpѐ!8KEDI@Uj&SVVZyo7]sLǓ~#D21iNla4Ԓ+W19'tL_:,FDY84kk#df2fa9haSKEH$'f"`]pyx O=ӥ/=;*)Ea1>o)^k-qF0> "r0V8x.yfA$ %lL\WxbH\$\q6Ξ^+Ѫ!ɲAoH \j8!Bdh$y~XJY _$mh4S^Y(eF)Ayte4,yVzkmX!q>F}{i;c!udS槯.߸i㹫%;X\*r-!;vr/k,/"G[rmwlM#A w@zs*@1Ux+/~|d똠}x$T!AaΒCXS~?H$`uyɲo}? CČJ)ء-WZV @ }TUbU<{w‹4͸ذ/s=5&58A(a]~ h­k}'DDZPb3⢴h=~ B":RU>Ǘ>CbRZj1p/;g'zؠɆNbr">6F+*jI; UiuݚpSS)KtlC ?ocd k?rܰ7&H65bS-=Z[֙lHִ(/qBS* CC=By N|ݼCh{I]i$B>`4^-nħ\u}]9oF iR18iOz^|ۼcpX\UڗzJcfTѾ0!g vװV+Rz#͛;O0`2( 㭈P3Y xmc|!k 4g$rDE`pAS)piN7TD g L5dP BAi-=C :%؋T+q'Wo[^$=Zvx̠PqN>,c#CZ85Ɖmi"(+%)&'s)CG}d+, )D0Sd\5-UCoh>`{Բ-׹{IJMff1[6Ͽu#~NHpFpn.ewK[7x d@Ŭ KWzS0,Pal.aeLF]qo\o{̽H')I(F3]7.:Fb@p!;f2RUm?S_&˯7J{j[~Ҳ4tz? |1d?0,rd(tk?%  E q+qK9J[9ΞQcqCh4kDCGJuDq@ኟsJu/ Jl~֌Vc8Rf8(/8wۥ-j O,k+9Qp5P]2+h-Ncfn>J*kZq-;j:0qf+JSo<޳|~OEEÌ&j]iU作(/M'b}U*@pɞYY-Ni(Zض{Űdff;RGQŔ*4 >~URQUx-ZXe! רjZ)nN1Ƚ>X牚 ݒp#{{0x01<(bX@7'J<{,,~(c1vWǞX B2,-; A Fe1I3$8*p 4ٕ9Z e&g "Emp`amqHTWV ֗ƕ)GOvo A\YM9Y0g7^Z\|#lsE[cG]./ jv Hgd`sS7myͺ".xu4ǂ45BjmI!@pҴXbVeMځpY>z%_,FfT뿠X0P~ҳ@PKʗcz)M2~72he5i)\lɦ&sCmXZ\{tFiB",c/Vl *$"B+,Pڄ "A-. ,sdqܣc3Gئ:ܸIyG9v rC' N+4&jT4VCH˞)s+HHUt=(`F :'ҨK%څ(+)*MI-|$JYZ5<3X˪HRyro$U//+ܮ>}ߨs9\}wYdY6; !JR9~HrHH9 )g'$'$ZL "Yg+>w\søѳ%=Kk9/{}gqB GY m\4+CLJC^ATgB~43'ysIR4w+6 Á1rzāp2 ɉ*ÓՊՁBz>UzS>tZ1aJCgDp\@'$PWg~` <鱾YpWWH-|gjrrd#w(ʸπka3$Ji} n5r.LN6\nx ı#{͚'syZ 0QT]!JA/kvp o,aE5d!֙ *`@[~, L%gS3SIM0AL]q`g3;ͯ>LfnAg*ac3gy`m3ZA^(}dل ;h8\u$31ݒ4EWP#y{ :du9!OلP9/( EYK|gˤb0wrwT%;߬0,1Ifs+JƧ64i6}b/]f/1V+Ch0$f1pZ1l9a{X_e(,]qqKck8jxRúW|!wylvX`r5ikvY&8p20acG][oc;X&: 5M|~vߠ,Ӭ-PQ)I+f m={r '~ 4ׅfbz~sy$=ZR) 10@pt'O8 ]3HOy,p7B,^àrC3)q2AF&*> 75ƺ|>G[ziRjF몒cmJs1dRR3!>):/O5qN=/ի !?| mI zw{Y|Sk4YJpݤ`X!\drmi٥p}wR jH+V#.PT a8ʨ.yKٶ[˄H #}xrVuBV*:BxaH# Fȁ7*L]sl5_\AT+CYxVsinYV8 lX>ca@+Lyk%ܲg!ry0nJ3/$|njkh~۰GMzc~'-'K b,c';UͨrB^{]0"$eUl0s9_c|drBa LOEho8wEa=u+rEYy\bQ!P4疆ԕ8 YYOYY-j:*n_Xl <6732Aɞt7r\;fGO gNsV x>xx3+;wNr1CN,s3r+X:`SUAhZ醭>5g+m&\sgQNgYJ5ݍ~VR1O7YiZZJq䐲Rx5µr[4)˚N;j1wŋQT&xܩM6Ry@l&YGsrTٽC^BՖ'" o >c#˝L mÈsG(taHmE޻ik?0g/:W?? "{8a#4AΙV}vcˎm=ʽ_0)ή?M1"}I#dsJldf@Sc|S ϑ 6Qdž}<5Zi<0ϭϻ{;M{"a~ƈ"U֖JRW50CN: i9ʩ3?~q+> l@sGvM֒W oGYS,K\kR]ϧ..y 3Jāc a+G0 a 4c-4~7F$e5jO.:3-@XNmj,{~˿B:6m.Tr}7 Klxve-i5ưVJ, FspȺFbI~6YxYAlcp6< -FX5{|󘷆GBPİ\p][g$Rrk!Y\jbϒn.ӼC4 E_sn5ߤ7 (k #=ϕ|앸fh(j4oABH'вVq|=9n@ cxKf6p|%K% hN BZj_ LS58VzhņB9Qy,T\j G:>CV!-kN$'--7k@u$Z[[>ԕ&g!-3KB#ŨW\3C檣0P+M J =!K6K5:NlG L?rL!779q*ylIZ{1OJf)|3Ʋw.ᙍ*FÊbsƸCίkM!PUf`,q *?BRH?gw8R03L]Q $Q@e|gD}5L8, |ť;C@^=X7+_De{D0C2`o_"w1Ff7ְo$ v.Lޗh}!37["z#Wغ[PkˊQEƃ.F;p D[8ŧ=}mÚ0عFiIqI!3yipQ@3 ڝc4]xQ>4b 򩫂r4>{K#FzJGH &&;pgd '7089P.98I>Y߬(xrħfyqylcDkpX15|`W<b \jx{wBF]4:ok˾F12B"dD9ȁ&a<8Bkˠ7)T]#D)5mG.Cׄ#aISUdydv<t&i]2Ե!kVF.ɺs/Kef)d2$X]SkCʪFXˁf\ '~6l?<ɗn'78xN#vyk=C[7^>vOUB_R'KS`EtQ4ص'ֹ]l BZ^}1FT"9ǯ˟}pۃϷq?ݵ aA6{W. ,:Ok#@U5qk'|,fw7?H*QJZe`(JvͣU4K#m옌\D5R4(>w-k$.MjcM~aVtA3TEXQ/~*[dz a-K+0)+';=Ac6T<+SOG S>H\a!,-SnZ#v+nHqv caarz=}n&Ն~/`y3# cǓޙռs;կe^J< xK nT5wj!0SZb൵᭥*mY,أ}!j58|U~IÍi~# y5t5q﷿6^K_rv܆w֯75x܁A"+$on ^}maD>?Ҵ`*ZX+v|-&f&ٱg ($)d,.w>RץnHkoy Ic#/;,ec3' Ij S7hN'&JA\Hz*embጼ_@ +|sv~R"[BWV'A kHK5#\(3}ͻ?p;g5]>kFV`(JE#ܛ$Bu6!}ӌ$f[.ua+=ET!$01I<f&}n㳽 lLyX|'}|oo4SӉ1HA $Gsyw{yN@#2ϥ;Bm)Ij0iz!g}yM@qxe۬OHkkyATg$d#(ZM٭y6F.'q}G[?ANJ<*&?A)D"Qyz}KciHi3V4L$^a3-0-}Krɞ2Pk>gz/kN BI'N|ˎ5ٿa]1d0X<ᚇT9CRB*X62)[O>l( /5O'N8Z#mcn&taI! F3faYVFZmU2|?BJIw eɣm05^l%L rATx.?(,VȁûgxNF%[CGnTWK~0Z8r4&Lc|WHY7r/*vAftH{F}:`(+˷I zLb,W,5^ش" Un,o)s*< IK; Ʋ{W3K%̘ J` JW(+R~۫SϮ͍ >OO I3Q0;0.jY\OO.RT}d4<WK#l;f6%c?z$NŮ2c'ox8u=lo3=OeGG C \۰wNcB!ɍG Ljn_*6+C &&F(\;aҌ-S!iI(=ʲc!;t޴0X(zAoQVH.Y9H7`)JW*dǖsw< |_XfΟb}<)kMwPP+Z_ڣ-J(\RJ*afIV_lDM U<"|$뽊NL J0쥔%>&'hAxlc$OK<)xϟ;Xx;!qg6dIvklglBJ*je엞;w`#dG'+X G>ꐥ5M<_1.aݓo hĮѩيHSuq 3gT /9251E>YO)zO][ΟKIV$`ob];lJV3=j吼ڰ}UWM蓛[!i\p,)t]`qG \ )_ ]f@kgWJSז<+]t[N5u 5ʌ=)1F҈1,keQch58\@X<#jfV͍QzNv(ɳh#]jMY(PrN,>C$0gvJՙHy<-~eITnq@]} BU#G; UUSғteMQ DG5jn;#jd3M*(msnOOgRJI'>Q/|d&eLLF”$cF1h ]3 ; fcRo+Z{5:Lc}aN}Ski'u"@>)|H$S˙/4|{+ :S\}3~,[ISx7=$[2=uƲ-,ǃ@Z&-7Rt, X1Ѫi1;œ^Uq6yTs]jZ .׾f{!ӳs=v=ߺxsw7G?JJ2ىl`}glGGFIbqi76;j1XvGxak0eF`ܔ8Ѥ*,/ ak6]s㺲S=0iЉHlHZ<0R3#rsF`" ȋ=䙕\3{O:^rbݵx^?隠wh6.dw~yk7y'k|;x,r%yszY; ~ K]kvv|zփ=gV3+dLM& `I!H+%zoDO+ m( .BK+Vu2aHT]3$Rd~a^ٜ_ۉg׿|xh4|m5k7"/+hwQUG^h&(1ЗUҖ^dbufe` k6lHmSCIo]8}(]᮴@V5H'nE O0 h5B#ȗ3MVc&Jj1ya3k8(+;MN/x, E )%xRIf"+4t[f Q(H3\ZpyNRԆ0van3wO<N<3`WRP}K|gjv2.B݈@>*Op-"=Rc7]Fc 4yQ˿v d} -azz ^<p qmGѰB=DXam=(5Nni6 57>w7AfjF#t9yZAgϛ 0'|/ģklk" 1ثL[.lTe7ÃptƵWMm*`jz\0Ux~lV]cAI 7\!+Ek{.Y 'yM o^=[&ond ll:sdLfq%'GyV]W<" IDAT}Ѐ|F#ľde= ]#!$A!i/b15b"dja/Gn{cYF+'C( A:9Җ&QM]A{"Bې,EFlTt;ϝB )LzLs!F6ns4eqtX=k)BCdWJER|_*s['ʒAwDH/ ݮ“f+Uo:KD͐Q?(*tx*Q.MZ E@Wx>r/$4M|[~.FwY)#rrfh} d>}fےGVco{=E̎-1{|)7wU'\wx|$}AIW+^&ۧ%#:mg65S hMEe bhv(--<$ ` K9A. FOj7Uu=#l{Kﰺ ;7nkUUDpCZ%l۵pG%~ϳIsz$\sn (! z#MQYp߉k;Q+AY?:Y  -xY{dFxWl3ܴOnc *98O% OnPՆ0}ZM7)I'4ոy4FоEh|de#Ó$7È?8|0ٌ0"(k$ i7H >G`ceVwfĖ̷C\ytGZ%;na5v`nwD4Ihu"f^hQV,72PB;ljy%?'gx.>A3 R&B)G s YV2R(rڽ0p_╿8$jN1?`" Xo'-d}* K:RTafA# s|__0FEG25O-et%GseSk#JZM[}ǑC[,:LÙ=- ݁Kyvy,FBǾ|F[K u!=.cj0 *"/XK`ii8&A $![ TzX\⭞]ca5ybT Gu{tQVm KVuiLq]l3M>3e8ȍxo>J21+UlZؾ{H&Z<P*M 9Efua3Nm9x^@'M͌$ VJ v^ 챱a٨iـ[sc꒼v(xenkBT(4b2ak=A=K_镲%,G䕢Ю^D8`  ZGj&`ib,KO)WHHiRr-ko7ٽw/N<4l `ݞ1cR0+ఱDxV\w=w^gv}{%s1z1{AZxBWZdMcK/eߠe'`'%‡~FY jBέk>{ C^;l@ d;oLMlkVlc~Rɒt.[Sj*e u_K B# i涶U0Z .t]d"8#` A;z)=?2%Qnd[Ҟ !$W]vh&Zy` =6f"$w3ڲ<|+|9TJ %J$ ql1f\S}mhq &GDR)U)T:9s1w}o1uƩJs~+En ȆXk-Nt5uр!:nhzpn/giv(*,RQl&T"ŵ/'ƒ5B_1Qj0%J)tQA5w4Kk F;OOT7Gh5wjBj#NiNUOISwBN-35S DB!pS xQ j5(] *Q5"N2'4FRt w&УҨ:F ' Eq'IX\DFcBkCv$mtSS1P̵s|~yHK%z΄xPhhÌjRmFl8͑1Cm/a%p[=ʾ[~;s~cO>u>lO,R m9h깂wzC 'W t! ڽ0\ 'Prhz<B:O䙻èBgXX R/Y2K5jˏ^EXɁ Yȍ m\%xsZrOS,$-4J*B"yhrϡ5zj O;~i*J MI?6Ly|k|Rk.::vT2Kn ==VM5ɡ}jHeX.Jņ43e.K°BRAg^b s+nftd^oj[ *fKmr $ac(͜Y^c WOy*ȉ(`bB[e a2Udˣ<mS!ҬI&"cU1dN"]-ưcC@QB7) v(Ҡ5~ TFkh \b.Sܲ-(J{\^*,V,/rB(1ĝNs=Lu HSR(_lqmPҒz%"`[:=ޝI6FxQ#38.0"d"IL$1NĔ%T>NI*`qCSciTʅB FU=3=$eٲ!FYXt+W tSVa2ԥo[c4#Û^>ֆ}Snq#G]Bp0>e#̄R0-uN*^<V8W<Ȉ K qJVRT3?ciOE E艍zt-9}Yem$E AklĚK/}y*?w8EiH2H+7U}Q!rA^ԙNV[.`-/~<)YX&[ Ɉ,%RPS%uٲJ[\0$˹Z/(咧4+8.V#MzAT]1,ݦ( ǏI7q7J(a~9 $.( ͆OWP>u3 2jRf" c7l,ժ?&չEO(<&R wݭQ<̙.Z邒K/pf:d{ #Jjž&ѥf@SF5L 2R lJ;$[R%:͑*(JMddqE22V%LOW^}wej'O,r2KRSW) KceY_\ IW($x?>O<S! j<ѻL]9B9i'?Xb\mh{u=zS-?mw<3U>VdAf㭫tRH `U,P*Ah5<dK|ҀĸϘ)2[ 1RS|A\:˅0@8v$Uѥ© `Z89h\(v^ב'gD~+~o|+\zԛMFg6pUbw07qcOk9h4ٹBr81v^u /ҚjeOrm9|0r6lLA|BX&D:#dܨ {jF7jI:DyGz۞bgV)HnYCsǻI5Op`V3}=V޵B7.f>iQ (a [BrXY+]hǖs:)HƆSBɘkz)Q _N_;&Cxޘ~r't)PCK 6GPh7͊DIbeee2/$nk|#3 sAIZb%p\k-)F8> PDQK)pY4Z 6l$Nӎ) Mg嶃;ITB4#_K?t ׄt!4a輓qٿ?=G)yrCFZHSJΦ#AIt#7P01I=ju^iҎS 0jjaHi4ȗXR@j3+Hz=GPPaMux1AoHy;+2aa-ZV'egi`r,d, z.T+֣]욖| pDhqTdD)i*\첓8t{a!+9#<Ը 6O)( Y]Y/9 h}Cȭ>7Qjp4Sca݄0P

7J2K̭D rtB߰y: q_,~L C& 0W@;dei0E)5Tam2"(uLH;Ҹp.̛.c̡cvo:8EgP&J:)Gv 8.7nryt geL63해F=%x`0H7d戲$uZ 4\V. AN>H6oj`T^7EJ'*yn0Fy( BGb 8g?v/A/PH6Hgg?Tt'xzFyl.cs + IZRWq 2>^u :o'ncZ%XZv}{(ߣuHt!\*M⺃Qluԣf@%T1 }(3vljG~\- Q1Z"ZLΫҗ@}9;7 5A3b$5n >)V'M ktVEI8? bh_6cG)JT=@KCPiaJbjzpDd?Iz# # v[cu5auǑ8Ww?suXzn7,%c!~ࡵ!EP0?{К06=Bk.5|xIR+2bmnLXDނ˧H HemO{ƺ@'}Pk( W T6o_d4nˌ@JA;LN9 ~z!"aBK|/qロ{{<`/9?w;Qvn*C:SOHj48/Wk r8ngl㭭*y 1B"UU뺗㫔1PrͼW?/dν]"W|+qYsGa)_u_5J+meaQ+>+v CO *Nd:L!AG 0iJ V":#VH&=8."&AӁķ-%(+,+q(z6HZ=Wl)F* ).وj 2Z2iiFݲ O*V%ZPY\E>?uWŅ Ւ^#ˤqk+$!ΜghL`n\c4ZY錄_R+n}rhh6BB5~^0DN ř ~s(Y[K]r:-FUaC%ԙ_w!Y:t(ߥ9+s%u Uֺ{VAik5̭AYH;,ZdhTH\f7,+I w}h*wW )' @U$ nʓ$%N5k>4G|Pfu-fC1Z09Qzn GK^y!ťZzٌv7wЪc-ATH]ϓqYQN%J9OV nf]WRU&F9YPOpLJ?6BĢhm£Ђ43Z.ZUC{[+%&G-k,yM0Pcc kG Y ܅NN*f()ٸ>&TC h4|V{-N`uz#dzhŠ$ Ǫ<NUЅ[Kti2TPEHϙ_H^/G I(^=C /~ Qb_|je01^uld C)SMӤ϶m,-#5x]|#N CsK%h/x㫧z͓b'%[#|75SmRZ=Y"; u0ȸ6OpMۜLMdSSŢ ~<K"UJcZLF#. Xx4\` IĤfs̺U!qYRrE<6箻l:WxR*RIABhWicX<`i <g' *^Stv~ԛusjA(J@C zC)藊ف܇.y}zy/H$]:5 iz*h<OҊPݿq3uE=bzCJ -iD C6.X:{ucRJ0%OIry-<eΦHkɽJ^Kxj?ONMQϿh])Y fO~|$r7߯'h9 J)jq_)_X}:B]A~o!FN_OC1϶Y}HkZ>~/+4jHi W4d&1k&TGF4o?2ᅨRU!V*n2זKÜFcLByWOP Su˟Ve=!Q 'Z'9e#6H4+.dߖICJ>U| >j$0ioЉ-S ͛>lozZ#,&'*`,ubS`H.$O-[T )?J1)KHOKC-?x:gj<`CjLy9QB*{zeP0,݋WkbL@&rb#J yZ>ly˫ 7q^KRR4aNH|Oa|{]J]yg\=I06B)YL| A BIŶM-<ɁM >Νu BL+8a?YFڲXV  UI``h3ēRҥ,{~ |D?)KMóʋDX˦--?gC }vY],ZShᦛAz~3ya$kJu^8-wvwh:=Nx˥3TٽGY.i.r~NIдȒ%WDsv!D>t36Vѥ Bz=U5F֍U6onjAlܢV#:}q^F:Χ>{{_ZKtZZe$OIYlg>HC䅡Ԗ=[#5l8zSnq*vhr͕Lx AhxӜ]O J/y;ƛ~ (K<5R(WMv!|Opɾ4j#+-鰲^ϲFg$`)0 ₋.% }29*i~%È6LFԫi8=ct#nj JI~fiߗH6WgJ>Hydf\n qS }nFK q34%AP7wh-"u^ LBPTxKTa5"ym؈jXcMİF`p:w~ f %/ :˫0/APknB 3HB)R!O?Ĺ= !0Xv#*g=3h+ $Ta{OzTZy1 6v| dksϳy]*/!ĶM,vǚ(PmX[O@ ȱVTIaߣ(5 B* SXv .w#l<ġ0X$ZK°xZvq~EQpDn 4iwK`pcD^S,&TkW22g17Ai{ EQCyAuj-Qص [7OjiI}AƶH⒛o8aq)vM'<$6+zp !XKkڱ?8_`J+<_P y(F27B#{S 2w4<+AX.tҡOIvsľ{>t:C*9𷾍Q<&Vۚ,-(rW???{kć~ě!;&gǶ:/e{*NBNJ ai~z>xJ3oʋ?tAv=a xI ukCbTYLA' _ȧ1diGAi *ؐ >|t%@ < I-hs)`3'&wI{ _RjM-F!0kI H,J<]F e]U@8RܑjJxԐbAHpǽGdÆ?q˲<ߥ}Ξ9߻1/y+%]l۳1{$cR2W:oy_OXk{1>ɿ~AGDX=?z]7/"9> 3P\-_ gJ3= Gx+^D#20U/ xjc ϿV5|#ㅷiV0J2+H npK'x{OcA+)<72{j0E^`F0L>hY 2QRq6x8W,x22c4=d]~Ik $-XiPP$ c%7) F=Oܘ$/) Cޤ֦)33v+VzTK mxDJ[7efgn)/8TJ ~y|єCE$,Q !, u\WK-C#F'i h)7nqo2>Fn|'9uSj z===̆M?9ϸn;Z!B*jEZUI_x?ddYę3d*h't鱐|Pt) >v8924672V r=(u_Q a0(|,fR{ݻ1V1D+>Ife.&=IU*X8^ CNcڧL_ZFGNTVxm`f2`n)cDH75l9zKo) XM/(DIqApȀt d6tY(bAu9ߗM!1"H/pyn"22RoT8}Pi6|ҒRH* !Rk-x[M=]CQ?)r=Aa˻1Ƃ4nu97aatD?5Ԛ![^n?竟?FRd%/i3YZJxqŅ>x6>Ɉٹ iYOɆ$_4ʞ{wMaLxlTC+/S=4jE;±=*EU, }M h40:2Zx(;9kSdYAyR`-\OXSSH!}N%eIi\QjM2:V%Ma #6&GCxe_B }sDH1 YlgLX57}H6֜omu"GY|ǾƒFg语"t9F=̝ZJ6b%-Vv{Q*xRb\ IDAT͞6eviJ:p^$%T+dI1V|0+Πe|ƲgZ]A1tY$Xc§ZE'~OsĮ qL(vUDAEi2-LF܍R 3>|:Oj|ajŧ+$EH!<2^?/m ɽ2,t WPZZ\qtTW^o tH(X^ap];Fic2Qza x$P0U#㫖 !}a?{hK7|޻vW}* @HB#ȡ=( ^= "Lj4$TJsa*cq= 5j]k|7|;nٺs*YcG Y+a8_9qjsN12?^ <}߽m/bzhDJ#GY^Fx`wb,_$5M%9'+9 l) Ǧ7|3&{`m_^sفx_j'?I^WS/Z-X-UCz݄@I]hM 1_16 3v0w8;Lì,QN~>< n:'_˵| I.Uf{o{3_ e4>'#O%Vc6סI$dZ -q\"59~?YtKhcG9Ʉ⡙-+ *vP\scQp8hfA {|+K YnZGG&{_ao٘ZD(,wĐg0td5DC MH3.4«Wn/qx^]r=j3eh`I)" fօZ98zgt!0dn_͇inyzҡ8D{ )%B-ޠ OSau6|IsӤ@JH@ 3Nn@*Қ=хVJ:H"Ih$R鮮07A1ח_:]:zNoJ#|E9Ddb,`ߡUn}&rwzB0d+VQtҤ:HX\q2\_AƭTpAiPJȻ|>r5JTv\lt9')qj<1l\|2<8!FUϦ@PR & $j :!gQɓ+}=|+6pONڧoN`-GF}S;ySlؐ83#O,/1:Vl{+Z+ż1R/ YRk#!# N/ z@!GuCvNVhVſgf4<ͩ(^m|7S_ I'AIbX\OHMf2Rr*u>F(Ҍ rQaW@*j!.avBQ-9RmǤC%<~Q?$ sh9K;w6CTG.9 ) @3+ҋ@GzӃ O7}oY_9,/A#'[ 'm}R$sZ/) ȵ:X ZK :4203"#D4CG̎Ͻ0nH@5o{:kSA#վ!Hhʁ$Җkg .$0 N3}P43 ScUz>9L: Jo|K;\wE 3&rtLKU.u\uݫ ǎ7stwFY`W/zs<'`z<5FwlgS=C{nZ*1L!mA){]L',Dٙq(g!Pbbn݃8b8zl~c _w,7i{#z%*qo+Cb\#t C}pҨ  iG)ٳyGk,a@04[PÂ![.x8)ض/mؕYrd2䄾+8|:aP(E׶G;T{I6jbeD"sMv+p~I崺јqE ^,/uY^Иv(Go!Ϻ@ )uSTxuuW-gf*,3… xe'ɝ)Yn $>2j-<7)\H%{}"c8SH3 8r01sWhbgy?D0Bŵ8 لrEXcNbL5ari _sn bpˆ {nfПUV9yn9X8aa%oS)-5qrAV)(F#mQʑ\ a#7>au߹k ۫mbi >}ǎ!) _J|Ϝn85 GSdY熷 Zktnظ}+aqⶠ:y`q@)Y BEI3pEukZc:g1"3vSu!e rDX]ɐZ(en)n04a[kf}NƈsAZ$`[V-ia]E KomKOҌG:Ø)Y =J Lk"O0PX0F}|[Q"RJ.܉ɋj I{OF/rNǻ>r{./p;cG?d* {?|k~0Ց W |c_>|gX^Y%*X~/y/q8|_o'xK8ypP{@!_gX^ms͠Ua-Ֆ^RhֲW[Z* kR#[ԆԮ]~HΝozYVwc ɑ#G@((D2Ͼf >Ng@IQS'.0%$ ꬄ 4X k `$_M9&]nB> ˓xYZN8dO ֕%`#'Y I ,J*BuZzIB q;AF?#qM gu?82ę|ҔA1B2}C9Hh*WSC)ɮ)|9XifȼrcQl bOsDJj<cS :M%#"4G)EIn[Vq:J'9@pt,3, M/?U^dO|?I'鿺{]GZ b' ^,Q9c?nK:B[5jc}rMUIs`8p`/~~VGXW ޭe.W}8- =eOGB儁RN?.@P C+xd4sP0$K-wvlWx,u4;7~\u;my 34 gayG|#alզCGNң¥F 4#Qn卜wx㩂A5B5(I .a%mJ*>L$S%A#Hy!CO65=M^>AriE4T]O8sOۀW)K\T̖$_aQܼ y.ںDݣ\+T! %yYi՞aabntFz3MI^ceGOҦP}ܒ)u(], iYYJ*2,kQ %SeYu]Ҝ\q][⽷N#sN~z@j[ŖEJK3H"E,&%jZjA涑RR)Ij%⸚Y @(2 AZ:#hUe"x5VFhkᏉ3ˠ_X8vn %TgLW幰m ӘAk袔 cӈ\M$k"ŔSGz81سL٤;$L6<sM6 Ym <_]EffwM3C9tl,4s>bl4$+(CKXnùf·;J,BGv21zQ\dх*2B*2ZAF<lʕ;ᮻN1szʑbߡ5NU ݓ |zUU]@5Td`LAӨ+!#2Ib 7W 4JLMrMH 7\Wn!ܹ sARXzųhcS#'1.|yݨ;pf$[ɘxw.h'. H"fjCzQJXU;̰s6wR iT} fwL"@) %jUϜ|A%f$ӑ`*LA7sEZǒeFk'Y{iȦ+cGT%(9\ A/Tdiνg2oX!y#'H}RJx|&lC}W@@KxRP*C$.S* WwF ;FE=;f;׻9%3][\xa"8|O5P4 xX ˻q"Ky б{xOX=xoOX.nNnKI$qNZ@t!M3:H2@"=E5T)<\A3n>Y$N.jLDD9rPQ\uVn~V(%PESz(}>6-^)y."-(pm<$LX㌿y3GӒ?MkIRJB16:29. s~0[ +$YcKQhѹ;4-8vɎ㬛eb,D,䩦h-j쾸:\gߓ$0R !mESd!rgPNfN6?`RrKSVJփ WQ

)ط A#ԑR4hBɌǰcԣL!KBFak.:`nE5cTj`Ǹj9`߽=5ّBIl! ,X|0`_<9w<% ӔO֖yw)E<|I6c|ri\ TソũE>osŜ:yq;Ow_x/ o}OI.u$O/Ĺŵ+KNϭ nCrjQe3͠ GQ$7D ynY8J+n!89pՅ[ケ#= 6cuAyxʁфQ@+,څ^S*Dl:IdN2g*)]$h$g"JJJ4履E>$~` CE6d=%ql#bA 84f&,65WJV A7$yv8qbxx"~Xυ_+N_mV5zQ$tHpμ0yrG5GB |Ia}X%u;[ay5cn006̯f IJ)LMFss=hB%'vr]Ǐ|Z< E5ɎҬpAc,uEXiX!XY}dX|q {2" q)Gn;rqA 6R׈L⩜u}< ʳLMLᗪ, ';TۨpSv09ppՑ ,J5($Ij<'[d</&g=dcsoȣOX^찡33]fie[ض k݄R)uE]O?'ٽNb=Gb(O[X q^%o%܅E7ܰgNۮ vJ[؅UK7\;A[pv9-)AH.|*k,MRfX$BBXȌee)fi)&% w~R%yfj 5ݶ8Xd{)in0f`y  7-.pQqjn@;_Q6+ҁ{GXSSR0,c5f %A4nyu?jP/ ȩq2:B Aug{N%,JigA%.L k=xGQ¦9ou[pez3&JZh#c4ŅFʆ43h~|p+SP*Y#f?s+I8vv28D-bNHb"hǖ,THsKn=a)8" 68}{f ZrK9RhgWL\ZwRM£-1c0 F8y0Y.0ZBa\0kf¨|5J {%ΔY[m#*XPpꒄj<Ή d!}8AV/9(y^޽ oyxM7_}~`, Ҝu _>D`-۾=.>ܩ~ᖗK_|<ףbtζ;Pccӟj~ees{w{ @JIݜA7`]eOjFPiؐ8єI%,, |gr̡I5x#)fN[ fgkwR.덡4ΆMDξ$Ά[J]tnjNOJ." @Z'4S d&G9ٹ>mIsM_`VQ(8=ZIvF)^ʉ=(]Κ bյy5+ Bbx6+8irѨ`a`40YHkK戧8aacKZ}LiX$I M.v1&\YBY^s/SxߍnùNa!zY#iCNC-P¸6º@Ģx^@^s"%%OO 0j _: 60SZ'OS,OgtKC9TSKeC09uNj rb5cc!y! b"_ Wpx.aa5 +;Z!ipb sR.4ָ.`^<1HO0Y4q!J *%I>4g(ooP Zjoi זWNyU=9Ч/(6i Sc xo7O ˣ'ډWcIяo7pѪKǚ\[B_PA/xczsΫT);45l ;d(-.6b Յ{_eր0D 'wtE'45Z!%JD;׽sƈ? @yez+#N.RNet '"7? ,N֎3C p\cd͢-rߜVjWjT@ FQ!"ѣ2莀pGC:> r@< J_}W.b8<+U{Z\o\M9nHaQ}j<7dY6jtU皩8Q4,ݎцG<Ω 1V>,4&fIb54 p:qEP~;yeYZ(Y\K,>6 VEEwR@G%CiF=DZ( Mfgi| in1,J*ƃ]yjc)w=cY&buLk_OAXc~Aie=qx gcYn~,ijC6e0TlK0 uVKGHWq:m¨G],(록܌]xUYI-= 39U2r6G{z{&Kca߾NnsDn=+H][NGD"2:VsPU59]Y/gzV5Ԇ{;ƙ<`P2^OXZ~s?~e|E7j0b$VR*{^#೟,'BVkwu_Λ&nF>Q F(b(e0;S 훅J6pGI5nA;ob>*ٚ`sׂD`!hEҎ(=Dz IaFFa(`qy S  X=`Kn]gJ eSr? aG,AQ͈KX|LBQ9GjPPZk/W#(J u0d޻1f+/|ыٽg7_xѹo|%zevE(%\~9w˩&l o}+~}_wOL][`\9[ 3 Wp{XlH 8"尣=>a*Îf6DXK9jf`a2r( k,}@K ($7dr?6]`Ӥ; Nrcrx$y?y3 9nz''iͺFUAHq^Sf)i3BS84[\{' K+}?z,+ +TIb\CP1O(GzYz5um,O9U0޼*&ԫkn0!eA$vOĤÒZaczT``f’n`ƐvAs,,5e:*5b[[\yx8g(+&[N:?ՕIhBmg,5Ya 5UpN1es(W, áQr>0S% >j1"9j fB>.-u^1P\A*A[gCܧ f;G8t,+靺3B@e)KxB_ XXH9tZz_LeԄou Y^XPiWz#⿽&NY/eq hm=l@_$MM|eOҒյ!Z{%LZ7c#(gorFYxt դDb;> 7@Q3ÐIԧ>E fT;UQoF JuM$2hLHPy#7:\`_RkmӞG TP9EҁE}k0n`筇%9 *Gr\4䉌PJ^2"ӋltZ䑴6NIvl0%YiֳJ!  SÆG3̾! hR8ک'h ͚b&_ k,v^GRp‡U% S K)BR =^ cdJZ3Gj~Q >-|N.WiaT=5Ґ+ί*dX`rb!Q=^|Qa@)b-j㋇nN {EQ1T4eaXZ8O-(*Pk&)%D A-, i ێAn1Njhm*Aī~7r;EYVQhtz%Jƚ!c[.>HYThxH0]MUYL;o*2o~#"F2))ZO"u.Qڑ=*c;TyBhW tUuE( xY &+gY !APa7MM,8$NX@]01cvErG ? 8sOss-N Nh䅡يX\Oy k9混x]OWrajڐ8f|"7}ƂϣuN<FU!_*<,/ #E#F7!K]CusgL soZK+]C{ݿ{fP%YZk&l$xɫpr!Y6;`eݲ)6DT5{vs#k8S.?j" %FCN#vFZI׫MQ'K?lT[PG5E+T$8kV+qT|C)K)J>flP!N RDa_ܠIO>Œ5* W^fOD8pۅdKeEmS]X[5&bʼ2@WG xoF3Fhm$=%rEٶu0x;袋~$WxCf[`FvWq/QѪ9I{{>I:E;#MЪPRP !# ]xjp8 uH޼f7O9UB%%DȖNK%Lxm$8R薖H:a2{l o0SL) p8LlcN< | J8v6Y^")ȭA¯OIXߎ8Y#GWȜ?va~y[xˑ{]ùWiJ{s?O|D. s47C}>Wrg7@zYnkуL6%r y~baqc8撀FEбBxTSzj'w`NPG r/I C 5Q+%HXՆ8$Hns?R$q#%yl i( dְ%P&!C)O /5i;~3|gPbzN:lNo$stsJ5 n 8yfo P#R@+ٱ :Q=;[aՎA)K1ed݂`$A"լ1aɱl S '. sAn *J͊Cx!nsaX84!|vݏ􈒐& `w_dD+%D)7s7[w, njE``3,ƲaS agѻVJ#+GZhۚuR*ßy>y5d+пM` ېI-zLePd%(F[d\yGQs&4 sK@3QHN%;BQe lMmgBR:&a`jj]4 hݰV`l,Q1eEquLLΠGR锕.X)y 0D1AXԑ߻ !%iV3ʌF3F#mŁ,.1wX\bQ6ȆP)pf!Eޏx8B3CW.(+saj%e^($ITK?^/_O|0jƊ 2RxJ mFgn3 8tr@6X%ר NO/`)j#Ybb0c ̈́VF jߔ}֖( wWP Aj ' '_XY-XX]$GN 2ovB=A3o?u*D[PyD{z$ KǥfeX{k\n J7E$7J1L JCf#^zwϰa8_Ď3Г- BٙW\(J19UgjC,I=H@IIyT(>DZI)ٺu T^8)VkDq[V^b\fݩpDU2xdθcS9v$uf2 vH {ܷ))gmŊXҒxAp|(0˞WQG=+VZ.S $J Ø0I@Z i"&cO?3nm@_q睈ki4g^sȍϝ^'n1;5s7||H}WM{gCVPIئ8o,2W/ 3률 ."D ÐD:p0&T^IJ,h`X:[~bP‹<"|$*a7,5 2(Ǿ4) "@-T23B)z~>.pHa∲g9Va␋6_=Gz#х!ZL#\ԤyֺVX/bd 0SE$b rOGw20HA+2Z&VV˱eMc2ays!@ksLX OHVz$Q(XhqxZlQC(ŮA}|)T nU ETbum=91ztoBx_X#^IQh$X( 3B q >1Ԇ4#S*S,'J.r$ʫgnY?P3G"v_SXJ"R AJd]RX2B k,3`-LhHÊ1j0n2)-M_xPAE$5p(@/28Q@/b3#7vHQ?8^ra欔 0d0 Z1m΍@VHU~ ɼ1Qh H&3JLe(4-EN|s8誤,4F@{ O|'I,΂.Rpw[8de_]s%w1ZpT/826KO_ <{$B·>y |[? p}[Hǵ:M)T_?ں&" %i?Yˮ;k5#j5ޫy-Ui8rG3kDPCbi:= Ez l ` 3c}Qo_TՈ$P`T@ʧ@{#0H'䴻%ߒIw,7X0Pڱҭ(4XXhzb!Hs/z)Y%VD:'B/Eys/H~5<-Jҕ zkO9u2BIzD[k,LN()@⯵Y|<=Aآ+i6B:Nj쿰I\LN45:= G;~v3Lj"4!BĨ `[OɜgѰI< I]َYoFH,J$^hP|RxQ fs/U* A#%RM`uX HWRiC%Z̫a81e>ܯԤ:{7οE>?s~& ѤKOuDa}r3bQnWƃ<{2t}wݼud0p ca ^E/faawWW;g[y{+./:3dYz`ٔ8 WcR~:$[y׽VSgNQ74׳PZVD:,x=βaN!JT S=VRC?78|\26GUdD!91wKƛ)zzo >az]35D@QU?>E^qN&rٮ:+-B8[S %R2YA9Q|@U8ͳ ߰"AB3C+^0R33Q-rI<"O?B{`*hM CрnEBI)(YtDEs9yzO Ȳ(PkضŽ!/ 350>FDűS^"bu]T8Ɣh(mni( BI4wDwZl,qҹdl!|nn_TV~c3=Sˈ*Kg}f3Ղf͇",!`پgO#MM1#ֹޠ g5Q,yUQ1ުqm'ڔ1My1ӔEIWŒ8X]/G͐3}CCY96nLHSC#tƲ)0j8֔8ȴ(JHZM4bxoH)CܙR0; ?عslXfXXTKOOl塃T!ARz=yc~(^*Yz%S5M-Xmضmv<\As&ɪ.Ċ']{zp1&_Kl2 3xΩK+練v4(6F)Ee`FHDb006@99޽rృ?Bg>6ZBըa&pHG *k<;XH\qb4%|$y b8[tY0l&WX8 ވ(4o['|Ǿɣa8 7c߯X:ΡGOzsԔJP&ȭ{9BFX?ېX{£#7=5%"P!^t5>RVˬU#D~+OƬQBؽgv;'*`˒/̩.s2ipx1cD;ǎ7^@ g}Lf+ ~k,?}^w2 ] aa+M&xf#[`aA>%=}w~E:fai0# T_Q38L4[$`7(C#F3?0"a76CJÓ*`Kbza\[B tη߯eAmMhN}D Gz&j=[? {(6"D# /cq@XJ^O&}i,俼Tlݯۼғ }3>{?.`Xo k"Wođ`y(G[ť<)$*"ԆcY&u<Ӑ%AEAĝ_7t3[`Y!{ܹqMfQ%w/ʫ{'_72}| c>Kn..!?q=f Csr06cqmp#KW]} =Fxg!.ۮ閶F)>p;r"G , %.NV-Bz^iEi5*(ZV%dž JV*ӿ=O 8R]c:TPiO2J8c&TsbG^pT֌pɓt;D$yqll)_LŚ$)iN5XYͩǠsA3l 6*eU#+}H$!9YRs3JKTBS]hp2T)/ZC/7:LOLM5l \sӜ>em=\scuհҷ\&WH/qou?Ȱ0ږ4sDLŒ~H#^˜XhYI?-4.(`&(*3:~<&?4TP+n,(>,.,06+GY93Y-i5BֻR @y&ګ=k CdzWk6fv&;kZz}}&!8ܑznč`X+So2֌zm Iwƌ9GNH%޺)y:1V+Bб!#k98K ѐ@0;UjZ_>ays6"Zo| esH!|Z ߖ-,*d}7H?j(i]ə>k%JIaSO.S Pa7y ^rX>9`X_IZ[6N7 >:*9{4O< QL6K:yEԱE~3k a%OvUv/:9sRҧQ.Ոxsgwsm{\7ybwzȞMPP^4i`L(ȱ΅Mn%Te Qz^*@ g8 eaGo{G`K-Zq**BXsQpޣQ %A(Hqz W$ScLro4phdX8yd}5m|*WEuD,-e課,+jBX:5di9evC{-ÁF)S{h$#"J&禱U򙑧A BtBb | sZ=[#xZ6XΏh Aw<Ӭw Ŋ$Qh+o_?L>6SuD %uvj1̡)Zf>ZÕ#wm=:5Ken`a" , i\ xVz#O͛YPT83Fz42%==Z{;o޳" P&:H9̈́_8T$)_KEIMĜhcn\Ƥ ;(Rziq\RӜΛӽ8gڎa0pƲG[&v_";L%V"04_x-azv6yɏ ua`~'NFSS/#||<3imΥW]oe=k`qO@6: dzfjBP!^%%˦XP8G׼5^z[8/adt ߷J RLO /^-0vw2cIB-%>;WL7 -(C88 ㅃRKb1NGQLUip%Yfs`v_S |occ%54+3a% Eg^S֬.\l!zq&+{DZE> "^QO>%owrNLa-(F+|1QL\GIՍwlݒ}sloJ2flmZxY'v3ʢ9EcLI!":l}#mYJ\s +m/ùuoMPұ[-[yy=Y"EtԤY+ArݻtdZq1ۻ+_5> ̆tifA<5vÉas+E dO:Ɉ0Pb0 wӌ/dA~Foy ;+Gui -yad6`w)݂sxQ3=KϞMyYC-6SK+ =1B&S2pօ@QE;Y(~O\Oƾ<)1VE(anAWe]z!zeA^xLYǡĵFJ;QLiRЈ:2/;V --)¡fQ R~IyzB3s򀫛)3ܲӛhh6ka6ǾW/jb q! ls-ēlͯ~cq]w1߮1یQd\⼥rSϠ^ W/;z4agCT& hJT,;@f,Dmb$D#O<_Rpa?ʾUroحwv_֯^dxG'Z Ũg>^>Ÿ =unJgњ]=N>B$B֎ GkZ>9y4XUO."]0 1MWfBO!v-=f`XɎP~%CMCfy~ׯ^@JIYo'vӟ㋟4g;t>co''?|בf;q`!P>CxG(z2kKڷL^dTRS{.BTl=1Rp|.⥁al5+ˋTe&DblZ$(+iò,]'$lԣg|h,^z53kwp 3Rv pӴfj {c]9?NIbGHggBnڤ+T`LЃZO218Vh)kE$<-H7 ~'q6E Z!0gvoi$N.͇)hhRF1ȡKg"Vj9) ͆f4*i6bV:fY# ;1mB}iCq@5ݛ MYZUI[((lJ샢ۇ&*Bw.{t)#rEz?M]ZPT)Txhb)RkbgP!|>l>MF 4۹T I$OR!!l"w>1.o`sloݑcZ"o79.l!4 XM7)HK& wv=R4-4: pMWaKW$uQk$txo:d8*P4V); @OM+5-ʱC?~7qRc%]sGG SVH#»wevKѵw;>(wyfuChaC- &A pa;g})lOo$x\-^*d̋~Yn2cПPz%e⢒f?ħ pZ|"uʉq+ؑ|!w=YYZ 'ۓ ::W8_arPZR}VwJ$EJE TvcOo9v?Ma$#FJ񜄮α8vLMh0wXBi;ML>E%mD0qW^Exq\=زU6Qb\C,t.ҟ8r?pE]ܱ!4ͬ_cE(q`88c^C̴"1AxcMngUPkWz8𢆵N'B^}3b414jgw2Ox_bRXB_|):\fg(0e Ͷ#9q ,)sKi!#˰u~y(8"Bȅ{J؁ַs1nZ B+AR8y\Hf71qpN2$-I3qi(45qHqyeԅAo3]cCU9LnISxc*GA+~'9/ϒ&o 4帢ɧ&sG}]o&YA(HQC zЗ[^ؑqi jeC$R!|0];gyjτhDK^$+qe\Wny+x!÷퍼[xO_xO'qJXMѵ5 8wJ05Xm*v3= p-"u=8ܹid.AʘGxW1gYԱIbͩ)H`CJ6X`;*+,49b%)#p߅7Xxpyk^Gaqi(x_~{_۽]"_QӊH0ٟ1zϼǸy-&3zS[?347 O;_PP)g~yg.Ɏ?7[OM jhxaLA m /%3+GY;d8-d&nW TKۂśng~{aVa| *$z5)$0 `pxc$T5%;޼ȫ_G\ܮ9}u#9H흌Bny/Ɓln(;% !$4+)1I /;i̘*@Y҂T8m2Z30ׇ)(;ې77L,7J]($\·yqeʅ$I$M,ғDpp1xڍ\.,Dc@o=o>h5LKX^ZJn%Әۋt"_Y6MʐYeks?-1# nd*x<4dH]l3x[hpkl0H!y;*}?{dRܙ>VZm07;:le6l--l\8g8̃P)LMq4ŧ[6C #I;Ѩ7,:nGS(5riT魵4[LiheBkA6Y.6WgfG~OA[w}WKllO(0l++nnqW2Sl9!$q7y_AdVS:+x( wh%0eHK`48uzdߜ"4DfZH˒W(YRx-5V qJ(n] o|?_:,+ޚbnxAc9JvFhS9Nԡ+ہEZgQ2ZvBJ#s*=Eakjjґ EYZHا7ɪ&08f6B~+ıT(HjN(GΡan<;fښ^La+d|A#3{nksu`g$)vCSAS)I: 9ޥC <֚8$WyICs<' LhHx i/‰zuK=ҨIy6 R*%тsqd(MIF-,QXXou~Oտ%Z01Ha@!2C*V8 $M RȜ'Q.(uz,&VMBA#=NJȰ~m{/ӿ/-m+C”sJ!ȳ+|غ*ӟ8B >AoVPzx_OF4Bzjִ_KV&В4cHɳC%;}øc,eaY^ZZ8Qv]ӟxLYqלAW9X~~?0Á'sac:ح, [%%4TVhlt+t[I1iR2%f 2;T fxalଧ"L'l@:<&`~MM JyGpd5MnV ǖ%x[-)ˠzh -a9G\rDPORpo[ k)`fPܷ[x RE̵b 8/i7cmpy#$[tȋ-p)%-,y渲|&σbV\6#/e1 6$$OS@%cfkRmW1mrx< rz#"ya%a?UVLge]]<)ݔ< akd*ɣO_2CMyEi, ^=Q):9"O4sb\,M%e't(6W1J \~oBIkx$xWI8 ^%̲,t~_,gU:<1*ja6d#%* |?K|+[jń݁+^{ WQ:yIPמ{n7"h84Oan#eTŋP ½Y:7}E #%BoLތ,:+޳1J+jffnl .L n8[]rLiёZط AUg^ñzkĒfG?pb *d&ߧ3ۤ2k<4dg$ZPU`2ֵx4@R ~x/WDO~5ɓ'O'5DC;T;JK07QMHp^Lܺ i䣨Ea,Jx X HS \]Lia# ZF(iKڱdYOZpϚZ?E~}3綖ܷO΄=-I6Ф ҭ+pKvn{_q3ۖ noQ54uOKa᜙"u)[G+QWʆPM1]qg=gSJRfGW\fC<ҸZ.p"dsXy(~%‡umYr0!XIisfkxN?(w╼i|iaȊU@#5-,HO~[k9–pe^7ָ`K6c;3gbZ9kGHPl[JEUhؙ▕Gǁ7|YQszb&(r. IFY:VT҅̒$Zש+@0F4POկmHIWC+Ʌn8w$ZR׌$Vc&o)vSˌRKo#M8\C#+|AϢ}J=r -=OϱL׳J1ȹ:'f q&iBC#}-6*zxJЛTjA#%/-:i3IsNͺԬ[D7ٳ5>.gd Fqb0.x%O³AhTXQddk+eai(Y[xALZGDD&m#_%^VCg҂45$24"YQQYOVޕfC4.)DEwͳ3Qp.9̷CZS\Qrd5"+B S;]l[AضЅ +,Z9ϐkxق9Hy,ŕ ;m >9!(M56#3XFlRM4j+P%zF\[<^Ϲb{$(aTYUBlP:jvVđ(O?)2\[Q2l Co~7_ ιT{qg vIyk?z3(]TV {NFlEX!;4%BhX/ocoKrkЭ#EI)7熹DҞpȡf`.B$,$iU\d4>P Lg R *%5yB6wT.OoZ*#aII\1TGd#̶t 'Ǩ+%ǰw w䕥rI9]Kk)VK3?#d]Ӡ7,I.svz[9,#QQ86t47/M(<4绎g4[9L@ Wמf8S1(9vx4իa2~ԕ$3[c4A@`BkԆDC#X`K2%)hɊ"\nc(=V)$$K^G 7hz#JCW0SӔVgA3Y2JOR( ܬ{poDi^`?q;qD*5C0W'U[ b\('''* w}>.o^f[ 8-#̓xi5CDČi]=߸+9 ʹRIFY MϤedF8q\;Lnf86D2|s7-ijCIǎޔ[ 3O-K&#+,݌AHtBYBa]Y:8ޡVN4 9/xȈgH/l\ ~vb+cz4|seQ[#Bic{(Ӓ9r3gFH&Ox)@CMCv %geɕ g#?rPx^~OmWynPuzƓWAoD<C씝~A{&f8Cn!Śh_iF!%ZA[\ر\: N#9OQTSd<*CV%pLaAYXji"%aJaG =Q_!'l f+f~$un 3j2Y矹E:j4b;߶'gBJݔ %x?Ŗa Tepu=ͩ}kXcAxG(VBhbZTxfg=E^a`@+-쌦98 F#fg Y|l|*մ r )Hn[]u/=9$6(rCL Q 98# /- *Pfc9ߴwŻ%r^Yђt})tV\mξO|K8/!3"k k*wLz^xe"}BDx>/R`gqa +d)6"v#T_/ؙAҭy&Lg5LrO'Q8SQR?{vznO IDAT:';{sˤt{$n[6lŴ\8n[۫q2#RQj^8g EE =ξ܅ЀzgF́Q̱۹ X@a^)& Eq?%vQ$Q< ڊEa)\; jch\ڱ66.DIjdNF/"AU{{-6"rR[W'#. 88w/z.=:씞iˤ^6.ٕh3I$0’%!ak8zhpFryݱW96dؙY]E[('87N9g/W-}7 9WNrµ$V,/t+ &Y:/a^jq 9e2-vܲ1.=RZ`\h4xb0FɟvR[3P1OwiütKOXg&Iw;x7nQ7#潝Bޚ"N6"N$[%^H4#c}Q ^-e PIpˡqElK].Cm4 AìT :,/c H)FZw?5Il褒 K۱-@GƒŲ5immЈ>cu|w}2e;˛N@BTu)%itC^igbn6gOLAc,q0f^>ƛ!cXF 1k%NW<{{s/w8wvyFM3&dSl|\+}2/5lnA ҴrLQ{4E2@yu%EĒ~)Οԝw_L7\z8SI|o̕]C.U1눣PKDI65x GOѣG&DxǬ1Ua}2a)ȧv;'䟡}ļ7O qؕU)#Yq ݶ9M,an|vNG"86Rrxp\Cq+; V #ni)]" Hqu~,3smJ{s,0=/6x=j"?bv#W_A~vxkXlD9OQiL]ql=z'8 y*U/s0XJzoB,%66FeyxڳXf#U82xyS6!OEt-kyHY{p6^DxD #qi!d= Dlؓ(ɻXϽʠ+٭u,DJ$MA'=%/ec84jH%`e(+J RQhѷ*%~}M{Y "w?eM$BȜV&1+=nDPv$X9`p72[<6D`H^X>5*< PnV#E1f~@`L<0A؍DƥЖ)tXPjPтMx]Kj9xI/Ç7W4s2aW3+lnY_Hcqt5e.m7MǔeŒ W G\jH8F0/Doy d},u8|6-bv I0.qpB!%$P|;9, c>!g/WdI76l  <''+$IR"#x`VsSN&y-&61q䳂(۲ HզԍCȄC+16\6\t.BRcwc6c}ꦦ9wA&;q>l$X'1+NAY5O-27Tsd5!޾kđ"R%p` (emi@Z[RR׉? PkG]i( KXIp+k%Y(JJU;z<' GkMG!,:]6e3O+{GƒSw.>!cq c%٤:Bq;AO7ɋ0fhyC.WOQ9F1R$'ӆ:vjJ^m'εD]Y#(_9UaLMS/hhjKр1_ Ǚ`@W¡ \lPU|gi dF4 INQLЍ;B%y?%K 1¶XsEJcjJQࡸIcJB<>F֭$cD$##T8ל rukpk q(CoȺhtHz2,qLgkk_XHu{UgY{/ΐ*F1 VEQh۰k)B2ZVƒ !Xw;:a8|4_Z[a־mG;2q#=#e+ 4,u өaw{B&rLsNp~I?ps}O-{`I'}7Y;#윪TtN=wsWVAI\.1TPhKC!u@Z(]']=۪c.G "l3Hȉ' J2k,&BJ*#XE :[ICe2JVL4,QRR9 Go_ 8$^ GA&`jT12hH҈$]{1Ƨ8O`(cc\$:r&B%8gy%&.b)Ԛr'FT¸H6*2Rkw~ W.y'L`-އ k-AHwa\Ax*2Ee\_7o: y^\sML[$z(6!@gVutqCڹLpHnCS;]d'9<8a8]L֮3B$[; u㹾U1WsDQBXXG& Cf(Ҏix!Ϟ+1:LE=Dfָ<**hZ֡wT+IҒV =e 3g-e9-3÷} %|=dL&qJ͝F~ LUR]]@CD'$1*ǠhHbr1+Cxܼ 2}ghmY]W{ln񗎺$G 뻆Gt ǘ5-q$oOJc,qTaAɾ}]q-qܜ$boG!+(>ygԕ ;5qqgDž cz;{%Iw#À/p)69pGY㸈Sv6ETgQʵ$A:u$D3-2D!.E~[|>Ԣ`a^XHhgu"z zԍCB٦*X,+Km0!s4|&L7/s/_A;P!. e8rN?IIHLUJ G-arh_}wY:Wf 95Fn膵)c043M^aΑee!XcL[C {1ee9 eb<,.$Ԧ=Ls"@c=z8Q߿dR yCYiA/Bk B*Ĉɼf%@6Ha{ Qz xO9u4 5s`1auCx18:u'O?WF3&3e}n)M48 "Ŧ278q^aMsPrrZyp3SBxωqjEIN^U`Š :J{S#N8I@*a!^"1"0J#A/ Q&p>Ŏ]pVW_~_-G(4KAф Y' w"ё0F,2yΤxoNcܵf emСn<$DF7vk^+Aa襊~üwYÝ /€+LuX'Yx竏sjIn*=Vr,M  : ok_dVk-q\"/`P!}GMOM*E"ラw=_Plo𥧞AiqoYa칃,sz0-A@*ב\.648!In˨#I%dcJǤqܶ"|<G43,"hOn{xcO^MӰˢЖX"RXf5lUdBe$.<5l_\{툱Dxu(w*O R{t3 +w!NMM|՝pm[Uc|K ya) E[:l6LoG}ۿm8n'o1)>􁻹T¼v tz 8O#)*CD,RƳF[<13{C!* ȡj!ע2_%lvCl>lmu6d医ヘ/~4Ǎf"cJpx{(o  iÎzicjҴK]W@;}0AkO+ K^Tv Oe,ruƬI$T f{äZCq ֵ(lM,_:Ke{K5~/3j ګnh -x3 rPYO,Bhu efIh J7֡NpjY;(dla2㖴dB: q6L݀sxmi#Ol՞IRJ< YxovkWb t3+ R@^yJO 5 N$&;Iͨ˒( 3c1+lxdf獵aoq151N*ɔ EUP?RVAMZPSWa'$g4 Fk{fVŹ%\ 8u)Q:úԹ³!+ 3 IB.COSx'gs}N4/$Z{Wz<-yοQrm5;;u đ?t_|]1/xwW8/ĀyǏk9<4Q,S]uN\%<քgh8yĨ㽤Dx&dRwzF' N379Ү=?cćgjXbkD2 HGVG3舀%D ,$NHUx_:J/{QH#u>PztB7[xu֞8ކ ͷXHKT_xBGƊQFcMX)n_I'!'Jp 2PRщVE0[oё!{OKf:P4+/BQsc\ I#7XTמ%(g?gN IDAT޼fzOTBi)d!tb BЉq!Vƅ7XBy 7>1]r+LoPo?EDpϪb?W#tZ0B%B._|`*e9~*8ԃf`cY!%nBŹgxNѡJ8i&;_GSMh:ֻPDp|ikP"n{xLG, F#da>4QB"ӤdjbT k }m"vcI,,lȣH RY0=~yf촕 M v)XJcap䍡(-{3ftsCd3E9V;"H%j~{m'A/1or_q𐩖VPjB"u>{xl:`oŽk5_"dwdq1h"8&9@$*F{F]XYso`=6El5Hb+[4F`Zյ&\BrrL!Ojxn喥Qs_z {ߺ|w}%%e)kO ͝Q}@E1PEJE$Cv.<ǹ#K֞Tyr<""%؝6&gy8HYl6$TPkɬLf:H{A^8ʒn#鮄EhJpc]jߞhϽb-'b/]1, cF]z8x>譃풍튦[eIs7C 2n>binðUJ aVNO!UHv֓ ;cC8|tH'JPMӘ@Nm_Lgߣ\ "3# VH $C$LAA62Pσ;9bAc5yHd(ěFR%zoąc aR9u^F۴8=#Q0"JHouEʮ#o27Nޥ=@a$cρbZLw42n|)y !f;3p$mcyJgl]C_0_s_$SbG)s3 YO_e̬, ^4kH` bٞxr;;.Zlׂ!~_O}{'wC1hmF0"t+Z[^QhLTacZ=Ά:ya9b 4bUگW_]C{H-AO,3}|uђLj!JL z8j-2;3:ԥF9q\z$w ,i,Au!Ź׍Y9<"5-z:fu_F"okW b6JIeߣ=yNw풢pa=a}6 )aS8 Wb&󰉹1eP֦5H$jӳ$͆5&D4Fk%iGi8  ޹3/kh 5->#FrP|˕Q6>`u9ewҠ>ݴA3Vϝnn/(uP +#QA]@k*.j(jhE,R6Kn?͂兔ïOpZpv}@Cbo$Ƃ5| )9ur(f}ܲCkE:'҄PEy',agwy]?=l"B|qw?YgQ$E4_蝣тy*C& |n] 2(Ô U?s>9}1 "aT [83<q2rB^"!{Ygn5'ajJOc=:p|4k~[MKi<F T&PxP F)ҲHKWi`I(iњ%@pr^7-MN++$;u"(Ŵޏ絉ř  LPMiYd@ő yXøړ]wnDS'8HP1YRBʜ'.q[e\z C} ?^xJ Im!׭$"#b5P̭ᢂ#Ur2z!%W^xUu(X) 7~'STC?Ke(*|mQE<lmn2;?N^{^nީ./%c{MDiʋ/q~'{3H4DlRk8jBCAOl%[AϽSK褒4ܝ-k` Z(5mhW252m^bx[?yXάq/Y +}I?vu@óQm"/%(E ڰ(kBW 3ƐdϜa>o_A+놹 XBӝC¼sHPQl\n- 4Lk: qhA̛@̥=Lx,"V-u, En IT^l+HbcR?T,vD0-!Vo=<()(lCxg}-KM0SWj"wpm^g}!,Y# $dOkrμ4({ˈ W*f#Rrx)$"oӝn|kBMZ#,VmpHJR"0q%a_ :ֆ"nΆpȈ(c17R8Ʋ4)k-iJP.`Jdm[XKXZ4' !M0X؝Za8HȖgxH=6Ί^k8z+cl_x![ɐc>Wsp9]mߑ2!4Ś NwCt`MzQ~277߻'Xacoe->c#eW\.A0*&H!W3"vLEL u3ܭlcKdkfM-gιݟT_*U$$7`z!A.6pO{ΰĎ &46.qbz 0 PKU*U{fw1*f$c$J>(CgJ‘$aͿW`od=$^C1 ŋ1DA#AS oU^C'j%%nH`,H蠵Fq>L*2Tt ML-5,[ iɵc0@$ ZiktXy {ȹU"4siCPFIcx7 mx\[0*ұC#l)&R.O~GOVk)H_$녧- {t*gvqv:L}Q^FL(= YҝgN$&*l"XđBIϹg6,Hp)7zɁK`8S* NlK/@]iGK^#od~a;wf y^f΃w}щO dG$j:g#cFEEQKe\ _slT bEԞLN79Y;Fx&Ml9;9[oR E[p0ێymw/[¦!c6OUa&SzpNv"k8(%jTeBx6D4  K#A0u&&<(҆`[TqQG"N5$VFH?V4Nf>aa,QGemƣHƒnʫWC6ЙMtaB'\+湇Rqbm3+$`@;Iצ׋QΰX{Jp3mҒW ^W.ͷ:_ln$Y3\MC=m 7>hRe(z@"C`B8}v@Si"ϸ 9,o|T `hpߙWq'na2 SoCFJq~zݎ-kP n_2OVFx!Ut$k K ;{MCgGQV ﮆnQ1)% *?1`DKk3xIc8z1[He~,-ܪI{H㊧_diiTp\)q7Nw;ʙiwADLa;gS|PB>W_9RDo06Syǹ$u# %Wݼ=ljF0K8ka*tە[lCg &T5BKjpdup똛Nk|bCO.|.")i4'ΌXZ&t),e@@0/4 J"\C9ڢ*cPZ͈޸SAً9~zsse]._씤ӊu "]qqVXZID`}fw3UyEKJ":f];3#ã[2b<35<Vu-{/豱cl5umiS#6r̈́B`ڲQFD'Z`M✟l(͘Kc, 8#]<@U)kړ<+翏?:HSXѷh*JQIŅoЇh *Q)ʢdiCE-:ĄNBdbT{:Ue3vlWpբb+O;jK.Xɮ*rq0)Q2/" *B Z°R@e2rds a&2Md4 mw%;Ec6%%HLHb)eas\b9qIh퟊'?|۹똛']fL*N*U !hw5n4i|XSIϮڇCƹ5FLcVjdDzO= mlKpvK*A/YD/"񭘡H '$x18'j2V,Caw\JI~oZ{mmȲ?7s\纋l ;fkQ,91Z2l*5$F{m(F;8w'D&hN\Ybx˫yDW\p VHK' =e&s-I"p&lW&l !!:\cјvhTa'F?}7O6~w!2d3#"DLp>ƈ3vz{Ϟńe\{sь dbLF+)mBbԆɐ4 󞦔$J},6$"ljz6DXbq:eT:D2vQ5#MmB|/%n.~Lb%IB'I*4~hGjHcNS+%>#K`u?vd@E6j`tݚiz"B o >diR翹vw G,8eʱ*Xd'(FJ( \/by%' ay#MVjT,ɍBFXC6(2ցKw~ԴRDžf؜yY;6k2U+! i:3:,ti=X;5f#2WagW~"u&HEUY8yo}SzJ Rc'\ i8['P*Ckz4llpX=l|5 ~H#IRTZDJk6&k{p(iU)ZI`I$mJ9$qƹ2س}j9c*GY+&F|j~'n$7Xk9ujH>ɲ6̵W\ x HHrsxrLC yrtŒ_KƷ(j Aq'q0Nj=GQXJSVx8O^v3횵>Blֈ= DO.~G~_0/e{"MSd\ 9ǣ*NY e8<Fxz4r9a}df:4A0JP: ouP1b FR)O;=ufV"j֣C$S+A&^[!rCIWpPq\NE,`0Ԍf;N G$U,/ "B|w}DҌgav:F$!|N{5I9Ц*%"Ram&ѥ@ݳp\SE)l< BHg/{4CT!he8M9xv'1V@ڰ SsTtG'1PuvɌ4α{O%Uihga];ƣg4UYza+QXEqL"&R\uy`n2XpdGM,UD2I38SNnp2m"$מb WH:GKɐ5ybRZ_ ~E{$q0Ld!̧^|BʐaMY ePrRg3%ɭIHgn:g$qD2l+22N02֩$'v(SH vK cbf=Rv,a:Lg/~DB&R{79:a( MRܿj;X n&K3ܣ98|~N2 "؄v2cRbɮz̈́SW "iwuf(<>E֜/* 3G5o9}R>r1ev2ӋXlQYna;s9Q*xrq3ͯlnj,q,1ޓ$[zAkwoC;}=4bsn!&.Hv _BF"01}m'NA3=@ʰa/%uU6<6B)&Եfa6Ռx56KFLww]s- 0Ib9|t![%mDH v(V ݜ X{}?TiݢcH=I.Wht;qA$B&׆qNzA#-=i9C\ b[2<Ƈuoa9vnN30#s̈́:drIC'2hYs[ƫpfsHB^yn#wbQ!mdobCMЬ )yZRɱchBI[O3Q8/|①G0,6L1w6<률sqpN nt0cLu6p>A,&l X tzS KvsJE~HY;ӀqCnhOD &eZ!4=ZY\[U\L@ E,Bc'd==jðvX)IIWlSM-r@6HF&nB=BCan:^]Gs+<旰k3}X=xا)-rtÀ9t46څJ*yZ!(u vM͆T9Fpmm&EB2kCn@S!F혼vewI,$DIp8&/B~tph8R]ajXr[^%è (OAE͍3QuR vZ I5uD@ڈ8qjxTl&<կl4 D8(:LfLԓx15q r%s{em Ǟy^C+(w8tQ-_{)$ PjdllkQa5Uno 4& J2,XuG:=XGH U( C8~.t@l 4"Pf#Wڙ`n. '/fƅڷ|NSQ K0l8tq>sf$ aeSL^|guwҷ,=TvKU%·ﰱǘQJEPЁ לխ~MQ`K$F9z"Z E"M=XZY RIAP)Ǥ7bkkͷ^hdeyF+/_PqdigXG)f -R9q5p'oQuhTg j(!i1ơq.(Gq>r{iN8뮻⪫n+E;[O`Eǒ$KpFPUU;A"&Q%4(g0Nm9y4YYṄG4M':ỏ/LxTQB@Dyir@'slDUJ\CUz@œP&1 h:$VXdZO<BЋ)J];"ʾJ0[3P,А064{o*6GfJatM;(3y]ڱg)87 ]#1z"iQ$-v$~ !w?\&L9%vtB#0ڪ n(r9aXg{q~ǃ,,/\uAJI'>'>G n漻X 76SЎ VԱ"5^Hf 4E VQj~f=4D `}hi$P䶼E>k42A(C3}Hm낍;P#4`&1`=<~1[=wxPEc`-9i,$n[ъhD 1=YŒyO~g-]98'>+e-vOjff>U f(a3 )O.Uxc9+P!hTd nnˊ'Z*ǫn]{_187B@i<(Vn ٮ6e@*Y3V4҈1N,崓qBkZڍچ 9* Y,D)A3U #{@F񈇖*V+rb0Դa'K`02DRbOBor f̹S+4 /ivLĪ!a3w"*9KSmF~lcG0 [D؉ykŎSݗV%5* ķaIӉVDZ[h- Kc,Y[* _9CUjL!$Y.Orxu̦ &CۉxvO.*#ͅz9_sޱіnr/%mAN*E/Oh{vcPCn0tC;[,f9sq6kj&=vlMPcft52Gt2E:}=0>w ԿIQxO舏ze{`G<%%1Tш +y*a|HĒݻ8ujkLRPV{:ek8w(F#FW(%y]?c"Ex沽+4q*ٻo^pNRzQ/WM2HP׎F^**H4X:#&'g-,kN?A>B 6ΐ mJҗCy\y7 _Om&i#$=Z61֨XpIaCVI1 a@v?88vs?m4_wp!6Y@#n[js X$Uf$\K)a"xϡ6LłKEXfP9A1YvSAn*jG1[T30PF FbX?v%HW" 3 JlXi c }}R8c*"Lr *ؐ%_{Zķa{X-VHPnמ7, F<^B]rv{6VqX-% twpMxbE% HC+.?j6%tEk'6+,,4Z-%ݖJƅ \x& 1nDXz4TI ]wV;t6Q R_UK_z=c|@6"$cف#ViqMbn?Vc=RT,"`c+N""KTJ2swðA8Չxtٱ>l]1p#:*\WYִ 2;;43s4)m|ؑqu>8 nıcCʢ8w.D%;^pvf&9Gm\K[XX8TnّZamimi6Pی߲gs? [e8sЄD"84dPi# m)ƕGȀ.X*3A 5IJ> rJA]t+715 e&Hz.ؕq75jr5 饂a&10g+ )@C{R vwyƑVJh4Ժ" <4x?Z͘ڸIT ;nF\{r[[LP꥜ZrvU30ű[/i5#pp&CCE JEI"b@Bb׮v41Kkٙ@3rFc1g=osv B4ammuD!TxK:TcoN IDAT4uA5Y^ꣵes؀&kHB=t:q$CG6v*"Hdj  'zAF[Do_#ۜ>3 rI; vsaSqa9T^rŘ#G{pT"ܘeiUllV읏i4%/ aY !Q Og"d:O 툅6CP UԵ()f#JC',Be$Z[R)B 3)Mqvi`hǵ$Lj/HR`X4YHT'xV ~a/S%kɡ#x&%,u8ql];G#YtTmCUh0mPO *NHK :~ft˯ۇ4 ϑ ;Lt3sWX=-DLsw}:2(G"0SYę IxmX)"InX.rxo ɓORUI,LHG\pj{_GK2jY[t*Z(23~1`'СplOke=8א]h/pPjF̤ҀC"ưi71 #خ@9% 2KNԓ;HHǓD fIF:wi: FQŸ87rԆFf P̞sIEhq%.{IZ%T,j)]+YJtϠF TnCACJq!D"i xՁG9K+ D%%J]<|C{`ydww<0+'T^шt?w[n38FMW>n3bOWϮj/5$G5KR'޹ͯגc?9qϾvz^ͫ^~wnxeZ}-O<41.${ '^0,E^yM$≑ }_3>ÖXrM vE\za&`iwZ3rs>ԧUp!Q"1g>*(.akX:KpOm?~׻Ɛ0Q9@E U`GR0(%_!)v] !<>2M/gLΛh%)s'`Oqau9ffR.ea/;)kՆXվ??&% x䎥ՂS#'F5dY&-r8h2^K`(vmA]swͽ2+kRI҆vxh vmnixvtQ3ƌr4m#aBH*[U%rv9g>ቘ@'{=4ɖ)q!b;k ma>A5d]8?CuL2 O]s`z\R`ҵ)cXf<3N9, v&>]쿼M3M-T*_R'J(p'!-[":9ʀ 6#-~Ri}#KͳSX@RQ˖Y sɱᄧw'+|3W<̀4[(h7y32-Z_}ۧ+EY_⦟ 7k&k&c_UY'9-︒@:>7XX겺1[͘0 8~RH%mpAKk淴|25;u(f?<3熤f/{f0.f]5&cvlc+HBdKi=*cؑg˛U[-* iQ잫oЮ+rrϞ>)QsQJ7 ɞ ^v8BzϾ2xaŀg~Ky3/:薀ciCsa`#'-|!+.1Dm7RΔL7ѕmM-tu!H307L4h4BMraMoa\`6 f@#CzxB zqa1'j0#Dp/^R+,cӓIZcj$},g@g)ѕ)<'*ZDwk~ιM-Nr>S>~$ NB(|aF!^Vw?'ʛn'!_=|:>_'_u7?fU$Y M3X9pz3:;D!Tpnd_"(-M^YH/% `&8q |k?v>|/u yA)<&Q':gi='aLTگ ׮ ?=e9Rxo;Hk3x*Ӗ:HRWX36Ɋnc/NYWBTLYi􆽸sɒQ%M`JPRYAԅcj纖hCZ˹e ؽܟ;t: BERQ ;\5w|$N?ONKnbJI|aш ^ PhADJb!>ˊ<7i5G$&6%eay+fغSwTI$YnšS9LUyY?}/h}cSƇu||z[(`{'?)6Oӆ 3Jm?[(CgBԧ&Ecp!QTUgΕYH)#*2 @\c36ՀLcyҌcǎ3ya>y;d֡#\FFyCJ%, 2CYz-⷟yՆ@S׭k'XG&Jrf՛hw*\!â=n[raN2ovf3"/ 7W_Amv.( "T:۷!AŶ4w}}k0l1}Ǘ23D~;%Hĕ<xN(bW*d4΁}^/XTgJk%.F,XTݳMeq6)mʱC 8MhcPMM)BډWm:bS^g,Tpky[Cgyc\NU^j֩GPo:_BkoVʫ!8 'RZ=ʇh!? RzWqdR%Ԡ+Xȶ H‼x=^I57 w`m S%U)FHa}6 T"/ [}k8s{ )%x~K$:XΞ\$Os*SjD٬!IBr=+L׉k=p3 Vr:1 f8t^˔Y.+_`#[< B3D!l6b,-l<̳?Lϼ.z&f&4〢rȨk@@]24!H׼ZZDJH_Y S8 SuA;v۰dJ(aȍ'!DI$026i㘌+zir[QD% <[ ;ԕ`0ZkH::D;p /)Ȍ@!U[ ϮFnFb;Ⱥ\^"YeDSOVRϐ(y8Z8&R#| 8%$ynx-4XxqYɉ[rKa˖}cUWp!?ϽtP0cuJB( 3C6'<(֧:TRnA,`Q~(@s b" Q XX!lل<? ð ٹM[C<Ѧp0]$l'7/CӔFiA6ރ8872rȺG' =nDQBP%I>yC"Yo>ba:J)Va]E3ܺEZj3pxѠ}5,d+F$KKN*^\,)K٬zct=|OJ#%cz/ȭ/H)h*&#^81 -a CzO{sH38P $L%kh#?T~i%R`XarNID1(ߴmZl+`"6,*$L&czÒK%BJv7bKăRD!\g O>w`H5]őLb*SfA#i:ؾI\^TV"dDD`0đb%r8ϾPk(G|Pj$ӭ|<ٳt3XSqo>0.kcuIo襵bh+ص)bqrFﺫx,9ƛ12fF9nW:m1 D%þo?|'ɲ\'?}'7XZ{1nj}g=XD_rUc|+ @ 2ݑ1;Sq=rFy #"o3>B5 E ^ |$TmEqt f>C)Bb cLB?&!R$(rĭy9C0Xq,LXXNޫa2 b0>KDaƛRw%Kk7;G7L5$ En~ ˛\,%) =XH%Hj!En(roJ@IT mQU }p\D웋 J$0sOڭ;?jL̴XZ$qؾ{Օlޱq+{YZ7N06^#MK욢,2NI?$D),Jܣo>["*B%Hr|fiǠhչ|$Q$ş}/qy2'N#c/&wq܀4.R&gRNHML}H?F%$$?ʑiﵐՎXϝ)Q*dR20BOEP)b nެX4:xx6Skh :%vKZjܙ1=K@! g -GYDY-!*QB TylXu `)58qHE} Ztn=%ab '$bvܿ +_S0ގ&˂z~ko~ǹ5ef&,C3lo~aYi&~br)p҈Btep*9^xE$`%ɵzv` zu+Rc7FyODΫ;x9KZƼrN7=["6z8 Zd0 XJ8Ƣ_ŷJǂzGdwm[䓸Çy uďq|K_"+ t0g8a*8g <$cI"b PAm Re#,w-RJ,wL :9I))ǁ І>ӳW{AĽQiqa3A#O爔e17櫐AZqDJZ5!k3sN˥@Y䷺Q1YT VXS^(L4}V^x]xQh%ɇ=֖6>(iG*\յUp47ߪ,_O\X$54X[׼taN圪2HhM2H KK9'yr?#td=D>D3w4رsg?c!Ύ&̀Ŏ^S<*"Rqa +kj@0?׼p6o7TPjuUSa7fB0q zp%az,"mɭu Q1j4tao" YBAc났d'dMRIb30TEEMB^\l7s1 vmkQY7ϷH3TimÑKr>rKuR!y^m|B163~7CWS:fZ}j%FLqul6K_}5|9N[Zˠ_PG,-t2/ySEV\‹7qoK0RKΣPRY6Aq(Q#/{74 0$Q\Gy}@ JX5 k,-N(<)Ic3ѳ)qvJO[6%㵀2q*B @h q-B؞ G#m!s E!s[tOP]x;ԃMT,ؒ#[!ދH{BwPMu0FquNS +j*ziƾ^]!c,I/lpk"g|zJf8@Qu\|uDH&+67~eqǓX?W1u0LO<4^{{Ʀk̎a_h-?ʣ_CzKn̩'xPIc, z8eiy\hj $ FxŎI6rA(iiyNř`LE}\7_Pv J%H=kc=2)@ǻCt(Іn^UȱQ1aU~/<Ҳg6b_Cc,0TQ 5NF i޲k?ǔ{=L'5cΰ$ǕO5띣`AF $(gh݁e# p.ry''Ζ `$Nrn IDAT"[k< ,ٯtٽ)`*H೟op!`~々K>KŠfgFoTaHc"LKnaL3m3y/8vG q( %cti>3daÐW,RK= 7ﭱiZԉ y4D=1'FWs5PjZ!M |ʶ "Jcq~r93u EQr:7,t4a0HBOk5c&X ]TjV7*Z1N#*TFKZ 椩fn51!qXM /2+l afvv끭;>$<\PLMՈdy~V/,x_5bM5뜾ݷ8~1ײ !lS*Jjzx1Eiٷ07 mڡK?ץo8K cp4@7j,BI3S Ƭu {lb+zPhKdy ND^ ػIzf#fn$O?D?Մ>j]!% F~&!T(W"FOاZocY v"*G#ˍ 2IpϛvsTc?kE}>@xyTY:(@v+fǎI3[1:}vd|S@JG?% .吥^?GOgo*GH?lO4pRf*tIQiaJ͹Wq1KQ HjyAmstֆ$IĮdR-yɧ?NV;u ?C'O"ǞY&[+%ȴ4@eܴ#12 A|m!/5qRPЌ*P yfm"IW9 %5F3&I<||p7:>rjdOʑUR޷ .@;Gp|,,IQ|m&J ky=հ.=$հH{J{̙Ԗf3@C@)/ƚ8!`ʰQql7Zo3ǭ5T >)%uX+codL3$.s˿~;Qd)hGH'8&w!C ~1VlQQ8^~a4Fx{Wd!˃Q[5~QC37_{m /omOTtg3(BS*|g{ZpnUs7d G+q _F3`m@wкd8,ioyw@VROvOOq4!Q]F m<}gۯ9Ƙr?[[ʑe~, eƐ. A R59RY>RJKiiÍ&ӖNhB͛b/mb,R5/*^Oi;J)j4Cg*.NAg#E .}xC ^h4B*/"R~7Җ˷ZF(V;gD5e8yPIja6 $ lt LKP12ͷ#M'VYxqZ=aמY&Dq Kq#p17l';qr՛+poL6zPS^ VAh'Zc}GW\c*}%y?)L#WgpsI>?L0 `0O}DԆ(z!#/pbiɍƍ>Ѱ z^( _\5߿,$ԥfSjq^`pӏ#$锍nEiCcM_tA?w䙎QQ9")k3{ɟ9fgX^8M^z85tl~m&BX閱^HYk gW+{MN*Jj)?ǰJ)%R0Ђ:Pҩ]~jX$ҤX*dN_[LCkN%d;^*=o~ͷ( ?(Y w,G'/*^Zr][)V-M ֘Gw1z5ըv$#Z+Z`a%_oS͎VsJ:z$*Y˖Se[gV(?FX$>1|m`G^MtYR\kNoo7EёU}#cnX˭ep!1ȑш|^JH #Qo>ɽ |NÂF"x<~i΄䥡!g=6֢C( s-gHC溕o'NG^nX}IeFқ3-IH~N*c<<-[ >X@Ҫ Vy)JeI,hexӭ-pr?pWuINIQ_48RQ媫X]I}h@ZzCCeahU0 &ǩ+އQ4XK I%Ƒ`qnɐtG:<~EG^M5YI%iGJI9#XZ&ZLkGAU8y  &/+ҟ"Z-dm-)x?0-oj~;sWݽqˌ$Iam6[/106Qcjv g v$C\3sq\U4 l 2O t*p욐̶%1 Xfbf*\}׫y_>KrDιOWǒ 2XPRD1V4# 2}VUf3Vv6r_\+RfקJ2ZN64ZEم" &Ǽ'N8Pe>#/q400T86H.=pƛ&mhvnq͎7y#C|C\Oj(Z 2ގ1_g1YPCG$A?-߬8rakA[[JJvmW #97t5F-?䞻η_}w cؙO>aT¾-/QQU~K4RH_)˯ia023&[knlXGqp%V]-davA:\F_P!H Zrd4.-D4jti"E{˥ʢ"= 稪$,- [ob}іF3weB_ɘCvnm?qe$eQ?>~>X]a,,_c8H9\Ab*=R8Z LF!E^.$(`~K' 2c,?"}EkVE#ۮe+tuNxo 4ěasbX8gP>uP{[ x<[me?r'W]s-/+ٺm;f(NHя~O`+.*: '5|nUE1ӎx쟖$w FI&$8Щa5s3(ԓgˌ6rDE YVy\3 RCcS7)`,$Ǭ fߑ`Xz=}^{' %/ ],x \]}a$f_U\+'ep.)}~켦L`xO̥g_oMAH ?#!pi%E3 eMU}[:$ 4gyȐٱK(+վ/kqh`Qh/ d,w|ϑv#f0,}-lr/'ao>q =!GlvSdo]9t9T"CDSzDlWq3׿v3d?,XZ"TV3^'IQA2dXgfQ0ՂN/G ֆ-S |~tDbyV(;bYJɠ`4'*c0f%ORV%1f4H %Y)(^q~وFas:w0W8<$|_oD޿J5 +Caqi \&#+-QmMWFN^2n2L4#K}Vsi8!J&(H!XB=tV =K`XSo#B`(L/^*Tƿ'Y$;6кV5X;C}45aE^{Q'pύ[[k]5k5{cQRPRĵYvLMn^!324Qh5 кB%FBWwv|{x|xO5^^I>8|Y?Ԫw=͉C8Ԑ'ad~_B\ADF`l6 -xju2Mc8kI" ,t$3xI 0@ I"<:a6$yXPzbCP;DS"EI1_ËbE#[7K} Ab-;n фG^Fv|a^#.|ۻ*yYiŃ,fI\1s?{s}b}?ϫ^:7\W=O 'MnaIJ-2&{ӚTK ) YDKפbolzu,n*D {ݩ%K$ LHëH$!I oybq}E,."]D3f?{> _N5R p=ㄕBLaxG<|˵}Ca{C"%:H{Ή(G*΍R=/xpN[pcfhzv1o^`{l"H[[[6ǞzH%:bIAVD[. S1uDiOZIf*iĔ~ 1}j+cf\sS>lpԷǥ˳eG g~\M zx}o;`oq%o^<k ønPTylsYҰa͌tn\1`2.()ӽH!MScZs`J]G@1_MמRW$rX'3CU9iaK:Ql[ٿ;rGk%e7:QLW^lk$| OǎŮΓ=x;_Łui9{~K\^aJC0U)Uc<4EY5H M$$Y-Gdwv^Ȳo@; D?T?2[aKRF2v&x{wbw=WJ lX80311M7jkk4A%wǽ<{fxVߙ@YI2ťv1syR9DJͩ;Wxk6H /¾,?$.YٙQ5_xyz D9X4i9xŋ>I ̶0c8:YB=٘Lj{^ IDAT@-7{ezO5N '>OGkB=k|j&~0yE^G2/)lDi%(GCp$7Ɔ+*bS ?[Ną O4\¸vM,y@ZҔeg͍k+MXg`:9^63ܜ-Xo~x+_?s?+<ē|K_>I>?WWo\9vB*a\ƍQ%'z7߮xrΙ˔RC?柽'X[[+o>v*Opרs}{;e͸B%IC]EВfEgad "nY:q yӊ,w3 GɄF'JraFJ-3(5" .__煗.sc:tDi[8;}$k ,Ѵ'׊7/k*iXm$R=tjSqoY? 0+fHhhRK^ޠܖkۖFi;Ĥ$Q\hU,S 9*#+7c(]`d]yKΉ*BKjJ*? (⌵O0cM8vz7*f.e6$<XYtvijGCe gMP'j 5B \K7* -h|̔8$cB#r),$+8[&8#@Ȅ Hk=c|?GѴūcF5>n=(磆^딲['!HSN$"]ask<-e!DŸ@J#c)\7L9p˹3&2GZ|c$RjJu":ՂvL UYյ~ \کgayk[EYY7-̉Bs%HhT#$H;d4d);3:m 8 }`VTH׷kVlݜ1g5k'Cgx) XU'ݫ_eaGy> v]8f,()Z!h!D])-=.9ġ}MTp(W9{aJY\[lh$ʲ$UQk?G8scBkIm"6)!+fws?avCLQϧ0WE]gsy yu"QBkdZ%\4ˤ0.49>rsbgkiIį1-NFo)g:aNW\xa4f8PJt)ϭ3SOXg!8.Oܗi ָt ' hB! 0%<[ܹ!ƅȰAl!2eID$H]x 1&S+|C5/R4 (JLʂĉ^;c;!Rr[rp8C3Z:1Hp`}? _oT";Jڍknƀ1CesQ.E.Z*J0J'>nׄI>u%cި$}EshhI1[^VH1>e\)w/ .O4z<|GYï<9NV.8'엾?| <I r㣏Cn؁4Kؼ:?L-v@HT`۰S/nY!ل2D3$BQo<D -1zOa .0(T* ƠD 7O撕_ X0mɝ2.l8K5hMO+jtUlN%_qg#gWK|9?'x?9孚Nl\w`q`ʵ5{-k(y+kbu!ey9KH@q;~ @ qމ<ˡ}Hijzm`h62t$g<4Ғ'Bc'il,o3X/0Jb3$iN=CPՠqqt31cJp?Joɝʔ2vS?(QJЀ$;O uK:1!ɓ}kX[iPL *Rdy)=8,6lϯ~c&q(-pv3Gb??~LI ,)! KKaitln|?Hmn*1БE ?quѣRBUP3J,RzHSi֎4ɨDz?2l않Ǭ{7{hb- bRS4g:#:m͵튵fghhd )TU i(:6,eqD!0+AS1~VXɳ !Nث:RyBYyK!<>Ui74npQzgP'֓Db6)H,uaɥ}$p|ΌdnXĐ@28G$!%Iغ>OU:d "x1vnvt5VJaJ5>x7 z`R3˵[6~1>݇|{,沲aqhʉ\}˼=ww؈;oz[_˙*g>g%$O6鲷Y!*$61ɕ}xZhkRyRCz&Elvȷ`v*9aMd+E͵3!XSJ)ӹV 9ظ`ha2waUfxWqז:B6w1B4v-9аX5VBay3.}_c~ >ؠpXİ7 ##8(ٯ)O襂oO"!ʼn M%Q))VgdphA02= #lnh;ihRZ k{q :YfoT⽊lZss ,Tټ/܋)yQltMoy >+ί2 =_ܘ4+xOޡ/>g;S7@t;yxWk|Kc&ApzIH:xSr8+W5i SLu$.؛87\ݬ(M[̹EM`NKMZ[1m" i6 wg-[?7E mC5yE:KfX5ޜ ڧ4AطDČAH&̥ \ͱʂnLUaT%ޝlQT$9 ȔLMl|u`To74/1sX:J|s,RQY S+Rt qMm3[FX~ċz'jkm^|: 93ܽdRIyeVsNjΏfrWsZ/8:rʹ90-=;pYR=Ʋ7 nF(MEis{ڠl" feĹ~y7Z0+-G&p@LAII5s+z*<]IDKצI [\cC,jfӊ'>1)bC^?_d6)F؜`+zGzJt6y#!-ΰ4C9_znȤ(V3 ,e ݽ"m.Qk'dpoՑQ2E))akOhtG9;lGQqi;k[jؚ ZH]Ud"I[l=r0rEM9\`if¬0y+Un>ZAќƙly $4FĜ,hXOH)!{n>wO.74;+8[fxoщx ;[x(&_ܣ,yt7w sOm)Z !EBN% ĉ<6e2-Ѡuў9' MsBԯMaڕ|ڬu$O_/40QzaK'~INׄE yFKϩg2 lL`V4NCqWGl`$l4,j#gg8%˰'Dpt$ e%*|#,[˱Մ*n[S-&,N'%Xt8Yu`C`PۄZuwXtAfn~Ն!U^EW.GA\{D8/x-9^ LkOp%((--Mq83MKJiI>v$#'( (p8>B?`?sW :neӂ?Wvݑ* BjřBk#`[gV9 $/dLDO;'"e,K͡#SNfYlfF|3|\KXhńqYOXHJX@â lV$d}.ܜ MO2x J[5rrѠEm@+fA ,L)E2B#%J'DCVBВT;$JcW${Zƅ:NOi2 D2*&v1S#jzW/-~z!d(<>Q/s=7oqJ㱵eX>C3TVˁ xv#YhIj<{Im%ypʁN'y*p#S aďq6z%`VYe{7&K\62fcIay.D8VsklިkƆ̢dO#n̅.\ d'엚o"JJC5tSAKGjR]7ѤmۻL-X2|Eӯ Ɩ@mjތn*cc8e{#Z zm3 $ysfɡ%Ee ) )w\Yj&q#Zk%P*n `\;@$T4qɰ?P:~$$I"yOmR)xn[i^B*I5;r7DK2Md:.*(u>LGӈj7n[lw︇QAm KK-F˛eDHűۗh.33;[XlZaci[(ք٫ۛFɣq"J5ϭk5ٝ9'jĵ|_1l\9 CC\NKq}ϰR]I(%8ly,fQՁzlb+!:>eBYe,zMTFcI vז sHkr!xWܶ$01bLibm)*' Ft9{\tΕ}F06pBIQy㍧O<%EeGIrJQްdc5W5.Mii'݆;[\oP Y[T|! 4stfQZܕYHj ybRXd2D0LLzxm;ףBp;${#rCq"o']V]|@"3,iAe=8ϡ 3xoնYapR2;CSڂd8ƱTo[㳟ߦ) GUbu!W|i eGfٿ9r+}I̢ɵX+k*Wy"y͝xtWE~%$8&8Ǩ5ڶIܸ[4Ϣ:QbFRHNF<.iKjE7 ZN6QG8 &UYb-P,kzk=i֍!a9k"?)+K56gA#Z<._F闇m u1&5U^~4DܠfVH368n />a$f|sgk+x*;oP4y*+r%Ѹ^ɴGn[fo{ V<:W.?d!6&is%"D(Bןbg7n'_<>BƀA!$Z ɸ1 vl8 @:&,,6"0,c_Q$Aw#'ywך[DiHFASEN'$N<!K% |ӫ<}%$g_xʸݾWͧE厢2QjM5"֔4%Aw I0[*A&b(q!R)R3Zͥ4a>DԂ=B=Wn0E^:%x;c?7=ƗS#ۛ<^.i*O%NSԁHik*YRhL5%tVQՁi 8+p%\w !usQp!7 :DB|$4@C ~c AfH驼 S*MRMV(^qɜgrPYĻ < W<,;u]G|#،7{#i|7ȃ2Nh(JqRx Sm'藆$D RC ]!nu|}f,, X¬W%bSQs-T4Yc 3@!<-Az/0:Yl/mE=~wR/gsgF"di%'u{c,'/kb43l,BTU3_3,EzsuZ$MܵxYPg fdZRZǁOR1 ^x2T;F:Dt+Rq0OK'Z9yAJRjVgq^*[(m,T,~gNOwf2)M0GK!F|jj Dd:qH=NqюS?dy+ T]omEQ0 M6IՉ':mu&Ӛ=W&$+E刍IŎ Ms4u&2dj,˓۰olD4, ~&I\3oH8̺l֜uf\L8ѥk#c4^Ie"d:1o:Oo<ۙjP(S]>4Vجe~O}2׷+т.k!-nHɴnBӹ&5jQ6;k6<"<Ͱ:RO''/+wւieQ,\ E21au_7ӫ$:BPI KMe+nq(phmSJ')c?pBS[ ryŋ*Py6ǁH3,N27Ws1:\Ԇ%Vakt'̓L0@ w#(hzRr&k p@РdgobyRƠaZYXqmKlFpigsA $$PkR1i;u3; l iq!}0HB,MC(OX7wKg^K}1OuO4 ߡqa'ؽW5M=%Ujg:VyRjH#ÑqQV5J֐p(,[[pyi+<ּkҘFh; Vq|bK&$K꒤r0F[w/#dWDR`y9>QhhmtRFH$ȄՎQ*IdiI]:Ohg,/?}c Y# J{O$J;5zy35Op҄ c+q^=Ev6sD2W@d<2GWӊHgkDbp k1NJNL&ycgqmʼ׍i\Zx  De1'3di^;x_F3|LHƵFWHr,%KjanY1̵4h;bEPw$hE eѺ&Ko|$<4U)vw=<ַ^=!5K!ZjhXEN8n7ڭ 9*?]ktR//Hr#gWi+boP]E{1i<-ſܣX"|~On'H/]ŕcaMQ4u$N5Eev,-B@Y6B0[kfqd\RN'&.1iqEFe³ױ& $i Qw? (P7)6,xw>lRV'aaӰQ&Q>B vszeau$K z Ԅv>hGFg2MI$!қ!]g6w8 t#}|O|z^m&F$R (CvX&lSl̒k|k{50($)Q20/^3lb^3uέ͑GYe$k~~;c{^v!kZ!% Ҟ Xi"~ i=-In`J VyԊAgV"׎QP2mS4FpnIP4ig5 #{t V2ibTYMD&~ow~!: <}wT3J,-$\w,aZ o|aC~~ Zqİ"ϕhDD67uE9|n;[]wEr7 J8*٫NY}mXܗNyάD r/I +zVsth]z#eN$kst"J:]`!.'Z˛9x6HcDC?ؗho%cYh ~IL+G"`)L B1Jn9N,H^w_oX&_j#Ķbq>=^(H^@f`6R>֔tLkϞz&5'Rx J!e% +=pwW74 g]p~G1n*%;1 M=CciQ9I$ A][iaaXڞCS~d<!= " ޸ PEp>3|J:4z)W4ssXL O^YB1cCE`4\lN GAum0CD&=yigM^PLhrntbKo.[_#?~^8ᕄTIlSbEԕ+=T+:iaɔ "&;<_30S IDATLQז3vv5*f)#TͲj4ucV{{15ށLX\smAwK썂cR3ͽ"dH vZQN>em>w ;,\H)jϨXw}︟_ocơE䅥lWyAQGdY)BB1)$X1rOF-':GaӢBJ\73~Y9Fʹr1 BPVXSk8sK"4eQ]=+*wjoaWL,HjmQMxgi%e|0rjA^T͚d)Y䥹lє{0+ɋPԯhW\۬8u֎J /L F[~O+OA23Zz1;5 ݄CJhR]<\V}X ln BJ|cgyBI0P7MkQ29n>,q}mMRgVG144%{_+C? LqD ]H8&M+QLs" i" BN0lji,iq`m~B Z1iX\j34:lMq$IDU;"oRbL%&!uP/FZa`4Srox&ޯWn}(ihCH#RL$J1vhLI9#X9qcapu#B25Hv c.Eܘ v'kL[M3̯/ar8W.`b)LmLἠe)xAwVDObQn ' 82 )pHp'Q@\*B&Zo8ً%Ȅ9tURݜzd1iǂK^X %؍'SpIHНX%]>*_;ר(ADRpxQ8"ӟ`<X'8j\_c0STyNO= - jG O<՗ ַLc-j.mUŞ]ñ%[&Tpewgطg!I:)HmL _x:.y6ɳC$zH7V(#H0Lgl0V x|7 rLl;hǗw 0H5Γk"q[׎3acYjrq@jCWթpa#i/gZWH +1׶Kk\EYV|]m:s:{r!1yiagH)ecYЊ ~b&] o>wU񕭐᱌N PΐGxǤr n_l$h1 `-s ۏF‚ ^(:Ѥԁ~"Jc6w =:pd;~/x/ȸuG3ܫE@Klʍ7ng0V2S(f0[ !5\Q#/,bX jF0M )~iTrx@8TaPƳ_7P6QP'CǒX@[8Ic8k+߼»ԜXs\D<"c4ijpjy)\/ta9܏-e#xC+lnռr9) G&ԍ"a*]`)o{G %`{FS_:GypA IvJ6]p(mL7ܵS"XXKm LPUHYi:Tu8n^7~7ټkXd>lմvdB^ZFh+4LrXDS(yb K"e1eӇZKqG2.(:mα 0E>Ƒj^q^<'ԍc4 d(|wU\J%$"ӇS6`m%xucBZhff^'-i|jM޲Ѝ$H(xq'sjUq@a鈓~6 T RNYd;":f:8s0O[G?nBkY#*8=qQݹJ=a5)GM5y 1_"#)Z)Mm\򛤢 Y_qm r񴗏n$?;4"±vvhDW~\~yH37ga)dl>!ÐZK I˫"<,,Qg[+g׫D;Kx}z`}bgӗ:nT-_TݫCș6n[MYYMjvơП'غo9 @JB8 Z녖|cW'?!U̐ӧD 7 0uEECCNGӟk v`+LE"2Yך'^>7 }ZϚ~7j+CCe`mg9Hj A='7glmO/<?KDH,b,"xbw5en6Y5_X^Ktcq,@p+aw%Jlٽ_k E]^ ޑ%=Uͥ];-︿hЬ:8LRkO7!H ZQ.m8ע}0g$ꐏ6Q1lO s%X)ډPU"(e)\Jc n^0h<Ϛ@*DD`j >V]0ܪξGzKT!$\&Z"$;ɍ׭B%-N-{2@WL)/;کg85X/%dqĤo˛Nn ''t%v66HLIT*p>]@X;执f Kh]KFO b qrfE3TTD̃ͱ3iAdA.%æZV{ƋFK"U(L4#G ޲ y@j嗞g{*K͝l6QQDGIMn?jmK\^*ʵMcSA쏱w))ۻ\[oMwr g╚: gfo?r;OGi)Y s Rz`o0֡uH0MD7puH"b_ٟXM1v K>l9(d YuŘФId 젴ܿf͸w)_~jۍ8QG!׮cIRXg=N̝wr}} xkG '786N(N#?yѨɺ]ih 1ȲԖ| ʱuل?3re/X'-y'/(HK |/+9Œݽ4ST_`7 Fk8d$iޠd=Zt(E o*d~~Mxnҋ;XڱH$?p1S5 ~ɇʇHaYh.o4_ךOc}{E2jRۛAC)H"j[q󈢶4ƓĊ,F'+H۾!!g4Wi} 1x,dG12JBЙ["Rb{CW0jح`dP;ŁyngK fVR M@ߤZɞd0 UՄXk=mBa[av*LXOO9Dp 5v5oBA8l%| S 71, ׮]?گٿ._%.9 ƳXB? zTijfm";}YjW2bR+d91Jz C w3 v3[S\ !2\BW4`2*KWZs@xj(k6!wpڐmpkHA'ҏ%Y8ܨ A֊iGl4 eAbf@X :x_+PL JyqO×J |/ ! V1Ech{ARo>iМiπx=*Kz2 KVXJLgLK!oVǾS_D݄c=wl~9y hh'npZAMYYHZc *n X4evK'F%oVE\'-I/|J~Ṽo֎[O9Tu$@5 I:YeH'b?y {|>Veim:SW8[D‰[OEN^WKK%=|涓=ַBuSkCPC& %cˊ+H(;|QHbwql1b骙ζ\z-\0wbg2/bӒ^68Z 8*2Ws{1EJ5'vf93Rґ:D)ꚍW>69/\ M|?BkfIUf)i7zÝM -cG셜kBز湗Gqݔ=^󖣒ߝ)\E<%5ݖ`sFc^ ! b(h9I+:P%p3u$mGR2F:(ba1#sr1DqOp$qnOUL,ѝK&g_xy r} mjP)Vkz>?gYg.GOP49hRi4s"RҲ[;fB6^!d3}FDqю4mQM4A)AS $xK/S7X) "p89v|&kE/ݳ} Kᯮ|÷\2n<Wx MquZ;7,BvO> j3JJqPjqB@",dq}6"l.am1 k)k`f^K(CHEHE]ulF 30)cbf&өv7 f3 @zaKAQF:\ye`Z]{d 䣶0n<#Oҁ%R! M"EՉ$R`s$qDqFRoN~uJ+g LG.]  >&xJ ʭ P6R;iii xKqJ+#XR%iq./m5 djUгJseǵqӗ3-* >CM+-W^yeGbԴSNfiֆNA; n n]DI0h uh0G9hvqs+xr Cpds{C w[^୏<^B 1kaJYGnҖ O{~*miwx 25q4٤!fs+t :[qU*'eIyK5,cƳC,6,Ax2 U6`i +Lʂ}r6-*u@$QjIiY놯a! z>Hwn3d`aCoyx5!;Ŋ$UjB0,_~2v,MHwO4=Ɠ gQJ~<=K%frx>]Óύ(j2n Btۊitk|>.G^$vL 'WjV2Oo3\Iefg Lsj?`}ʴr8 /,DT:Yyhv s1xK#;#HIlQw/q>?e%q/Hh/ցuϭְH:3WSkA|m{[;xݽ 8ű iM+[n(WeN9ׯLj`qmĉDkv ^~ ^:e`F )z6Ls$ J='2T>th&ykaTĨAӢÄ= ~8H,I ^|w6ݠ5A{_DJ5XRYH0mAIX 8|fxZT]C"=BDjI1ui T=GKIER FS7Ce3Ƃ -#ô#cF` )Ժl,+]<46$Lg!kA«MED8whH9Df=3tihr mb^hbvfA!; d0vSL]o}vߞ5 v#RWC.q2%e5g֒Ƃ.TLj\VF+ta/㴒>!"R'B")G AM15;;-zlbTJ&/ uC^TTED)脲SobPbWN6ib]w.u-DE " [M(jOGWl @)=;eH3YZNZ؟^pFLlftiO_S7A?BVhSQ Y7ޖrX +y{R'jSj fFvbO㶟"/zy锿%crx%31éۉX[% ka8kXYmb`F5NVQ16 Xq0Dpֹvct&kmhXO9zƹ-yh[[?.e%HO~[JEh%kE+Zт$qB [ҍeXPX4}7DYT4UC]7du7'4coƹs+ e:@B/{aڝ^y2Um5Ù[Ҹ:nu4ֲ1.&l,a}Sݣ9!ZjayzyILY[ *q`\xF >b.U`%EػI_GJ) #r]''mqAT{fV7Da6k0k(Yys {Jg1 [W tc9rjz'/HB*נn,錗vi'׭nNƊQ X6w"ڏ@+jIc1-f#?|&EBD>T޼η~Y^z@(0YT&Lq^Txn`!Ou`e=9@Q{Z픖߽!a5.h-:m9>CM3`Za4 ;%e Uz?: 'a4M]6qib XkSMCpPH屑LI S`bP  DZ(Vn)Π?yJBQNbKdž#p0580G^w50hv5Ͽ2F8zd/.$˼ҘCˆAJ&?C'K䌌G7D!1EE> o ٙx؈ٟ8V F;{IL ڴXx䕗\EVX5\QoOZJA }~ZyƳt<@JlJqmh!kh*q$OT7xbl8wivoޞ4;.|7(eQuYP?sgpX4o h%Vy8an|#m#9DneP Rrؙ.@gJ~冮QN Q Jڣbc褆By"@CC5ʐSYN 'x 1C 1Nd[v0m !xL{Y(Ƴ= \Zo5@h3E GjڊQDG@Q[K!En<7fP̡u8"5TAr6 7ǁ92-EXZ%iXB̤rsB ݖS*j[18қDA4w盉/jh_U9мAz#ܜʀI8ا{Ŝ둴inh'n.?uSrrxlbK݈.gf3{>N'6Rݜ) ÝmyRCx{_c56lWT -#LJ޷/灺T'NQcȷ}7y3yLXYv=FS+<[0:!֎^'x;x# g{r9'+fc*&3{VMp4QXe''O-q3a1:pvpџ`kTqpPʐ?Պo Ùc2*[+Tb7wߵ«s4M愦p#MUZF,-;S]w}[<֗Mksܼ9x XU|V1Vp0/'Rُ6sFE$hZQ;X!/rӰWyơBDhS8)Oe-b\MEYt^hH)s~2Ǝ>3N<%`aVy qr/Gi;cQ%5h&S7!Tv+υ}ǸSŏ=˕+Q\QPfY/_~N+Ga%]2^43Ҍ7 C֖;TRic$SX_cc#mH¼%RQZT6lVښV5lYh]kPL aqC7V4B͕MM(pm8%Hִ-E E ^BYKe+F/(T2ti%öۥ¨rnQZ +QyyReS4zрx-p|yO&u!X }~W-H"'!I#gT:S ln,vkV݃a ˚6~oykXf9tVe8ܧ*o0jRilnIYEc=o_煗'4ڽuck42z_3+Lg3.oV4VOjn)8slҰڋgq^`h,\;E'@gZK%_(1~Tv'䃃 YJ9!-R%sNJKG8q8ekyI#v^#AQZ/x`\8J6>Q)8İ3YQ&o|Yk&$5䥣T&M.S$@S˦,"foSJ;yo ['#7xrn,D f M]{R6 U]41rGxQƁsW=sWJ䕊4%M~?[z U("kt} nioW/DmkU*$5NI{aZ_ihI{Md8pu쩜6h(S7??/P?+< MPqZQYG6h@Bva䕇q&:'p*0Fxy $&b2٣_綣~{CP, 6K7TN1uh('BGeB{ֳqUsd}s~ #坚DI`e3.:%{\u@Uj 'mխ1\$CVB^3,=z jJ_sv#aVx6cR~@itʰ7Ts[Rf5+pNBAA7Cͨ AZ[jDPpnt l,UC6#pmL&i@L%'*B:iȩ}= ?ţϾHU Ee-{9&py7+WgkyV/74oG7{QyN**&ŷ2l!6ZôN"SM)G <`Ѵ#Klϸv- z]Ä )~ipR6ęf4i8qtO(ug:K,fY!;Nev#؀j$?umO6y{%~'q^ygUT6bғ{:A߂owwT{L iWa* yPT:B#m,&ݴa:c_7$l}74%lW Gsd5ҕ).话Xhg *JΑs%8gbM;Nmhb im8bL,LAgUdbL ?GW#61Orɲٝӕ(7v+V[*lG3H-%4&'ֲQDdȯ|US۹}7Ȱ2C݄-!W/rPʅkGb&ȋ7 l=Q6zj4q /.=O\xQX|qae1(=ĺFvj!BJÕ"Yn7^LkQi !ȟ{@l#|n jw"DQ5I®tr 6l>Y>P5q,nZk6Քd`TiS,(Q~?7ZYxTU!@+XY]c4ե+>FU8iyM8lRbm ei(f @0[-6CG9|ϕ 9WG\6>&Y» rBÇ*/0Y:O}c|&.*:秾}yVBv]xFx\/Kk8R2jCSSHTb[޹J"MF4Ak+Ak<6@-Ѱ״%txp)<4\ cjՌY帕؊xOWB"g\Mq!_}ŐcɈ$5lt()ƕ?||gq֡mI/ T4^I%D]-~O8v߇y}M=B0r.tW+2F dv-kmV(0s9e`b$qR:`!21Jk3da!&7ʸ:8i3%0I]XХU`ֈ qb/P8Vܽpz^ّydB+ ~;1}& [O0e^qgoɯ_ Lg M-0tjV̅rN*4U^M[ZikE>_}aʴrOr5LJisstHI7Rڊ+^41GyIKiB>hpOd[y!+ʢޱ΁;O,5udqFN@b؎-{}fxIz+\K  |J+Xveݜ-NѼxaj ВmKQ}LPV ًɯ~iF6VhLb6 `em7k 8!xf-V;,l=l4yX\NFGC_ GldY?BńZIZD-*`!*1 DHë=395H1@?ةAfܷק"}pϑkCT*! ,̬Ėr fZ P\֐3mxyfk<@/EONTs{1ྕg|Z\R3U,bE;e`k楒J7aαvA)'3gSG}oxr $R8#Nz$(;&e`/XQ9ŕ OKXe_~9N9Ùnww=|wY>g*S [݅C9w?jl>uP; Ij{عM:b8 X0?C5HB໿{y =sc\*p׉ue9QZ.- x2<9(XaU ҁ%%cxMt#kYᥡf3.D;c\3(=@U-y(BłҮ Z+,g"X6+'|奒ͅҎeă{|D*jz 'H{+ms|ˏ__ykϱ7P ZW^٫%??9lcZ+i]{Z-x*egyiB|6N%![tcx&c^`4icREfSt:兛V4r=N9/o|/?|)㺅/rdfQKt^F3EYg29x4[z=tO?]'xϩSo8OiܜQ i,t0Q,YGr9a Bv ,8|6-F}"Sϯ0YX=p0[[h9u*G4VV;eizQ4=?@J.s^yL){Vġ R6yM)ˋ0S7FL' ITi0+dٴfxP&NRS{ gyBf7+_yv:ؼDG+\VHsDZ(*Qw-XLQ^-dQ՞(64vm &F+Xh Qu#rA7 LsO Z x-;Qš;"6$8wG@+L; FMgX*1{3#a%r#6EcHJ+~Q˯Qچ7C: ,B`\MiLR } 3^.=稭PK;Q@d&緶` Lwt7b](jC@ $. o>2.?] 3v+ş>qJ*H;Og9yU)Q!’׎k䃇JgS+k,Ҥ ~[򾷿Ǿm,Bũ(yr7N˦.mug E؜ҖmmF*C==ŽK4 |raȀ2?~9'o:@?ZeD&pj3J_}(`8o{tJ%}H"M'3 ?E;[ieF;/s~>uaI;cݽ`|5.am1BkL6Gڰ֗ԍg<ԍg5^K=scAJ#"NodG;׀u{ {? =Ÿp8Yhʪ;?@oGָ;"VRvɭICXuƹ@S(HM^kSȖB.w^;V,GۤƲDG+EQ1zm,c'e!NIZJiD; R K)\]ymu1 1[K Y/𵧇g{e#AQg{dY3Wk*C.rXg&c4Hy%ľ'krԼcg%*_pm~Ҋg^%{fZV2ibX[0Yx/Fy _%1UET~Ȥ<I%4oβDN7ofcge!MR!@j"Qm'Q3(οQ0l^-n>Ƞ"5:^~NaiCna E9v_$[ nŬ/g|C)CItL9xjabc;Ģmitie1+ Y[翓WGvv m р'?:~c3 J*pk+͔`lO6_pf&B+`A.5oXW\h-t ur*uo[Kh XV{clM:XkOμ]) jEuN:jQ_wpj6G 4D iq̈́=CM`9(0b=L~o TbXJ\Fx&1kxGne($8IHSl $P8E?=f^fʡf{옕{>ވ?`>)8⚟x9Gx{zI_ F2bʜуE9rO8祣i9ljt (\cA-$& y㬭,t,2=&XOBϽr“A2\8CCl\rAWѿ;̶-b*# ޕ2u p8¯0ƝsXSҝxal0x#8 )iTBxe;Z*c8sl>^Tk ô(|e%N!8>Fd&+,_|<1ZGQxQca|\lKF?uRgS $PAP0Q[RgJe=s\α'9ox&p@:L!?`8_nժ|BYVc`bBPhC2,Z"\~Q53s}ų|y@qK 8Z͈4'UCg=~+X.iC]T,aJo5p $h_g8zg8qj  {1WYÌcV *n*c[vGv;WЃ5&0|yj O8prCG7̴h*,.#u~h(AkGߌq컉gjb tQpLN(ފj-}JBlۺ~1Ϲa٨ȰzjS>/؞qw6ɯQd=O"˽k4c,=GYΰRO&YXOIuȖ vqŁa˘$"ӂKXxUuN%2\4S#dy -4cgveeTQ W(o5,_RN=KSήpk) hbb:y-@ْ ^`(0 6vdѝ;^A*XS/F˕P3 :a:XzQj肓9H`5:ywlaQ_ uXg{D%/::Nxu(ْdVW C1PqRk{ Tj=[x-YoCXJީ@z׃g%J(*+|F;m iIV5<VXPIւ5BocLI.3Ʒ?*K%/~$1.5BAU72NS0 XℿxsxCw#$ az5b(i)9r*ԂA6D"n{qN1j L7(TY)C*am h.$7!Nk~*yjޢԪ>w?RKN IDAT,|@ }C֖ $oFs1zUau VLƙnJ5)CV{0_~#ɡE} YuKtnǼ]7_=A{0lHgy vpej!H Az Q(7o_=10V, ߺzH ?WhP0Õ>},P1tytϹ7{ yNw0yl8$X;nA,1 dAkÆ eahLE^=Fa 1n) K{3FֺkC,l߾N87%y衇ꪫjPxw( kvX,- nc]XuesNkwRO[1Ј~ J_UؾS7n\%d"$ EQ^d|( |סSv,S[y;6O0)CD3@EAjN`%7pf%: sڟLDZWNj1yD:Jڗr;w*J)f.H%G-%L1B%|!|O W@aC,Yuu$Eur j88I(( ZxϨ۟JxCg`(>~a  d?};˯o`={+$|AMcUɱM*.Q`Kõ#>PFE i 1cqP8<ݱ\9]ǖtP02X]ҍ(Hr6Ԉy}Yu`K,45돸[ٲu+eYraSO/9~ V9|KO=$Gʯ6e.n{KvV];C1b>,Żr,lf}m#k䥣T*uO =`XىrY;Muāy~V6ΰ873=;]_# X*&@:ZD;₍?\`Q ,Tynӟcߖ&ΖDC $ -E]3Fzcάh5E.H)qv?KGcE۸^GajFDJI^:ZSXY: Xa+O6gI!j9:6oOJ\%⾹ZDV03kg8c3vVxhĘ: vaY\+ F S1G:vl_.OΡi@ړF$PAy$w}aNLJP>HI*XY걤,  m!f;Sv J$αBq\I"l6”;*D ǰ7w'GɺX NvfH)k*K@23pv0nt0(h{xusŕ<7#A/a w T^hFxݝc̟Fisc4*<*/lUPF!['8~/)A㔮bN8|GyE evK;`}Y\kG(=MR@ЄQdNPkO3"玓tV>F:8k7BҤ`v['5*tVPW$yeqK($ n_rKfJU&nst׼RF[1sD(#z#$x G?ƃ>ȕW^097L<S)4w?#0Yq$a0-c(]OhiT%Jf$' &TIRC*šZ@VjSLW TK@HA*9TB-aRp:cƖDB+;3qR*534@0Wy SLdžh=:7,@5NO`2x{QSR IY[vVX<7o ?nY(S}P B狣]7uHD8|WQ@$ЬhN,Q Z@EuDc)\=$T{&mȒe-UϬqx5j[{1l W4G5j~|Xc~%Ă l8da-9EU94yuU>/qeϠ~_y:#\uYuOwQ“>f~x_~,}};,$5͖3CUGOt4\- Y%nS};9xnUH#D()d,8VQ8P!Š+, ~gws+w rxŏXg3}2r-iU%ϿŜfUh~7?ZAVZ1jЪ{Rq lUsʆfT<4" Dۗ;s˚J>/TZJ=v<_St^}KMϋDQlE=}KWmr4Zkv^t5]N?Z aNqlo|,4 ]q(*D e VġoE^ X$'B^Y>z)D3= ǭ7iw}7m;0`@3Ʋq";EߧX:a( 㸢Ϧdjpf9/C<|Ga-(j,+%BulH&3dfiU39sL6MUX$< M)A[+T˩O?|+ (JcyaAVfl֦Vbdcs [輇VL-ɰ CtGbcxj q۳ERHVSTnd %$7<{Oh %)0YiMTCK4/7Ʉa)rDS暰:E:Dȑ%6bcl1*~⃟?%rlԦl&".;ɩWY΍q|f<³"C?9'~ŜZ1Y3Hx!YB?ba0Le7|8w\0@F᱖>~eFq$iƂz@7DC?4b ,zn9UEk*W=d/Z㘪6Ht< wrIG^c Ȉz`im 22m+Wyuɠl7:!LeK쨇V =ߧ(Vd/ҥf(h+tpQNg$L(!|FUuC; 7|F94ln)6=y,cdHkL Uϓ)q{~Ҝp Kξ} h, "YqΖdF' ͮ%}Idaz$3m04YiD<#L>.T9,G q$CJh|>! NF{b8Ϲ\09η~7Nybi`z6~䅷ExnbT͟j/jD Zol+TG=≆"\0Um2,3b8D'VHdڱȍ>zԗ c= r1~X^;82 58`K5k),-.kD,,!랑ߨ! $򠀫.d^u{T#R AM\<p NiMgz qe^G癪+~19ePdCq{.:m ے;~m)K3rz/eRK^iH3 2. mlB IװֱA?`.PW*ׯt'J^ =-J;r" %(ti|ߝ+yt+X+CBH1\%VD)#8XwBڑ,厓Cː4g7Zu%䚋bά[JZxiVh!qiKSXcӥЎ]#zI{#$ZS)GaSZ/b:5笲Riz%A9M%Iok2@LCVX,v{ K~(@U(-X!(8 aSs?eD ;Ǡkz%ص0 )s J )!0-{6u`A8h*~1zAVzd+Qq0 0K-NM!/@aLO-cU3t˖Z@4`(cUEn!gV q=6_tos? svGpŮNb +w5]g˛^n7nٻJY Z[Dcj{M>;`q˰vlcu=C #z#왍ұ3LTc!k.kGqvKQ:$P@vjE~IWγdi2BD!F,X:u]8gykۏT&(s녃 yQO?֣dp.]K*N/jCkI^ͺbyJßXk7>cdڱ}yY}>y{[S̜-3_msߥZEH10*-Kcn8p2ZAq>ud,UCe*wשWKo_r&쳸NCh|z VRhm7~PPZ?šjcnf;ŏBlT,qGvH1J!fq3&NnM\k`0,J+V^C_mJʢČU‘"7k#n'u2sl 5XҰF'K*V@ AD]K?. XCd6>xnvia(FמO¸ A S ؐedp_=ŗ>sT \50K@`& R(J_P.?5UD?(ΒZs3тt1koTrHd)< p5wtTZaHd"- {"k?޽Q0!eg:ʲ9ӹ%iq:c)ãgGeoPX 񅹱 Q15 F!(aш|Kpqbt &&dV( ke=LR(L]YpG-a &S+K86GOU`Kш?~7m"$(CŹ%_R6;v7wq;vbns)%|+ܪRC >V}3kݲkno KsՕWg>™LP:R! p’ qM({&-~o_oy [7p 4#&`!L"bۖ aYB;q́̆욭ku4G-VYaq=#8m|G8vDL [k8LD\?%I clgKLpb~pljtSIjG Q襓TcҨ׼aXF\u.VH-lh(oJ+)P/㍯M9gYvn2 E9MV\lk\ʗA[ۑ*-iY0ڋGYIh)R؋$mjST+UўVZ5*8NaYFtSfXkG49G ꊬv/Y72^]Q.c,{j͐b4Eń+fl#;\I7 i%, :/}͂wև5~NSL/,9Y8݈x~E"Iɠ9ȗ K'1LVywWpNF( 5O1wl~?g%Φ!2$B %ϭʆVkfCZ(%txM§afhH3/2lOw TҨ=W6L1oeua Pj3Z&ƫl=*`m?4c<iN%,XZZѣ?3PD%R8f|ԧ*v]c-8 I O^b,(7nY0z&H19 Z50\8 I@ʐR2^=g&_ԖjR4r8͒徥_ziҊ$LQ fXaXxwUXHeB1QMM{c;[DH27:Ov$TmtKs"!B:oyRA+4H}~S84^jn =c93(x`?1utF+bJOƐ!i2sz-XBճj1ظ%J&[UJHH YI?)駞p;QٛYy!c"7$g:k>ia/MMzw9ŗO|f$I!M>p+0ym4g7s3.g߾e.)?ؼfZ?+3czǎ3|ei\%?7]\&MS= =߹|3xk2zOPfN_Sos_e?:v^ 7ru7Ǐbt 1VW- %h2x޶SݒjnK/e8 +mw),9ccٳ%ǖe"ֺ%dzO2X?ͰDXD YaiTJٜ,4!뽒 7x|eJ& KJ+Ƙ; $=T 2/m շm:$`[6%l4㭀$<~4aeطk@Z^ >8`v"S,$!-|i릪J:زx}' gcn]3H %򂧏nr@jrdXЧ>w;/1Pk8X;XT~E֏{,̗YG*<9OZriN?7(tۜ,(]fyMO=XXq2wI%ڳy_=I׸GQ5V=,cc YC fm/.sdzAdTACi'I}5RH4Ǟ<,i5}uM]QZ~2$ eumgy l$U7'Sl'/i5=gr`KIE+v< ٺmÇڄ"K-s &3{031,gn+Q!J3NoʃE/zzO/ =9!z; aKo<K-kJ6O7w E)>q`I2+A˜9rkkNy* =Z>s} ΄,s.s)YNi,mwQMJJi5F.h˺P5Ct 5x`^ 0*(5NjMv;HVA3^\mc'@ ?򉍦B) 8)Uʪ #ͱK'p$uMh*<~ ;4DciJX>"mNhwJ4v@EK)4|H HSP`sZ#}-xכnMx5O~m/xl ٷo9Ү+aWfb.f֝׼ܥJ[`l$@ 9t\q5ϝ9_ǡCGmbHuO <±). ^s{jE}AwՔ҈k<'>eSV0 r\= %[E\IJ=V?OvaDf$)$?ؕrEo3u<9$K?إZft7+O:İP$T33䱜(Tyx#т53>78t]IVgIZ̆І7DNkDnF#rDO أ-L7Ha9+/ Qc{k-JJ<9Hw -,aH(-gm{ liPUcF]{e(0*])l),Ac=UHBU8W=\cX!-kҌƝ!-ol޾_u[^O=Dea-7(⡍C,+!ME?MZM#%V[w 7,t*VwZ$6m;Aң)NAT>8|%ټƓ{.FZ(@$3Hᮩf##L\}niyZ$JN } ~O9n%JR&â 1xnb\&p'cA)g .Er$qt$510y 7/|5/lPN&'%IFrDc\$$@*,fDQXbDm8TBG?t-o%[ae ϗ䙦ވ(Rʢ Iz9[سwV !*q"7yCzS>W?}=Evc~YSk,I5k'c"ͥHQaZ EFar/ea|q~Zسgɡs=ֹ G2r Ш{Zcw9uoz輢Z?S nӍ=W^ƅZDl]X`k &P[=s)ŧgҡ[>չ!ztxAQ=c>cRK֎FVͦq PuW OZ_`09Z] DhLVu/K=ȗ[^*ch$5jH#TZ=" CbclE&"p:]S]׀0 -,,NRYBϲsOľ3댍 u@ y̬ۚPDY'5$̮kc ||O"qz!䣟کQ@ E%&+A-XyLfiK {3gD`$II͗'N&ҙo[pd?kfKYX!+B x]jl@i;%.tQ,5HKa [-eJ_ <,ghwrIS=-=G2Dn ]Z(Y?n(' Kmw N*$}^oXӯ &|l*mzc#|BKC<NVh'g FF-|u]{ڔڠc Pn#VH 6N7kYuz;o5lm҈<&a$ȋ]f߉ ?RQl6t"kKtFpyDOU̝W;&^ml>B lם[ǰ֒s_)iVv7';*hH*.d> X]O~'M |GjġdV,6C!K@1 ? 6UE\~ v̮ɓ_@ДSS5ju0r&z)]SR]LY5V lΉF0N* _7;w?!s/x^O|6cLUF!\pC1:RYYqإI/lFz'/ifN+FKgJDd9!JTh|]8 1I//7gCpԙJ[; j aq+.8#S}ҡX $ee9Z I @1 DR$n L4C7beZN(7ubH!,q_X8( s-r"e,5'Tՠ0:'cLE PtY_ځ5F3:xV*Rk*aHܶdP/٣.iX<b2;g9qaIZuE +J;$+ػ9 (˒qD_8y)v*-J֏H}C%$+݂n\x05&ێ$A_|>ַ<7ov ; udp>"gNMS\'Np>oob{7upqC^j$&>˩d9vn7==]N+]b iRL:Fy57ܧV)%U,<zswֳf\/q~ mW R+(G8% zh蠲$Z08vTW|'N4޽);W*hKQ0Z$saz,e_us?~ncaϒa(vϣ :A)rRA'3d wC#/RNPKL%J+xh XѩQפe|m!}m9:δs281Af\q*Y) g݄~{;k>k4-_{|Gx-[<)w3 :0*l0=0h-v"sS&;iZPvy^O롤 4ug/,5X~7c:|-kc&|:d6t k,,qE_S`QQ$\Q $5Τ;?O7ĵ4nipT0LH\7[u@ c "Nx&H8+r4P|@< R8\V^fpa0qrM:/ul߾ϽŧwJ%^ !1T~@n&~iuϿőpC045yi Z[0:,2|L>g#imts':dǾ#=ډ{q{Vfm<}h&  س-sJΝlsXȈ}I;q%c +׏KjEU̎i9{4'тVC,:O&vD uIZZ o]KHZBz9;Y}j~K\NH IDATj$_%#uZuBQAr*i(24 ?QZI'#4啻/aPĞ%,K),SPְb1 hЅwNo$ي`r˩:7]QB򴫞|R"e0J|i%8tJ "*JM!=c伵J?Θwrde8I-B X#_3SB/rwhGOfdP5CQΉdXF,iaqߴ gLs7Fܽ5ta%];!Z#ԇZ?c #n| MA%=t?}{&??~X? m_O?|~3_n~):x'$VN6G15.X7!˿旾3?!Y sXJ*5\%Yi RL{lT] /{?#dIGK'ќ\N\1ͦ 1ݞ!=ɜM^tYvU%l JҪKs.Sj Z>K+4#L qְgoJ;e皞+GW*ZX/n>^Saf~wv!Վax+KzX6AEYQ!e tY.ޠGҝK68\c}GK2-o(OZ! aiw >,!< ݬr!jjPţu˓GAn4RInj {,w|sHJe=(y}cE'줖x91aӚ^Y{^K 5tK- +"uI؅qŢ8 G뺁gHF-jpՠVP6ifw 8ڕ<G:ïOQb+'P$_,(&j]@*|%?W)a`fE Eav2ą&fRTUn#MsڡJ'2\j\uaNo>7ט[)!@H5M9ɵo(uw8͝zі-I*H}|m n므G;LE,3rFWl~?gq*n:CF,Y?XL]9o2VRM *9SrY%ñ`U9x@F/0M;0@Pax m*V{%j6ݚh['|Z%CybS^dHs%|Ԅ4i`='%B늦*{msC+O:SY8Ϗ(im)Ȭ  ڙ̗Z E%Iy3[E(m1oHja9wu"?1E6k=Yї5%{>M X)LUaL22/IB[吒֧g\ڀRk` h7+,k7?07<ӿ/||+W^`^§o[.iET[ҕoy%jCC㢫r {7wu1;ֳrUE˟~gS:\Y3vt_G_GUUD)KE5mo^vλi ?.^{sY. @k1'.zR 5ɣO[կ߿M# ɀk&NX!sSZN=mc|ro|i4$-wm# \yV0>{%ٿrߛ.rATEݗg)5CvlX۬[3R>Tֈ9y"m3ݷc+d9[vGȲ.{dyD7A]f>-#cNx M 9gǙ<ȣ&<6oNʱY?=O]>O'J >s]P$%MSw).9žc)TD/YI\#aɀz,XTTDOj;#уW_8Dy`W_PߞGY8RmC̮A!ѨAiO4Z%獲Pxen [.تQJNN-zmʳj MFKQ5<RXj1ᕂNꚀw\;7CU, B!\Fu6j]%ME'W$#iQEjX<0@ġY39kmd: j44O?9Pыl`MtGhFr$\~Os=󮌸6;tݗ}MZH  HVZH͐eݨBm=p]3u^p '` 〫.dA@88ƍ7|LFJ.-eT|UV!F8s;8kd.|f^ķ$sʸ7G>(n\ eXCI6>u?@7uY+,!N-N4Vyi83\5eE X[eyt@֙ (y`Qs"AUc( ]xhy2rXC}w 6;` V{=@A\XG3l@}]Q͒l\hw) NQ܄~Е Jºҗ_ Pk-[`o(*E%Dy1'*K?9-BI7\t9asxyUO+奯e~9 sq?Iw|vncw+xݯ k{ㄶ|oxRmq nfbr ;g+օb|W"&x0gc*|;y' ξ9}I?a~{#X022P1ǎ˂(_R֜M1jsBZ9\m;3R$O3ХfaaG(`uy8üM]YCb fg[^sX_`!8jIKڐH}51d"%XY- y NjbQBx +P̈Y?sNŠEI_/xdYq7,׬R5=.hn~GW,0ZՊg^;|p#M5ӣcO5qf%c :]Y6 xks} ˲{%Ea`GmJc!fkd}CYʹgyl|Mnp|>sm&o 'W Mu GN»\=}oh`44}iGAغ:S˘_PA,OCIWhz" ,JMUR$)б>K Qܦbדff4B8p#3IJFFK!]j*#='G$FXZt>Z3syhRbE+<dsKztxV_J/(-FYdx5.~2cNb:fO6RH5g.{Or5g k\qhk!uʊ~x-+rwcdd& =ade>C_֠{{QʣԠKw#cOBV=q.?{`4+8T8rf34e"jc gSP y)˿%V}ekiR8o[cEJUV9s θz}P$%.n;o}L 7b#PW_oX pPҬyTEZAV)hH# ź1*Ytraz~5N]+ػhx5?] a`_AuܰnؑzL[Z[rN6 a\ɦ ­|ߥ]qΥ:yޥ@?*c9޳\0.y`}LBy"sht™q @WskoC.DahP a-%(+Kf4&SbM/l&m UJK9D`@f} |ZҒ 1=ϥz}L@"M_ aUIԽa6MMsϮ\2<yVH"Bb0X^7?wf/y RRYK-P$f<ƨjEÃoS1!tGe!YJe.i-y%#0sb];yȓw#a̮޵ÚX< ߽}o_0JmnƷ./|o^]}cvyOIQJlU!;_[z~9|qNl VRUIkG8@Y {W>=~k_~aFgڷ&SbNg1w'>I, }iѥ]:JWUW_?:ԟ^{MeEY ȁ|/ ?9WkYYKڋndߏXKus6.jzj~f0/}-\~@M,("w{^;׿ץVIN,U=Î3d_WWHq|>ct%SKgɏe]2:>ŀRU0I AKQ(HRT5OQ45#' ,hTڐmzQ6Ή唅Q]Ғz#+@8S/s,/b,MRf+ClYZGXȝwDSTAHzVЌZ\| ,-x]yi BEY:"T>֍2w½;sI֝3_"3 H'3clqrx ãwă ؅[j*R8PS#O $OٿУTqR;2xI(~ %!pŠŎs;`b$vAi!JɍN-XIaRHc*kw4k k2tJ; uB} TҌ$V Ny[X`ݤ2_(T|!=uGh\h&fӧu2mߓU6&cu~kzNYƠ:eURK|_2T\ ?TL<=pup. RX<|{GrՕ۸YYMBk-KT{?KZ Z5oPT;Dd[Q|uıK}wЪCKTX?S Kwƛ/ *"+yE3x3b~/}jѿ:=x}&w\Ew(_:t)ɭGH})He)puYώ.guj-ۿڙ,|OXaϩS9md #aP.^^ѹQQQA^D1bBd Mӹ:֩N>;gWrW7|>k~ټ~9kJQ4 ,oHgeuyׯ2sqD3!w<׹r4l۵CN?ŷ<8x(N5#sO?WP%ssfkkxnp8;uK֯\oxS<*0DB0]B1G8< xhӳ1.k %v.q @Ѫ^sTh56t1٥|ӟk|9"B`<{ӏᬣ0TJch)OYA3$Zq󭷱_X/HzGL]y)W^abr;8|\ϥsg hce /]0G#oď "P԰9h9ZqNſ-aifg3_|+UGpf'yyww|?Ο}|S_+{#n[y^8uG{hlt/>ƽsO1dN/ثxlEe0!|KxghQGKť'HAl8#[N6y\0J%U8|"dCЉ`onةq/_Ts|MTQa7\=Ovi^ ec`k`LƓ![R앜t~rNyRjrNG 17ϯQ,9IX걤)5Ά &9#uC+ 6~煥وIRu1ij'(_ۘyycMVTS=^, s1׶*Y[+0V|kfXpi`ˌd&Ȍ5RfTB9nc&zsx_eg-}Y[ 6v{E|9uM; YJGQ*$wTB!r-€!dMHJ^EA[U" G 2זk&wAaͣĉe-2[d a ɒ6Ar!hXX2c۴&mI$Q[8$Tqyݐf#?rAޕ.@fRS;GYXHD4 'Vi5?5 X1-vN+dV<"_V 1ZCWV_˳ ޕFiOO'yNXCtpṯWwP=2]Fcqs;BOPfAE03˲,fŒ?(q.xZ!ȏ xΠ1٠$/w|i$UYS5Z+ڭ@LEU(2dY#ډd~Aդ"Sv\Z дyKYܱ1i.xq=WX9vMfu}3Nq]6 E^ )s]'o̶ GgZ: KXu+yCtcWg8PoHU޼(3%ɌI8aVWX62ODʠtT{\y#5 ,ANyb@J褒kuܳ]W"b#|9 lUi89#XlJW!$ %*PfbORp_KNCIc!'f`:56tz\ܵ~L4': 8hG٧0 MZf m4)ʪFIB[rI`3,ֹqДGP㣯ylűV|ZBBP.0= T0l-fo(n)W~ߟ{Nt37q7?_֎TIt,GۊD9\혊,S^7aŏZ.*h%AYF7x3W>|-6֛su7w-v!ISC{7G8V"!Ց<0|ۿ{oI`P{2)s#<[d*cLx3şjMeg7|+ѭĸ{5|| CSl7XHif`%Ł[8f&_4hcT4&8(01^hIIT\;8WC̙C)6 y?+=7& L>-Ud#- <6d#3tON3 㐼5 ;Qb7Z7#˥;k'yk³-=]CQy\٪طܥk=1*2Z ~gn60Tn}GL#fD(s3Ջ-8`n+op`#N4S)~EVFs0aph/%3`>ͦfq*ecz!WdiiHYH!C:ѰE' {'nW@.JGzd6Sr\]<9*=ɠ *QɶIMm٭6$ ՘dmM3 2 BњƂ˛͡y " MI^t:M,K_kxu&x4gXL GuȦ\и &q5#k7<+:DhkO4o皒 .T~_0:7ƼsK!$ݚeStb_ҕ cVĮ%Uiu(Lg6xO7;gLjG fNSMU+"\Fuظ$j"݀fk!DJT"~ݭcx`[[q`̳s8/8Mgbzi;S}fg'[< TH*6-? HR9$OqK2*CZ -ggx#y%"Qǧ3.xbR:Etd§NUƃ}Ef*e 4cP坿37Vd2)`ȉ ے("4^ן+) 7xS/Bwk!(GME>bIV>d (%v CK`v23pC]& U&wsStwLqWvAiFYž] }6g 圉NDQ"!)jGT L5gy q4B3ǰ EpT37Fխ@HbYQQJg=2Rbo{vp]ӼgAh /%HGLcX:`'ښ^M]&=Bʳs[Rx dv&2M:b5 0Z0V\đ&f":{D'%H)x:=bk#"h56~y|ۧO](܃h%9ybX~wC4VrF7``ab̩<4SG%JLӷ!gՈRC }>v*)iM_񆁰U*wZzv̰6ɋAЄ[™ n,b{8"JG8B*Dr۹+2Yk v'fs#gd(MRn",2 N'&+ qDړgxtJxƆqɵB0Tґۚ(V$itBe^m.w +#DQBUXi :vU0`[h!<2&áG˚~EU${f>W g h>pOnSh'4bpe8 PqF„l3F6c[8I8 U(d 4LĞSҒA!8 %_Yj T-)<d!>H꺦q/oCV)#&ŁiFa3ʺbTI_ svR|4b-Ղ C9Sm/k/xs u03;Rnx`CYAΣ&>̠'?{ւ=;B`\Rݴ%I`nSV/P?#=8->c?/J~|ꓜq}QGdI1<߲Π$4DYp~ӱR488 FHǁSϧ(H";sh-1N2=oL1V (, 3-z -Q}AXAiBx5@"z =@,-ٶ!t&1SqC*XOSx /ilU &RD( nbCT "3+J"601AU{ \n!LR6ZrlV\\(tHEaQJF>ȆdƍyHɫATfxJ#aZu͂0,hKSZGz r>T={pw }Br>{_%xKV{PW\ng`ajIx1U;G7\ԬY%[MwmIp,!C$눔Ck~'_";猔(Zt?Ҙ.9 Kϰ 6!=22lam'p윎j<(vϤd6Ÿ:RZALłCX#g.ri%o'Xd%SW97$w-B#Ol``k`) KHzښ[w y $ "!N"T3BH5Z^zs[9\50*1wg穥~?VDP55YnKlJOs [%$Ex&IC3mhFxfU8{ٵ3g`ٌi%7|`ibc)+Ǚ1IXKg5}g*sǰt Ōޢ(BaV݊9p`2YauԵi"%X:74=;;E)o/ZnYsUu5+@0LȂ a3 ^/cFix `XiJƹ|x>\rkŰ֣ˋ,Eq:WI9aaBp8)P:&'bdS-5")h ٘$iy":ˡń{hZsđ`ώ7D"voOS>OLڍQU֖~}4Vj!ўF#xt-K[(]%s?\avSaFE W# bT j$ 6`DvMcw灜 gĩkszi cULH1O/uo~B5c2@ \4i4D3x_-)Wl/m!(¶,MӽpHE][ H#4$HJa[efA`q!&MBNFBZk֮|1o4 AKRx@s%|X`F{:ro}0Bʦ' 3<uVG- Q :YM4P28J㝿Nލ'1:F: S OLt5&1Ã=`5X8(<4cͫ$[9LEbmrLR = a ca"3j< -ƪ&Vٺz|Kܿm;v!dGyk-Ԟ٨[Կ}?sNt 瀮蛒sMLmʢ+VXZ9ݪȫ faIO@ wcM7-Ư]#ǷKPTSؖܿ&5<I-U=wNhDyj+c>w4?$,mK6@S1[~.^g"!\ O4-*.VW,w-=r׆ X'8M<7특ԍ5C#b'lb0,,RHY8ZqHέVjDrpf7X'Uӎrq0cÆ(M'O+}~> aj,2CQ{Fu(/o*lp&;.: y᭓\Y+Baa<]S  sKQ llU,ocWmظu8}fG`$M@*-IZ`8 oލq+ s[Jo޳o{D,=&ۊ孀tIJJq&9R_ )ʫ39TjJ*r S}-A /-Trr8d~fM; uP0pyI,/mNKK+Tc_e"MkC.DkfgM'\"jf\]U*dWT5qNiv9zC݂g8EWH%GmB»aSE{ Z8L]3*,ebǥ߳$񬬎fk<~ImXq"عfD;wlE QVc=j|ւoYˁ-x2x^]kIQ4053x}>)j EnCvǾL5B*8, 1quXXjcpB 7GhLm_u %3mAe%ݑGHxb}NSSԆΨʌUZh&,#ά*7Ʒ9q`-y665;zVLIJ%廨=B_<#)4Cׅ q:& @}+uø9&`!T:|(CZٸz6:`)|`l #"$~  뻶 EdzѓԶLz Ef~ʅ5X=&݁07^YU0U^0=[`igYP߲c\#ўzG#n9U͡eiNKzvc@JHy̱n="nZԔƳcB g,v<4Dw?iqqZ89%RN;up҃:dj(\CyɌ  zs #vO]b_s`طe+mc ||3/=M Li) k*YUN$ݑ#R@؊r f$yCxkc[px/6o.L7{ř|hlPȫp6݃#Fuv()R=nDtrr4QP[ LJPuؤ|-\Q;ODnbk&C8Nw.pjEއ<$k=C73Z 6Vm|RXZMmJB dQHJooQ[ɉ;oer<6˰["`ev& 䣢"/le¹@+KV3`0Xر{Yv׺ߜs+WwunuTNHH Dsm0L06qp 8&c"HuB9TJ;4}[}a=W{Z17HhxݵW׿|37ЁyX27dc`kN$}RJJJHp>^)W\]PdE1QqWҺ V7H.28,;sad/0a‿Bp](5 >RZ<`CݷacQǔLSK^D"G u_xd5YDŽ XW&"ټz3br6]ଦP!%V}$GZ,ptG*D9K%$aOS $jqrپ/uQcW96L'vhJ$t` G z.-n)s[|[!ZH9/BG }zl}v5=YU >>q(7Tsr')_{8~jqe֚Gcp]2L5YQ01UՌ YcfC ,Y‷m/$`qyp X1R Z5žo[GD .Hfkfĵd~Z\rٽz/* 'wy ~#wٖN\}gWK mǎ e^-*CL!H*jEcQA+fU27Hv^F^XsTj.WJȃ'm-Q G3|F{5$Y0T5ŗ͒ Sj՗YB9MѨV>Rz>dz|Z Ynu %E1.hҗPZ V3a"IiyG)( Q2 K ]?Msrrvɹ 1 vI~z q($(}&3_8I% H* o6ֱE黈&e] #׏דD# p"`W|KUMZ,FXȀAZb\cNt3CfBDsLxUuB"3i^e cgiLO3!R Lg,/ܧXxB6aIa@p& KAMIДVЈu *!bF%EJSu ehko+˞F@xV3 k%#Cn,d·I"W1>y *>(T3e dYTڊ`xqf|;#վCC/% ,@:6%TCEiIceuMm\K")ǽ8bVw2ɜzxh`ȵ'M %ALƄcrcyg [-(i/x+kmΠoצ7Ԭ/rN&ֈ21I>dlA^Z2g-'W}Ie[AclPiZj˅[";Id3/Q([rhTR{ߵ)rzhBa8j|Sq\3mN,5BqNɐ` 'K$j^ vn4df"&4u'aIVSM1ba!')q*R ~7z:HeV( .̷=5 |8?8PPWx%ygFiP#JPfRHVO~Fe}aa(B"mAXh\0R3jq[jcmngR &gQJ. ˞m ea䰰#yn8qCfTMĪYn z9d[p8tjG36u!$"D"Fqp:P $ťW 5/ɱm=:o%;R>JUz?gm.3=#rq,4Ի%ұIȋ,c4g% yaBEQXxh;XOWa9*^ "G-Hqjé6mj'Q>o?4J(Y[K3ƚ$h,3l\-0ֻ Ғ$ D`_cGI%Z(em݇Pq6wYIJP2ƣaW+6WnY[OGo|GYAP80 \ގ[jIf7wJXbtwP!,T!WH(U+kj㱡"%aLd# [:B-9c:ՀFDnslݶ G}v`ɩ}7cAG,^y7V#ϸ:.q3_37/4#7RJ+dL1 ;k0Y ?*xq0,:x>5<ֆ^~ {8$q. 1plHJ-R HV\|WuN8u I5dVPP1 R!FvUՒ fE)$ >Ԉ3͐VH-صu r?|7 X}U ]d="/-ܷRN1! ?|_yS(Tt'q8?1ߵtj{ 8pl^b0̼hh$ѓ䦗O~)_PaXϲwcf2!/AJO}~9_*k]o}$_gqχws'YZgβk,Q{0 l iwr=,ruDyc e00L58A]Dyo%''Ϥp$%_=5/WIiyTZǠ KYlKhTCZ39pL'h \_T R;2hٹ1BmiPXuב.ėJW"T_G8}r;:)/t5{*0F9^QgjfszEHQo~ Z~s?Vέ:&ߺ}Tm5^ OXAX3&l]_U'!Δʫ~I(Nʓ~D#?t#:Cb 8D" Ä#/禤p<~rHw`zֺ͓ƇbU áa݁A<{*ksXzRH P %Nl Uh+~k{^YM*j"gGDFv !^s oue1j+r#X)MgՐTCEnp#}+0p!JբY~W @^v9{7mfŗ.&6l4IBH%-C"4Ou7O|[֛DT|9QTk1TX՘`#COV1ryIohk*#?﫮Hx5UJ>^ђg1cj xlaȱe֒e,Li$/"*S\Sg3x&B֖* 9AS g "ػ1 *4jXIO]EF11QNnis;x_R;#eC"E +];'5( ! ӛW& uESɱhAtH D0ذ|/?ɯ}$ԢKxe 镬v4ɯ,O<ҥ.Ieq%)! BωVBR -W ?XrtJ}yCPRjP)/gIPpĀO=R44k.j =?mK݀o~o$ː|5ۚB[$ Nkoc2oP0 +0Ï~xZ>'HB2ET7NdIyʼM? f7q^ޝE<,>kdj! /4G}zKRK&*p,P[uHЩ>+G,|j(FkHuE k?hO8=^;f\67Z}GpX_47lḡW5O,qfQRYjanU6(Egȍvaa;채 8&x@1^X7`W"C8Cz aD1P!HPkX7pAp"3>hG4t[JŖ rg)#Ai}# * TÀ}Y:q? Q+lc亣۷j;1- ~jıanYO5, j9N ca׶ՒZ Chxio׿U|>|s|3bg=+x~,Οcjz{x+xk|y/m> [T }GGGd BEK]{;8~DɆ.5*Hu[Gº5 BpRP>zbG' }^9N$Q+& ;y.bta)E0 5%NB"fc'x~~wﺓZŷT_wsYn'}+X)9lysf) eS /RzƑٕ!/̈R'8s`d >^<zͅ{,;HelY83xXhG_ 13r%1U>OOvDQ@ :w8S͈&NYJ] ƧX]5Q׽Yz2-lPjtĹ 6F\u>':"롔dze8:m̍HoGPF& i$&--* T#R]}h[4+ Ŀ'xK.ة6o%BH[CіkuVVđ`8H)!'OwGe$-Cz+KO!姧{3O)FJ:j(QRʦ\)m V}vi i~7"P=# Z[$ O}OIKYb[b8x4X-@iV/?r@gdΣ88avol]ZgTa7߹$z(h$S d]2VrK I/O2*Aҋ@Y#Yr=!MPpS,Ew1?G*,HaPxlpgec~1}X~aRYAPA࿮ԥQJKOJE2TQ|{>~)%_gߊCxo6w^z$&7o_ _-\*orl߻~nױk^fo%Soyۙq [CS0z.j,QJ_gNg"t g pb[9}`-`]HBe^ϴL: Ur3gۤe^e!vGN}9gZ(e)ʐRZZ[:B)(N K{qW_{©`5Hݳ5" w'gY[zz\9DzT`Tȸ\ Y[cJwo}3O dET,%--K%g vJ"옖Tɾ y܀ SsuSgRimn4Ͼiņvg_^M"|#rMwo}!O9yw_?Qn| (UZ1 ~.?yOռIV__z|xP(-!%L,,q8 &QZEg`RjEh-z[8]r?ƕ[ 03[8,tç[A`f25?yp *"%LTa%9aiޱosUfg"N/kۆ:scK 矐6^B98Tg IDATQBdXxt3ZIOVBJ >_#d  Gi_cgFSOqn;2ƫ>KeFAV"<b`k, %̎u^9s֐KBiqp7=)O&?9Pp,ݡb-ꌵYNPpF^">k$xOz^ɀɄ JRۧH2Úk$~՗;i"1x6ؑen&VBե>@m#ܟhX^uẺU˫_s%'-28K>D췱"B:EG xOlfa>%- (Cbץ}'IQh&&b$<+)>ϷFAT! Y5#E2(R3Fnk< Z tR!#L0'0)C#xg'.5E YKP08۴KmKVׇE>ci6RC Eī) C=PKLJDMPNF; 50QՁd0(xc˚t}AV~%NaN z{ѓF?GYHQEAL=eɰʳkL1/*S_y /y+!'?,ejy ߋ^޴7R8ɞ 1[J5FTΣ.ϋSCn"M ѥ~={/ w$P% Z]9Ν=ܦM>u#'h ~knx._}7ͯ}#'0>>;ز"jEs3v q5yW_{/yOq ^ξ/^?y<.jg8pf#jߔTxBX1:LcYw{FYzgN\QԍZ9 IL l`'s1\L0p19I(jZCuW:uvuY'޵Ay~y_Kj@$5'!pŒ-Ê5ƺ;T0FYкd41{7˂},SO^/8&ac1Tp)obR*If=䱯˙(g%f拕.<nY:+^8CvXZ)iR=mX?)ydF) :6{*bx$"KI0TcE85lXhjBXz\"NF0:2I'ifp"s§L>1'093M*I@x`kX9v7ZۻN3"^Ub`#pXaĊɈݛb>3 j W{^jӨ8O3@^;6ѐw2Z ?>G ǯ?#I(\`ٴ}kFw*#N’G s:}y,}psL-Cj05{4c%w~h8l8:[oR/sٵ1”ey9]1|$6]H5$EI tVNsf6gez=s`g1<4]iCV' '_jMoH Ҿ˼zU`^INĺ+.-|،-(S!$ZB_PjKA p'>½&5Ζ8^Gv'' }]&eFYD]愁"p>JD1@ȈFDi.PŠG[# B-XmIsM1)1g F>%+;)Q(Mb3w!XR )rRGxeau&n”]Ք(<֭;f"tAQj˩*요m3L;&Bڠ`ƀ4XZ}(J7 z#UM3ڭ7sb&IHKaT$BXSf*ۘ_[! [_k%O 09oD )G&կ~%{wl*7?^sRR5 s' l>{oᓟCV}rjY:2χqRņcXYQ4y-2#k@|[,BsaR g]Qڽ5Ѥӛ7nuVቺx9Qiy ZD T^'GzV'&c83! GiJ?7[r$6B(, }!۶su[OcQq)K^t$,Ov'gj>ۦ# C2 #jE1z9&[f绌4 ٿy \Q`,a ̒ "h. 4ˉcI票$+=dU/;}$cXqTF6MF:Ih(K@5tSl8xU>M`[~ar Z͞/IQ>4&O W$#uI/m|C#C~wkt#`]6t|آ~ae mMQqJ 3an]N5#(}4 eԇaٱAW^P-۶?$D/ߊ1 ~:_uΑ4E O6rS`KL٧J@01qtuT1EQ^[ }sS3J jP;; V֑{^jI3#uAR#| 's8 70tzq!PEs01U%MKPbIHC! sQ"y/|][YyFC$19AmiBHb,s,:ep8|Ea@Q)tiٸ!a[L8FG#~XB&KijtzCdY 0]_Z=}ARqE#,,Ԫ#!/yg{;X#b zPx sI(߁lIk!$ K5`fRwQY_~i;)~ e|vFCI%s;;=mOZ(M[q Kh+cieǿ㥻`C(AEZ*#?~%ne5 Й? P~KWŝ?>_=P08 B|_`0k",0&K^yWs-غy#{/yaR9+џ~u[w7 .&>ás?~/ W M'翜dhsu=a:pdl<<ᆛxOB/ fΜBkX7=|s_ayqxqm_:ǁRJ \BeEa K~πch@pv\1Ck2xѻd?K-lE2:VJTt!G!Kk94plĈ򾔪$,E$p] ,v֖j=fvϹFDI=Phhsj!,4!kCXpϗF75l 4ۊ(DՀ(Qd[RxZ-L ,p r(DSܭ~] SZOs(pKˁ3%br,d~E$׶r9M]E{6/EՕRhD9ĺٜ )ohD]րAʀ߲ĕ ~naN^8t ~ɾxB e*n[]BJIf~"ѥfs @YI V{k@4Mp^oޏ1RD',}T̎BHH;+ BPF G(jȽJZ͈1N }L@_S|m}a}aZ 6mqޫsoLIH֚)A(beMX򑿾_ys6/!~A *Gv79|9 JaAUp&cf{V {w|$*Bp"kSe+) 7y3Gּf8Pr}8r- vMOaUm]:i%C ˻~?0+KҜMn5>|;?VMR?P$x vlVN] HPMYaM{VYjj^|{?c8 x⎄} KWxD)E[u<0)5&X?.xd5Ll013z#]"vYK B&uUB.3J*S}Gcr6pMJ BBR +-M c E/T5Ry68 64w/?Yԇz2PE0VRZ<^v36%LO$6L$T1s]+0׋iEJ60~=.;FKHaeH儁,<) '2_L ըBI84U VW<&lh!藠W8f?@*mOnkw&RRB ҢdqGgi(|2QWd,p$iŚdBV8Juզ|,} @ ,u%1H0!R8* a:) J="qBsk 7d z%A#pBgӎٞJ)9nb96)_{9޳Wh -拟#=?a˶m[-ϝjlIfnq(k%_?Y^ IDATbPTbxdq'|&wo[~[^R6nxys_00,w]կAJIR222Lem˾}.P9\VyǽޏǏ^.}I{ p-`iz*sH>TRbS-R#W\yggfg??})u;Yɷ2wtıb*_A7:G6PrFq + Q1fXZPrc1 Xy񑐅ՒJ b ( xUy؁75 a-RD7T$ov䂝0{̈0Tӂ )Š  iKR D,=)XGu)s!`%IJJtsGqIon@pQaz#ľucm1 :[C`H*!VP=ҋ']L9~` cA TC"N!铙/λt+4!BBZ9y22T+ q(饹ovŕ2׃(R Rx>TR QB~NDtZ]ҞxO=Ӭd GR%g& %S#!tϸ8a۱!&v)h${gI9z>cDcǺ{)J˩evRo|%O*jH/D!4>R-HKDkK{$Ah]NJ+DIhepӷKG1ȩ>)㷃 Akde`+m,? HM6GhroGNvy<#4Y.8JX:0-CG\w'H VB+gƠ" jĹК' dtTyY189cBɆ+)KG- XiTbQ()JJ@(vn/-BxL58Oā\$FaNK B^2J ڹo䔄#Ml B!Z >H-f-$s>b3؆=ݥ9<0Z9,w/ĕsB0yi<*;A/ q\$`U/qD 6@Y{4G J,bPZk^Zp1K鈫nꟕZZ{$ b̜9p=;22FFk{oyK$J)L\WHmh#\(HL{Ohz+G 6rG)fo$0([ JDDA(a1@I,T/WsI5&"$`e9!gFWpJD$`X|ц:O4}rՀlMYz[1iJRƘ$L K,"AiQ2\sS*,-1wԙ7z8tO|S;䡇Oo~A: Aؼʓ/|$eiQd):sJ#vZIN1k2_ ؛}bǐkO4GցT@if$z>NEl,+nN[p덛5R^Kh[Rm+W >2X$@Lz5\0/px۞缞|d@0_X}pvKmr#qXC(nk ތ˛$WSK۔B1${hI3+ g~ ڔ`P\8)qΞX5~9"0B00Z_CIF)8ݴP8Fu|"%U8A0c4\ŏsZj0ӓ{X\[$5(>0VɰHHIaasׅo;NEIy,Uh+(?ebrcz;;ơZCTh Μ>ӟ,>oq;λX^G;eʑ3̝=ǁ/YLJsg΍y;v]ȍO;n^rW|>ʯ,ΝÜ~Y^yQ$ٶeCGWt'*P$҂uF:P(⹯z" C>W>5{ 7شB&&qǷS>=jW-1^#Z-=~ =`uyZ$|YUISxoo{B~uw6>Ozزm;5e~ըt?R;)8״֍-Ă;k<|O)vLE^ Ext1;5x@vW8kٻA CHe1Ri~zY[cV ֺ}]?Bi-F^lFX0`e;طܻT^)Oz #4ji}T.}zu^rhcO, uC`uc[bo#mBy3]4*0)C8HKPiVG\axF꓎jU?%y`K'g]P]d:ot(ıdT^jH$ |S(ֶ.: F;\ˡ(,YiI"wg6Ζd2 TcT4j2o Ydɐ9P%`b4$/ॴ/˒t;kFʐ{u86_3aփP=AI¿> <<==!!/rEAYIO eRI yľ$UƵdf~ T^"Ǯu>A@5iP\1 &Z\o&*О=2:6R8zJ#cM ظ^"@ }~o~aDɄ8McY^}Okw>9QJ/@9|kW񦗏/?ZftçC`2 dH5^kvxM^jSߘ:%TJIVV3 0&Ě+J@*j+ Ǵ{^Mo|+ﺝcs**P4׼#=F?- D`Hh;h2C{-7M!/ - <)ZXaR^Opw %d(ADh a$Kxch4W3ܻʱ]~nN}GzӁ{%4FӜ"fØ`b*ai)#ϼoǶMb4cD=QrȌqЮ>8I*X  I4u-gWHˈ,r1= O㱎J'A(Np3#/ߙ'/j$IO)$bQ'%]14iipeL KgOb \Ac7:BJ鞈BDBh $I! FϐSk} ] "$}RqWlmBxsXrɰ`D!$`4̴&( ܧ:Rm0Yc)7kK(AqXқWWJ㘌|Jsn'淽~?;ȥ]̙S<ƛس{7f\^_ W?罜t7?E_J|{ S76ƙZx<9[xmc)IVj~af>" CR<9'^~{)sܭ),VI+T kOBPw[_0'&-I+اwOw W^s vϱX8RiTSӟ9ME Z5DR J vU,S BҳG?[!h|m=yrqŵO}8!j 䅣έ2$3~ !`tDْV;lN= %n nstISj?~QjGYo1qnNߧ[ndgW᧦,='Z8!8x*T,({)ˇן9l/6tm ZVZF^EgyǕ K=+GЖj,D;*, 8/یBBMP{4gڜ>a bNsŞ*0{M8S 饒n Վ7UC Cc!KMMv5IYVDnR\C'wD|xUm㴻9Y ٶ-faK[bR~- QA $ՂH9 $O|\=s8kHK0"&^ҵ;y많B-C 0VSIC=[bakyt^ezEfd0>KѐlS,G )qRT"?w@>^Fȍϡ8- RFFep yhhQZV:*ؾ>3x`ųW ze~şOݽ/|F[|悃8_ݞ&+i|DZEHxfL,z\T!c1͌UI,i/~{1>iW%,,ٵ. Ga@^<`lFf.Ă;V15EA)h4B͂HY֖߱pTP/jtWj$p bV&1ٜ0RM[oT;hV{vlqBO_4qO){)|QsI[j0ULrVXlϥrGOsvǞd`E~`'H T%ҨRQ+B5yF1)5I0 C-ʊqʑY wV3=t4Ic%X Pak"1 )`ݐ8$G77.Ks{K vm"Z()rw ~)a3>>wqo}g1;5| $~&_wy_5A@[~u~0ubf(V$ )%jgq2$Cy>+r?c]an@QhzH29jVWC`kbuc8pqrYg̟=](RШL ˽Cq]$/Bׯ@F yi/qǘ'AHPj- g!pݴ /WS8(cyi&!w=(k׬y#IAo f2;veaB~n2Ch5t[餖~!8jVXM[kf,5͜\;rѨ)ٱ.fX3^sr34\1) mk}o6:몚"Tm1+…>ka0=1t-NFw` ƻncHQ VoϵEIHEQ-¤LIdoker[+<1jt2l[ W%QP"ȴH֌Ĭt k": _n_RN@E B.^NYX ClYM|5BeB{h8ggOfX~- GW'kp#[wbyq;8ٶn7K˿m^5/{]| &&EI~/{9‹Ň>@ N M%z$(e+Xhl_C=}]R`&-pŗvye;4"2ЦTVl@Y~pgS.¯5 Hm)ǂ7}-ADeU$ ,iʽ7R1Y+}囌O}{ya{ňzmU嘯}~MJ%￞c 6~2Y7$,-t㤭u.|MZĺ (|Qxᮈ,+褚ϫOFohw BP?+WcOHK|JU1*Y8VW1fbIf?ɷ;e4Qo^ #)q1yfIs9':c~rASH8%*K)ǒ\ Bn?Xʼ}79vs!@9_ ȃ't:9^g|РۈvF' й.D~kiw)ga ?i zx`GzoClJ nI'²)1$儬tz>* c!( ay5?2驌u8*<W S-+f&=4wba#O8QPdn\}'{?}[%M%x_} 6on^zy܅\{s>QxI,JHT_pMߧ^]13o{ON<4~t2[ˊn 4ѝm FgGfˊ~n)GZ"iIĎ)|S3SGټ&uaOP3~w~λNغaV7Zq;9^NXXhfxi_S8}FFBW90_7$^"MŬ,hX֍]t,;V: s|{;p`oRړ`1=cnϳΛ;牒:֌m:C>'S$±e2stn4̶(ެi}q]-pk'4 PFMY=zi'6ȍ67s)ϾVWPqTr>f:7dZ F/hC%O׉"b˰^c֖cs}9D8~}>F{\'54Jk3{XQqH^f9穌-Ic_{*g2}oj|_5%h滾Og8v<@zGJ5,5Sz} olQǹv4 ?cF!N~fxPZ@h~ BVZ>N*IqN0T~Ac,kc |[zIP*VCS G?|SyZ[Λ8i,yRkв죍/িkKk7bh@)3RR2dIhv5j3/ɵ /&$^OR.,A WҾ %"Z֟ c|>HI1TO6!'*{p#\K `h8 @Ry(ݮ?ۆ!3 hs|&G[`_zD?3:Xne\|9k|joC²25!@n_])KK 1h훭;wj3LMM1;;@zO?&4N 1|J=]߆1T~h%4B6 R"̵-\V0bdr51 M(ꕐ'Y%HȝZ/{v!p oЄ0F7$m$~?nz-`qg>( \x`$ֱn{q !2oH Xr1`$)R/pI I$F*!FփkjmxdJԌ$,#d"5$mcA;țg-D 0[+v׭$p<| g%[C;wku76qIQ R&Ξ&B(ND7WI"Fi9? l߹gtMӖy-9 Ku+~Zg4e dfoNndi ֮sj:]W>^sy^˻_ ?$nwY_ ~p>au.gFczOT$7~Ffo=X3#9LȜd]MIG6K}57 @5#rA9c) b˂$]BiE?y|z_"2pǾạ74.Go~Z~u^sB䄵e* זH)VU4_T}JP|bg0)]đ\SLnZؖ2cXD0W1FJ8Yչ7I)%9r$XN-24j\wF*߲c hTX^$༳GVؒHp vl(<R ftnc"~/ 7vfeqZ|Y{AO1Ub #VlXa`~[@aPJkWoQ-Ө'Y=ޠV j5DHEcͻ'5X3QCH5^X^(c+JIj3)r]*8r2k5,T*K-M$[U⤝PSQሕ8ʍ<{4Uވ #I LTv(J%$mVy?E]dUuWTJejj~L\GꪫE3g('K/tEbPdR}֞OX_E",’zìh B ^(@ c~ʛC)*u-cV ˟߈Aүgutr?jyͱ:e6 TT438@%"OJi*EfPG9W>>֣ГF+\[YjFV7I)BIXWzi?Ew͈- BK,99AB$rK]XB`:uh`]UZ$'`,k,H 5 zLk+ȭE_L{9ÊW\˙gM? &$ɦg#K/gk{k֭gOpCx"*`p.'<3TP69Hc<"o7ع$Ž@bvz#bOrl~\uy)KhU d Y&{t,XzC3?硲wy,dm,ྣT[XcIn%_b|5~>#I 0/t5Wh= R09c(ENߐJt(g>s^r5w)FK9sc116JQ"*3l Oo3L 5NWYoSMZV`x$׸&6կw!j%SGYw9V}JC@X=3J*G,Q{Z=ε77!E(dt(`r,sǦ]W׾O> fa~gν(.9rN5Qlwnc-ydocG{;+y1s|0kFyp_JFjK馚Ŗwlhi3ǨC[C3%}+Vd%;v/v6Č5wܷTwP4j!Ґ1y3xdcrF%u{>0yHtBN?s~3yUp#\ Y?1diE*H!d #QX+8}utC R(BK}! <$q劽9 v$LpDQyәdyCD0V ټ&8CṂ-rxD4PJ[SXA؅m3ITYR\#Y&+,sQ(FD!F )%S먖K謅qj@7\|bs9,Cc)ͮJ+YfYZ +|@ 4BI9{†fO9J>XyU!iV 7tѥ_f=wRh9c# (YZI*(jM4W>g_Q*Ku6v 7oP]Km gopV+hMX =s C:Gu J2g8wBI˜0,y|\ RptL%MXM2Oy J) e(0&CF4je(+ƛ?DP"ʌ:jrV!E.0Ot2d6`!WS'JX q7G,6o㕿nRQrL&}6"QJ>kkBOrlIOhg_Ue뺈傉eCq@9  QļhuT0(.R܇"* IDAT$f &&,}Ou)TZ-FIr)t `0i~M5R+ᑂNO0^SPЈa?z4Ք+-Ez^ ~Mo/]{|+原 Kez!Z=C@\ʈA͑[TPIrp Ͽ|=3# R̷?aRamm x}u rؾ:rKEWVAQ$Ijc=/F^:Q~X)ٶ8_d!Q k0x500)KU! (G5K+{MEg9<[PXbSc@ڹOVkmX\4h# OrK u~%#$8d*)>ړ.;mNf PU)P >y_ND@8eSNQJdoPo?=ͱoR.k\HW#UzI*o|sab˾قoV%jY R*=GQad$, df$#C1Odx߼u3Z2P^xD~潞yn{Hss*cӋ*t5 fa)&w}KRY#{^On,qwBukk==41zH>UB6F b{l>ٕ6Nyީh ~A,t)r #rpx2PLDg)VyezXngBq( [V'v*N7'$5IV( 2Dr"ٲ~<֟t lP啯=N@!M8u{\|X̰ӛ+%>z's}~mwO1u/}~h 7pmo{Z/27o>' L%XASʸHvU`(JYN1VzG?%儲Q08Yy d{{.jjF%3\dݥi2ѰZh)>%׷*R-$ YitRKai/u^:^7¿fO\UT#A*Nݔ YՐr,82rݳx$g0y3,5;$P*T(0& 5%H"I75翿\[frZ6aA8!$5PJ3u8X jX#(4phҡ8s0 ?\\9. ^uv-cr`,c5E2"[kf^ %Qu ytsrYUZM 2RCP!21<gL7d9减T*rAp 1H!BVxpο޹Jrl f;TJLs) ?8 RYuU% $y$Qp Ń'3:xx¡)R6E8rjeq6rf^X:RБr$"EgGਔ[6 \ ^S@\q1ƒh/ǽ7dXk&B{Sq)%!RHM]MzL>OYgɳo#+ 7?0ϝ{|}8 ژA@<Ӏ#/,']]t:6LxFq%kس 8$$9{W_8, Phmy5E3}߀8KpCsce^Ml]W#}(q5h-80Ƿ O%|R$C>ȝ-"#=bM:HGuիټy3=~*7u4H_t,J(K=D RCVjۄ@!_G!!aʣR6 3^*A !r ,JB v &V YTROYR{k#{g ˥V9;jS<o $=[g~z  e)FG]K Ӡdz-HĀe B[o~PAzRn4Uu)WZ}Ǧ>GC?YIA(=#hZ8(Xi{$BR{!ZK $S]4$G3J`ok k8gpg:PO2:}g*&1;# }6c+Lm~ntMN@j,z/ɝ5!DSD{׼׸gwq/aigma~8բ$3)tS@H.ȯ5oVu뷾ͳ/%yZ_t63GQ >?#EGk'> ^W~({AQ̆Mۑ?x8(zկ5*2+Q>7dy#{eUg 'uI0B P 66&.$" #DI`K !5ɡs8>51k֚^=uT džOO/g{Z>)zf!LfUHoD],j#aLsYJ"1݀UΚuH`F/.׻StJ.]JQ/q?!>-%5d FTFLj̯}̗%ێ_^v~ ul>fZ_6ǟص%̨OYY)iw-\jc-l< FY)Ojʇ}3gnfwj0^U4Ǐry/{s/~S3}UA5 F 3x'_:S-qn}KGLSiz$"=4ت~>D,x5~zKNrVKZhv,j5.u<2,p]57'I#[4+֎l{99ʙYj+2:)${,,z#eXܸ@HV4v߻1Jֿ/ < 3AZC~h}FvV:.{o y.qT@' Vqe6tQ!d1ɃJ &VbnYPK"D`]hlN`g! ҂$L7sJAE#:FR0L-C5EVx .}l9/0s$Tqܿ"69ZE1N(;@U1,l1maq+3( DٖƸg!LJ!rzRURdp#3No8VzҢ#)nHB^Qΐ3^Y!/9*%*l!྇[$Za4bǮ%kcd$^8.(4*s* yI%QɌش ,^R4Ѡb/0N"*.-\G赬05<]%D@+ *71G5 LJY5qx* u_?s/ rc9~kBDj<DBzÍS AEwQIWa~=Zf*kXYScϞPLxyV`}RI0bGT#vIZPDU"mOa ŀA!J n)<J%QG)NQfgg[DZs]w}gann=x,_K47ÛK_?,,l|ݯ_Ӟ\~˯G;g{_#};V/J}dH31tJrG ;hH{!/BAy|0ⷄ@kB RŦKώ^2s_9ϺL8^ۜ磥ec)g&Fjᆦ~u\˹w@L`ٜ\Hty>'lgn(8 O',8YnYxҦ'mI+Vwj.%~ɻtKN/xJO12&V[VVXbIsCQ3`xp_!"aw6 zD Jt_]၄NBG}9',v_KO~U.tw>ܥ0 SZhb$f|ocO/br)#G EyÅ V$: 2N8a]S#5:ݛ[=S8huKV64z`XK(S  G؍$H7 R4 Ag Y{}{7UU2:,'Fm2úKO=UTӐT^r&KUkZҨEIº,׼CʀD MwXIpB:eϑ,NK~}O~ Yd={Y[[@#bd0/Bɐ,0` t8h-*EI&?*t@( 3Pko b Gdt43:DJ))kHF%\woHfdGYw,և@T\i} Z>04_7֠@lsG f^>tO|9ec?Jrl84g&#( GR@;Ha?ay (ƅ'5B_Eژ$IĚ!@O,/ܿB7+4Q!#b829^8N J',YU"}- $'L`à R/$ :F#%:F[lNX_=eb>,=*D+t V&Cf g1Z# BjMhSf=Hj:PsdeExzoz\#jL.Zv~⊟416L@.tnDf  #%*w;z }b)iox.@k)Lv|#1lڲҲv|3<cSnbۚ1s?џ(R)|ҵ'}*|ZN޺K/3oz#W+smNO| ^@\k\+yW C__tfrΛ?Қ~rv^wsx׫|s;whʃlJ:^B$wlڼի{(l@[JW~w?o?T#N<}|3gph?K_B|]I'b'yƙx偒zd@0Vؿk7286B&[\㽠λEu wd0+%x|5Z])Gdr֏&TJ*t30v~ DٰGHMn`'E`4*8~KVǐeOz%%%k֬CX5`U_0Yݐt:=tpW)t ![OeO`0qO_2V% sCm[]Wr:[\{2?s_v2xū^ͿRqon_-׽MWs^p /2o~:>082cE{A`BX>{xEksU֍\Oe/~*?m)U5`t@3P-Z Y 8I-?di1C%µoӨxnz-5t ,RzG% 4\ǽHRѣG9}f@(ږم8z?Q* Z1j@6 KMGkmf xO9}9Qp2R^h#+)oZV:(U4er)lb\$"VY'U=x B0^,v "e)2 Rx-8isN!xp,w # ( ,uLʀvJ"{ogOy<š,PD"t3 m^*1cc.R Dn G XiQIAa/elryYeE&ut#Ac`\چ4Tu(ZXd ab\1%i6֢d JCj³v@Jsi5ĉy -s(Æ[Rb.K$q޻cMk O\p?R@CZTZir@2L2?Cm}Ϟ;Wh H_i $dJ@[ǣcr/&@/\OhILa,5AJ J0"D L5pZ;|h đ`ϞLis2;HX.pewPN@B_]j,*.:u;1 'sw>o{iuJP|wahi!P }_i-<1sXcB29Jy3e?b|4e~%;&Oa,KC^Q,˜LiZ2dC0^gU4=ܲc'*H#6st)1߾ddbqSLrhdAKm * (R$ѓΡc!Y@\*`L &-vR.@@A:s:D&u ګ`,X2UBU'$JEfEibta&ق<ܡg&}27/g\~]Z"(ǒOR8] (%IV> ({lz>׿~5$`so%F >f,-oXZqzlmϡaҪiN\=Aw1>6mA)23Opm;7~HfaWr4gWXX)925݇s_d~^5I\E"u(BW;7.svnY.*I #yfy3)DK "))KOե.2shD&GAFuc 'ƞCt:%=1؈y 5$ֱ !GHxعŞC]bS!MgϬa, eSMUI\#SI5c(cmodc \p>lCH1v%_ 4'!(fRQ iVM[=I(,J.մg Kc11n0Y7=^"+0JJTQDH $T 鎣K̷<$S-O*]SldKJ01_uT#- &LgFiws:cM]2t;+8/“H8"hDni}7EIdDQAǮ=_-k"JHteѝfsկoz>˹\}O{yo•W|Tx˞#_/ogweq՗D%񟼌57𮷿|񳤉75C Em5_M8~Cw5%zjK)ɦ7ť=g-O(~+C`M3 Jinw6mU/9oֲ{^5R :/xus[{9y~$Bpp GL!L$9s(6v8۷  -nKԣh0Vxɏ]<~#ON@RQwoz =oO^N\90[- i:0GmF7b/S20QqρVnYYʸI.7V@Ik7THEcqؓ=ԦV9p`zMb 7(d&H5YFDoH9jxE'?):PIs"ɺ90<1p %$ k!i,{ bEcCZD ODŽ5, [k`w7^B L*&8i"16#R%G!u /s(eUst1'M$U?p 媴Ļ"7]2=DyhΔƆYQg=.D/ ;`ЁC$%eh*ӷU8iuok CUKG&@CT$UJ X!(R)KGY:__%N4{)DGvۀ6eXjHjQM 4ҽQ$F8MdfeaKI(i)AzRZ;YB!%( N\w.TcKd9֒vfcͶװ#(8[';tmM-:uc+<@SO7݇grR1CzMb (W_;93&ǓQ5 (QO4I$Hp]VzZ7Ksa#uu'Hc)h/ zHiFQtp3Kw*MQ

˸/nI+ґ9Sjg cAa/o_A;۠yƶXRrϞ.IE u\'v3$O[^s.fx_y$Ww/~)asϮ+-C7r ܏rڈ1%N\劏Rɑöq)QUq_WvffɑٖA 'HG;;liYX#6tVĈJEQޘN(XaݴֱRi"%$xlex71ģ[xϰhDչұX'W#)~ɗg`iz*kynf#iRQt:N$=}*: *8l*H2ؐlVchu{gɧsot&"F5i$1=k+b-JÞ"<3#(C' '(YR Gc-j1lI%+{En1ef&/ Ń!y`$| .H婌UI顿"PI{畯>O}l=Tk8,>g=tณNAJ7;\ē엮FPDVM0ud$%u8t~d2L-VTe.BJF=5ejj)# $]z fe)4Z*fL,O}s:x-[ww{fx,ߕdY<YZ~)#h-ł ړ_G<<Zf|f̘K9ːuVGЕA~-r_Lnϑd'J,x#7{,4j eq`Oş{gZOѯx@߼g&Hkk$т$`@R$2\-W1Ƃ5[S=A_˭ȓj(˒4dYN:B]F"(ƪuCqoE)k<󭐛PHK@{T aIoٞ= IDATt90·bfY#2H2LZױܸ3ǘ tLfff8%YnQ"+ X>>0ѧ>4:E$XYӈťp"Wp(4|(g[H*Z2e9[8DRձO)yڙ LȊlh{71ḣ ^D)u ŪШp~E`a9{~?4 kf]_GoМk̩$A%d%6ƈZB16NÞ#_:Ca=ݛ GyH( G ܹ<'8A1'<3%M@cf-c-- F#ݵ^nYHZJBRI4O8u=~ݻVp.Ě0mw?~ܻcv(9OQzZ-CY `U5DA .=sLMMqWvnbHwJCa(gaqeM) O7f(J8W߿MY{6ƫ?B70sp7Jf=.Ι6Ҩ @; cĉccbbllq q;6^lE hs]χ}$Yϛ7k+{-k 9:>]^!\!  AٗKGL5ںe}q؈Ϛ(Ŭ]?6JT u#EcL=pQ=D8TJGhyX@($f4=e\F2XhF9Ջ*3)o8uK<͞gv'ĩervz'eI7dp|;96byVlPJP)I*ly ~PU!g0x(ʑJ0Yhi| :lo'k͢5KM΃;puW8 %&o{P$ lyxxf1(`W15R)RdXYiDk $)#<<UEY1 ZYH_ajNe##OJt}Iǧqjk!%}v,̴ډ+ha8 PxiwfL7^ E-fZflERoI;ynz  I 2vdإ]NA2Zcvb-5BaG/HErRI 2/#sDx$!֮(?jh2V76N_,KT>]/ϠZON'5Ĺu&/aIRqb,,vZPAUWDFaR%eIuNEVW3 AO3)svuˍE ٕ CA kXb `ef@iÊvDIZʁYF°+V09=ÃRcvkPr%_epZuB3] Jo|[4AaZVXEfEFsVsƨw%]X;X3W)34;-47~^17bA)RB7Iy1N94eٿ4n+X͈z䦤_~ yn{Lj!Tw.7#.5$Ó|=>TeC!%_s:emYsA рK7Y;;Ksj͡l~ҌK_nq1;3MT`('t:R<8~&gffcn*6k$gvϷ 3gw6,>BNIGUy5~7-T`?$s1ٲx-K |k]3.68T6wxa_@Izy|P>@"Ume{IFɐ,8M%8nXpsNY/qlw`!%}slF+6K&333MɝWvwgH0R }۝vMfH-;L1ȓRP$YQjAiZmϾm[5'<λ3M|Kcdbղă=4yD#YtMНԸ.2V[ZI@`=I}I;V7;!K 'IGV//WXauFz*bz>#`aBh>,qK|0h!|QAX5i7CZ!{|*zdjYrDQu{a]n|-?MR s(gӖ6{g3}=;~g@Β@ R!B +354ۺ+sMTθlaDɩ6I鯅웊ӣ$GfHRX>v!B3#5Œq D*Hxv/R|to:uyT.C(asڗR,AxǓĚv~"'yn˼3{_fQ}Xz}<騅:*Vs!& CVK3?pӜ4!,nP2vKC)Ef}Cy$NbP %Y\L\=5J+ΪI<̐ɌeiY8ky&8W!Lƒв J| F#C[6R؛;Bd " @Z f.؝:FRO-iR|OI^FQB˂utBJH;^p)їw3)Bu u0쎺ټ04c,h\wSB t2RH炩v7-VX{Hm)%H!7l5A33s;q޹g~Gj!&r‰'W\XRadyBTc:'wg p_Wopp7p=/_G_ NŔZ,W_^uZϳWĉG?{-#QBYllDZ{vn{ e}܋^ jIjMf }ep/Gp 'sk^y/}Ia:2XjA-%z+=F H`k=RI U<:rֹq'ܾ J0R=Jm7L2{4Mݛ\XQ%z]atF37X^qQ'5~;`mX[O®M[#z7S#M =L74w_pcT>Z`ŀ Z ZpLC/8kS އDЊ B*;+'i}bs&sN+xzzy+bV}pFL7Cnxr 'oQT*DJ$8zeH__sjmܭ/- λ2޴2f_@H2*2ٶ"Ʀ4B왝!-('PtbZwn6ӱ<;1tBP,ɍ@[ e˃gl'7e.C as8xi/ҴL7iۅ|Y˾&miJ 1Ey Zn j[أPXrA'Q*@v{RĐ9^O(EґʂHxmjǽZ5@ PV'eDڒ"{K1!u0Й6 Xhf./)'*ӎ4=:MhvO\[_ͪ@*(PWz z|IZBF^p(Zc5ە%mFlkSH/tSJ7:iڸ's*O zkVђ}溭<3A?K}/c\p>]D%APFXئY_Y!2bMJښc߁h<@STfіU#%z=  iq]KEWkF+(O& ;ew__A7^Ѱ}|iHrgS |j倸!\,Oy%-j+]"˚褆U=r`xaAeuxɌ/B 6$hgG9jG8Ʌ5P$X8S % |k (R EF(Ox^$,4lOӓcVR$ϗ^f-{&j9*]3WS%\dYRn;gw8b2GPMFk[%UطP -VJA;Q)%Pf2v lIkF8Z\׻vc'ICS a񀳇%u<͌ǺuGrM ]ߟ 'E?S]w޽{] Sg5p^8zEQ*z+wyGR}սWWRroÏd9[\pʥ왚#T׻l)N_~ƈҚ✍!NCʖ'\b F ,PKA][ ٶAh.;?svRڝص ^a!vVM!=4D-)^r)~VzY()XH'?N:>Wb 9b{`!+ `9#.. \_b&镖z2TJegpR'5H%]vvrQq)5nc" f$ T=cAP*i^yem RBOIKw a5RI$wѭk>v=eB۰ѐ߃T+09r͕CJ2Soe$pPs9vC<}v5I9֎h+v8p@+J81Yc*3KkWJɏ[pxAo(Ǯ~2\SN$CǹH6cY֙l% X)$l7Z(GBP=${ϧT {Tdc-ylDWG$oOat5ɍS"Ogd~Q7f }~>WWsp Y:J=\qڙㄕ'jJXR6Zb\iXw(oV&޾ݯ{-D_iH&Kf;1)w>䁿O}<>?o6;!{rftrjBCblgσh^O |Vz9$#GgOGsH@Xp!dpP%J.^S__?oz %K.CI'H%t)W JVZ<(*^!p{'d4"CŔ7j&33,4p͵_{7FԵm޶@ͧ6NcM I#N=wH\_{7}!$cc1,:llÜ[yեos_ yYX$<n4;x=6,:!}Ed|F_#ǟx}'cM: a -f'06a:t i VzjsFu[8u۝nGԆeyQ${A h m,êGX2Q BjY`2%vMDD2#$$#dEY^-]*^^3֢SM!l`קZqd۟MٱDg%z_RR*KLX=72}a3LV'WSJbQ<BS _t'q`+)0%/Y\vD9zc,V[j_dNW[Y@}pJI<Zg{ę972v2qN3+*gk]Ak-H43u@xBEP7!c8R?!ܑ̳ _k!hnv8KC;FHnp' )-iڦ3 X/,֐t&&PdIehn(t@gYRܯU$..Ժx_Ir r^ ]u@Mn,UEGvfjV6ܲeh/b{Nk,n< Att@ZȻOhXS?NFؘ 拟<> o/Zk'?sS0uox=q]sGC nE.=-ﺊs| _:fG-(p7oᎭ|k$o}v3?ذ8(WJkB{#mWc,{i*~Zڗyygp<k wMv؊gHsCca4srr/" {e<CebABashg|]nMSʂ Wz-;,}/ tmrݗ]& R<⋌ސu- a8'|*7Ӎ(/'m~Ӂ.ftRrRX я oY7Ye;Zx^r U|o.m3wpeCJASTE jK٧6qӍȕW\g?I$ZP-IzlΓFI5OCȊ| \[UjI-I~.♽)i?mKQ,[Lk4dz^>̑!VNZ` N?LR<#gZG{g31Xc}ZGt i:Y}):e,*sl3,(^7/|e @N;4;L;Hp2mQF3u1vjٽ9qbXԧعޟ"I3xҐ9I2Gn8eeQ8I-F(38R =@~P1XQ(ahOf$;Ƭ_-넞!P "ɃsyyΦS3{szntpm)ŊhG[Zq[Ϟhjo@w3E)<v9E|>n6yw#qvB@',DνO-dR ȍ+rmi'0 Fhci W Q]!KQ`x ۧ,i-IWӥ1J2'sIFF=EłS.H3 +S  \!l <'`ϴ$YkXixr$^sQkQ̼FՏ~7ԐM%Ʉ<+1Xѹ{nkksL5Z#l4Z9suHiiCmҞmHwmSeP&g4ɱV#@HBj)&fS{I#EkKlݔwNc~-oRbR:d&4'9 i3E D$9RTt%n{F&#Yx*yМ[4bS((m&Cf`>w8Z5Z;gtŗ\|/R2m,^4iTmXX9|욌T8) f;X]Ptjz Bz$ig3 $(H=.DF K; ٷowZė(Ѿm4Z I 8=k 义T 踍NZ]:Na\[Z&G8_7;n@B쬻B y$|!M8ˑ~@X}$Ӱ'`O#? @X[FAq Ñ/".ty ]t EZAj0 9&ҨDNAjliQgXk&um Y S!jO>;3C|c7^zj58#ʎq$K #5/p1z&wϳgn֬]w^}Gu6b64RqXkx _q=v> 55W^|o{{zɲ6o& gξBN8dBf[`sʅ%sH`_WD,L%箐ܵ۸Bž058לt*yz:ÆE Ҝ"dƒ~VYo\e6p/ъS(4κM\h|_ey駟Z)}s[vrZo/{w#VW=O?t .xyǸ?UNf>:ēOS^ģoaŶ .9kT*=,^ ^ 6{.z)TpRAvXrם嚏/nx;1kj#9|K/eI,ifػg7/{Ō~ _:^tιy: Ol92硰V|ğ625^E=E !x)y"fqyNU/obU_: %>s$ʒA@OGv%3#tbâE&bjEEw4qZI4S*H2g}\ @)I}߰bȧcK+$ڙ'#Q2tYa!հ{Ckrm)<0Πg0LY<`|Denck7-C9X {!"8=d٭T&lҤ< aEX fR( pQ+ Tn,k{0˪:Ċ]UihrHPsfGgtFQQ, c"&C7tn:WUWu>~ pΌenWwԸ!V)A_|OL &"V0phnwGu=K%II& $qѶHjÓ9ƽ澲$(&S'21[ W@ic1X?Y4gb*ͤ]ΐPM`P*K]g%= UK 툦S$C_#qJGyp1λ{ ƸZwSjuT҅`5 0VOoj)uϭUh]o)2VXű;;ܦH(k97oa.'+WLvbϭ Ib<<4D^gɒ%{xRxaiI%]}|ȡvv띎]аmZi,-ΉQM5o^ǹozvuzqJmC =Vj9x+k㗷r]Ʒr'z;w!!Ώ ty1/T1r?_7%W2489s |HOy /3kYSNYq@DB"{a\p<ܱ9K]jmO/^KcT\T)%-9:Vvh'QBЈ 3{Byj?=6s;2PڲêV;pQ7%K1i`}{ykYf8hv: ȔصNDSzjS]ugt$s', #<'-eEԎLTb]^`b*EXA{ _YTFVBΕ# *-|Dh.cfv"-|'ZyOgigb;Q1<n.EX\p$k%rv}F ޶(RJno$DÆ-)avOܐ z5exD+N]@2I#Iض}}]>BIǀ:H؅#~y(rkEggSسb>j |>e+?߀U:ó_&4V%|rG*+fv. ѺF#/Gh t(K7;J3/ΐl7٢MLgrQ&bH_D'law-[2mJRB.%ktaay$ ; =+ it+萰3vx[H~ B5?%NhExN+A|XI\]N9yҎ^vFW*+gn<."jMya)W(W fzXe43mT(ֆLab?dy+,/`ZO~=ԥw޹?D +hmnV'4rn{l9s87˗KJjw1\ylۺ޽>]w-+#/nZ=&+v bH7mfH9I3W0T#KNYi@$ C Iފu]F!hԦ0Gu~qಋΧPGGFrJ?'E {;?MWp~{Fw>`)l9? 'ȊyqsYS*]GmV={[| cC<~gÖMkyůE)̤QQ,9qMwsđG5nWXģ}9eē㌴ eL\κ%Zb'xpI'sE Qs7OʋϰV2(Q n[)`^^K5]Xgqz|Gk,hj1ItxYe̙!IASq z ٟC+qeӈ,5A(W>~6h$daOc{Q (pV?wI/wmHYAR`,0:aFw@-*)!ԍBF$BR1ede]wC4u蒹ELHξ_3`ˮ6 W4ZmaVɪAyEhF18bY]C144,9p%Fo)!K bVIrIzBI]y5iC2/ǒxN%:%Wjյr f˱X7N4o ϾJJw)}+~1"I AR"1*04TXP4 JfH0 On2ƕɘ3Agɣ20ЗcҢN)6 I3"Ic19~5`m|&z9ʡruu0 ftEɜd^e.(Z/(XĤ:BlQz>M1GFbU tya8CL^FHL,4( D}1>K/|mD3P*0\owoE\slh\jg2YYš3]_z|;ߦ{Q |o|̊Ujoݴgs/LIs{?)ݗCOHXO]o'uuQ9 /| vEpLC.GTiܠ3o5?՝{ Jؕ ,]4][hņ:/5}qOy;~uwu'kG9f/HȒ/$6].72+9ǔ$NBNzCu CI;2K:7R(Y3ZZRt 9h-شNxј᱄tze>os\R86rҙSr> tԲj@ꄡ80+\0ǎ})+S#bq'_Oe_ЕW4cM+1.aɀܡ5>/`a2ՀcY|1*bޣ 9E+҄mwW#IS K>aG4%)M…!>G RY,(.*Z)[.a)N GHSCpv;vIQ-sM!`lb.NҌk<'1 !]f[gbnd8PZ'"?yKW{Rbysٽg ?p瞻5OЎCB?"I*H3YS&v(gh6H1:~l/QN ].yıc;3^=wohiJ#S,Wd]KyE$I ~YOk)|(Ed,5+ÊE^\siz$8r18K[!=tPJR C)y/׷>1NÇLE6@(Hbj) ;Z " :ڽX,rO%5:+i#I !+#/='iǎqI/7ծ"TyLyaompmk)(i =ZiB\E %F[Hk -z@mIƌVh DŔqzϞQӷtɈmmM$T̜dg "cQ&7y[IMK 6+ rQ֖F6dTIN@ͦ yࢋ?mM7u}Zե`\.}jzw|srWu/«y~& @e 8VbF4+em(*NA$/Zkyj &wsGĪC{]4%f1pȡXr)p&T~5׾C61Q͆%[A/V]OSt+KG+['^}W003~;w0qםwWӈ[81Kl4Vg~?[dR.Bn|%O0rOJ>W_ /<7x74HWFw1qڲe_ 3>ByV%Wdc_}Vm~إ?U+)i s.=_Z羖_:~Qwr<\m[pm᷿%><O=y MozGx٧w12< ^sgw&'yesbssGrj99맟^˛~DyϵLC12Y#C˧j K)cudutz] eO)<@<7TMݡx~G%yϺ܏HZe%)R:!/%BXǪ#,ļ2EhWR뚍h+#2ӥ),#`XK;"RxvGLbXJHԭB>S *(As(8f€MhvkѬS:`t8Y)k"[N]Q 5t&AIt1DvgB9;awRFjM{JԕUcFRHB1Q𥋗Ea@[=E+M> $47X17DB64Qq'^v& s}x(f] wTL[uj)f1 6 gxc?ϺmԅhmѮZUI'F)?`b'%#uHSOHx98n}qf3;Wn0# =KYs8L c0 T}0ugth%S 6{*Ic7)'ik3^ |IЪD6u}5|B?G+X4` Iȵ}MA?UPu/ع`nN7uu+S)(BDceࡩSYظNzN Jb3ZZ"+4dÈcBa({88W6eoNgGZE9C..!xʗ%X+|K_䞻 <@ M0hڀr 5 U߼N2V$԰x >x?jJ>N7][/\~aGoy$Ix#'\^>kLN߽{_Hf_|:N=Tѿ3m,^u$ 0sÏvhI+lfw9s?tuj85~f0q4Ixon{7|3'qQV 0kڹ.<a)c:z>mѮ78蓸MWryyL ?Ϳ7\vXJ%S87dيZk⨍ӿ#M\/>?z+e,mє +;fR#;+TL3{?+ڸ&xJ094[TCp R !m(JP(|2_&SYƻ`],М/H2=Z;24>9_: &JXni'j0ϑ&[SgPā=6 %Daᮋd v8_z~_*Zk LMD3Yc5N +?k'6Z:szFIdR>2)Q*H?aab먦'-'W)^~Q4M t)4;躦` 'pD$֣iYIB N:HnپT#Mº˱) |WhCG9Olx/W^/e[q(Bvϗ"@1Bdk{R*٨`aF X]VLɕ^X;U \O7/3n8,*j M>9_EkhŚ0PtYhڐ+O ʰt~>nSGI`fǎ:]SUu 37R\o#7px8sdͺ| 3:$[:;lD[I*5-*n CG2bMό;LTڎBMt1Y6_((AG}۪m0֊9T6u1RZ@BoK5r s2)!E mQk4XgN- 4kV` P1 kSuXRHg6QKNǯרLN򾷼?<'bsKyz:B?yua{n;p>yf/rm)>9>%矃N\2}Y,LUƸWRWiǎm)>ANԖ_T‰Ǿyiӫ̚J1 3{lv)'(&O,nT"œN/m$N4hPhwǙ%Aer",J',(Y6Ox޷\p.r'cc|=g_NÃr)"MH@7v9|Ї+>?_3Lʷnm[,ܽΝSO?KOOV~ǙczRV9:#aa1eЩ-'x ?V:z6v _m&+̟w,Z|m|yi(;WQU9s~ .g銃95cZ?c^~Z~;9_{%*1^dgÏ>;.N[XzSVJZ$1.T~\ӪVIJjի زN(G1$RxJ2Q"PX=}]cSBuY|C$ IDAT- ¶( ;|rMC )#%$3OI-ʪ0F  91{Cq49q9^{t6NjhN^RIf%ꖂ2 xbF*Q c ΢C_+NUT@a30&x{R ZBLHIR]쬂d⍔zfl-"@/ Z|\~r7=XGJC-+9y|WH7lyzRJ1YtJL쪰On(t  V򅯿BJ+;oOlٲ:%NP()&85a.de&cT(ɌZ^_px Y3ώb%i&.u $Q %%A>TL%Y38t$ȵ #vhE+U4"ܞn74\ߢbN1Ks, |Nٱ'Kr|֐yrmssG._26ޢ(/GOSÒy%nЎR@P* #;P{;tt(\7IiCt>tT8<|ϫh9tezݲ}(vr@[^GIw"B@>ˮjsu?WtfiO)|/+$" t)Tun8xwrskᆯ}tJeoy_ֵeT( ݽzripGzKISvx.zs-ZDOOk_z7 l*+/Q~qMlu;#ưy&+ jK_/ڷ4<0ǝ·$'qG{ ^w b3wsms!39]ʊ+UFveڳ9E7C9"f9<򉫸ƴ=3^nS>%>a!ǍyysPViBgw l6) tQt9鵏3kxO3Q:faټnuRs_Oʶ}t;ÏaWOk\Fۘtogaʣd7,(MMIZʓT)=8u)qVh,fuKF&R O8Ó.|ǭ'M J ?g_ V;$vЈɖ*T-u M+B ]\W Fkp ::KLN6zvMX%G scZEi)) (R &<ĺX|%!vpУM=I.֮yfK'^jb PrY/\yNֈ,RJMC1'hT[mɇjpƑIGWxAn04|{YyO$hzM~*jN& {Vih,Jb:^ AP,LVlNN%\DEgכ6=)ܵ E J 6s-:Ny똬n/RB^ +14`_59ODu<-3 ҥ3R򁤧77=Ixf2tH>VEDO_}3wnifܷ}wl{ݖ&Z[RM5t΂`Ţ{5}}|nFei%nG2&%psgg5cK/Z&ږ}˷8O Oٻ3?Kfj5y'_d}oep_&.ӕv&x -6waʕ8U,]vAerwСRz'v*Zg~<ή2nq(캷MvlH+Obƌzl;%%]y::%C[6o`鲕7#v}w0I~v_~8<^Z[fᄳຯ߀֚S?{ZCPVg%O駞wwM!{FR: OndF[]S,S`P/QA@CX{%bcx,q@Q{Fb>֔Pjc Ih%P@0VcO*T`MBCA"pL.A*1xGOکArD han^$J Դ;YOxCϳȲ$Xԧ=yV-q3DRq3?;Ϊ9߲.;e'! B ^A#"E (QED)D^BBH jos?曍\w;5c0~׻|dïbbA TMeV;+c2 J6RG1Ok^%=di+Gѹy,օ)%HR~ab|u'tK2̧슆$EMH,x%,E_^㢯)jZQIK:ˊI)AOD XS>((j@*0rE1T3ĉ3ga̙R`h+)=hލXĆ!ԡsO:?74t u(2If+dZ7 I!Pԛq|mgi/;ΐFR;JW|D<krAPA22|䶀%\_xd!a\G+RET~fh^r~5sl>=qH&KQBX(-th4j6%Q<Oana eez&xōA4ܓ̰dK+u/^lyޫ#`Mn8e\@CP qNZlaqB8## iS갹GeP2#͠XT(鐼yԱ3Qo+E6Hhrdu@8/A}1\pWB )X0$2[}ɴvI__#֚PZ6+jV7[V Xig~]E%6 GJj HqqIKAV_G_3N;rR=t\p.|>#=~^{.BX(Sec]qGyq= \P6F7%&Ʋ TW %=&fO.__q9Ş͘,:mDIY-4~n+n-ͪJIDD K:ؒ`H{$ %Bu S 0\ ~{34W N?g;ȃs^;r3Ar1}1dYFgJ f}Uh6rktqwb̄ɜp 'CÎΗ~o"68Cswn?$KBE-֔t|هta)|?bݪfBD¼S|mBg+c9l2cnXћd10Pym;Z % I2Ɩޮ̳.VJnhQ,zD1Uc ( MS MLx&B*ƆPW25n^yk%w 7qh 5]֗ՆS馟> S;/,n[OjY,#@NQJ`\`|d݊,x>4Z;kO&v)Z7}ƺ# cq JI%VB)<3}DJZlIMV&{N<:7iciW89N [;b3H7 Q;ZR,SR2mW2o :8_@s5|` lәzs|j•dP,R4v,sό搢eB  V,e2 #Oiϔ"zú!MB Hj̡ߢ(9C;>^ 7HNI ěXDW]… }+ˁ'7p7cP,߰wϮyᯏ)zcSawWF. ]t!r q`|_x"R]~WIs[-%i 4MOp!khǺC~(ݟ| *4cKaHK}ڍGu/sX+$A,Lm'P6tҤ 'ym#a Y2D9yQ#-c;E[Lȸbc?Ǹܳ)Di[.]E{G/bژi4Z{PbN>xw1Z̞=x7Gy4e Λ!OP(DžvfΘHZ`=bOȋ?_9(/|jg;ʩ_Bn?*FE_c Ro6isOPp_ck[8cf2u:/߸<*Uc^<=䝷8^g`֖yfOw7^Ǔ>ɧäͦUS;cbs-6ߜǟ|R5F~qT5gRW@D3Vˮ[ZWo`f6ǠBob*Ɣcıaߓ Hi9t#^_ӈ俟rr)oHPy$Tc&kl̵6X:qIm>S64SKG%td$υdU(HWXc$oO}ՋQ,--HyO}{n]o_ȋa[ϋX6aT3z7'JZ(cۉh|I6aԅp\)v9&ѹ1>4R.`lZo`Hj`䲚o'bꮷ 0$Yo VfL~%mj#CpM#hrD&g M:*>X;$p,ejʒ$\L$Nv4QX%O5h(ĖN=e _x[I80 :{&N@$kP~칻7nK3H!yq}a $@$'!j sMA@PpαO iº)VsЌh&F~8s ͸΀)RzM J}y/HVm33fhƆFS3C# [6׬!df%l`qNEctr^[\ y,ŇmhDX|NG;#Fu"J72(qbwyBku[.h?8-mӣajv/L&[ {7^z)\r z+~:Ba{L:+VbŊ7=]GJm Q$ix1w(KCxqD>mO:K($Nt!!bR ޛv$>$bC ,cSk n.!2 6W!%.(3"HV3Qy6LȼKM>c WĈFy6Iecc-#$Ș\/Gf5al Ws;c|DȲ-W! IDAT9*O@GG' ,O~yՏ)>LǝΪ_:gQE8x)yGOwϏyc:(rܔiT~ЁZ(U 1g&O#NJ2I!yсXi< a,-`sFۜo2Fbĸ*ě_il@K, 8sνˮO-\ȕ?1qw4Zk~uݵWq's?`L|ǖ8e)/<7^y~5L^I~3Ͻ2g-27/|n[ɣoǴRxju sߞf:̢E}=Yj%I_} Ǟ}yt V&Ϙ31XfSo>z絧rlFLk*2>~ue,]R vO8ygYC>uЧ4y R)VeKv;fjN=|Z3ډN8#q{[l%{Ӷ؊7>M\uMV\γ_F ,-;ӿc:H1 ^\X9tg>6Ddy=*bC˸[/ɴecUs5i$ Ple$LDgJ=+$H]U)J XuF\d9rh,D­8cn (@H{iTm@H"M|_҈pEVm2CHE`QlP '7+*0qlj=e1Ly> x.5ZGA^_O-$k |A@=wމS <0?\̂Q<j!|sg?ۗj_sק?)0d[oq;ng?s͖9?q)@p9B l' uMd[C'GәU'W<Wf鲕X#.lxm $Up]9c~nQ!ZlHuλp[nC?yk| KYa#0 z1{0wJӶ$w=g{:vcy90(#.R aI|0O>;u 6]d1cƺpg#ʽ/,涻EVs oySoNuxM }N;vߛ͜9W_3Na69|z_wWkx 7Ǘs^;rå)*4ՄK ţyPJ'ӾfS#rbq7be_o_q3h!122x_K@`.w?}>m:UK(;PE- }t≜y 3w=1Wi $=c< 1[P%W}cs:ʒVLkyOC f?$AwLYᆿVU^ZmEE1P) %L*r_}HAGY.ڭvBpSV.HJLM :J>JN0iY$8n☭CrS꿼: );*;pb (pvđ&I c( K0eƌL[0hS\FRz-} #YK`$Ndjgb֑:L[R W 22kYPmeDqŢaXE[XpR'WL8.픖Z^|n kK|-.)<<%bP^qcf$R_3()i//IWMHJ{4$x Alk;0VwI3KMahs^yA\ZN1ȠUތJJ<)=¸vg2hA[czO O{][}O49%Q+̨8AP\|R}c}e0Ԥ) OIu\ƚɽZ4WcpaxJ@1# ^=Ţe`-Q& (ndQQt{ T %k9ʠ,r-*@2gZ)YVSvY];h+*,pySPP6rb9ix&yCB[Q39 9Ǝ#,Yz#Ǔ,87>H6ٱ-F>X $>_ ꉛdQJ%Cg?O>qҠnR[ ~І2-FfٞyAY,LR,˸i @=geŒEtt0S3_>;ؼ`oZBAr/߾ r.O[mˁ:?JXL.irb$' CFy*{wF4jʫ6}:'mƷ.+q:'73flάiYVkXj5 o ޙ:ݕ}8}85+[^ۯ3M)=ΒH?3巯CJHxgb9(aѢE'8"/|7Pik;-}>I$>Gy mɺ!6>eЃ˧6O{ :ފ1A5a'z.v W]ca~ ?KݏͶqCᄣ?˚u=A QR\&kn$L}jIǘ/.Ŋ*=71Y2p4HOV6q_ ڼL\Iwb@E~6fD|7KPւqeIh&1:Km^~ܦ)/-T4c Xʒ FZCN.7S3|H֍49OJPh}Ƃ*贞{\ W9M?+ sB7I@I :`uJqhYgsY>L2`Y2@[GSc:VktMU&uH\70n 4/$(00 /2N`XXQH7]HtK6OpW.-uS?,t0fL`:eJ`lVT lw C-67|8 /\.I3$+򶟻#O? b_}5]| ! (i(FjoI=մb,rF5cPg;n<+W姗_]B:rhZz$nC:pT3Kk"0ƲuIaIDÿ_p.j/]{3=6[;We\sGaŇ=OO5,5p֭l`(TU&>΢ea{}8ē9ob|WɃ<}K_Ì1BN8p '/ syiLymcn}8+'zzK֯_[* ?"wFo:rlORtEˮE)ŁnK6<\gd@A$6՚c%YV9ST43ڗoɾ?Gq >| $Hkhe/ }Ej *kBEGI; eMJO?鵜s833mk#7UJq3 nzJEEW¶q<X"fo?]M̩Vyw߹OhӦo|'bb>p/GZtyNұ7`GﰥRp߽1cB&=O:QQm_nɐZ#!s[:˒B' 6tDޡ؆$qЗ}˹MigUtx,u,oEHxBfO+ߑڊE,442y6K6(s栻D:a!T]zH,oTFP xP =caX!\W*pwͧn( cۋ44ZA*K+)0eJ7+2 j&i+nNw2W#Ֆqf ȽU,mŀ3Է©uSϽHàbijIXB8ja& %Pr)Gp]ϲqc(iFGG+Υ}ǘ6+Jx<ϑnJ)Jh632cs}Sƭ+HRL=W&Ì) ܫթBi咱%ϒ_õ6^Xqc$3}Dn~QЄ$5ؘRA2h %ܩG^td 䓖E,@h:;"::Bj#1C :Yu*!4#*V.-+ 4ͼ3;`9͗XЈ,mEH"NƲYO=Ѓ{]+\خŲFuwJ}䐝<4R:>i竑=o<gu;#gurh1|rL:_#<믿>u>*&BvuPkUuV !\Q!3JdHahĚP¸φzJ?L ANJIk;j`KS@D>i%X:bI;(h1 x`("z̎"i9| O"?7tĴb ,H%2ub'CCuL;)xJN:igl5sdY%=jY{`g͖z4,s!a>qcz s౼pW'}k=̺uדk22"Ȩc} IDATٌGoF,sgWXa]!(O؟zߛI3ܙ%zc%8Ib4R)\&> (.Rg=^I3* ^f TSRc Ggw;[v jQ;K.#T1$P:ٚI0 )0){oA:|fkxѽ9y;' ;iAчF<@P恌Ҭ䐂C%ٺ%y9 ~@S_BaR~0cZ}[)2kC[(cyrg30|^u8ٌ3>}:RJv}w?|(7az{{g*PkM>h($v JU7 rA/O&֪B7{I7`LJs==.W<`0)Ic$qY+$u.-:NhҔV͋X\h|`՘*'~*1R.c$uBKr$P8@ni~=szX\ʽ-6ԡg4RkjPJq/>pAb6M!T䣙5*!`tB3SmILRZCbrq@ͬ)v›F 1XȬL2+H$2g<,X>w8; s6`LAQ +R7?߿g=Xgc#s=`zY<72(\fr}-'!NiY7ƐCK2ڌJI 6dn00{-\wӞDQ4n4AHH񘷦ѻA )4 Xa}ԳO-$|[S}:ͦҨS89m1&uss993fmg؃n2歿7v~7&zM,yz9}m7¬YfY{,Y?s7 /ᰌx_DF\qʑqytt!Xr?${NdVH@ O&V% 5 }2 C3Vb荊,½)hYEnJhŖ0J{N -pI<1;_r&<Jz>,/v&mycN #2mpꉇc+=t {N<~s;?䏭°O.իV= wv+wu ;?T.TpbBEϜ $u-&)>o/x/e]%BG druB [eEpu0g\'[O+~h%'9hP=c-Jl?DihY_ hz`c-uc5Z{ܻs4l2JF0"`DtAE $CM':;gc?;_=_wﭺ笪{9}=_g̐zF9YE {, ܴ0 ]%I9dFu@]|m݄"rH").J @b3v NXKp"(lԸn tB ]λPrR\g6`Z##I qM@R @SBpSpIu-?pY9!l45 {|w)&; o%fbߤh#u lr~ BHG҆LK&v{fƛw95xu8M]&T(c T1m=O%J~F9cc՗_Pq kZR è̡ܵb˔S,=ӜxOrMY\niZX2wnm1Zuβ#y#WXC1sS2CfKwOK__fw#gH3K3vhv"4J8`՘~pͱp`qGEX4M= KSkZ2ύ,Ejtfd(U'&ZB/&fQ,db:RIUS>]IBaP:33eWXוParzdW/'mPPEeg ʑ&[ F[F/`uFڄDQ^06ߍEu+J'= !ֆ.(YpSHI<B-kG5MguFIE@m> ФVrlnY9FhC/HelltOgLim}C ,> o]M)M eeB̐6vYz0n#|H:iTf?TBLT7r_ʩo;'x0 9w㏤P(֛nM [T+ S7T:{8kWmwqٮp/f|W!__O7rʛyvޅ5ZH`nY[O'JL+/rIu6IT- \dՕb{_z饬[׳qF.V u5pzBAɃdyR8Ž5䛎s*6ДK<(GiDŽe2z"AQ9~fApƅRQ7- 8mXy%#AH} _"Hsrhpn7)KAUPZ)<=nԖ57B#}j^1ӈ9`{˚1_+^p1=q麐Q O5RP Yt a5ZRa6k䛎&~1V`ېoNgqwq}6 :}znړj'+PҌ]q?Df͜'4QT!Jh < G5r2#H O0aX<m5Mʧi"Xc3$}7qs 7&x;io}+/|J`}A+Ix\~}q͛6?%_<~9}h_;ә?s'x>-P `44-7hwttmdpgnh0o|fqn J} Rȯ|"ᠯ^d^9g}Pƫ)K#`\a֞oJ{;O?(;|ԝZr؛N`h1rϹgΠ^c`2ejQkh~\ gcelJx. |Q@{E9c[34^c*فp2^n69f٥}9MT'=3[<eɊozw-c>sXzwVd?뮻\oZO>JWN<=碭-yeo omH5-⮧L'bb1̨(<td*ւt1?cZө+=eIΧm 88uM,&5Y<|:ʠfmf3u4s{bj5ڐ$jE^RFȲ$Iibj}HRcP ™X'eVțP.z#Ն&e$ZY'6bϱѩկE> ^'эaB/wePMj6%[<<%)Pv;rXa]J+2tZ$s;}p󹄁C<1):IN{GZG*JvӢ#DG9鴁-ı&KZ4Z#KmlGޥ`4Vg˗€rwJ9k iT*̞[bc҄ZLl{7Gz?ɑervefW<=r%z~`".b>XsOIj댘Q<t/'뮻ظq#ׯgݺu|;߿/&"3gΜEr>,YBT3 /3OwGG-b]we̚5 pma-0CyA-k6 S!d~J^55]7躕ei-(z-A2'Y?iKe 6Swkyq(O|E,#N43X E "wشR t9,?y/"6he1SAm_-ΟGLSO`tF~<-utr/GcQVoK.fΜ8W췜pF$_YGE( <^LʏgOnV>8Y3OYf5==Z[嶛QHNM0{<9>0_l-jDT KOKw624ł`aFưKbvvX;3Bgk]ȐwJ+^}{!%ׯluv: FHAь]b@M!YH8 ĉNfڲr}MMF3Ԏ3fwGXБKp/!azǙ sSN#HkIP|>§W>I&| V'|aP9)"d|pbyVӮd ޒ`Ӹýd5|+­;&*BvDGLND *@}j&G]D vߡK3+~~όbRcLP]# aT|MhA8R? XcM1r&(20s[0# %DP3r+$+2 t.!1eu='%McBC.[EJ73HFѻہ c2 3$k{ؗ'M`=wN=x9=]<5 QDV>p)L;?71wǟ~GX&&ƹ_ɋ<ğ IDATQEkwO|c W_q9/*.O#;wecvY+_fTWV̒#3_ >[_+.x!Ǽ-lz$r'7)`ndi)y]:%fEFs;S-'$ذ=]|^C-HvUdX cՆ`)*AMq ~?|_*~j7a6;=x~aX¶HCƆ}lѼ5&nm,?-\pއ8~$ Sѳ^_<8,~{ϸhJp.A#UxG}$k-޲V(Ռ浪˽},Q;zIF׼ЪѮj{vʑb@Kiiۿ:7`?I.PRbX=j-2}č@r#M@A*QM[R(T|FǚX& H?[2C(](;LRs~:6ΐ(Fp@-FFj[ȬP׆ZK3;I@{QjӽoƒFPyDK.ޒ6鯺.'^cz Jƴzua ]3njQ`嚇&߯uJcfd6H"* ]3*ʜ^T4Ǣ} ٩[pCG Єs0C' YTPĩqSnA Q^DZSLK!wa[LIf( iʈzBw˷^x rQ.zH)Hz}nh0tQ螡(<&/If=ΒMVf$_x+/hmup\vc +$J I7Dw$9w+)ԛKr$mG&RVT;i9KW@&{F<&.A"Ib=^}ZI>xG;9]B! flv>_saO("n(ߺvq qȞ!a=F oᙵ짿.$nzþOUgxyF.c?_mpiv46v\˟#-><0޳yX՘ի g KX |LDc֞o<ε.=3vRH oGDs=K;zjiZP\"c^[D֐iT˰y$3ROݾs=ʊ9%){ |BPR ``,Bu`r-w_OwN/sΠZiB3n, |--3ݣcN9K.{-|'pǟo%B`Θ>hV$evݙ No簽=NzOLeE*!OM )+.R:;ٜ~StFϚ\khk[2b A >稄X˜];$=痨&kt Vksq໩Mf)daOA46JjM<J{@k|$I[ߐ6F) H0/D#S\j! :==B!K!l=h՝mez+n RJa= ;lV?S*(|O"w-Ҥ.-3f{Uz%Ij412OM3x L6 ȠB%%D+#9EK*$s:um^o|{eEm,rg ܶ9[+=C7ϝđ2M4z3kLǖej-5: Bs kw%/`XЫ`5{Oc RDyMe%KLe&On6~P)ɞ$Bx%p./dà? Yi{,B)~PrI c-9EHCfڀPAz'"` $FR`$y9N.\uw {)$r O>RHi#9i[줘?]v5fקH|@H 2wOt'K-(OO'N+5R@W|lR5C7',=:fΚ9{Og[6,?WpIb9W&BHfNvaKiXO\{OU q=F`5B>|8&&F9io *ͪ1ESο},\fIETk5o)huxe so^ _nc; pӜ^]?6^_wL_zʲblt;*![ '~:9X)YxaFG1—cMdD_~"|~x oSAOz32<=%]Km7ӛlnQX m h6݃W~ chu; X:O7RLi|Lp-q鷿!;e`YfO{o:O8 ]<ʾa) TbP % n-W-58cY~~\tz4u7*lڰkx'pǘQMK ;v|Jj ttJ3`i$>F̂>cy! $CXڸϯ3Cd!|O V~tvx^Dǹf˾24fd ʃHL}7EN&Tʊ0 pTf-p9xtLU]w6ZYP‚0OzKm_:)#TA 'X*A-qp%i-U ZeLDC Jb#ڙ=", Z 8C՚G_E0[LlhfD #H|>'Iӄ$uW)$GRDg+$Jr!X!P~|V˄Nc OZ2-|WZkief%8cep*2Sh 5mMc8ZfyGRZiu5&TdQ\PR㰱o>f1O>j0UO$tT<:KS"ۆ!mE$4uHG߾Ln{ % PiIi)ޱ6Ii)$9]oQXh{'-8I ~#Ey ǶwMk"vqyO ̲dn*H^XS<7a"B+b-M rG]*(YvѼseWc&4bi)z60;uV"&u,Yr8u+jv>;GʠXNy;ƛ2 ;_6#_<$MٻKDx,[ -BxVST)B$|})iTI̅\[IV-7\+Z>=6k1rrHJ !qO"AV.1(VxѣI`m L d0Xft :FKuz::Hّ(sfImh#IIV#-t2()4fsǟ8#˹/w)FFS -KG`5pqauẐ&) I%X;uu&t`e&[K7>ee N*P (~뻜}o} בGsN콄H˟ߺX=KQ8i݋[43f߾t1=N:;oo}+L6R 2'?=3t-~sMd d3%0k? FJᥢ7AubDK ޳q m|'O *̟7=w]I?T>ŋmbhh;_y?֭vnjhCX}ŤL謁'Q!ʰpgpmC75Xɵu:(ʃFjPv,L=3HZu"7;Q*ݜrWbūILBdHlޞesZ!4k[wx>q߽,sO!̙ 1'5#d!,=yr){b۳&RlF"maeZi~@*T;36D|J™eqϑDXWuꦪ *HteN ^rH m2Hg[$*"q6c:%3dI{ԒevQ"I4%,e8S>me^-06 WSy\z;EBB¦f Bqc,֤$㎒qkM vu9ĩv,)0:nT; U ۾!Z#t/rʪU,2RE̞3U^Y.2ԧy׻5]HxE>ًwC9{nz7g^~%۹ڟe,^pR^>244<06KGQ롇7G3tG!=2|D3Z״F@ܤ:>FRRJ S5SP4Ap?]S0P AB#Y %$pIc -BAX&e+(HҌw?+݁w'-e_"Tr]5142WO"ot$fV].䗿Q>7AT,26:ca()|J)<[x9ƒ 9BzÔ {S@ ,r#: >{@H;v4ێv6[F ,g/.@& bLۧe>HwyX9SBts/PXM.# rHe N**Ɲ8͛B0fX_I޵;E%1R#i:* ?=ͅ>+.#y8{ `XʞEÿ́FT`0ZKX8K'&k2V8rʢH9Nu4z dgaJ7W/T@Ωoй?z| FZPm9*zs]CW^ 4X+϶aMSZK@b(%}}<9rQf佹_o۸CH=;/@{xHo@N''bDogސ w TQ( 46θvF57okS'89k6yiO ߛ~%O1/dyߔ eʼӼLE]5d5OW:*yQtk[~XH 1+vl5 &uBIWS:.+%yElRu]'Hz: C3pvW DzMK6 8%MB%Bktz1Bf2 IDAT"kecJ(P?m4 %6Y2ହO/߸!Ng؂7FBeR<:&̩K/Bv$5BVkiĎf,{IcSz /mHe׸POz5j(JjM@ybT87{%MC⼑XUzR=dd Ц3"I-zigl#%L.{ R~0S2? oNSܩ+SQ-$8燋=^Y}0fpx*kJڧcDZZAX3Ork0Wj>8sS?pIJ!kR1Gq" PH$،ރ(U2! 4N]uO ^UFD&|3 BJ04-'v9,WkPXw{7 8O@:: %L^ei#$qdH爑(mc NKEfXH{e5} !¤3ȬLbh4(J̝;k2_ >??  Z>IcqyN8<@ |!|cR%x*>Hf;;g~*gsCcuN9d7XZ$!"vywrÿO}<9brjKagҤ~: v#1Km> 0aH7`eM*Ma_ou!M)e))C$Ӧ\HIf2"1j6l@`g7F$3aǾ^i/7: =lۙekTjP &O^r[0wXGu3rbMEj6(<^yڌ9Xk9-g0+̞;L)C12VO?YJR<;:+kDZA!mAm}߲a )0[Q}l5űjsk kNeUcA7ȴMҎ8v-w 1Sq!AK4rR:v>pמ!B,Ц$α_d85V%|bu,=~%I EyIZ(GYϐq?<>"Ίzi()^t뼩Y#Td4op',5΂`<v:-T6>$I =uD6OS!BǞ4(DwTZr>BIuba4*+hOd-- sֶcT7N:+!*!L_0Fd$3|,u#NJOA!h/O6ւ($5u[bO~0cj;j|$5}fRyŦ1Z;Ƶ[g |ބjش+V>2Z(2I')y4t*5?(Y=Iw!+>{n&Jdw 'H]D cd#!H {iؓCmkSm-:͝6/oM}VwJRx}mdXg,`!I1/g1_9lcR1$:K3M+7 lBlR-0`wH Һ%3%D <]8hIMs# RzQī0O-eYCyt&B@౺>4ˁ(a8ͲüIR(v 7r 'p}xQo8.WLyj+*QI*IYu-MS 66U phH!X]s &'$My͂^MEKrVCP$mUiG,""6oGE=k Bβ'UKNS&Z6a)VR|Ȓz)2tF (H=[\}kN>w򅫾ƩA;Jj~ hZO|{X6<+>S~y_)g. YIA ,ŀMp_L 57 D{[z'r'ٰe>Uz9|'lٸa|5a5Fe>Mi] So.9(Vo?Q(~qj/iyl[ Wjt"N($;$?t$ ?MK[ȂuyPu_q޻ 1o\y\7FeQ͜%F[T~'v8m_ų[ ՖG8.^Ӧr,<9hɱ}4[?-gO? IOnf.:6ʲ+vIZ\J ICVIZiJE) Ycgܱܐ Y0D"Av(K5~:.d@1g'R_"D>\`qі Nsθ̃ǝ p1C2*cVI#4tr`Zl7iB@Iu,͏ {GW82D-?5J(%R흢BŴ~vp-n2 rtgjgȖJq6;KKϝQmdU]1֊~#KGI= q`JQ2)X*QQ|Z<]B.ތP*bIsF;eZW}(Di0I c>B)hn5"7Jc8mD F MJuԛivېͶ41/@x,;&@E4^䇬~j,sbCZë6[T?/Abk 6.<67ǞB;Fs+: otcAs+.S.*{nhxPׅ"+R#bϘ/ًukBA}CcAPmz(]1<Ȱ^-CZ( YR)eAb툯u WDrdKm{^&jP_Wz?صk?ϙڙ#1BNkS,}yo) w7 s[PS҉ܟlaS#ǸlcavbC ƝQ:E%F} @J> ؗh[g3H)_m^:F˧)|q.[ׂ5č ~n⬿y#&X(|w_MZk V\G?J)nae_??0>k 7|'W_cp )'tC\+y dzx^]h.nUZ7KuR P5, X3ܴSTw\t tq)8u1%sA}^ф:zfOd{-7k;QN\~6rɥ¢{f#MVE3Y۲ `GrR8cR0Sݑ3'VpK0s䥗^-o{;֮{drιqD߸jSM`),8x"J2^|>43`-6nYݛS+~yRrQGC.cl|{sgμyLFT&(Ac{=}L>|8]=zl[>|F') A%^ڴbVw|T5K_7.hH@;XC))F*pA!P>t1)Lj6D [~>gGY.N0@zwGH+ HŜ':$1RMިphсZq28{_`f!"5wv# RB)G-;Ӏ@ yo52 Wjxm6SBMC#ύލ“C%R$˂xJ cR*ސk,.!(Eޜ)o<DB>CDۖZ I) Jj1ڴl$:kX9i>r3E&L*@Ͷf\(/IX(C~h70)+'hƆvdD{6^2J)"j-RAh{R)d d'f@Ix#4T@|hDBǬ!Ck a ic=0@jhg ǶWQ oĄ;Pkr!$͌k[3\0QkPoh:"VnUP²bظ;v@ۿo䤢:4Gdue--[>5V;/zĶrQaj$Z'WF[<0v,iu;ȅPՑ֙ \N KcR@QX'oXw?Ѱ{Ѱ%=:Sl_тH:Pv'ry MDHDX)HKO58zRR(B ԕch&)XqvmD*@LwI!1IRy<gZ,JFb'W%l3|/Ę^ˎsq7) :n\GG AP ނ%=V}'z B^{}=/ ੧aѢE h^+UTf&3 0IJ_bhf7$Omij$v Hx/MAN8& e72e`{6>0m-i􈔺 h<ƴ?xU#p4o$L49ϪWlQћTҀbFyta^V߬|߹$~߇\) = vM344s5{?VniysiNV”Iݼ~9󶷝p-c93O~5{Fh6jھgcp׬o?#;|~zo9 ͛>$W}bW^ ΍LcVMsOCronl3/~+~r Y0w:;vณN?A[riK^cH G\q>å_{4ưdYU$9巊mQooަ(I$Õ%Ie ʑB_(5S򎑆AAXZkh5rM s^U̅;qHPo4I -Úl BaBq䜐ݣ-N;r6߼I::{or?׷F2SS0cRaAZ$^2T-퀧^a/,Pu" 1v>,:EEeL3AHLC2^k$Rx](q3{sI3M əb&MKi# ѾюTaJ 򑠷C1XѴ rV8!}"D$bR0˔rJ-+!B/+Q jxcr(H!xro(8^ݘ8&bO^H  ]P"3@;!fK(hL68کffQ;7c-6yӰ:͌uC@ʹ'/r.Kt)$č7IG#0( Ik-%{9ʛ[38EtL@0"mdDjc֦(:pQ Hl?vo{j| ,ZFg.ϜGߟ1͛wl${enw՝,Xᅴ5Qihv 7-VITn_ Ia/Jz"xm7p9%KG;u|i<|eMt0{XvDj8'Iْ;w;jF,)Ԫ,RjH*<[҆PX>_tc/W+r[XrN{w\c`.Bfﳀ/"pNdPX ˞%Esv9BPӒ>.'}S^©qS9rҋڵ3_^r)_2gDwyּ k7l~u?=+9v^ܓN9s0gƼi38N> wRIA ˆs ?%xoXp!%:O >GAIGN(kxe>$c[v0#2 iB$jD[0#C 7,閽%7%ԛbI4fEӑ T5C!G|8ZӴC I1*粯ߌToZ*Y 9޶ii2TێѺ)rJkRBXVmC18J@ʈF:k "AC:^]"W}s̜5%rPQ9SBSo;F2oc1Cb`a+7 :CɌc8l5D r&V Zg ~uL4Vi\"&[LVLT<1&k_l |`}Q%P !3)P`P`ZٱiDS r_ Vhm~J-ySl@)lnij,vAK@^ n"U;1@;G@;'9֌Z"%h$^jB?l{߱P*uk#HHb]3VFK;527ml9' k^ޚs >.k ,;X̎i%AG) 6] 1ikR@O@;q62=XkCahfqH6Gbݴ:_,2*Y9{S Һзxt-?^(SZ +,:t@BAʂ2FT@vm#bs۲t|i)%7߉ ,pOX^r ΘY{ =I<0"izӸ[EeڽJR ΦTbJEHF hYxh.3 (ʯxCT?~9RQ%K\/ ne5-cΒ%tuŚr17]{qA5w<$ l^aNbe;%\5@ZeOLiDSnzܷޮ?% TNB#66M"m@HS5S:|([i$ 8s*nWL2K?w9߸_ÄtK0N:x8|⤷7_~siF8oha~o`݊L0?4MYts]Rvj:3KXf%_c+oKYD٤(ܳ!ϘɌ3IӔ{O>9B}~\p?pwI=uL\yYL>>sgr?\uk^Pёw U߹5_ԇE ܽA,`…<ē)K.$FPolw:8vT/ c\m;Oϯ]E2]#f2 Ygxe/%xH'#eIMLۆkR&Qm8S1{w,?gVRpAH4cuP. $ܢ &A!`AE[R $/+c߿h.Yam_pZrG'\nV,ǝV:LּbکMAK4c& Qݱ䐭4P<ΟX@>IYE:; mWi]c4D͇P}گ1rD}yހ\1d%EZ*ȃSL)9n VLl`c!-m5s3slF r~HWVLP,]cC5ӻwR={Z) ɻxْR2Cgx3%JY5PkC2l1fA_Y!In1d/K9x+XOQmm XG_QROQ h8iD9cN?HZF>p{St(Q4SLv{8T6x@dWrch'qw0pyrQ?P9{cc8??k,1Z1[kLkM.HV*$e:H ܙlܼZ-oΏ!a=N8'=fFH$&F!RfM?rZmK(֎8!B (j!, %<9ZoLVur6Xg`R 3][kj1c#h&rTکiPI=*6I9\Nzc m.UPԓ`X#d3 i'%F҈R=Wyekvy؎$)qP"rD>hp̱R׹?:GϬ<ݍ>O>˰{.8_Z)q(vz̥Phn흜v,^t0x;s`͘bC>RU%>\Ș$%Hۣ`VRo;֯94d߹E?Bx^UV9Z.M ̛K)xq3y "?|%Pqɭ~&sdn&M=H_ȳ/ss'7RJoxA22r^^^Sj7³O}iB95ZRi9>;8ik ;λo^ásEgMP7Ì3ٱm+|<E<|[Ɵp՗|Ha_̎MZ<\{k atd^`Sn5{_^NTNzH͐Wj7%a iС6b ihG3D;ƛ~CfP $`dRJ-J,Ӂ9eQxkQE864ޓu0ObF4{[dQB:ѴZcirda'i* i;Έp#W4O8x5cK)y~v{|3O_3y218Svey4u]3kw[/J)~}}Y}/gㆍ<ē] Jd]vcut<|LWw.Ж\$Q@VO*ϻ4xAvQ̙ &kqoo媯} mO|W;Ơr fDHy*ugǍ75u)[R&#tUcOKfO=;#>1Ƕ>N8h/-A1R#K2t#pbaˆS@Ԇ,)ymu/74Q 8lޠm.\9#;9'ktĝO8/:78 jF1$h8&15 :2|)V U!sf!zv!Dchب@96OXF x38T4ϯyU `7k8+ B# zfݕZx>~^20=CpBj/Gr;xf`gtKG@j%e6KE R q$}b҉8T>%S2ް6wPO]?v&L3Wg ꉥ{`-` ĠeWTV$ns 7FJNtcf5[&tU>qbKO8ڕv±+ԴolifV'2_@c7: 71Mlch,GIC^愣:z TX4ލ?'FSvi1Z{:2̖ #Ԝ~^~ڍu⼤Z7H%7 %}`lc`{{ORr B{I6LZ6ӝG,l  뎹ls9N=zZ‚X;XS"cv"X[cp=`a1һ~zxmcduJTZwN9L@VVӶ{Y>v0:t ŀގR>b)Z;FLd$Nz@&&g!V0,)§[ T)NTHA_Yb% 1ıB]x@9#⌗ΟC9N=9_fmdgxy>@bl{"HB*wxq (1~e~G Hˉu|ue4+*-r&Ou{cHÀb $Ln~ g|@ )yi ^V6'bzwdRo25Y:it;F<.4c=,,V0Q 9’dCimou3&,Rwl;)ཻ8䰅 ! wmo@&"?g0q[0S~ҵՂT}cK(* ,I$kmd t|AJ4Jm( ӤLl;k%'ơ12ɚf@M )&iJP,=U;F'y O2&8y9q^DHj}(w,vsp;;8:j-wiazYR(qFR\?7RńBBLv?O0SWbHg! '_K"Z[jôw: Y@EHv{(tOQެ8!4 D|@k.k&\LxT!ؿ;C߹̠j ,F%MCA6wN)(o8H}o2 %ӎR8GC$}sNcKXX l|M;Y3-SO,0utz|g;v6oxW,Ąay}!s"A)dl~ A6$OrǓUVnX5aRCg/IZk05 Õg$nl\s{C8u-EW3~՗_G>7[2!yfS.vko>q\|gH wuMwn' yq1λWW8,wp p!KWKu\8}S \tI;pڙ`ݗv_ӥ3Mp5$ sX䳡A7Q#Do?=Dд߮AsO>ߝmZiN\QMnS;N~oK?~ P0+pH{*_U[&/\λڙ7^};zgrRtfH|)Ier n%S(!hk_;6[l R 3cg,HZ}ӦS,0Zģ~P#O~||䓟g^ĎsJt% ǡ mXSR^L,FB ] :h{ڞ$Gs"wǤIv_ž{-mK,,cM,ffPQ6h޵(dTpgu GԎ7-jdֱbg=B(k35Po!8w ㉣l==.Ԗ"';/,{ }{ۙsk3̀4Iɴ%X%>W IX]u]/DgnfhF qʥ2mFZ/!]$lea@-C[~Z!Cq[`9axȌ*V{@;;ԭv~/(2 .cfϙ/l M/[o➟o}2;4.R:;cu$kV%,g mИXCg)Q|_y&l!V'_hO R9OI$L6 FނdpR}{_x X[ݍ駞|CDS2GsFgo~_⏷G+ּnn0QO9e? UǗ9ǝx򿜧 W^|~;?OT]=o11>ƴ9чQ߹xΗ/{z"W\s!|OZc0֮eB& O'޲4qfLB̙"pvMigB v}H/r%ܔt{Xu>sֱ|߰h^|7wr>Efh(7^~=;74 }h|l|L5f!j΢ԤHRDSCd$ycX$ٹOj̲f̑S>9WA>(i :pTf&(FP ':DS3SV$Q wGTpq~A^ሣcƬ9ޏeN}G_%pHm_q%I-%I>Xm)[O%'Tn&v?l>O|Ŝہ3xd$'9KwN2\FWlwy%%P "rKC; hZ`UmPJǨg",h+{Z{AfjEwxYu_,$NbfM#s$ T~f{q!Y%qs0#sx/DErEOѱdbD>ΓL,*uI Rhd^{z+Ԣbsÿa@,#mvSv9?+FhOQ B#f2'Jàa!FJDRR~w|VI!B&Kv"m ,>)1c!1{YS~5Plk\k?>,v[|Cg``}'?Ir|a~rŗ]=`O~AgK>so}.֯;/z_͛Xa68Tk$x'ǝ|{;nӌ[|(Miu/wTdFoBD c+QG[7rCE];B\ ݡef%`Nɂ=93&+ZZt"B"-6 VLQP?!O<ZWlHwݭ?畗_BkUߺLCֽi Τ\~at WJ('9~x߲n۲;]xk4Ea wot h&S/CЩ%tM6_u,*8ƍFĹ?N:%m3Dj=S T,^1>ޒ J :9ݟp~0BҐK'=%|4ӜiцKrHõTx$Cn|q/qX]T(M-$J F:3F%hiOy|+q98-ӊj(% /;~ ==_?={֢3xHd:d~u=Kv)rksfrdYƁK%sJ] 9ЁT{9X.tF`eNS#!}׻'i%-zrO|uFd׹E$ /P$yNA9)ɇsMDFjjJ|&3NqnMVF>4sxvS֑A!hövyv:u9RN=J{q 5c\`@";2`LnV7Z|0g&$WLFôxrDѭ<+aYf`=zRĴCˁeeH`^('H!5L 0 B7:fӐB'i})q=u>6wґ7|2 є3$;\}%%B-KR+ `Z=jX j|AƫJà%D#r!*d_0KqZƑ˕9&*YպfA=mx: g Q17j ;u3wW>xA'l?{W3Y=|N).oġJڈ^k?{ PR(_lO p7Dщ((a(w5z=K1'۵=N/) Q@e\ ȴea3kŧA{J& h@+Y֎( ) S1[Ͻ2֟?%8NǓl& ?w d זs)6o0雚,eBQCo/.˰r0l ׾G g4>texHoYX/Tm(E>֑u)2dAUf+!V(&jA@w$cZHO] 'K>{6ړuhD%d$s v&V0Yn*D0O/ŗ^ׯ{vK{Iq\/Ys }Ls/(bxh7\q7~&~txrɇSapK]NTwagH11]yL1tnRKyE,$8f 2QkY֍dNzŚwm}y4AKW8w iЋuJ꘬C1dR/*;&}q>'j5 ʦ1#w ;v>r:8m?K />|,n/2%oRGi[3O~|Û$|@ئjvke[L5> ^{i/qwp]wҙ)JA$!2^{DˁPjuXojOXÆ;Lά]tɡ38w6tpx_'⣜#xp7|0R4j~ڶ;~sdN"RpI,gWJ2Ǟp{,ًovP'zD"p|, {$ƒu1%쑯қ]:1GT,8C s LB~B@[۞8 $J:ZZ 褠{Cdh~w!;?og7߄zu'yϟG*@X2TRݳwވv!CCL[tLdp.ڎ;~;3t#h;ɅKSj6He2uXY u$ }E:"G.[ArczBcjѲjf͆Q& S g8dЉBI)&R&(Αj2 B#+K,;8[L,UGe|qo疈6/iKL_Yu>Q`*ŢbÚA{1XI@g)ў,2Zf\mq'SC!^LӶ8/#{5oJ [8T)S" % f΢6љetD7!d1h$zu,݋ ʱ(`龋\fda2iKς\(AR)a Uq\"W}SQiY&ތd˦:pKH M 9]L?;|¨$@2Q{gYR 6YW;!+j0܄>bPJވw*Bư IDATH%I ȶVYe / 9^g0ny:^lLš X: G"/9c\ZC8 XtRn4B(/6`3RZ5WpAM3-vY3Gy$ u< nY 7opݍsg|iz1_8'=e*׭esn-? מKg_H>$W\xuSOz\|DA &ib <;( ښa,IX9*_āORm, .Bb>p֯LD֦d8  D[; 1=w=˵. 4j(aya1x_̊IK3Z˧VuD(#JY4_R`hj~I]@*֌LRifY;tλʝ$:ͭ`zn7xω'00c4al4 Gj$CZ->W.n.\g/N=s7^EZ" (#&At;Z(( 3(䨖=)^!N}('>ChZ<ȣ$I,}\bi-OoXbI_ 8?jL)Rqt=cagP2uo @(&$y[jCe&()9ɴr@)}f l5=4UaHkOE%/(a 3dmI>83CHr]0!*+3ybs>})sˎ]O<ִ4 a:p=19G~//|/vO O>6傧Qw#V8<[2#n0YГ3T dD;&eJ@ 3 3p`JNv(RevU/Hbbh5Ϣ<3{BBB? +iPj o'+-sdF$#%ⶼ!VC/Q1@wmۀgpzN9Q-[(~;3#Yþ BBEz4$j7 bgQaJRs~fĖV"lEyN 'hYlVB8/̜;DdFVQ/a&W$+GSZ- פ6;BP}0TTr@⌣QR)Xƪ,LTSaˡFM9-6L3lX2#aAtPQ7aA(I\yt`,L5y|q)br'^q6cjڰo(CʐL{_5nK阱'ݡU<6 :ss!]]!{/d; CI=$RogMAO!=K; H%} 0є,Z؟ա=~9m§dX7ihxaCR³/y96>#ėƁ# }V^Dcc -ɒmrJl٭ϬuC,gp!aqYMBDr v҈gGȇ)7loۥ;l`sq' :UB稶7*P+T=U3/[ BXwRMK"X ;NA`! :"RƵ';9 tThMg5􋈆!%*%oQ i{8ӟ/^:Oz/{׿\UU%'?Gt8d;b+?M{G0$Ԛ}L9Iȁ~<̞`,{u,Yb]ݱhSSWljbylÛȠM5j׬{՛5cuG!J9lUkR^dkAs4C믡7wGFH߄@)G+(>L8i3Lp_$ CyϼʫL aQd%(&RKO({>ti8ɧig/4~ Zݚ`}:+\;螺:~H:| Ss;zsxk5N8N $Dzlܶ;Yz}ydmR6h ' \@m۴#hGC@hL(o%l+X0Y&W^r!9X?\G?^~{\pcゥ[ itMfh {{niUZw6Pfa( DAĂ1MF11Q`H JS E6t2az;sΙ._{&W^EKۧ vı"ӖXI>EM?\)*-S mDIaiAcMv^ne)As#c)C:_4ceM3-C B*Xdm5lbpdwnPCeI.Z)8Lg&>LRg:}tww7hlۺ^lyK?dYPE8C9 YszBIoOJ}Yq睘)ܷ8qdK5 h75NNd[.G,%ήrM9`HBMIr?<Ca%s 0|_>9r5_r_Įw=&GcJ-gw;{ܙ!1cօVN9,,-If4T7e0ɍ; ԑ2wgtKɎ؝XrXeXqX9KYdH2Y ko1УM Dtǒu+BgyqF樣呍w 5U0v{ѕcݳ9/_^|3`"s(N-+$3f{HZp- $,9T !S TH5g SL6~G)Lzs~#UiE!;C}/O}BЅc8 ?~d;ZCn,rƤdEP$V[R=7 '`@BD$$̧ CeK A+!t̯}cAˈ+V339S.dAs`B^LfIDBd_8=t+I# Cr?`v(μwBa'r{M=8~_ vuIkZ{6׎@D?h9p?gu\xv] xWX{پ^~xc/ K/.eFA-sX"aB2X>6w3S*,5&2H}]?1TDF GpHO/}NYۋo%!{f4jw&`4҆D /ā$Ĵg#(oZ]*+yg`/vyU/$LcqZ\hjǍHc= 4X3i7ףf,-hGJe/Gof!R?L\9& DU'*zP0?M>PJ~XJ7Ey.y #BGdJLJδ q) QY&KS?xęmt;*dZ'~cIPIZIxrB9M ސWtpXSR!- kF+w$O29/rVp${ﻅrXxN`c)  v;2MAD2$*  BF#J,YXHz 'rt&7Waj7!i5 $A^wɗ[^Es:bBnc-g?Sm G ٶ?  8sOJWw794oۊ$8*{ʊ>Wsپ};\{#SLȏ8-^›.z;\,?U\yïdzrr/ofQEC@\oW3] !7~q;?0?40|9l~vm~rƧ]QcV?˿ V@9Ro>\gurc}&5 ]iB"LGIwoy?߷([#z!YRMU\I;{e4oD) pR" Ǐ;<|s8\"x/K}dQWCnv={j ~b)Y~,N4QqפchD#% TX@#Q˨0mZ/kbe.wHPNTItMw͜3;>rRpG4gb \soẟM١N-4ZLg#g^8ۦ=y7nl{>;B2j`aeŠeDŽ/0sT#Xc:K$%ύ{KJS GE rb/~ig9 ]ZʢiI/ʍܐfup욪+IxL IDATSp+i9%E" 3[jEH!k{C@9^&UdQVS4'g/~(4sT"}S6 3M0b M .#P1B'KwAx\+W>U_Wz򚘘?!R E)ɞO@HyR0yHVZhd aLJǙM^/g!wVcՊtqYe8(B>@Z<gr2քAžamܲOPWfӸч:Ԡȡlgלt[^zko&Z̲K)Hr-9{0^ʒpqs AN9 xM\21j *[V:}wn}vu-Ify9xC\{n#I36 Gt UY0ֆ\}Qsϯο #=~žo峟 4LG0dx=kUfMtqiz{BkEHYV.R& }+ [72ʘ7XS^dSQ+ :°urKY~}9 ĎP ^4 2c1VtI2? _֡a]󖷾F/o8?i8RNojCi5Kohic9Ǎ6~+s /DMc3jSlnIa\ISz%jSS;rP$ZB)ɵEJhߙYH긭9Tΰ v4D+JN-XRP5fd9ϴ8z;LlLk:9Sy?$ QIGD֝UOtHR%jUkۃ+fZ^7y_LZOze/r`Q҂5KJt.+"9Ğ34BED UνR, E(OJVFlKI3Ko@m $IʲZ`򌮲z RvX\r ZB_[ڒZ:K;ڴˮ4$ NmCXkڱ~m:P^Ҟ~ @F(?"+tE@@@& U BOsN]쵵qoTfى✧) ޶L7;%=*̽ ¢0f igLP:JzVr$h$/ҴNqB- "j7Jh}l{[&"8:X@0\Kv ' -i4vrhvdY@81cAΊwZb{Fz0yh= voֲWeEE(8tMm*-o^hp2  缁VP3N&t8_~|/q/qo#2|_[nPshM;x'(+G%4yǚ o|yb +{GOޘOZ^7Lwvi[??(~c,6<OO_'?aQH(-=1RvڱG4 K+&Jb1͎ج65s>X*,y??Ór8~`K;u4h\fxxYZIQPnI9u'ɭ^!b<s< Y{kO8^/nb!GC\Eǿf' zb $ *'XZ8? *hΡe@$`@/CG"=^^yFyj'Eg ɬGġXҥ-#\'|ಿ!I *<}[y!1)@ &F [S+ U ?X'S8zycoO[Z`.2 AXb[ %8W1!cGQE|*Yѫ`[J]Ja: qLwv W uWe _s"Iҳ Re>1a$ H󒗒r8bLv$LҤr`8t#CqdeX +iGZ%W-xsdd%ž||0TK=~ ;g<(p2 u!CQ0gpX)Τ8S~ "2,rĂv, 1αBbG!BT_ΑJbS˞f9ih |(hڂ+tRlk,󍜴mI7ߌ9 VDrT,i" 9/>f6VbHxygbEO'E. p2PVqUrtU#r-&TNVJz)j"! M]k ߖut8*H$^7đbE*JǾ@p9zB ϰ@!V;Ds (_7X:>HՒ~HVb_IJovuNWκDm%[ CUG9H7g;gMr[SxZ,-y˲s2C)~/sIɊ>Ɏ9GggH\3( B0Np*BٴsamJ8Te\3g'dT3##V(, gvr"f[K 6 "]\v=b6똱R/>3O?}<8` ̴5}Qk(9 8åS'Q۽ɍEwNbyL%fJ}cRxtb v6k/I =8!yg^BuWɗu~ܻ5VV%s`ӄXRa˵#}s9K+FpƚM36bB'ۂXP`idiE*6,}a(b_f8u:r_}'Z^CR|;xydÄ*: M0 e#{7lkkxdq$k{{X 2kHvtbg£#('xY1/ʔfviA[/ (9tW$my˒0=8~ &`3.e0đ㞭ڵ=O>0:uAE:Kؚ5AIFJLc&!7̲gbj KO?Ef .W-#yܖ>#E$DaGc0f>ͣZ/'p~=(I3G-}D<cw#|T72+wOofݰ"] "f8ᔳ8lyVm$vf9emH"Z㬵 pȡ7h-Xܫ{8̳=Oi4عe6>;vgg|i NY?Puo}zθt:m>'GѮ(67@Q,]UͯQm:xg_寙2YMu)'r:qkN=t z{o]ΩʒjEɉeq[/_d(I\^RNǢ/ E"^y~ꠂ<vu0e*4ֳZ 9rbtqy|?d!ZK^3-U1aRuZe8?CɎ%H}Ep1]Rpǭ7ſo8.|)f#/h{?}s9vkYFʾKpʁ73Tl.`'7:^|lRJlH-\cӱ!X7,* Z6jhƬDD1ĘON{/QX%e)H)yl{FnՐ99s5;f :"iOfnX1ur|QZȪE@=\ǍnE>w[A- ucFgs/jvn}cKꄲu98zL,/Z5C;0AO'kcCpBH*^=*ڹ˰WcN"Xp `Mā,m!  `UBEkَGF dl&gn@(/*HJHO8>lp*,:>W{bqTBAI 2N8B%RX' ^v$~Ԋ3 p lD BbcM  )&  Njܧn:(3+738BP 5ް^zA,+)j`ƧI6,3:[W-vcu\6`;$G:稖%]KL6(l P$ $:  Bg;%"8lYΉz+ZeouW.WHZ%]e$ԧP,)mc Iee1Z0WK=FJ(j& BP)1WLeEn]j%@*E ! k}|2Ukbٺ%*u˜#"|УzJ=;ʽ+Q=Ei:T\,Ѩ5G+ 5~-#Hr[TB:(YN/`eU&cLDZ9S;mlS}sm Ky*S9"V~Xr ~/s?|_C}Y‹Џ%@hkF9=%%z *d!|bkו~և /~h)ޯ )łR`Og~:9uM;1>zW]E`+{-HځU=Tptǒr ɍ$OW5tҜ(CA ԦIֽ R[0TԢqA ^;lɝ$(Eg$ # N&8͟+,sRI:dЋ ә!^/pǿ8wv ATs=|X p8:%ሆװPh %<7s۷ }32?ZsW-*̱kβwǭt2ws m:JHoB7 gw>nc_A/psk'?M t<{{NO|m6 IDAT.l9tut+9/qJf9GSxӞR+ uǜ񒹅L{w6}=W:v&׾|lx 8o: 3=Gb5aPKGf!%C% M0bcg#Pr6I,S<;kxGY T$r+kf|]L˂ J0Ir5B;VnYJRK fI">n-ԂVaΞCHT+MYc?w^V%ŹMaߢe.x]'+.{na([e׽k -ݬn}lS cePDZ{g f; wJB\ Bz#놔8R8 Bv>I\yF x|R})ϔ.,yOKJ 7r藺I zp_O =z1QwtAT;S>qw-E)za=j(H$8cLEIEFU;襅3 R"!f=ˎXǚoc$ǻCjݹ2Iy{;L"|Jq-4&$XV[?ЩF)$dHnbٴVS ૟|z '}ɹ9}%F@y=)UtK`(.6 +& .pBPwcb7rGvXCI`Y;sSʶ} (@aBjk=O>t( Ip>"/e@a^~9/}8 8a!˵zptzv7'K : A8ZAIAn+IȱeDŽdXC/tr/t1Z*T kk)Zߎ=}}!B(XTe-Xbzrx@U:Y&#ʤ]VQ8W[-[ '߁Z(uz.Y觖E0rḆc @?u GnDץ`lj8\sIMOa玝<}߱'w$Ʋ qqEbyq7 UmvJEd Lvg$ӂuEֱ:L:fikY;q'U6cErSGz<{( TE J{9}"ط?@9څcUq<<ӌrBpEN!K+w31\7<#朥&+I`tڣ /0-(T+nj Lw /sl.aݘfmh'6nh&2X;8r`c5X:ћx#8otNR:Z^ދ 0&6k|):?9`],jp*|!(XFU(j' jƖK E]'qhF" d,$ґZ\ʉP(#NHj,UAh`[ @  9ădc=;/cvaEB틯ƪ-' rfWrr H%9O>p󀢕%˜~⼼p 7`%azEd~O "E_24$ I[a?gqJQ!xro㋚䤥+h}^VFƢM"RBc v?psX8Ь, ?D{;CUQ Y=pi9:=i8,hg(Ҥ6&-,ysl\ߤ 9}"@ 2;Ue'H:*XHyTK֯ KX)|QUR8NHNxx7o7Fj6Yjy%I,C+od?mPKkʭ 2_yY$1|5:2ϛ%BA L'G / i*<N Q%u 8^ q(9ok#y`ݧoشG/'|v=s7~-?~}XpeMk`""< %V5,|Ck?B8W&[6'<|:s› $1"H8ڿ9DʰK<%9RYuc $(kqb ReL>&WI%8HuNIr 0n.ΒGfrmS$:ew/r=BX@HD4r7>9;J@:Gn @P~wr:Q7ZFHvVs98c饎a0Fs~z̵,i79rxzP(rmçs7[oĽ͍.;NRj.Zf4!]4"#`5J9Fv.ذe^G<_ν|B0 $%n7ss??ۻą]Mrَ_L{d>\o:N, xE(6{[{CU}{m wn.wrs5Ar[=>V0׭\< L/3y))xǦ %xTNixJJ %r ˑPHH1`aH..,m\[-pA7C)Y{??um:st E`=CrzE3v$9qIM5F5XO/?:Jl{YC'5l4<-wcCli+ś3VnL!˻_KԔEB7@?, &ª#<3SȔP͸8~m{ȆDȤ".x֐P̝B ,|AzIfC1yl \p 0=iٞ)CW 0Z %W^ҳW\8>ˮ&>"+zv#Rl_/Z6iXǦf&BoHTX|i*B'iY]zd1۶,dԬ!Axbà.O:4ϼӪJ0ӖVq:Fa3N#zN pcs8j2%)J\<NP5W\{*{8L ipJ8yzh t[Pf! ~BzZV8*q@DZ2Pi Q d'=j*}T0 @iV3-!uBN?~>)tZ}"1ӤYyH!C pq882lcȧCk=T"û$ L= ^v&:+|I0Pfvc-G,Sj(&m8!2M Z(\&X0R1)#5@UpMÊ߾;$.*SA+1M{8X jPgPf.*}ޟhT6^TD"+⚋oHeb{Вic'xӿ|ox_pC12|_>Mbr>!Ro`S#ܒ# +׿FTs|?p5O܋׾As`n>v#_Ǫ:O'&80}ֿwffc?˜y#-BRmvv LCu;o.C"yxKWJVo+,&4ck3Zn)zb៺?]Sw3@'bhn߂YC|i68roժ<$60=6NYzKl$jS ):d.[ cB H+Xq?)3&b88ᨣYT<~0>ȍ7?VP=WJ|Њٟ%Tcf~y;sdœr+qxy9wan0'8#+ }B_#[02<ċc Z-jner`txc m!I (2g&0ǭNҬjp@`d>t2&$?6|qo26K_pՠLd*` R \u33Z2! .(2W:ZJ̐Qp&2ȔR֌VH_ RKzyFhyPp暀{fD C`vxp2gkthsAm`b-wC<;_I[%i*i_P}RSxzR8`Kq챣^"UEv8Th =EԯQ FR-9-e+M![읱+]Y=2K?5Tcд{VhC.l\a=v* h 5tR3]y̷ZG"I2H PHM?i#~mamrאmj<%4QR1ypMLnaL-X,q&bR8A/$/+Z^#?\;}/M aA8zIf%罔Ynyf3J{7-{ рuϭQ/PY\7hr?ܛM fӁfglYl, J{ى5Ԓo FV)0r[|vOKV윥/?ք߿fxPGCOcdL  m%9Ǯ#_Ow$wd;yajja8_N&>k}#d$f !d9Z@Ȭ (+! $ȡeze)q, C?QI0u"KڠKoy9JJyN !\w5"7c:B)%H򉧾MIeגo`p$-8fSǏMrcJ}7J piUBQ4o ŗ^At:-,/g>_sPU_Ŀ/7^u=y˸{{ooHc FiRDJ?FwڦS8>o~V-I{CCäir2Cヒ_yuW07p#UsчƇ&pH RYܱ8@",Sq^PūzT39*meRpv$ s|SeKrk àsQ'7*<]]C*Nmnyb&tHiXFBfwТO]:?ge;ZJ& e,@,@r +L ;B[*se;2Tp֛m pJ踲.VO;YKHB-h9?=mIl_qM(z7׶,}qg.gOPC_mC߻{7pcK,u ZêHpQ( qħUȿW,ўĒIpM馚S|1K,طwI:Jݦhr~QlG7 $/ط$iG(%zrnn9A#_@e j(hDphJO,1n6} 7Kzٜpt:`MzN`d(SB&(-Q*h'rUZ`!<@kD-ވ_i),+bUiĂDkcWJgNܲ+Nhdtc,^uyd._FX Q SwV ˚aMkV75Z|u{鉉E>/3u$]nwH3?>G>awp뭷Pז[*h ck58L%zfpIK7,ŵ:QucX>K IDAT87RsǏIpR>:/}XW"XSWOƜh]PJrΰ -9qœDY Xrc^79ߠ|~{|Y(Lb+q/]KCM;MXlBSZ4^fW K?,'JW ̻ S=anhJIPnwKʉH%Ua-]!$Dw1j++]opξ:0ZK5nkEϿ~:m;|QՎ@0X,XV391ιIÖ]/)?h~tN~]rr3PJ_eOcMʽouv p8S7+CpBfroLupwϩ<{W_Ó{/DW]LޖZ 9rL(Q{߳W9 gm7⶟N:+g%|Y)W$*z~;?Fj}!x+B޽!A45}%3PHƊ N s^u )Y8 Gvu,2{YĎn7j^y"ኁ$@LPF+v/Ёcm3LKS{ROk4q\߳>t_kj]%mX'EfUg D%T @X+ O/ǎś5] HڡZpBW7 uL"J66~7˪6 IVR?k,dJk/z#X;B3y{=g,M5R :Ebe?p}sDJ &T~T%4F%F*H֐1Ls*Zɲ@9z7]&n98R-,qA{ElX>8qZɮ9K?󝕁M+n9XP aS7C8k6+\~]}?Ӝ{E\r&x173z.~& Ƃps73Ǩs̯]rVGZG%9{F`dY?K?'v H=pq<;vIhX(bhϰ aMb(Xaٷv;)V\OE^Z@8ljHx^CsRȀ>\%dΛE%^bK,W:I;#aX9Hpxqx2dkxkڱ:$NHxElG-sKPre)D@1b؀bmfnqnǰ37XK 0aGf +\aZay*'6j0<2ʁx䡟;(C8l~M$lEY| @sG'WW=p(0btpNpO$N0^p[.A'_ 6_ff)''p$ĔFMs|1;YTuB^N.dP;ȿ+ V *bAX52N_ $%i+oXzw( ,,Ɗ^>?d!I=YS8E-BB0S)L yfO( Zocz!#=IȔ{s%漰>M] ŕNNIQ!Ҟ$?Lt-XW%Qq^rf&9,se2N6BT C3z%d) %Xpm oY%h !X]׼AyMVN rZO s+hu N* Y~P&KiRyē?9k-!N6e˖yɧx׻řgIx_N&?8|gJ[d,̳"+}H;~r0'/jC VYzen)g~z7aE"񉼮$ U$X{z:n" " qlr:x A<0@E ձA)wZq }U6k31+"-@i_|z mK *QDU2㨒,`_ss}2KTXTH!(tPt]itSK-W u@"ɜmljUV5[OxXΚAuWy Ix6e_Ȁn[9u}NҬ'Y(gl\uV62G9^/~/~o#XsXS AnCUTdDD5dVyOE|,7<\~.ux^ÍGG; zN"3ǧެp{,937l=/T C *UU|k"5^! nr8J#JͭNHB4Fd^뜳V2RN0յ$"x# &P !ljorҴJi< tiBrM+HrL2,(jǩ#,w,vxov8@Ö\û_r '뛬Uhơvf( ˎqU5€CeUUTtp$G*}Z0lO aOOrNj,qez07nZ88 (~Rɼe8>K?)^5+DqHn@*b njFGTu9EQ l1^7a|u)y?3QJ8vkXǫzE!da)CS8sK%8_ض}]) Պu޿i$ZHXV غP8sSZ$ 'iOUD{_;D"9j,/Bi8]O]<8Y@8(H3ׁ`vjn C cXY^YB+M\8!;ODZP$RAprJ1VU·#[Xvc݉l GIӜHYXY$1C+pR~!3*@I+]>8!{oYw/S2=@B (X(_D HTD@Z!&$鳧W{}oGzQ=kZ)r]WKsU\YtQN&pU68ϠIg͔D0V7X# PE)9q"\f *a[ Y@8U DsL; ja藁=kL$|=Tޢ" ,0ΨJiT,"OUdN 1 OQ+9~(WgXL:0]4c误xA26u[gy~o`/(}'iOO]q59w~h>Z΁G᭟ 泟$y5z1׼+W\gJSۭ"RgS: {7oB-[x[s^..!"c v_`:T |S,_J,kʠP ?q`)y /$榦w1o qΪO!ݻ7?!(]I-W(Y}da1IVFS'租wc "@(UpIO"CQӊ#,Q*piEָ{B[Ż?E*4ZDb 5=\K" ;SO^ t_(wW8f1Tϯ)#swENF<({q"«~&x3V]U p*KFLsNGzԕJ] N8y8I#vi?2^;)D!QFEw*V)vFt,; BR"JR$aÓ{`;AC$9 EJc-15CQXĆHy R\Z#1E"o$2J;OO4}/wѼS%wq83.UiFdՄ@X YyblXZSAiIi$z,ϸzZu-Sٿ\o;_Ciy#~lda%j)QRv_c7d;BD+"IdLėTـm YGkM4Nfiyzݼ6Nڲ4Rp.w+N]:g8V:m&;aZWRTJ5$K#z@=X0J1;!3mUQǗJbUi'I_"˃@$cƿ[_5Ů u$+l3?S#/<[:aߩyBpy_t'^rV#ߣ+= nXъZ^>qhՍ@$ݙbc(ҸMt{T(_>\01UCi,ŷը+5C{7Mq3#8\5DF IE@ :`I\_(_sUD=;$bz<"l6[&G79P`e/)OtsŧorSL75M5~f5Ez UI(FiYxμ{ y@Dd,=✚vjV -7*ym_E=Ii$1:AQPS%^qNMNgccHC;-"A"p.MVd*\aWM+kS8z$>s0b5T)-A[N U\S'7"vaHjd"2134"xSS&4c&|?o8( R_r.beec o}{o|x{zk{4S7Ke^}i|w-.2/;y7W=B/ x7pA24Z)s1;K4(.6DL$ZFrM)W^EglcG/~7oXĸ{>^Go|=> .2ɧ?O\[|y /{]㛷cnկP2y{o^|~w*}=I{R7"Cba=u[j\I?-9w/:=?}ˍ::c!p܋V[' OiGXi%m 3*^>̏kXhs[pA3{e?Wt:\V ?5X<̶ ;: ZIrVSy$*$y0Fn*y!<Ryך7>6&@Vz67$)8F6JMQaHUL DnA+L DžҶb<8ʠ.мZno= "p g/o&(y+^=s .9XMZ).K5U-ZI5͚#0t5G])84cVAk7SlVoYF`wG3)1WgL.(2C'R(GMNKR6@tDP4La >քxt$,蟾{9YΝ4"xɾgŖfB+bSKqNc]C)tSFMmN-1p7MAD9º( $&g#@yܐF2ӡR6E% wX6r;q~$ $cK%Gs># 3"qXffpZ5yM$qdPFEۈ(yC;fSZ5/|=y4y붃V<|OU9v&lߜp˽k.Qcu'R.8Mww]*Ŗ46WMskG3Khk4f.tf]lZl IDATڣF{F`pt'>_Ti6n1ى+81ay5 37c^55ևLw,sM+\=lt3jf==DS11D0ݶ-s Y?,n՞VM@I,J 5_qTAOiJa(Q0ֲ~('+4A IUFR8+4֤DlsepQ:iHZ&hHp%I+==5cv^*֔y7B;OE?:N$jHo*=*z,:~L٦]d;,&"-VKަHҚP ; GE$R529s-,DYBI@d 5Q(ZUњ$'-&PD/ |R5'!ўbe:;Z PLN **/H7j8EZ9 |O?_Ba<1ՙbP)CFP=h藊IR2YI?\3Ph17?@N = phiC$i[-Z>wT^,ZEo4YUjj]r5m1Z#УeO;kآB՜em|{;YY^`"h[j1EQj /| 7oa8pm7Jw][-l0h~|o3wuh߸:ɍTu,T]Mv};K=&N8~?˗ ÊՍ5ff9QӴ:闊9'&,?}n-\dzcn^p䡻qlx^u'XscC&X v'^]oil/ o6 >ᤍX ÑtYJkNu;8ڇ`5[gt")Fx'񊙗ѡ3OP,>l= S`k΍ȼ.w䃊H=y娖f=ۍ4RP"+c-1E[IZv^q!p$P9j"X[>L[/1'AL A.t+A+LM q͕.pͰ䕥 )E fjXM6Viy\|żOW59t{8pT;Y$k&52uJw6bNp6 E w1g5D+%\ tEꀥSW ߡC՜fV\9b" l)1 hѡDޖ@'h3WDFcBِM#Dg. > /AUIlfS5{Qb<.K?VAʀa2/~J+4*F𓗤ܳPryDN ,0uZl`"MA +_'JV*;99'=gt]Q$Ԇ"U§MĆݹAWRn'Uڕi8DV5 kX9#ض{f&@Tndn$C+aPh4bb"UaQtCp Ixۄl&zb&7qѼOLYZ-y +,fbQmw(%+įBCBk az2av%PNpr60d *»@ɠS) ijطPad~cֺMt`eGZoj*EQ/Ӥ'c#aRe$8mT.{>a|B?n&~\ɶ%XH'itQzP ecFB)(4m`R,PV"4HzIK&Ʃ%ff/^*uR&i9\]k7,p񖈓 9End A ц֚ ([⁽w?/ #Qw2ؒQ0?f9kxsoa:-HLW>恽l7W!_46Nds¥aFLWnbn%g_@0רGwQL65}<=LLNWb C?>O|}Kb (x;3kQ 9)4cPjr 5vlN5ݒ09aU0UCsgf۔ X3;.5:Iш8azQң>vno(Xe1?1()|DP<y7|uJlD\*w+෺X k/Ω! g=0h%Jp< F17fwTf J5\7ŐzE#ngrA y)mV8ֺ9@Ab#.0wi8T竵lrI\1dGi@YJ/ӱ^Vsvҩ[d3zp4נy_@) 9rI7?ЪC[1D Oۣh' 5Eѣy% 2ZvZؒ&VTu&l)m &Wts8Y_]e1[ǁ>+o$ѶF5'I0:B&1y%9(#>n=9QZPaKCNκ*>0(W=" yx>|y6F,/sjwy 7 Ʃt`K*`NGH"̀A*}r᪊Xʋ9V&_:8oZSK4<▬n.j0Fyu]Z߳< l =O&ɿ:Ddr fb# r"ʶ [K/meiZj R`i AGVdiQLV ΟR[oըs\Ϸ)š{ RƘHf[K".T⪒?\jw8?O+7|~sy/d= Ԛ|3+M\(lmkbz9b5 G_rx{z6qI[oS {=$7c8l $MGau㤣+-nQю K,kclMɺ+7j1ykGN?Ġcv Oeaq˃9ZyUNcBd^Y|Ž1d[qLLI4EY"^0.1-jtd0V %_}zXTlDGe2G1::Y`LF0(5Y.Q'V 8e5 bj%b4mF8*:0wT/7?Nbn$4Bp?4 9H ŧkQË޽"u`9P`ɫRX 5x"3d4"**I[ AR;FHk'8v󿂲dȍL?1,I~^:e3G"8>эT)yhXE,NH'VV)I{YܖO9RN"WGZ9Uh%== F]AJNSE)6+3:|$R 󊿾6f&x1u+ fW]*_z5stR̵5͚$FY[Ť6hͣz=ťXC+  24ymTn9gFDpx +Kfl`aW?`b" _?Aocs/|?of&ܿwi\%i@+Q]<(@r撸ǣ O3sۭrqc$ό,"\F?#<~;{-/~?&?k D{ ,s"G)ru#P/K ^epF+ hVTX`b}YBĒ]{*N =僇nYH9"h#j(EapbpUxCs޴SiܰQ^bchDz"c6 kY\+qI&Zrױ> |6jT܅'s!O<m,gh6xo0ZދцVJSzy/R,-V(Af4RV1֊Hk >D,v"XXx'O ^d|ᡣE @ȦuZbBB on950dUHZ3$Ic絸HJs;9z LFp!+hF4"Ejg:XL6U-{46S-܁lwVFٺ sjl:z_ e iFC11LBmJzs&Qʎ_u\[cqr ۧhOifgkd^sqyd[F=1B8޹OUU|_K,ܭrNI|NYh ͥ]G{lS*;? ߻6})׼"y/~vCUU\7*^yw<Ix׽Zsg5/~y?)E{Ve*#랤.sv_H+S+U.T GNyL\XJ@(O=X~WΗ?GILi8Qsl;[SkkJ6pѼjݿ]6Klof:\gcf9x˭spǚT`YV8fLbW/ߢ qxQRpR+ }yHѴcTLK:^tϿ['kUl޶_>IjVhyT^7aC>糹e8qQ@d\KK4MgK.]sDqB+V4"X;ttb|Cq:# w9P3UXT7(]2YWFm%>j𾐤#uf()7JԺ_HAQaTV*왑nhӡ8J7tK"sJGQ IDAT.pjq -{&41۲̏ p, HF=X)Yh33.&Rp,*\(#mϣ&A)>w}$Lq锬6bKfXzϯڼQ 8x@R0=h"\5dNb!1~okX\=8qJ&,-ʈ.6φlN"(>e1Fx$O4\rO6(8R< `՗o= {~_b}p6}w~n_f鎛y6y_s\WrxYBy1͈f" k/:Qû mt8}}?͇SFn:X?W<2>ƶY}҆iDQB=I%W:S-3*a591rQ Jch9ܫ!UVR3Ny/15kӊF}N;>O*^ }:G<(˟̳~vm{H Y8=l䣌{QJS%i U@߿M[Y_YX@6OI.~Pn.r(U 4#-/.}݉bsKT%_dhQ 0ؑ-1v5hCP28 (y*hyͱ=c(1iEV8T"'b6u%d_QGOu-<(f\L@ݬf 't[ YA. 9aSg r$=I5ny12lWU`pU/(}F?TPyI k7 xҶ*h #$6ĉt*D̟Jl@!i '5#`w !NlI4c(#P,ijG_y 'axw oJ X'^%JV" k^p_=ָcɤ*,uQBЈC{?v=v$\Jum$ILQs~o8]1?{S:U3#i$ 7lئ)\ZHC B $ j0C W$M]M|_ r?֒43~9[(c8y/eoNw F/ϟ=w6E /T0 ,{#q(i>,wc?S9E_* E/ZZ-#+]BmEЧ5]KI ǭ 9kmț2vLdge۔Õ]#60~QNa2~roYA5P^K;3W?8Ga! W`Ƕ_ ?\ܺ}_YǁܿqS(uos}pΰ)OG>}Ux>XlD-57( =e8m\rR̦C-,vr; {ASx^q+- ] XKkl!GWgr0o|Rv>mogWś; o'J JY3**o I!}K<匫;'Kϻ[\v8x~g"8tU PP MͦfM]`p: +(cO[E,d!!ZUiviO:<;wY|ʷYnx?K^RVZ[H%>H1p$ j ?$I•aMZk0whF~?<.Gs@x4=O/ D5fgx s]YL=JWrG3ЬJ!V"-akJ3T$`8k\3]Õ iŬ*5 SA5TĊJܠcXݐIp-V$KxpViT(2c\.Iْ;wj9x'oRTXy_ֳydNGR໢DiIldD7LisGnER8 e9tKN;Jeg(O4# kcѥ21Y*d&۝jSe}w̑,L‰!7)N.DK. Me) GCH}42,F7y~ >(4t4+ ~++ ,KVLF+xQXGEᅂe*A6l}<)zeb.Y?z4%]Ңdf 5c9oRsŵmr8em~WrO[okFZ}4Yoa)1&tOǁN[ `4RTk^9hUw#_vr];w+$X+Դ=xM[ٗX8urݎW|>$IܳIg=Q5f1)*a ?Ďm~Q2w}PBUcy/}Kb\>s]7p=(ϯﺝ~⣼ݿxf[q#7n]Ƚ䟮Op4B;mpK^0UӧH";o6IYo(U0ݳ4bis=22D-2hT4i :^aLNRxETP)'OJzA褖(Cm?ݚ9'UwWukBߟpʳc7LaH XYBMQ6P]$:C;wt'lxhڼ,rrHeu%̥VBS3' ˒ekEڠyp2\v FBǦA̓ u6:[LLɯ(iJħQ0cBO'͏ yҹ,isq,/-׼JnQVtSh}:AaVV.)rnj-{@3TJ s.ʠÈYWbuܸS hg"Z(Le|_]8"Se⾙p]!N(rW-gcܡJq'v%߂~FGF#/a0j>eOmǻ|kXW,aHsG`1JK;/ T匢P@{RS\2=u1Z Ͻ{RkĆF#+Y锤V%{!Q}p"?RhJg)$If0ca󚘓No#IJ&VU( {)90(H>n1>Ҩ.yퟻ>eu㚇Ԇ7}$I&>F#E8у]<߁ Dee%s+k?>Ln5kDJ6A{ƱK(R:~w}{'<ϑVbe`"HbVS+p맻k3^Lϕ=%%(}{3vE"XXvG᝼DPeFZyϺAؿr<)L< ~a,^d痏xgJnNjŰi WE5,ZJ16h8$[.PE⇨I.JA^UHNn1{`VDv"//1F ̀uc}3;bGk,¾8,q$&DBNXXR\Vsڋt-ޝȊ(Z* 2gbȰN [=ur62.`h*E?mbH3\I*}m3KbӞ˞c'aiƊ co<$&N{}Ha#ɫ78d+<-(Qd])QF́ 봓z%?ͶuÄ!{ǃzw:q ?}a(X=8FuٟuZ*= x eo9;ULˣlݫȑu"zAmbO=BI(KGCnYT]X Bs萿ҵ\|zsoE&69h-TVܱ3\\v< S渍[x>I$V8z5YYvrgKPZxbiyᅬ8+?eOG'tT\OYyϹ+F?=gG }Cd)CŵqL%[\s^3o#UE4\U3y|׳طkPc,9Ox<Y\TЉz2+̵p3Z 8UVJwk)ǩ58L)JŶ)J'e5rc]m] Ԍbڈ椅!42e̝WH]B^z;PUq }[Bqʄ+}sb4.~0^|9p*&9*@yL)4q#z#R`d3qx婆G8{MK9S,jFA#"l#Q{d(#A^ xϢ,@W si݂]~{!z^6x[N~D9z,MHauކi ̸ɘ9ڪ㊟:ib&Q>@)X 񢟘 f}@;Dq)G- p pLFp.Y{20 ֬RiBһqh#n/MldXJnuۏ4U8p+ڟӚl}GaV :RjebRܓzg$Kϻ:&)*iV KKUXZkRvE!Woג`O% mZ$L_pZ^_wʒ /馮oF8$2S28^uޒ?S%"=<qc{ezd?_yё +)xihBV{OsK+( 3^@1VJ|4,-EayrX?s.ZZXҲ+rT;z8W?v1 l iir^J{# Rⱦa'ME'#!犾R (@Hsi0# XMh,I+rb@IzxBWB^xFC VƮ邥l&K'! ^=ul>JclI]JI<lY]aLVTtX&\hs t-aeR+נ6X#,NIGAQgɘ)˾+_[:H;s7qU{׿3dP4[2__e$Q,@Qҽ+%&zd8cmS@uU$ifK=GسpD׬\PC4 ZRO12z_޹g^t%zE2 S_C\P(rV(e(-{\LS $)XI(;瑩8SUjxv=Xج+LR5it:i Z%3P4"'TWո`JPDB&:_o;׿H P( W%7 >/z/%=|׻x_ʿx??8T4QZ1"iYI=ZWB]Ʊx-bf7ޏy&‹o IDAT? l|ӳ՝ZҲf>^/'(*<F7Ο\6.yxץ'څsp椡?kJEQ(Jï9q&-,FVȕvDžucbnў[2X ('+,HSY@$s]E+-EW[M5Ej#Bْ@tc=(r˦u1I|<ߙ+tDRCC1; O;䗏JVU&'s^kYniewӓ|Y>3g gpW(Hp kTQx#&oӀGV;qVϩ,I_:IuN5x:zb3OwhOb*&-X{fD&z>Os7_mw܍֚~J>7 k<ٗwg6g1Z3PUԴg!gZIxEn] -HK3< Pb1wE~~@4U ZG zh,E (q &02: $-ɋ!P8PTC/>/H#F6,uaǢ# D%2_r 3mO^P)*ܿGd4K%Ji^^y~~~~3DƢd%%s$لF{}}ZȽj V5@7^ ^* ^'UxhWBNi\LHe+jLk`M枤8UNװeB% do)V6IOw!NRv4'(7D19&G$""cGҒYihZ4*֒tl܍!x0k87*Wa}{ԕ#+?3KL6o_4{x¢+!t$^UMueC.Xbj7maq( 5BZ:FBکpWt>E!AH+q`Kѿ1>Ⰹ<hq_ޝ9~}Nrh2ԌXl8ϧs.;7ocim`lΞ xhFWPhtflu&V,,<}{3?ˎɕZ))uCSZp+y] b (*(F']ZeYTo+V`4#62 Ue`"5IJزIZ-痲{{=1pgyL!T0TJ &FbG۞VVRў'u@s ppY񴺧TR8i.S oSvflJ-dQ;)F߁5U Ptpֱ[<*@1`P;td2bǬe!RIk1' 9Uy:m#&50:duS1ڀj?=X)_j!j?F|;_(6$/ -Y!/x 7pwPU34$|UȁV){䥧ݓzV гqXq'vvlr(L qhfȳf$ױ0z._gI[o_ug۝[yg5f9p8Fz8&uvНh%1~Rh'a8F~x&C)D6n w _bv@+I;8&8"0ti`8*J*C!su61@B=(tsUxw-IVɛ²wrtIQ=Ң4q/V\ oc L]־h뛮I!z<ֽ%.IUg*ˉo#䅆3E^dz%tzNzkxΛ>NhO]ádJ3uGB]hT5yx_iqG|`o`3Jl@jhk,!/}[ VՐU4s\RƬ^=DT6/=K][ n*8x@!~Q1L![V{x:Cْ5 M-J9~hLwM%y!8u}H[{|ZGRr/^.0lJ.-0*ѓyŖJLJRBAZ#jG!O=-H-ԕPˢӝRi kDy\wZZq¸AMc_ecynY2ز.$LDC5U`e~6g ҠЌTWҔv7׉7OyS;rh9s뎒)F"π.q/ijv|_⥗]BJ- g})u?NmP='H/O` ć=yɖ/|۷wro'I XH޳u8'b<1XG+#-y)F&Pi, kGZdVU5̳vdEAg4+2lIs@,REamEqZE#PAR\_^JgamUtu!e4iP˴q܉y2'Hm' Z΁-%Ė^&/x蔒DP Js+E[¾ْn":/ bJUŮس{9J L%fgG5y2MQZണGwО e!l^%EG'>9O$/<LYj:9ܱw6Q=Oie!yNC%(}@BM$ֱ|RtBC06ZR#ÙgqQ F,g'C*ĭ$yVzٖ<#@1ZU:drqoWo33: ~. R0>Ј2Xip@%ءY '`Y,҉́Ifocx/^K"O2L==GJ-&)*S#ͪ<סDl1RrpY oz2pE \e|A^Z:yM?lKlߤx L_ZNDF5-yU$EupǪhZH)RHkZqq٪MR@j'ml"5͆a*a(c@bad%vM-i*LuQVB \o&~u%ig84DQc аw NKXeue!OwhJʢh4:hrpѲ N W*?;9̍Jk ߾~ .=Jxrڥ 4fD >Oyۿ>z;k@)Z%A+S$o."2tFCy%+쬉{݂vp߆.YQxaIufұ-(IHG'7d 9JSDUVO+l6^T s`!{EiZqcIPzRS%lpʙG/nGXL\a9g~L}cN˽T+8EMgY(5o{ABaj׼r~dY^ Ƕs̨fDمˋ |ǻS 9ft?R9͏w:LEs.{9U?)[6_5W=Sa^bRwW$4 (bQ@TkE]Nϯ x+X%PC\>y55LQ=rԴs55û^xg>ǻ>y##*&moJo?<J <#C>&w17<$ZLk;9*\=+VG :>]LJ.aC/wibMS. K=RE@(ύ{T挣BBplj,gMPՊV\*brH&{?EYPj88[2Z_yk.ȝ&c6>J"w V ahD5. OT_K>GdjJ?iʽLv6c0ш(hX#M $KjBaKˮŒVw3VijF\|^:eDW3M'S0%V;nsͥ."JծL&AhcH)KYbN}ڥQIĮ=}M[q)Bb~!㺟⮇h-;8{f$?rw]/7zMMM}1d)l cy/v3g@ifGCEF`1-"i| ~?J4Y}BJAr&a*v_;s&2<_D>ԽD-`SxN扎8RE eUX jZY,l0-|zij5^g(S!Jxf $!~(ĆkEwtHUJ)Jȃ$m{gYYIL\QZEG,Sb}CjR]2uGH cod0/u ^] *5gvxoJR\v޻'?-(g0QDAy2-q|]s\摇>ܗ]l8~;.Μť`߁ܺے&YǺ&>~#DU/C4򪗽w~DQsO`圱m3vF܎lVѱrnL贖x[fbXč}kDw+O]Ǘ>arXa&mGz_,s3ǞՉXx^O lZs ?RR0"g)277SO妛n'XyNG'xp;BpOO/^4!wFkaPZXZ9dRK.:j zd1:pUsJkVFTM0à ʿƪثFl 1sN+)8c8arB+H%^6xPhUQiXPtg{ lbu8R,,՞c+"zF%$YGvw!.pNδ,qvN3K;G,6@5* J)֎i&KV.3<E81(I,T%c1ZkZr@]kY+k[!%fr,(SeEhg͝' kR;=3%Y+>c7ػ /㼧]cwk%g2bؿhI֑9/|_rSWw?Ißbbg^I161AKr‰YF貥|^'#ڷ鶧g=lZnPAēHeEB/Dʓ02pe&>pmHj_짞ϕ/cq)J4ǨjZ$$6 #B\F9t$^ʉ6صMEKKWX*&f0-)008UVqDڱ|LIlx|MWbKEqv36Z>W:bse,e/"YqZ5jxbƳH!Qx]G;&!2)졊3<&/K; ,c-GTerꊳd-Ѭiv͉0 L}To-{f- O)={%c˘=2x_M*OSŠ9ϥ"$ƊŎ8gSM O^C|+.zؽw_Hۡv'v&I/|]{Ƴ93>kyg_4K̓2p 7( 7ag4)x[&⬋/^C?Gin`̋HyO j"b/vÑ pHsD1fjz2+_C CeoZ9ԕ10)r縯Ѫ8" ˪5͆gl_YX:Xr2Mm^ϹO"?M]͎qisWsn- G )6дBL+JAKO;2G̔ۜg*# #ze?"H 4#X&2/i)5Ée.ʜ@`sXt"1 "Uܤa~WƣXQ]A|`VÿjŔhnSr86IDDNWH5vᅌJyIUu W堨&|-v$"\^c(VRr>@K8E0qBpV2T$W`quR\0}K 5&ЁvG81 (J)h54zJEfor`a1xËg;Vwu0Flox >HºsB(qɬ:[%=|O OӚ&-H=TSqRJ@ JfGr3.9N2O7~&v%Zi,sKN|@ +J4 Ĩ8Ȋ>P 19=JO 6rK(_DIDWrtv5N|P$ 431XB# ӧX&EQ2\}E4x$ {QaezT4^ )Z Y) ^(]@\EK`d`ց? +0lkSD\y~rLMazY,hF[uKPV"@i6o9x74?;O{we\|R*K3\5[gḉcb`5',O}msݘzE "LdpUzh'O<8Cc) u Yp_ѳm+F+B;90@UiAV"\m"7iLl44 T k"NLPpHt>`-ƼdbAUTE'ȽC0piPR4 $$0Q౅ WSxCXX*`!t{2deū#ƣ(τ=^G?8v͋\ 01y.I:&c+bۨ$L5E0pP)|Bi4,'[* 3\߾|_ +V?9ᄓSiDPсSV=}!g|X8n`ßnُ)rpªSO˄?r?F~,0v0{x+zI^ןzڅ]8/A$bvN/k`ESG?ʶ)O⯹16>G~|LpalobH^ǻ_+g3TD)5OR_O N$C ?9Ė _f:OQ }x%!ΨCL[n C6{bm`%yZ1 ܦH _؊ H5}"&޸(I<8prHN1H$t]\1(UQ]1ш<'܉,=I:xXllXo0ז ]tI⾆1DJ-gl$uTm%L0ch%u@;`<٧VYyr'֤Uq1i Gڞ٦KY^f)˂N}: 8\QDhQ1+0ujy*M"bL/E;2 f1:c@l۹M/D)i:%4"*! u<${;N&WhwEE 8Y@Qt^ .XKddE$g틔s'EVS+:Cq IDATo[8/!է{G@= %䵊RjnB) 0/lZaϾg+^Y[JUBY6L9"18fb֏:W_{o/Nsev(~^Y--Qcr㎻񱮌$DU|C$D wֲS2 p*EHѳ<u+Swhs,4D}4kSJZR&i +'$Mr>InQE%baN2FT2QItIϊ 'AձH)j~cnDcL yGf=– 1<(Mf1'4ܹ`ciX^&+GfA6Wchg~N%'!{fPF\I\ʣe ǁvz]֎d$:P3?9yH\p\W71+#N%+#ߺ,x_ ><4e~nn5EA$l;\Ɨ`| >o ֖4ٽߺ/riۨDB-H=QLB(w SF"0I" 5@߫@=1jf锞p*hpWz|(%DQ 6TdPrHPŢAr8"|F1  EKRњ%iugPPsysmM-13qohe>଀J>DY T| 54U8%UEGY8t`# Jj@4 5ݣYf-iDp9<.ȵZhvt=K]2ͮw,p^l۲l` /M'_ @YL:H5ѬLe3.Xv`Ð}STc3kxGIYZP&XN.BRƕ#xͶM+xk?}4C~HRu2Zg> K@|a?|7~]qZk8v=V}5"#׍G^I +^Ég. .Ӝ6č8g34J͘^bC$yEl _(K #Fk,POmjhv.xNI[GJ6yڎe]ᝈJpx>`zs滞ƪK1:fŰ燮G+*IDy\Xшřhf>[6m&' XPysFIVl4$cC%ڙPtBdsFuNbiyѹ v|Q_#YS ͟Qc֦J)B,⫉dTҘ+ۀgAWnfE9c|bNNKcUO5 nXPJ} iPO`˲# <[ `D)G JK@E8EFql*81hX>KjIDd>z䰡GiO V WbONCx9S 0s e_xUMC5jHb8y͝O4)JZ Jk6LVֱu 2ubEz̯vqBm߯4 u}^wdy>,1 $܉Gٞ"+l;ee @s|_( V(9&kSt;J˶e[<|ruV|䥓B=M_hԌxw=i^T -Q8 tsAHSqǚMQQ$abThmpZHQC ^9KQ0JW i8q4bEM*1XJ=v|JX^0&"w˷ q1vKYqĎ&1.2<ޕH1$)=ѳS3rE>. T#I~-bfqE*&tK˥i[s6-3 +n;{[*iaz?/ٜwfLڗ]s `@IȞ&WBl9T.~x]m' 8ۼ㶒c1WT]WyO锇Ȓ5sK͛n/rw|k\oA}%s]D>0۷ous/i=׼/ǯ]Mw=ǿˏҫ^Bnßq|ocDB7T-Cb˨f[[3(FbR?m#')L3Rfne},jCLfI9v)O[ teWG}vZqGqQ?juk<}_Az9<`$Uǔ6!8m[/z/wu?ox뙌 QIӌZHu8vjIsнXuR=OkMizBGytWB$^kN"k\ .%(k{(>c5͎-Ҍ 1IrҺ*IK }AFÏMpx,TpL;{wRkpE@G/cS.=9 ycj"Ga$JJft)Jd"R:_=GfR z|uHZ%n s"ǑEE|銥O4R Ŀݷo7]p@RSON[%*N:= ͣ݊LZƦR'ݹh‘|H.<{o' ]e{IB9oFcT,mAy\kt!3#-L rK(&{=!7K뙈JQQ #mKa`p*EE_0?'N {L5{ɵ 3}V,.xY{#<=brnR 1#£$U Z`#O<ߝt:@ nߖpNK\)=0vՅ(*+#|b'Cw1Ճl gR*_AHEy)傢\\NhAZK@~$Τ5gлl|fC9C{g-pҥ[BºPEha mtFbL7; 9A@tj?mMj~7 (ϥiog`T Y^i$&; '\tۄS s})BWYcsڈ#r-Y9+8BU:8i*a E%)Wlos2Q*)kO܋;^VᒷGWӵI!zNo x_/?o~yի??'x#jo0<6Ǯx?ctutQ =u3;wlgL򃫸;tm9x]=\r?Ȍ ?!/Yƻ/hR>'y{t_BnQ^}`ɧr yN>ap/Ysqյ7s?KxJ)GO\|`!'zgmcAceI°`(㴆fX :IIQ-4-rGxbwц&AP))fW}t9ً IoőQɆEV,lġ bFbKXv6 I<6-ȭ1)n%_W,Y΋ah4,Ѯwta6}}F#X e:oñDdɌ`udq l[%WH)j-3rKI2!D ń<[ZiwRpEo}!\1Iv?]Ccuyl}NDZixp-Xj3$L%JZVJVWq:w{j ԒN,ڝR,liBaaN4Gi8tjgq X\?K'IdUy8zgy/Xf, 3f̤{`hf  BZ*kWc; |66i t9ZI xHJR^ָ͜VncTBW$yNcHrK;sEuї.GAa uM:gqUͨ@u8\k]MYKPDZ}3(O.c"ǮvU ->P Y % G97*ˎEf⦇qf-tJAOYu%R$(vpµzR_I^ 1z0נڰyrL+E(5(f϶a@?>x!3^A2_ AsFl:CXrin}^WhBRu߽ 77Nh̠ 3iL}OaK%id//u %Ꚕ2q#grwƺpS>{A9Aܕh)e7͉m(ْ$ĩ#78R 5r]&(t4?wN*.STxbK((i_y&fl}k-4㊞`~ǾTK$ gJopƬ̺ٵI!(>}~DJNah V39kC=1xRb~Ws(ք$C1@L0)Ƈsz._'+"[<4ªU\qx{ 'n՟} +@>z _fΜ?%.S(->rOOozJ`$rIjV@%ؙ_:S|!,ZfX9+@HQM3qEHF8񄤿dDr`m\Y+QĦJsz_ujrr?S w+|Fe1§9ٰdr4ښ.ɜwhũX)ytW$5g.n!^G$%˜OR;j";+psq |˰Xz06~?;vQM0Gc8؀C.]s8rՆ$u×I'u tW$a{b4ra;q$.%Rѽ:w~43CߨvcɴRk.UxɵE>z+ҡDe%P+̢A1R\]h"kv8EC(Bi yY`)|m=6秪8d.h,"jE 1X(@%wI;Fyv _VL\g $={Zh$"˫ܷ=a!Me$̜WŒ`aa!-"deה+,GliaXTj D=QND/Mrhn盗|mT'9|<;⑿2Dys qfCw20tAY,fs{1i%Hmhkֱsǚ PTZgۘ@(hePč멻G?i:8 $Eayfb;לVIo pYRZx46PᄂcvTkI Y_RW~n1.ÜipMmxj >5}kh5j- -ay1N87=|᧿=k׹iŝ"B"<)˃|6uc`ւeٽ=E5J"]=PW^]ȕ,M_NaX{ _n;-Y?y.]CXr5Rã斻)xv+JyXqq7ͥ~|y<2 '̦Ad=gi=;q/ӟo o\>n^J2bd2BF͞'㶻8uOmBO+Ηޟ;^D3({Vfy )1n3fz"< OSb؝e(+C#jҲ`S_n[ V==cJYǚJ8/ $VZ-InPgjxG7NKg30OC px x L ]Jwf/Y'kȌ+$Ɣߑrhv15^X7e9)X[cxN8V`WL k[)`gEb%tww1f 2]q]Ԏnu}4 f͞kb۶ IRd $JH2 CcnEg C37):PҌS#1:dQ+{ISr|_Ɩ)ôr)TDQ-Oob֬9[嫎b8>˞=7oOfuײ/\JKsﰞRfO|S Ԭ_^`~HjAG)AyF*_ȦoBaXϡՋdg+NZ+s_ jr4RjMInYVRiM[#/W4F;!͜HK8vtxΙg982=X,f mEM pL pVy KV1e4L'!-w ~ L";Zc AqIRCZySb6A`hr#inٺ/'\hZH(^+&.}_E镘8RI}gܺ;n@H\Wj7|>4|Ij5tu TF=I!I'y"OTzz#dAIIfF{4oA{b 4|abS4ꌽSQMٴ/A[88RP3M=icÔI߷) Kɓd[()TnJ3AcO"rq}s06I{l=ɡCQi&sK&NiDwQ@}(e):wr݆Gk] ,9Vd+3w>{9F'#Ǯ;gF-9a^N/Ks2=ހvN+α™4䅒me'8h${hE{h:a*@=N,-W}<xt՝#6"yn*cltJʚesɇmL$w%h"ʒgQ@ 9Nyʧ I;!N\M!p 籖("Rg&ӹw^M|-o8ZÌYs8i:Y,6x/ڢ](1I1q" Ks"rY$&8Y.dz4G!5Ղszֶ/ |)Ɍ!4 %Sm|Zq='" ~qO55tՀL8Q9p2H/+<vijWG뮘v>n;(H f;'J J'hFZ4ۚ_{5'5M9G u gtwRyzYUeqUt"~~>|NvȜoEJP/c_᲍'3:t%2b0~ٲ0=X.\0rp7G[}IgxBrF{z_/|(#BkjYhT@wAq,>0~s6_1Fo|nv+sϥwfm;cn6fuX|:~sјW_7l<|5~/K(P)z`-K<ӘJ#EF_CZ'2j)^&`ΈzK4`"8j!dQ9@Q \(\3u]rm,%(r I4F;ĥW|*jM|cіZ+fJz4KAv|ayɳd"._;`(֌Erc6KBˡ](+2+#"u \D%qcJ;!7&cݓ<|ѝѿ3<8YƋaO1`<;3G=O}#pb.}װxCS' w<oX R Ȳ5uЎ |esw`IfTci ~(E熂߅jXKs_ZEC˼P02&!=wRpYgşnxBc.O_:_*^>E>_`S<2m G.;2' R(J`}̈r. EE!J8@zY z<^yKDK0p"?" SI7M醞 g4yXƥJCHz;Ey"st[vj) Pg^;fbH6ZJ :u<墄CZ('JrW,):<3cr{ K/*Mg gͱp1lS\ v2qU x:G˱4bs1kg'*E-vN3%ſ>ċO<לa&)4(=Kf)"a*$1ruD0tI)( .](,%R0\60[r!"ZؼEnatgVJ[6(hjGN#:B[cWOec- `qTjh]Zpe-)p.ÎXe\ pgMҠBXZ| 159Bb$iΌPPe'2q|k_B 'CvS[ JRi =mWm`!dj{?p%sm7;o<^ױyLO bcMo٨WތZNQ# K}Ng[~F <}O eIr`AF? 7-w,m-ϑC+N9 Il-r&Ewd+V`wh@ T]\k.4c¢"W]2,3$ȇHeVr/\3GqĞ={ؿ;c9+׾G-B9J J8h2:O06kX.O<0*T|&4b^kkZ/`HFH<1!接kh=LS`fA7ƚ8uf nZ/ųhlO %̸݌N%]yΦ%vP!KMI(Tf.M%jY!q)Bz2rrfO$3㔙}E2naFcK}[fzzm Y !fXaHR'((DI:!$vpY?Cu/^ϝwá:%BQ6b]##b.HLOLbq+|*Kn$qb |:KE)g>7&A MApAB(VWTd&֠TuP̨HZ!0 X9zTz!pm 'X0Ȏñ V[jNd@, U^C Y'3@iWdLMO瀰ts~Qú+V|RTJKWԦg8(gQhN ׿uΝ˙gLk,F32m':;&5i1Vrա 6.|!_ڢEGV|'4%UXr>˗ͤH; FE;֤9L,c4qLSĉfR %}݊EyV<9>/\u*"LcןHW#\֒emP,, :M2$)H[ V4&ՖTmy/k y(L`XPxTϢ IDAT' ,;({j,uJ sݔ#(P}Ly'4)@:1t$R$5#'UwFxbA[AFS;9شAVJ2rg}?=ԧOWmlb6ŊEuݵuG``/2~p}wSO OcM YaCA7/,Zs} wzcGTB\NHdǡQʓ#|8㙆eY+P&{yze\o|kLzًx)Ex'wnCSfQk3ms|?/9GGLF=+ڜwqK8u0:2R6^y?^ŀ=3_2KwͤP0޲<7jgg' ]%X=[R,Xf$~yc=sV9YB9J) |Z| ٱarC1P5-ό1+6rˆ͙aef#XYV˔efjZ( <V6U򠻻,Q~HY N)8%R}IqE9r@O0*,#Br]ZAQhhiwh( |)g^\731?+Mn-[/?VD-0EY a[&Y>\V JGc& }Ֆ3@(hy& [Ifh,'Njf'Ti±4o2w~+y;.Mo~;X8g6RHCIW.Lx$xչ_$3X #Ʌr7.h[X8סx%(yn]Y!&E /Kyeg:&چ=5OD @%!piTL:1y GlLhDJ*Cx@J;)bvB2EӑJüX)Idk~ (\Qg^T ߳`m7/xB$3(B*.Ŏj8w!BP-*tAJ45Dsh% ؐݻ馛f:J4·G5o]W`Y7 8f@c\T ,GI<nNOsq ѭud %]eE;D (z;+v%sCs&ԇ;^J4){%EҒ34"E[2ڂXn\/Ryj oLMf ?wI9E; ٙi/o /g_}ѧw@4O0\10Cuq-31>N\}w151Q rF9җtV JBض0L]}n ӆ%XR15-jA suW(|\/N̸XZ< RTT} EBZQ3PqR_ծ!, p-k-c3 #$WnPG%YBMsN;%f ӖW,8x9qO\LmvM5>;~Q&Zn"#GK9<[lP9,:iȦ!-'Yدw/z7vl!`?K[7SCYl9;mo~'HsAn$hG1]$sf#;;vrkVB(N\UXGŴ|?> ˖-楍O#rEo[N (d^tSci7VC+(Kz*x9R_bjr9>Gp:2;M' 5^ڗL,oi/Xڣ9GE?y ΘHyIP=V0#@IbΠTaO(z (;KZ66=1$iUdS3GcN-xKHnyk*8VkDaW)*B[Hw+ T=֕_6=ʼn'3^`s/%'O=[7GЍK@AP\L  vgW 'C 2kb,rݟۑT||i)s^ n#> _>y3q#~#O=5kɯ5Ñ웜_>Y'9x qɲ-wG)ta`W\N:2Pߥ!w࠹Bfayqt>`i:hRfxHz;u~|3k,敘ߣ\2xG+bůndž{]!BZ*E|-{b@z+G()! Xto6gϖٺ~yA1{7I״Yc ͦNecV89DdbbݷmzB Hsý|g{Xpu[A3BF"1{Yv8<ܔghĖzΞ6}Ok_U,>Q>N xJdͲu[8:Sxxx %ϳ * z K21w vh4!Y5/,/hWZE q{M/*'׆,lqr8.?bɒ%[3W .%QA $rg R),&4q \v }dnrR<D d_p]n=Ԛ4s;lٖ "ʲLB6@]uH-61:`+r@ 幑)E=Z!HEѹ:8H V)9a(1FD C]/;k6ˈ(:z, xݷGHgf"Ñe@ZߧRwEpe'<"aB<))HW>𔠯 >5:Z0P Tm&Mj.B}g_ÒA>uReRo:$ `llcE v,F4 rP\#ȳ{Qرi4綛o`q͏Ǐe*.tg?A9D6nXϹ˵E,W>s\wI3̉saG˝gGCӟ]΅g1BK݁VS-ͼ_"z+/^P Ҹ )?W ʩG{6Z۹m-_o|\n89us09'{X)ؾ'~Beh)rB87s?&$ K"ɖIX[dNQgV7(yن%ߙb%y_$`sfK2niX #$<#  '9@B t&$X];V.ȵZqvyr[ZmiXl=&RJ15n6Y#idNo_ſ}T93'F,K,e\_N=90 3m{]rhF CKexbF7uC^,(W{5|Xja;]}|Wr>5rTj] N~ۨVu UYr%q&|98:H?(qx/,bFsι!;`B?bJ XH(ȌG1 r'9 }7QPe֝֐'#PreGMO v cmZ_@MNjͻSZ.uNER4o:mjR)M`Þ޲$Tnvjf\.@Hye,Fk5߻'SU"ӏt:2F9ƸCc4jOOE96n}%YA%\J DۭWBHt: PXNw4B$FAP*uJ;iCHy j F Xq0rv K yogʽ;rN[3pDC=6$4ۆzN[@Q2QJcjiMH*5'EsМފ,# M[1^0̋/S_s:h3_)vvk$+&v BX~vo8Ty¢Gy+̢Nk9+_尙q3Gq8xũUT)%3*…] ݃6zjhd Wtz&~KIܹ#x}XVy"?f@zdZ͒8h7p]`L,[#[$nY{1,Z~|_/R*P !iM ]RCy_{%{_h]_h/O=8.?wC# , |Yo䋿 ?{֙|ICWe%ؑ C nS 5/U<'hXb`  IϙBU ?%CIETvt=T65pK<~̫x.s\ ^hKR+96\@|TIF%\l,sb hJI< HjB|DE2qQqznv8\ `jbL޻`[ީq=S0)i9կ[o!,#|t1G)v̺r(R8 ˻ƌ زsƢ| ]1d8bHr.,/SiQܔd37$rbIi$J`z0hX(bYOA IDATG1Sss-Z[TJ.Eй[cǘ4,ٲm<ˈ,}I_5CwQ?g%,=66;)(E'X,Q V+#ihʒ9> Z v(8?g&ɲ) y\p0b@xYs ~!F{$k;+mI0u;RژJ9 q']{yTٛk%-j˃/xY/)E.9Oڌ\F nmjא*%xlsѷjFw2%rtG(|Q,2ta} h qC!}=E 4AZKkT[%=H(r#RH<L,2V %LvJ:X=WK20lΥI$SM1tr e@N>0)y?ԽFl{h! 5<5ёMY_81o _fp51ܡ ݡIvkW!'AVX-t}n=c՟)B@ ,+dJxҥC/UCg_8od_]qq'oGp &ن^4/&Y.?)]f PR{Rs@/i~k8b I3`7<=A%Ow+((7[sWX}||{3)۬Xӈ%BH;=~XTɂ/B;Jd4悆f1x&%;fJj/H\d`Jӆ=t,d+~YBF>ׇ>>pr_{ KAʾ+Ft(W}XYOH:mN&p׮H(7]x?|'w ?!njMuPR,AP&].x3  8 u "ÇJ;SiBW Vg()xHJ>z\+J]]:wv'i1Qc=W,񺕇s.lr|dEų-9(ɼ;9cEĀ{EFRO ~5{P!U'gOqz,C熹CG2:V#Ge[myCOka/YXíZV$FJžUT(Z%3{3.>݊rH#Q9`,#XpO= D tSu08/(=,]%ť sɛ ,xk(/XL=A* rM9B9@yjk4؎&~Sig2dvQ4_\( k2̈MThkI;0<鼕Y}>Xš+yũ4iIM[4bCn w>bwF154.r^s5 G)R"R85F39٧ crP..8rr,l&זd_]HF3LjXF!nMm $u$7<%aTN!v*)V/uĶ6XlW&Zt@ezcc9J܀Y&y9&&mޚHa}iYZl9%e-" |DЏuE6loJM5(,)>Œ.p3N4uߚ8d߳3ݵKv>"%Sr{"! JJ 4D$ is;ȓTBI1T̩( nl= B8D-WF3ڒ*w"TK)puC  I@IU< YOMHX72YtXќG5IvPw)d/|c559oy 2q7#B'NrDK}*aQ]3pM珿oX=X>)7URt1o6{,NgB9بadY;Fvj o<@IPb}{B6_Vv}gz1 vo#U$ik;BNjM֨8{hb }^sf]5XѧxifǔaVvcbhDwY1ܧXPjdhj%aҊ6׸ł_`A;}E%yx>/8T .B6˯ݻwqm~rn˴L\AmI"` rĠ-$i,!7F}ڱeXg *ƚZ2jG Cy{2^xVRm)*rG\y2:x!b!gӼ N?<04bK#`b*gz$ ;vنÝ,) ̶zfң#ΣE@w@?#3qNji+75ںZC+֌L`p(6E>],:LD5.jo_i[)7@bi$8afiNdiN;'ckr cM t-͵z9=N4t0ZKŜVlhM'[R{[Jt\&GP᚟_ͷ߅Ru?o?m%N& 4[N<|s_j%ߙV hismKujhHͭEYj%͠F[& @Q"','GJ[rkXF^x45fI >V>kcJdvcxkNuDC/?S:<ϹorIpa>Pr 1K)579<ϑG~&n<}7/?xM22PkYCKΝq.-pI2LXRbGR%C9p$H,Cx.I~^|($mc8jhcaz H#d_0ڲDBcuNY$Pj ύLs9uvh0`1\fdrEYQ>jn ׇ}B2ԤٓsT;Tlf(тVOrW|[8xyoO|0⛌BI :OMʌ)eA$uazZ-XhYT9<7C#W&6.hK-v\4|ɪ#_ AܿA;xLOMZ3'w|9 ͸5t.vR|{O[6u #>fr&u& g?Dgk_6'" %| $ Ҧ,Ux·)vzRPoP30aϫ TD;Ulcwk0@$h憅U8dO,9Ra,Bȋ|ܥ ŭ*m-c˚!-"iB@(N8˿Wc[IӔjW!sL/Rwſ} 7x W2M|~I*i?y SI } Eנt+Y~Zw/WwhGkY8CRK#5(!XZUܬ]=3{fRŖ{RA+6}+ʝĉvU %5ys78u my>^1d&< V;Ν?geU{1fXy(((HRJPiH_w6Oŀm춵ՏVIEіh@[""UkWsp~U}w?^'? k1>T :;.χK1|(ealJb3Ӌ+gcB3>Q: _T 1q$CXP$:"'snhu|P'jKIcCOjRg?G)ՀR^&l*_o}J7)z"q=?d&' ޶A+Vf,츅գuǭ)y!q(H#pShN-$>5KID1Ne}^w>S)J֍*al GEn"3G=FJ>(ov!E[P*bղ>b@U|Hu 7'4aqܵך )*OAIJc^qT 9} ^Gsx//t /g0 [K@w fǼY5jh sO?_4:Ae3ā R:^$)Yڢאc&3Xc)0ˁ ߾}\pE<.NzCHܬ:"%Ef%L*I*ݤ'Қ_y6;'M| =6*ݝEAV]\\Ȁ6mʲ+ygw&x@ӆ/N} bk-?LI IDAT _̴!؈8{>9?y秾HYt;u9l*Gy3rXp≧F1aɧ?Ni-زc-7qV;aTZ=fȽ>o9Gv!qօok}wƆc.Wm]ws Gv,`,<=;mPd"O)ͩ;u+Q9Q|\w- g!a+3ԉ!KJG,̢M%!'DB*\`-xcц*8qZin-ÚOzI" IaqNY"ej9Ig)Ĵ 蔸⻷p+"I~twټpꋋ/2;3͗>H ֠ 5m#Goܱ MRGbIXڈ!X[y̪QӉ4SG#uA,f_1?Ss'JV,]> +,b7|o\,@> d-AL]:]M/g'3֬/s}[o-lԭU,_P ٷonT;f[(Tq roZ*b#<,_DChgo2J enm`$3 : yɺ@Ir ݎyfY} ZJ ^>\Z@2SURfxC+K GȆa@PXe Qf/?8I@=O?DJwۅDžy]_R*<|^e5o0(CxrOJ߱td˪0Tز@(q`Cd2䌾YR+`TFY=QбiB*cαb0$g&~>*%1KC1ā-ۚ jp*46Zu (jpB"q Ɗ@zO7u[P8 \*f,DJX3"GUHs(fh 8(ppM׭[C/ fdi;FA}ќ0??=Bq(2Wy\bk?62q~m?VrlO8 CpIc_ds>:>[N7q`u03?O X$dRןε? +Wa+NcG.㑚e.u,&6|ЏTHItr]:hIC'9%gr5_ᅯE:m x$3E_V8OWOe"KWd o;z&_z6 \K抏J)rwrgMഓz?qoO| _z2#/<10:d_x<1r;W!S | _f'ҤFpi/纛ᣟ"ghy%>q4Oe2ǤV":݌mg|1geLfIt\ 1;##r jR.e!NbFeʪ])_hg;eU"8ur\2i65-jƌa!68L[&dV&^Cy 0*)}x G+߫JJ w-[`~nO=Ï< ()'},e TB0X JNn(siƐX05举AYI=bh˨,T$VZ  X7e0ARrzS<}ErV;CxQy"s)!C[t^w gn-s1`f˭7, raF*eEPR$V[m7ps :lٵt^s1z!NJ a@)imDw$NcmCfx֎8;)fZTq^;>cݚͶd#E8/e#(=8^q̳N$:5 ؞6W1N72b bQIŏ'9#}q]!RN3n|#B4 YfY93 $A\ 9 1RxAy a_R NZKYX!seOIjydwEM%FlbGSIFCQ ,gKêB hm&RAÓHYkzI)}QJ,2cWf|"58*7ıdm{E2act%[H3 {ޘ\;E YUc6@ɒHXדdBD1' 3$|:i$Y&kdZ^Z(e|HK.* \$ ڍ);Xԓ<:brK7fbo6EbN_}5Y8@$<.UJm7hDұ`U, dH0V8âq=\`ĸ􉖍C=_L :`LFcydg>U=u#2AjPA!SN㪫| - uw',*и , 뮽_(?jWw*3ȖGlDۙAg,f572^zKtYr:\p7n洓WO,{ dͺNM=-bVI^w%Cϙ7e}F*%#9ɊJ@(COKQ2$ 3ϸ7"\mtjHC r%?5?`ӹ?<]48 N:W{@N>,esy#,_pK1n<|Hkٸy hľ.F'b syK{RGI\J\(OЪ-0?\=ej^ϴ|sWrk/ңW~4`h?`9zٲlbHH.8>2vbP9A+lJN^/zlYITȦS_{ec%IbαWr¥ߧZ@|Dz-5%S3]ԜX2Gd5M"LYޜ:f\2ǏɴSBHPD2TlӲoޢeHGE фZRe@̧?(?V׿u. qׯd1X^/ 2ac VxYeo=X`EHb,* ӜFSB^X97pQT@ bD"(pW"J̡M{/{G>AFC\DY.1tNl"`9jdl5JI_8dN'M9o2/j"B܉EDOb[̅4BX;XZٚfA.Igf'#S BZ͝wTDny\˗yEB:nwlo|#B1v!qԚ73ڝxe*QMKc&yaT $GɦZdNL/,0]}iouY)і|>`hѾZs$k<^IClSCZaIt^:2F01e~YcRZeb/:O/f=B| 讟BF/"JyG.ޭSA_L$ıu*stt^(?=w_F'J0X ),Nk:hF2uO5[ G'~Mxg/mKmWG.4 %m/b:J@ʗ޾RJXKPXΐR">M\IX }EJEEn?%d0V.YI:&SKۣ*v GVz[% B~$ׅU#dDk2覆`r0K6On$¸?9k'Y2My0֛RTr?"KkМjꪣHK7tӌR^ˆՇI Ղ/ۥ$=)$QE6PlZ*ˁ,c9$břE:swqK12D n%"it;&˜2NRK?)A#00^7nz#aڙ# q9zsH &x1 XD"3*@Y?o*8F B0P0_ _%*f|\w4qq dKxvαf(D>$LI,x]pL涛n`֭LO{}a._2喛cxi~ڱ+neÐߡ?oG{< ?gb*!uB_T;@(U*B`!L[cA[L6 #dc !?vws{vS)ň h5L5 Ok9)__Ҫ7q}m|tCe&L7,-{-foKO¹w_w @4N:QKOt oPYU,W4ZVr I< R׼ø_ܽӯ,tؾ|cWF,)Kx2 ƂъW57-q k๦g9&3OxX CjypF dv0?ߤh _gmF 60*,j!K~H^tܘ xOQK)) A<y=rM2C _\r K-I>˸owzm3_J>O҉-ht O4&Lm  P9LJ`*KBPڌ*jEGm_Nypfߔ DL$InaGڞ m"Mg->#z)~_}{̺5lP ~w?}'_p|& 1(Ja#9W9,#}rﴇ/(zS;$f; YAY",^?2.)o)OD+A6%if00>c݀d?G&܍wc,X`OO3lMҎ43#ц;~3s~ׇ1˰l,Uaf!eJ9TQB } 3/5 /6*C #Sġ $&a=&:KzIT Ekٲ"^w>Ş9}9/Ur0<+2Km^@./9UDʽ,-団z߂c+@ID4QSm)*吾R6v. cԛ>Nc)ݓk@8=?-[Y7/Ξ?L;UaR0>QK]4R_O6 G!MYH98$9p`f+{ش?ĥ-=ԇu)2cozP2ms|j;0̷ Mã;S3qԍ5Z!uRPbQ- nB3<ij(mek$zbC7؇U1 mkLMot8)Q S.dc{Y>7{,K|7v8)afMK=tbh8hn{\ նS G {5"phhkK*,˖PBj%]p q(/ǔ q@{D:O&gP*f?'T K%M4ag=(o\8oM |1 %v R ݹv=m!%KH%潤"Ǣdp8 xqrF߲E|j=f2e8 1̴|{s7Q[sf<2Y~s` lJӡ&2L{suc('(8ubN}]=>I%䥥 ×DYmFyv;9r 7|z?.ԗms/hiYVcuU޳C=&RU`kmYtJ sڙ2 :jb踈Dfێ~x!(~cLѱ<|),qcʦRa&>/y;w< \/tjVY֚D͑}њA24%<"`CQ7YlK1$K$'kXBmϓgf˖ma~%@'3zZ" B'c} #;fw_.>= < @Ss\p‘Z0 5Dw7/`k ?YnnDHŔ"RzyiIJHeF 3OC(Xl;کeX:uw fĥ<120KvF>=;AM" $|qPQ,ı-W])H!T&7ۆvNgo}yvag^OL~T ʱ ю|I'H Ѕ|tsRcb[jOyyA)ݓs:XjmPE!nPL$Q#^];RrRPkxY"xXAmqj3ԧҜ"8 Ji[<Po*z⋜$[R{:]CF%Y*k9em IDAT%2.)OB}ޗP{AS0ON#XHz`/x4EM;wJ1{˱ā_SiaMJc}1߹XLPxK?Dy!TSH: %5`B 28?3KL/3Ζz3H9Lܞ60=4iM+NM4v`frZ'gRP(/ts_s )1I3!RxRu5ԍ1 z98icEi>gOl3= DhQ]F d]bBRX)#b%)^OЅ$}tjaGwRRŌ%(E'g<')0y`/CKɹ::( !KV$e͟_ތN=mSm +GACZG5Lc6*dM N.X&W}%$]Gl@G$kdx_7]ț^<> mp[[1yErvx5*m^_~9fvMLS>j^%`e?/)!hO0?7G%/Xfk d{^X Bذ<`5O(|Q=(j%Ek?;uiZr9VS G. 8by P*hZo,l2l( (A @Dt ^Jj% e sٵ~ˀMiǐ~ݧ$[Ǒ WZÏ 8?(5\-Җ7-@Ex\dP!#$2,[:'z/ˣ>ITzOw~:5ĕWx{9x)]ip @Rc69,zr6#KT3/Y]bl"u YkOC;~E_NR+YA7y s`!B.`"cՐfbB V@ďnO;LtY1PoY^w{酲d[^ X;\!l[6A qٔSVxڧ3^{c:7mgO;uZTI0/t*õ\ow0YО%5>#=EZAPYXKQS P!%SG)l* [&dK9lL * 7:|1o9>XswW}6c3Xp۾Ep_\B]7z`if V?5a&? sԯ#Sہ\#$h7X4< NHuJ|P!ꒂ蠟rG:"廽yon;E j]C R8٥(ᐜ IE}[7\OZg  $ue Tcq}gЇ%e]' 8Rđ*|hc1+ $Gɳr4"_WdQJcB*!_nZ%BŬg$ WF/Ƈ!|uM#P;L+@yң8 9&f7lN 'z9G)$,Mh45xjof+(JBp`%CO[S[3B Shr`K~(O+nz8wf]9?epN$-{N_` ᪾4]$l)` =`zdBszz Y"+d>q7%Ӷ !Pw_8ʉ+c^sb?;ĺវe'^\P`:)kLmJ[И15xtW-?,( N.dݲ T=.Dڔo]䦻9kwqzpX%p)z%5o8>Bk߅JIf$ϯJ*)ƪSPR._S*_(ih(*==Zxz>kD*xD'sltsa@)]H hnXGuw|OXDoCq˥B ȓ igq <Y,e+Xk FO<$2  bbONPվ:ߴtOXvNw7R]Gr|("S 9zC f OMv ?8/>T?嚫_a0ABǭxoeuixi<ϓx/'ʕI%c2K^6VĀH6XNt&2etyf=qҷX>g@ % E0ʫfI%&jѷ,i&h..8|_Dϲe8ws.}{\=Nu7嫮p;wTcA#qܱ=:ڭm۳<(h)Wyƙ,- D+!Y6P&k:?ʒɄg(磧n^`QU*5fà?4X'9yLR,0 WoشEқ ;Fo )L5GGX{h2mswBX*"`e%ePhYMYZ-DWV iI_͜xV12v»ךiUk#sP+ =\)JiK7b<k6bO^fiEYwq4l.eúN) ˸`M"I1=D rdBnbа/qcfm6NP*Lu(+<3 T̼jւN3iQ) 9(ɤ^a d.$e9O%V,*3>briz%`xfg :I&_/E!;i\4*FB^N#k7NtŹ <DFGBIFŲR$uCg9+5=Of^ǴXW48;V+Lp zŮ3{2 )9|y1gYNS0Tւ]Ld|J'IM<3|)6L$#.w32 a,vbS[|&>҆)8ۥZ)6`,^@VydD K*bd h%ТU+f(-?Cw9_}` ,N [,.^tlzY$ٌnOš4ZMʲBy1F&3 L Ԋ+)eK)G'ÙEʟ8GbLAj./* Ev  g8r;1t2Oa_=IC T4#U{fnpcLD[ZIN`4Uͅ'U(G+cs5?zmƲ9G'q3/I`{sjS$BKg܅- tN;eG/`!$﹓-7108_^n8|"KCe/o;3 o> *g{ϽTku^pZcUEq^tX, 2 fа"a{tMgf gB&U !)kGlڰ/$AU":nLUuzUYt)۟ J?z3k9'x4u*4IG.lKEOt{=Q dFpk﹂2\ 9U>Wr>dOfP@d`fwlHXHsxR /Z+֮=z'6ldGB&w=4Xq5XH=siNaâ& YD xEѰp1eVGhȭ˘еd^1hdesGɰ:ZmnNKO5ñLOYSenˆ=0/<> 82%: g0ZIB#|+QHs1ڗ 1fi%RClE"tchX `]$a;2! \L/*GP;]6$rU~+ڻtxRUUc6M*0~?,MP 0SBúo!DU{rC() gKe$=01o=fsN7~`VOFil@R$EB$d&G&-kpAXXҟ3gQ `Krj:\99g.<ig7$NHdyv6Ga)Ebid1yXX\ri*2 3JK,04*/ZIqC8͚ Z;x+ԃ s}iơ#G1  9M!qaL8.a9rq%gɝm)>9Ûzqcg熯}x嗳~ s|KˇO^?}yNx^SCgԼ5K#&1]J>v\xj橜p訡V)s⊫?Śdq |{%]YJ60Y,& ec=4b@Y19l<$֞c V4`ɕ3W+Z0R5̵;qɻ+2'*,6dNf3IֆNH%y]| %BrhX\VCc9 0Q/$@  3-Lܽ-P d>Ԫ|p+o[ =(rDY#Ϟ+_ Ryhit:pi\gyJ#y+Yv'۞v. mZ;g6+[p4sEÈL B7Ҷ/FȼځL.2hUup?=wE$,`|eyyrEoo0;7V4ɥu(U f&d'u) E(dYp, IDAT_$;kѰp 4sw^e %#Phwx1X~D{íOn;:4hxٔ=ґ 4J|Xyzm(B39aSͶ4Z)4Nl+7ٌ̳3)^ίmϊw2X0FJ!*WP<MISl\(yJl@?gE),y3ܟJ܋)ڽhvDcNָhLsExCe4rֽLx|Õ-Ali*TRa"Ռi0x 5,J\'{H-y8ЈF nC'l%RN~aiBN=$f0ZbT2ʊ6XnL>w⽼b$( InsY}7|j!!`tb15y!@M:\lP^t1  ROXTf>)qzK 5͝l7r8ĆEJ)+Cf3P-9Ϯ^757BqL}ƅ 0=to8 @2QV Lf8pw͆'34<%x_o~v1V(hD{lzQN:xʑd4JIluS*ک'p}Hv[.8.',l<7gxvY5Jؑsp+s@PMg0vOʷ\;>w7|fj9# E#/Lδɭc+##R\kg8A@1Q';r{;ff,#is ݘQL~o_h`'63LpF#E= 8͟ςzξ$%jckgrvxKd[W>>thSY&CF׀e ( 6y_}4Eσ7F:G+3JӞv.UCqIt KBQy`/68 Ż.v|+gzJ:eegqetQT)i!FS#+Fz%xQ Fd6#w0)W{#3 7m˶^,J WKq^Ȭ"Ϡ ])~L# *&#ʧie<4[P4yrd\.H]c'.YT3 VPAQF,R)B+27j)2d+ҊGCldmj^k6WϓNԔ#)rhu-yI3^Xu!gd%A T1yvOYʫ9j9bhG9mm$P_$9M0QDzJ)Z{ь`"=3}J cלerܓ`A14s|aϬZ_B3;S6w-erISTiEbRPX% &G8 6X@ 'tRg哤f&oٹvdGqۓ9>[s9sd J >AB\E)sП]@y_{ȳ.(>"R'049,3@(M∘ogdc݂Duyʊ$T6j,!Msv]-OUtMc4edR@?zk*̩X9Y:O%UPY19wjX{&g }q+4 >%2Ffs˃=LKXǮܿz%<|q 2% Y32EP'tI褆NfܻEb4e"Uɝe!dXiE⯂RGY<'P-pe {x[^,K6C9`A}zmel7xۘkYb%3S{ߥߗ,㆛~ĺ-S؇4ٰ1n*ã,:bymo͔,LoI^8$KNTߛ?~ټ7u}sO]0:6F|>Cum?~;8Wv2! #z o/.'P1JE) F) 9aNHc4,*y}w=M$S&dã0A ¸J\cL6X@ISV3σʞhMK`szV${ea!0|zށkkCi`NIV ֦Og/83y?x%_[!"(I>÷fi>A X+DW @, ~Z^֜ vDsޑ!3t5?g+OHvH9DFw?L LlWrH8M @sU;||ͧpUgjIAi3i|ۃ%ȸc~Q=Tj=ǪXQA |I#O|<(YN#, ɽ$ߑcE&P sXTz),ci>c6C{χίQ`XTRyCdy;3ySS=0>;p}DbX[@iO=ki*֩,wm-9 58eXqMI"P^t(vNflڝ2N?lK<hϠ 6kb!SE$5n7d{ot8xy1B)綟v)Z(YΝ5;4ZI)JZQ6pHQ{X Um cqA4Vz I/^ B )R2ܩ15$M ./*H"ߏλؼ!@tEiP81ưb!,zH B-o& ;2AdPZcKMKAI8^_WZs‰'Z[6=m sYROTtQɿΪH*.=DΓ(LYYW v9dԳ,lŚJ8q뭾g߷x r{גf)t,7P[eͲ P8Z5$WI05q!eA \ EfDR*=dkQ &0ظdIBSO9_f;88~=VJ? ԤtޢCK؛(H5>(#'Prc#9IJג S@GHѕ(UHyDj4MiZ_0- YsImsͅ> lG?V32Q>pرɻxuLvbOsTc[NCMs+hYd&C Yg*nxbmF[Ҵ >CK6(Γx)qS"zͤ=Mx@ ƥ f3,`X ڊR < 2!NhYO7ST4S63T={Km$RDMNF8ӻ2z|m:1(}mꁈ-&23=?7]@s+?4k?Vx0sE=RsO)*qƜ'rYΏO%-m#d\W<~rz2x^zȟ" ae \6<|cWp{>Wy#Ɨ0s;W tsG73t((PIdÀnBo(dyq DR-XxDQQ/<|sAS*ؿuQJRuNd1*߮S<ٓI9Z|#RbQ#ŝO',tătﶄL6r!42Պ{.њL MaYųf!brV4yX<P&R-ā"b>uSl=O|10`gOD1CF1t~T b%I31YL3LͧbYvne&_oSj1NZ "X6=k=q )PDhSOh$D~5>S*&{;+ɢvZjm2:,MƝ m!A)~̳mOiAN0.{ceZ͔^?YySx䞍BMl \)@6Z9(&f3 Yg? ,eGdVr$%!F%*K2,T"kh|2XtH)k9k(u_!#uPUٌ^(ҒEԏZ|X0X(eLa??i:b#ַ/\q^: yٜpo˛&gdJ>7w~Cd?7^tgn캇/o_n='| ˖-`k8W{m3%yO",vyhN~Z9LȢXjQsB #2Z sI첒X<^+Eĕ:Å+6sNcLJQk{"4H О#Z(@qTXckK9&!P}`_"-mдQ6L1Ҕ7g,.Օ.hǧ>I/uyoD} Cb!9:v?r a\yѤ8-}KPNDTH Iv dq%E7dZNnhci&c;jٜ'w83ΒѺ! grZё%Ɔ#o좴>45{D<%wDʩU4H(t~ڧ{ʵ$"  =ӥl$[i:R siusӷ 3XLgK0?ϖ?+u,㖬ϯxZ9GŒF(lKY}1'{gYUZ;XCuN$92f0aePQ:#Eq!Ӵd\*:U'ֺ/} w3ݼN}k=Kpb5ZEZN=8b!#M-,+ʡf!Y4ּ :b-Zʱi?׳Sk>*s> "il"Hf&LPюf񅙔w2%]:xШ"@ ,sylou^{.v?0/y OA ~uٷ*pTg?o~z)IphPҊ7/RNc'օZZhfYLs8Ph6b(*?oa:I(CM9BQ2QB5;aѬUe'BCInEsE!H .\1UA5 '?|C!ٽkr[_1dZ肸$:^C3T8"X hU(laUی$2i{f0. ! 6-]^VyXHSLgO9G7L,̘i;Z]޶D|+*DQEƸ?)ܑ=C5 CY)J)*=:l.=!OYANq( N?t* z*-`Ϟ=r-m~pQG=??9#Y.yZ7Kf:KJ9+d[h%ZI4LͮSOOmW|/^v)es4x_ _Ǟɇn-9N:lzǶR$8X/be!t|@r"x|RerY- vp kO?rξ|h6o|K. ǰyVuF;keZ jo{*^*Z{xK4]o#s{)?,Myӫ^caWG2i#C'QLx~[sIY_̻,#Kb&?-vJr4[zzӴdS^{2{;ym]>#S퓖 ŦiV.Ա+iu'q uBf e"JS-+\{rk 3lsp2˽,m (b*OaC%8c[N։Z2Vvw8=2տ 8dh!VQitbj>'P 1­w{{1_QJ+ oz+wv^iڵܵQ:6떭 !Ĥ.{@ %Hox/  [yG% b,#@:ԕgPeݓ61jxPA: kI֡ qFkX3FZ ; <3dȀs?6ÂUh#ydkT]Ci}z;;ӾGBx7ʈ/2yY=7*< #)LwKzVX+D'SkZpJV*k])4;vnsٰ@S\rjՀUKlڞc79CvV ;,)s~>y/ dGkI&1aER&ԇW, ې $CujaOގ_H-3.[/c{qN\N) n&/-B#L ihDs\>16S2,w8∿=񌑉.Wl߾뮻//뮻m۶qgsE=ӗ}Vub 0l&e2\}P[F;˺CyŲˆl55naz 2!d*Q3Fh(JbhM)'\8/FM)/U|P.x9YfX=QdkvP 0sisEb LOg杓/BYg%Vxxe1Y8T.z(5[&HsųjHQ#~PT4xLZIhYPjfS_:n۞4nrK8fB# Z/CS X3bHTD3- \[|>D?Okr'uyzx%կ[6O=P<^NÀ3֊x__QhJatƶFD˞Yqމ1An}3Y*Uqمsxs_x{>Dl`Pale#Oׇ2G%8n}񽻙×Η?eǞt Ig?}x?Fy,L(99ԡue?,-1v{kXz-T2?cc WhW鏷K.R! )Vk]}=Sg(RL+g>d]6MXZeUٳu|Ɓb`8ߤj8jYtМtpW@hI޳Q➒K`PQy /*ݣr{'gikBV@CRJw=ږ=IcW5R0J9`ͪ2A: WP=񌛉|/^_J).b֯_L_C-5T*q t7dYy48R.GsjƊ82*N'zEweci6ۊ{vuE8_ "KvR ˤF=6p@HM=AѴ!2)6g|q^E ]H)8ټ&< l (>G~wa4lX&Kx0 Zth]0 4kgn h?'08'I ɬ#Ű<6add]p=ڭngtW`.{4gq|7pk9>"%@若i؀_<8J$1j2~|AVW۸x[W3s m+xT ߵ˚0ڎ-wp#/z#y۹7}~6N?*篛M~ 1us8\8ve$Ĺ8oācs=09kYj?.xQX+oŕ9ʩWoo{䗿n6-8N9o38+9yTC%\|v m`Hk!r?&fa9sK^ɛ6bypl9 z<k/0b]],</F"7=[: h:Ō hY>l9 bkY1xK檚",St'ʈX:HAʥ@ӷM=? iLsڙ/_͗7ںx (ص}+?ZsHZg:EZ"RP7g:/CD]LMɭ٢z=(7LNFYz$rH9gv<{gclOƧ3|XDƱߪP4ۮBm-\1X7=P2 g-5w7zP\W,YES:(Դъu"]-.YJ\d Hƽ Myos]KQ\ǑHr}3"@ r`=GT*U&ZކvXR$^Rdya:&;F`.:;L+a+tjـ p^"wVrΑP<ϸXx1w}w}<nyhghv 6D<"5E_GD1+N6[<MPqo&7ҹVœ3FgxەEYyڑf]SdNdr qljXsE=ǤQFM.\ \_f\=E"4Sd.u ΁wհh% F@'93vĽJCE)s^_uM1>=GT0xE,ʸMuxɍ$ٯ{ pzS+T?<%-;S!'zNV)Wr\y- IDATg쓗;/yѫŠ7e~q2?tٴu'3)l>zq&aTLjsJ ,k6}H{rސp{ ʶhbi&˅:t5+jZN.t=Tԑ)%C#V5|v6׿ѥ?o߸}>t 70r|Ts3TcM;,Q,4#u)fӼWdX|]Eԣ&u[\ӹӟ_C}#bpd!o"Xb%e\tD3OL%,0L'|zU2~H>mo~sؗ-r aYWgM)%C%N M""?6ljո֊[,OzV%am;0 0($ʬQdU7?a94R7/\`Sr (ySSZx͌,ZAVZL%—+O缝?V[hkݟbaK?LGu B1%Tۍ A2 hR1wc]KcY0?(Kč(PT "2$VB,Y&[S)IdtN(i \ K+1r_);7O;p!KRI2Gv+E唴chvvkKK8šbшjD))BZKBYfq^K'6k])ԳrQъ$[yFCs|$#ĺYqr,6#0Nnl?=ϝ11;O^E'qʝ7iv$3I ]c(HI-"9I=O;+ZZIl;z٧$9B1ueR!#ΐ:4#}!'ZZd5xP1<:B\*̴;&Rq]MmK)$ J53tƒe+-YO W4ъ yg/3s I&M<7Y^ZLqYנTIҹa>0tѤ)i=3dk&/w?SN9L|k_ӟ4o۟x4,ޣJ7e+ Y0m"%\Hz J{)< W+EB0W lRbq+/{'>Cb2h}~_:?j|  ذqǺΖ%^Y .gWѪb-8xF)ˊVH$NGZEZ@FH8nDEXT5C-ϽG4ǐ+C b`x m2RiIyZ&[Zі!s2'x}OxO/:۶P adxG1ZG*gt&O逤bZbxiMN֙ KdޖfwpTL&uR8'ԏ$fhRpL<yx( .(,FDxmT){)AnAĕzG* bP(K3R V53>P'r-*['Rsɭ4׾5s7/{&/?صkW_}5Q` +W5ҭGZϧq 6RBA (SpXikw*]zڄBz1J`hB7uMg39/&l$$ [H 1FS YS"rdRAq :aƈ-݂FP^x&\XHʒ 5,AD,,{v,6#K$(}5TdfC]Ob}di*1B^ }hJں~MU䵙’V*7{g9OBd4'q% faY:?޿sya1~Q+4qޑcKկ|5[v!vxGU|;Xb.`?\}'zS .^aҘR'}KbǞ!*Z|ax̱nDy3ӕ`c:Lm4rzYs⚀%K8i"(l˥XX5b?!OY@rxS/9|zV݇?k6Y3=n4 BL6J dvz+6k8R 8PxSk MX[:VBSҲG5Xc@YC=dpżݙ6W~(W|ʹfw$(+eʔ'hP:{{:+PUօXѰ%W>\inU@,l6QJT*:PrSV9G4p0eW=K,J M{^+ "+{ e6@VD(CpZ%ZQEБW ^G$I,INn=vvWBN8,్BC,U,>MJΎq~5n.RIA^L׌FLN$2왓r϶)*ky܀{EeffSt8yEIq!ϤޱϊSͼPk"elR)Ya=+4p/dnAsNa9@ -9O֞ݞZK+qx &hfmdrl|0N; E `L=ѿ{Eex?l佸wNoьX$(WK`@F|Γ;ŊayN &\m{T|\Tkq;.^9w~HdgkXn>W3F&Ȳ }D!4J81X*y"~_hN"(Hb&?ǬFB5Te 4~VELE ^Vj an=}g`B;2[<ń}h&W!LaD'mrepy³>_"EAPUUȃ#pdL9rop6'0Rrj$F3 Cm(&#qm%Ո3-3CǞ8I*G/لBuJ40|I)2ڹ&b" c|ǂX3c~4eaGò䈓$7WV 9eL&#@eB8ha];sR%r{*䢋_|1;Y6W_+^r)8tĎ;[;4 MםÏoDe8:sġ&lYw~<YSFa2_{[([t5<2-AS"=v&ZY+V|* *˽N5w +V=Gn#tC䞻ל4d<1Ǭ<3aQ=AM_ϒk7s˯~BI~;Ǟ/86$IΥ$/{7?t $lJѱfahlk͚sg/o+cT@%mN)R,X"zp~2lr[agN-yrI GUܼɰgAhk!͌UdS5FvI*vҨ5#k[buhYd7[6}A_LXqi\ss# CrF!s.8Y2萙TR$%#ӛPkT&_7$v\6.Y*bQP8b/ȳywL+KKIU6&9\bIs)ą[wњkc,` m.> qٔn.*Ehg{J(VӘ"#T,AbtF\4z[$2WV&XUS ƊUUř<6!QFZ 9Ce <6Kjg+6Mk e͡CR}%p eI+r>q, rB=L,(r+[;{:d4ދ(8I{#}&Xe#Ӗ3Nko]w-og3 gk0VsCƣ8sҐj(+4o8351OWuL+qFN80r헮)VT4ݤA aϊ[X5ӡcqe1/ sF,T.=wk~ }cGk͇.|{ a*ηϛy|?Xf Fiհ c)4`*;D Zh1HFI 'P^R"⁴&v dQ<2L @Axh.~ywٱ'\rבwfȲ$a [.z I/򍊦(8 R'({_m>պ#HQ&.M^/տ)/Bӿnz E./5=Q4HlJ(qhۜ] ؐ[+JAj*BZVSX.]Z#4(T}( 3)كL*ʔxi̴R-d4$ebh"wVͅ?k# +AH__vfۖGvigg[[-lG F ;J9|qeF4 BJZO5~*:O)ZvMM{[V.{}03L2ҋE([&F4 E5X"J(t}SwYk}xWȿ?S瞻^k=iV hj= jne(?( 0xfK53_5wuw- IDATT** wy}\&]61DdNt$2,(6\|qO3OZ`ʅ>P4PmayֽM2X8b*؞D6ҩ\>LΔ$܊'-{%k !ׯ r x5T5^yE\7׼ff;x<4@yb7>zٷXt Gaqn_Ͷ]{эwoNzv|#g~f$đ EolHss}m?gsۿ?xgr$H1P+"o=D5n]8*|R?RJHFA-habŐbZb ;)l,Ռ =+o[jd<-󆶬A;@|0CTg!Gwv3ynq6;R~>ccG@d85Z3'ϹV[Z#Ot&BwxΠTJ&Bp6h4O2f)pT|ו.Wb=Md#&)gy%EVR*eSx/Jwo,VX/jP"e*_4'Zf|L$C u䧸Qlb; KShwc˞6+6lpngJAo9x><4{G$iF!Irs9]=0m Qvs{Ѱѱ3Nd8'.@HIEWe}VXeh0⠃ys%)4hx+9*xO-6S)\ܡ񪀧7WO퇙c|_?7E (BJәec洒'V#kْVZBQ =\%,bzA% V"|%Ž4ZU~C\t;>Ϸ .? dͩjHx~zz"/=fd7crq'p ?9^*%Mws%6N̓m+X4a׭*ιKgZGw`Ikj6<=ンyѤM*,Zk֯[KE36PڰXQ}[EO8'#L3PxU4A+H)>S7g< ^1'0ŨZAj7Tk+:P)zgjfGCz Ll7VR1SU2pmf3Wt^<\#G;?}ﻬ&}Em`WE5@|au[RE|7OV";GXm^{7 5yq)BWžf B: qy_)]I7 ϸM"UWQ.s˝=|_~UGg26ndZOyVOhnvL-<=MOElƹ8yU^Sdw F[ʋVΦP HeP 5sGbPzApF;9I {0Xl:/T_8ʑ4Ě#(84,sQL%ji%6,gNH[J%yMPYHgcDc*BE(e-0P ЙP4:6q<#s6 Ki,%LP*\vyzGs>OZQbPt;g΄{EqX(y_dC7penb@5<]W5@Yt6hA l1Arʹ#O~"dzö dX@ :aݻg\K`_r%\ve\~^˗|rV^__~9Ї^I]_җ8(G*sx6LzzŬ2422%<0HNw; Oꤙq*[SLm+zG-S)2G;SnpZVJ 8!/t5 Sp.fhRL]P ڳ_-_eb9O;>&f^DH1#xBP*74ʚ(L3~}ζh%)c Td3b ocqZx)bcfB\1AlަH6P e2 XxG j_`x急d4|Y{3)i@«)Z9T5S) Ν/$aaMq0di=9Wtaٴ?ҴOO{Oj"͏pտ_-q,ZKxݥo!B$6Pyqij` eE\ݿe WNP}!L1>N2R-@YYK=RoDzRKJSXi/N]Yai婝yH-ɇ8@) )g]׾wPw?Lldt3:,~BL܌>ȅv iNtPk̪H_zR4S?5&rA6ԭE!8rbwKO운L$2zh8KCذ[ sRmli/h d:M >jP1v8+kF~ B+{5PB؜bq/: Ċv%TlZR_"EK)c]&.:v|V6šDn .è8?h͆D6Oҭ}2,Gqk cxAiN1:ӂ0CR(BLl!PJж2hBD r],0SݳY\JLO9|o>A\*`Rx_POmƬs^#6ez{7{ٺީ\ZE3`BEdh4sA4'o"#!IzI DooB]Ϣx=#zFO41{rZ3QF24[)i3d%Ms@(b651 4ڎrOH9b#VL4bW%K-)㢍$W z\nY= GƧ2,''40AD$Ps#Ok 438Љ;u , {5Yfk4 &ۂ8/g2;&[2P-E}h[eu(zr bng8x$̈#Xâ+ӲzI-X1N3_;O"zv;ّ{:HMfL7,Q(5k׾F\S_4)^/ؾ};g}:;wԗ>yfnfbM bY8»}V؄CB( 9P mB:(=c"Ż eجEȡB,VS(bf'bA;f.⾖)'N*="l{+G)>% LI3PNѽ{rG<%`rmcTPJ?3I{OF'4ֈ$V6jςB9Kz֐fX֚u;7ٙЩ& 6{2Sfg[dˁ$RL"}dܪ]B+)Kbz?d䃸 8E aI&0چ-cgk=M&b.nW 79ǝr:tN8j~ؼmSqM8uA-Zw)OͿ{wmN3Fiv36>|'?n |[ױ|JU"qPZ4OL;Nd<7XoɽPɶE FeXﱭDk1/ˢ)U -Qh0 /8G:|в2XQzӯ8կe*q\_>keOGZ,;d>Y ܇yaszcJ@j-G%Dq3t"Ŷќ,U6<0t(N(k~r ̪jȳjN$W"sm99̲`驯aY^IŎ_`19?o nǷ'?6oJdQV4g^IhYJK ij9޲"DKDfɋPNw,W%2덜c;gַspvt(FSHӄ+/MR |kN=$NH !mH8 JhƝqG%  o>Ü2L:B3"M"3jefW{?ߓ:h߷3z # w6X=77r;f=ߎ% ]̼7r81,myPrVj潜z# I-ce{ˍ7VP8LfJ4Tx4cS9O>"V i2J~GJAVÑL22OfIlGhA:)(KIQ)KE杠cK.y}X`>nT][5EG ŋαT V-YiۊK s/5-}(0IOJ%h}l#K4WvÜÕاȕ@˳fqw36&v ?R;8t|HJ$(@L9Ly:y^&EJ=Ip^<۰Q IDATm:%rBe=đ<-Q W-fF"B=жu<%M9RKEkT+枱霱Ю-ԙ{3Rh9m[ ß2ؠLtpGR{!rx:ID,?r՝e:Xy7}Ĩw)CZf>:h[—3ZlA01 *mO5ȝ&q 178N_TGu;3lit0|Ih܁)QFyW Zmzz+gɜg1 xhQ c<#3Vړ,e9m ]9niwuF@n8w\,YBRuf_*W_}5Gy$Ǹ˹>QGW_W\R_OzH7"s͌LȠu AuJyfM^J?#89]`d(އWsEkAE+B"T^ryݧFfE"(`_/ӝ=7=/vD_Byu:=~P< 0%tyHje")x.KD5x.4*ІDBG=D/qt" )9*FkB)Ұ W҈eYwiYS/㙧%"N8"|A/kݜ?n79:~Cn )%+%S,Yp0K YLMqDJ Q!K9s*ܷ>9ctxw_osr8{ @+(֌5(""4.l4SO=:P8P'9z~ąG]CU5v/yvwMnُJ(B1=ÑM!T_DxGpxlmh$ś U9ؙj6u2NJZw25V4ʞ)^w`fl_ك Au>Rĝ/@2f,BtܽETzfQ6upSжH$R@s f4 챁V쨧it,ljHj)#% Zk7$?^|)^wW^yX~EP/ |+>D S*xkP΋q{)q#hMQJ_7)<8#mA1FQ `ۓ6o3w T.A.>VaDB[Yl| yy{(t+eXƚMjGBRr<w} {:c4)AK԰.$ PJ(H{_HPuiI<[ʁV7VcpYr }hˉC;b8&਷EhYʗ 3Ѵ$!#RJ袐te)Oj60ƓԷp}ʆ(CZ l)Ś!=<4P>$_Fb)CDIP-KıyG;D~(F*Iܑ) 9I=> O UE51ZS 5OlKȭN0DiCM< =ބHk@,cRzbw $c*+?}LhzQ.)ʆfEb;&ZADRXx1^z)G{ Ϛ˲Ï95 -v -a^4M0ZmJT, PP2SJz()Ny^)*i ҷ\pӯnCWqȡ~@ݤ?V^Q<4‹/aph'~c|S v"E h Ig^A#f%{BZd cQɁ(bZ^(/BV *l(2LBT,kӠ83ZcկjAE:Q*:u\zT1p"A9(RWx֡^V1MY%R@=(kM4qx2/ھ+%mWk-g5?ρ㙭 k6dRwRϬ2ulfބRh L-́zNQ&y. mO`ūVDlt䔰Lo3O_ʶMǴxrK;^:G5wsvӯ YI̞;SzCep!sΧgQ{r+k4SJ̝@\*3k=gó0FW~o^Sn'P1>U@8p$:; ։%4Kh%z3cd{qˣ4Z )ܒe)AGX;pehʢ>C5͎I< iHqIJ =6{:ؗs"`|Y0GVWxӒfB7ʚ80T V v7ZM",,rVTGYdCj S.U UB; Y񔩶@3FRtR7HEUHQ[RġEU/,|+W| |#)%u LpZ)@9)Pٵ~-޾AڝfQk?Ib zTSL┸=VhOr9284w <>q'HS8.<rF;?+S 9W9+Vǟ@Ay8{ckPEY#Vc :гbh)N>!$_XO"߷N>|7=1S-O0Դ縕&z۷n/:K:k?~,9<c|NOEO|]43wovvY<!o_nv%ĵl۱Fǝơ{!L=a|zIo㼡ShȰӑPTa;M( n,]x,v5k J`T&:KT&[9Dj(*y[bݑ{v/:i=w]Ņ_sfcGg-yj+o~UT̶iO+t}{xU\pI,)Y[VMTu^T|nQtG sg3 Ͽ-:I;.w_bk#~FMf|Pq7+^Fj4s't0 G Wu&֊}l![XqͨWUsrH,ԌcE`"[e`5©?gx\z֩<#RZB9QR|&>GlZ 0RT*xNe6ĜÃwӏ]QDgLHYIOxKb *5_Z̾MKb~m 2NA7ƈpos:ɬC^Z+mG6G9HKn{:cȋZ!؂V"M5Vϑpq}x @uU (o9feeC!h'I J Y$YjbK(X:p<GX<WM2\%h,퐌=Dw @'pxٺMfy;>c^|~hڭ<~]VjWY4qΌ]& V ۖvMq,tZEQrPfNGm4|`!͜֊T 5]1UM-ڒ ajb0޷Zi$N>N`PU  GkeWZhtd-eIS UZJwMΪ ;5b_s K_R>sM7qM7|/~Z-N=T/hN<Eeh={'Q[( =0<\, q 6#ЁPIMB&Lwf9)*}8b4/+\*Td5?ݓ!!*YBM3WALxة#PHnz.uy jsցuQXB& Gs/X?:*R ,!P{L1M3"S恨@lrohEϲsYF^"nQT 夯BG⚡KB+*a+Fg4KA]soxr.=OkZLdžj0qXP&:\39s/|1G=8yybvC ?B#2"<#m`M), S~x\~k֮7~'qI\uÇG|>Pvځ:L&S1zt4,/X Yp5<2c(r/궰7b: 2sE9N ~l]h`g^hJw['>ŗ#6>o~`I밲W0ڲ4jEK~3пa#GY֧iRm+ ό!kw89@VXBĽ%Bγ)~Y IDATU.hD}D{N+_$KI E 7C\7~y&gXz5,3z5FFGXE%|AZR6xJ2L4N[׭7}ĕ 5Mwѧ/d .18x/g݆wwq~bH(5[,'klcu-/-cejE35) TdE"5ZEΎƬM@ չjEA(d=]Ru4fɋFUxkT'*_ *ł%tSJ] ҘSH9I1  :d@T0ZWJjTDT_ϧ[\[:Rm@lm̲@KҊU" 2>iֆЄ%5uPjΓ{ɨzv' J:.aS)ېBQisqLg̐ZOjQ‘'VJHX_Hsf Tp̴Qը ",펠M0P, hYfO'wl;3ёu'd/ɜ F /ybxrfAIRbBifd IzؓIڼ֤ZsVmM%;ra@%R,6^Sr)..5-UHYc`DHÑS"-]!+Łcl<т̣ *0Ӷ%j"NPFkX/^5)E^$/К>$%cUD%T  :8Tc.Cc# ZÏC&jqײm6ZVm۶qu}k}֗~Kǟ@D+Ӧuȃ X"z8Ӕ}JpQ*a@t4F{D`0RB-<a9lGXh*Zr-&h%$`]Nw(0Bfi[("(8eR3[GԽT .#wMD!J+GIRz+)K+m=Tx -1! vkm,0FiE53C%V,.:8d^0@Lbuy5ѧMf]=YB W1TڒCZ( Ƿgw/~ϋ/qġϏ_P =i.Y~G?^4s.!ݜ[nAh:cE-L;^8pNoao@9oz+i6<'>{i.jxeN^p _u]Fyq. 5hiBeC_ʗK6 xߕ0zfڞδ_#/'/Sm^e팞H8k]Į)ǂ"(ϒf2&ȗW㘃bWbcj&gߔcVhe !5|Azc"(9v=<>yrr>܎=6/h*nA ;-߹4f>{'8zZyؽs'/"rNB]R5s>Ʈ)^A3v ,6Cеnc|s&x3Qq8 "jN<V.3 Go$gA+-P9qѓ^yEa R&]H8P!4 ҘL A9/CgJ&쁚ʡ@{;ޞHAGYMzn(`fx0m aBŋOPt( =_+PXPm{O3G`{<3c%ʛJ%۩tifdehBɩbTIRxH[3fixCWI!OsQ@ph2pNM#ִSqJlh2+t[6E! %cCĞjYXSc; blٗYWXleا5 nVg2ZmKWMU(hg;GR],_gՊ>j]]$. s&\ų.ROh֞ ФciɬԄS-DR;y|gFKPoeSGbK걄LPEU,؃b֗)E usFVwshF$I`wwd[_Lկ6/# C07a>z,2!^C4mqmimD@+w(SC) pdʴ\DIN%-􀊈|uN \)ؗ4RAEbM40heLU^BVb͹PY Brd.8 rֹ;DYIvγOo⒗l}xrVsl~10!/ēNK_Ξ4nYy@u+n^p,[r6D<_Jfozi(3<-eo1Ҕ)/R +GCUI s ! Cafz]v6?ÛOՏf&O'sxH S/{kYx Zޡ8<C*e=`$lz1.}+0AqS36s^w % <."8.y)?(lAOȼ&6R̮i|c~KO^LҌ%`©if2H;@ZG4;ij B(ja _ ݺH5 Y,#I6BLS[L_rD3`\BQSҸ( vt,E:$''|GZ <#t#d "uyd4s`9P3 b.fD\S42_ޏܤRB=TqSfb ֚-;s h֌fټP4hJ1!@yکc4%=ƓJD^=xUYL3 `W8х:L3jh5d89 d ?.W*zET>s+u%6?d!6ȳ0FU<3int2H2T E-QtY3E {ӷYd)m(`q!  PԺj,pL]ɸPZE-TR7g(ӨheDO^6.I >'x[qcmn^ڹf"rNDڡCdcJQx%j4uS #Sl,'FIX.eݞ* 6!&ŞFħy'8bic/Y]7VfΓ:OV84rtWdCAc.t-ZS` $oX 3y11sΓBg9^<'䬘RbZF*׮&xg Mڀ×y~n%5RZGVlU2RJ ZϢ4HIV˝EbUHзf~‹h[| F=wZ4xM<(P6i&i=t Se2*U AiCD8I AT$//uGܳK,ԑZh{}qyUv.댢m̦&:T 9zg*q(,q1lro-ذUkw[w{Ʀ3BkZVw)Zi@="w=̀v*jq\ rlBwX;yt&[9wW iD%1roͲe+XN>"֬\]I.vuҗ`Xx)2~, .bg.Ƨ[lonBUj]˗__v^93۶.;Dgm8Bj1In5chH.^áb`|_pk^t%WnйZ`0侜Z9Գ8Eb{vd񲕬Z%cLO]p?GX?Umv[ )6ۀ,=[H/ &069nXwќvƙl~Iz`39AZ:֑;PEh,kz>*ANZ$^ U)%#T"dvcJP&*RM:PaNu"|ONƉ7Z KBlg5GE:HqQx c'n#"YpuJY 'c4ʤ%ZQRȻ<ǶD/LuXR4r0w?r؉cx5-\|plѡ(n' 7g[8E5cnEq"܎C%ujav1Gy=bP3x 4hޑdbYHݚMcn7i;S[HJg L3vTBE^~xذ}4!z fϻ=(ݜ6=qp^y&ukUi] "<k}M`0_瞧DF+ S!d>k} ]b5 |oW'1Zq*SmGV]kE'qd?x }hS:mҥƕuZQZ}2ܹ>څF5읲3P7T#M;Y B8FgKRG I(ͪd>=-6\ ڛ״S'ƦB=Rs5X pRBe٪CyKdBY,vySO=8p>(v?OYt_r-|7RDEx171Ì~tWq䙗qڅ/e~vgw{xʁ㔦cCz#K9mʕq!c:6[6?Gmdӛyg0:2FP0`tDݴ(w\&߾QvLyrsdfr?4ȟ"͏NG|]ahr\A{fzl9uon4Xq~/~^[;d!kz';AbE4f">t tUcKٹsСq?…/;ng /`߿{ qlvuE;8)*&yjA3Ր(W5l{wΞ<_jcbv3q#m~w}IX*ԧ?ǫ^FGx G8,λCT*UbL>mGrh8=9qYF,am +V[ dg&(m0aM2NCjC}FL?LKTIf,% ӹ%h1Laܓ(ӶenDOޥ^~Imʘ>uhEOے?~fe.#ދJJ j! +<0ِ88d< {cEƊ܃;;*X@R'=Rtł^rhrJġ8rM{RR?1(i^VΏxr-#<;W3<;&,F/c(2 +o4^萾ءC,J*&*%yeWZ7Y{Cw-`%c͂fG0ʴpZsQ=D!x>#㚱Ƅt_zP4RTͮm @]nK|Pq4̏xf4&/Zw-$,cV'y͊E=UŖ$/2SOR8f.9RS{:MB`89ϴqH"v;s/x1߾fx>hW_Lvm{/x ,Ϟm&/yuJ %.r5 z_)97 o3 "wbSS4 =U$֕FJj kӄhE=231~+1K Jm9hZ!ԖbQ0W<1H' }FDT  6h)OO;-cETcU/]ÓOc6/2|;'Cky$XLUWU,Q%$"e&8r/b<,-{g óSgEXi[A@fy _׿}ěK5/'074usG|_4jq_ǝN!^g^srxv3Tp)dP =1/]l)F8ē姷utFwA<򜱺G<|K]G8ߊ.Ŕ ->0x5T]$/5=ծ!FgZ,)X jڗXCUz7s%=4r25㐩?s 8>)cpN Ա DSS7 "B\fTP"3{mZN>E#*gvzE<0%ؔuKMA2<) kvLz,00Եcm e5Jv{RhZl ijwBAkbPZؔm'4+aŀaH.1N1P5^fK=A ۟Gͻ8 IgZhFS9M$(IVwg i*Sz%/UaSkOi0*M4fxƳ{[9TEe|jiTh9+Vy6Dn63Y>I-jY4ԺɳP{zviQfDT׌HGk-G]#MOdx Lʦ։ph4+n,uRc4SIIS[r!٢Boݓ=/fV egFx8Fvs#IS ˆ;X7_mṞd0`DŽ%˄x;og>u-%}2Ѧ9Qe3B,{ݪf&ɝX . 8rO[֝p8wg^o㍯~w'iaig 4KZ+YAÝwǒy_6=y{_x >r2ycwwGZI Ve,t1 >?{8:[Ug^ӝ}# ; ((" " 1(.::3#*"".,-!@BNVUϋ:ݑgs߯u\uoꕜtƙ3?;Iwwbp]=8Ndgny=06<ʻy.{\73҂wz9"1:%2ieJ⠵|ҿᇷ݄25pS@h4&(u5 ^^&ci I(5R(w\-l5߾-^K{CB2ՊX\s_W_˺'SN-a82{Na]wQOiBƛ/j=]S?e8jiU<8R ?+υ_&O鵖(ؼHy5Kl.KmNCRTn?K%Pe2`X;bs!wi4b!Oo*~* DtCſc|ZbE#0~$o,V%_Yfn[n8R) *a"uUPJ`z+I=r=߿=.B4/A~'pyL:jZ8:Km%$e~GEezr ׃_ʰiP,4Wss1Ǟ>a:\O񓻿?<"ͯ }_,w7Pzz3e˗xR/XkvDžV>))Ɂ톎IPqI{>#Q5 *pO=3>cYg>>hZK$նv:o/Exǟx2mx7rs>_Ki90tB9 l^_xvQj؂| J1ԍ3"(ybӠ&ӖX=ɱ2;IyWB2U3̫(΢K[KЉCĹ#]F9)P !xES-Za*?L$s>ZPH),n߻efm?Ujo省&'-Y!ٽcgv< t?6KeàfaId~Ur}g00wbN8.P!,&'4uVP,L%P?7#Tܵ!kg. 철i-/o/nU߲e4~IJYNz\v& ]H h+4%Yqo[߽rpMMO>ȀsfM2+xbCIMU4֫?Dڒ|4j!rox 3I4B+7IpMAMJve$9&ɲҡʡ%6g"sGR119$‰+ ksܴ2QGFsEzhHGOѷtt;+n/JB+"ω+BJã ~}eR|qdÐfynFʁ&˴kzp)Yz4jMigU5`'X1yo8J X3tADʮA'Gk4SVYSdx2>l9tL綪JjK!thѧ~m5B8hes9'Qsfyt,Iߨm5m`+&SZsyR%m{Rp>CZjqb+czXhaJX+X-> IDAT l 5)SQB1/2^ːΠ/Y^u}1qI]]Vt7W\q?<~;_җ8묳HdcʽR VU.n]|,p)}'2pH͋PR閪1A_u ּӎZe V(c$}x҉'wx҂Iֲ߬Vf9aKs }#,.ĥLNNøsL k,`d{/+> ~;h5Pop/p$ 4QfG/jIn;,&N}Oa.ʝ2k3VtV>L6&]mF{~7 fN?2~g{(.`V#%}z߽Y~{Ν+#]1g{g>9rՁ|D>7b|U#aopNkXcGw;x~aPR, ZX˗;mW70YOibM8DӍG!0]a8y$ΓB4K?y'&nQ chBԆ]Th<%piR9r/,큤#$  m6$=\!!ɑ;|B#V090Հ;KMG ࠣ9_ʊP,2w7ncZfn}~dBsOg([ "a@&t}BJw^=ՀenEŇJ/Î ‹) *$Kxi$!.ޗyAIE_A WV`rbwt*B"*KBuG 4bFL5I>P0nFXi͟cO3sta4v`e)hZU?{b3N툇eMY4JXŜn;/^PDn%]9T8:ѡݒF떡Dػ %M3&'J M˖ 7˹_T {2k {k#Ss8z!I Z` &Kwz촘jgfbΈ×7D큥6MD $,3,54#TF]d^$lpA~U5s/;gN%0,F)vH󻜁 ;()(K9+ .}<ܱrv K~\todeG1g ĭI^g\5)- 'r[Vר}==P*-]C)I[Q⹏)A 4!%oOR.(V)P*8)h/*.;9AfhZLp?=O'w^V *|z=U5IJiq24BfZ1"DG}&shmcܡѭD 9qTlrh[ BTr)weN{ DFT (p#a@I%h*g}bOm8Ijs(*@x T$:"A+;}kiX}%[5K||Pk-K8l 1[twZl%G֬=,ĻSpkk%P$,h,hш\eA1EYC3w:6@QQRrO߼Q5YeKyv&pʙoccEdF0Է'~On&BH78\۱s~?.xtZˢ7g]kpҲY1W|%=,l/ajr8=v9+%IKlN#+77pBh ,$YoR[s]PN` "/gsh6< D7qv@ M]n6`([@KK<)94CxRg`wC%KB)T(dFb, 鮧3Cҟm&Xfut'T|,vbU=LD8Ɍh#r:o3)Fmp6GiK ¡ DA'pIJiEnH JzV2fP9r$5+$ mdyA:Fa)VyyK~tH369ȮgAfNlIY2ܰc2.44aװa dk]J%@+>ù_9;{3=c ïP0% ;0$"\{9ף懷^cw]}SK (U Lo+.X><6sK-0$Ho$* 4g, jJ:EC&Xk˚"𰵌-OڊA;~iIҔ2ϭJN[dMۃj D(,,a>Cl!5n p;RaL/ A}᦬%39 (+H\8'-bQ|hZ\X!snGOSN'-B!hϴ1,F\pFH\K=$CCFfԌh:%3. z K8i¢,/U! al#e2<z8d4m6mXّJv.+-fjCà(i)rש! $89*x 0-p YZb MHY`vslvF%Js{{mQJR؄Z+v qP**ZFyi"I2_1+?"i Z845tog)RH;[o:m6| ߽5U׾guN=T&6lfÙU)wb컐r d} ZWARU%NrO8t5ܿn].842 {zlƥ{~f"O@eT@iebUp:W5s/ f׻0>/-Pzcb۝T4XA97O@Wj H MDRK,JvPn+Φ݌s"ͷ?Ʋ;*=M@i _S^Ot caEdhVJJ<B5[3bA0);=4A6z+c\4ѤF &SF")y)P !,Q&ft[5=5l?[F2JHQ -ڄ(u6ifJI^N8~C6?MHhe+VhN CV6]3@,-u'51˼y ذ9lz͑Tf_!:(r- qB=x饗ھ5rݵYr司袋i)YNS ^^;DW>m!J2,# h0rSs}z\r3T%o|9uDZk>nD=;UH7*I-"N- :+ SˤL6VC}nEP0i),uԊ5g`vU2ѲT 00Sg<)D̹|IGBvp8u0&#2o$m\d2 )ݾf,X ;&͇Mf'`U~I*aBdiH^i++Dɣ:qyl&,Ѩ?jūTvƴͷX?`qU0o ~g8ȃٵu3 vM*"HABU1!$5^ ?5't!T'-WYCs-Th"Ey!qTClPтj8L~`;oG3RRtY3Xiaڃ͏A56g_u(c"Z8 1B xmJ(_LRʩi%qNњ9=+JYϦX`Ѳ{Q[4Bwr<ɏV(^vVW:J誽8?_< *2 5"<%8n{lRAg$G+fc1+xiwĪ>`ptfQB1^ɌAI;=vy4\S< 0Kk RQ %Q͉ 4 /Z 8>#N_pS~OaŲr^%ܟ|'{ED2ܔ:0 I3rd 畸Wnb,69N0{wc.  olظE%J]q/qB;ziS!"S,%Fkxxuts/_^|09'IY<  O*p:/1oѲ{7s#Y}ڙϤogpjނ+.۪5K kJ j~\oq戶o۫өH우ȠLNcjGҷ'zkCJ+ MD,/b>iY~a}k1ɮ>v$EEY5?rA,fHw6FJh#oQl0/<׉>S29}g2~P舲tnuEөj<!hTX(DQG 'jIhU.¶\ȵ ]2lܳ#-nMT L lsp;N;/<4:NC rDBXƚ+n\1;@f1>Ҧk8WQ$O Y0B0wAo/9dA#WK3vb"VUo& IDATXR:@hbq%ʬeaoq10H t,)L&D?es"=h_Q J OnOI[V*P䖇f/߭2^s@7QJsf?JJġ fxZ0<89-[:/qYzZgyN8/q-_9R?nAX*uchJI-q[,MO `򏟿`筕|%^˸祔,wJAZ>%`2aXrǮ^J>7y N^;oeѢ}U{vdʞ$6>75 ŏ_ƈOsgwUOW|L(c{n2]BTb3Ol|9FG j8hp~,_?kƊ_|~f̮W,bycV/_پc 'z #[+y,=̵yq()Zq9i}1Ybgyx쏿K>ozu  [n5{4q\E\}pz#>L9A͒- K%ldjfdı/T+=Oe4@g)m~JK;JA$ON7,OnNT+pOxlT%1$΂Q݊qa`hf(3/FS,'/]AX-&#vFf8DZfŚZn-Z \{(ˊ2m=)笪(yE@DnApĶVVDQQ QTAf jΪy:";~}[u{UY'OOD,I359%:K$/Nb |]`\9U'?L23Jp _y(u)Ffr*BT凓ēS4;% <"ڝy'(,7?ObE"/@0xt͝3KɗH_ڥ{,u)=*9I2x }Z}8-Cs9 |Ƨr)Xʑv@_U;`TWh2,մcMIN}g{k("yR>:vynK ӮH̑(CTr뻕`X8Y_5bTA#EiLWb ks_9iw2P%Gr#Ur0϶e53Nm,6$)W,ͱ&3u"K@e .B5T|EA#1Mq"eɬ >Ljg }<]⺝؜^uffbn>,`.1HX\<=c?I3Sn%29;Y?e|AZR:V]cN-r^=tRQ" 5,{trv_a2@SDΎe^N#crt+%_l1tG8uJ2JڍK4Ď?'RzKuΰ21O8gع{M#x^+$?g0p+16GWM>y]w{E1~7Ċ7yg,}xP/1 YE=8-Ϣop!#;x'۶ѩ:&˹@ M8rbek++,J^42M|7p(?7םy6?p _]5{W-laub.y^?,'x*bq+M{p&̵-8N9v}<Ϲ>=uOcSt{%eeYR2 0XFA{lUNk[=̪5e>sزGc2gg>Yz#vv4Ԑ&aj~ʫ7OCx!{/cN BBti w)f=MZ9n52kpLN6_rIJVǧR,|ؾuH0PU\qVwP'[2zr ?{Tˢ<d> [2X Ij;)''uU҄0)@Y qJPp_ aAJ-r|,Ri &@"-.@(u-Ӛpb 0YJx2Pϛt4;i87owU /*6e_t{aGk y8ig}rbxtw侒3>r($PU!7 1\7LĮxKsp㣴cC) vr&b~3[{P Og+8x~ |ur+t}fyHk-@P]lJW#I9-!hm(0}l%~;[3*+"6Lh/m%ܐ?PX΍6%CWY)+dFq"naY#(|w+W$2.FRMt'$uDRz5ե'1?9s&e@ZqoYrmw - ƥLmfS # / Ω.~|^KsNf]SmdApEςf`UD[pglk8*rX4I;.+p̃/^Zf.H$.e±K3V[?9goݼ{oᅴ#e܎-4m8 $ǯy|SmK;9o:xUdsrX܈npÒjKKQo;yn, ӗ7m!X-IFsA1ӟ$ PYC]1Jx|Sʲ>nC}r/kdїm(׎lq!Z`EL+c*-IYu[xE TqSkx*$('+mj0rɲs-_1+wGNL?7 |/IJlsgs/OWlؑ`eeda٫_06 06&M#l{X4yay :H}T3#7 Q@SO\F/" nj#S7&rw>YMfVK6LvfYޣlr]qpnVBOE gA#^nF35Xc]׿/\iydFr\cވ_>Wfns$z9|Ӎ|k)gx#wuwfs -_I)*r*>D>.z9>JJ+|)5By+Dk;|KR +$0,Ԣ}=0) ʪCx9DzN+cŠVyv E] ˊ>Kcvj(k炒o9rE.7(E0ܴλ3I) B*V \p\6T`LQ/|T<)>0QHqb_Cϲ2xʝlߞScrZB._RN=+~F̥xYK^wS Au s)aYhqFЪ*^Xޗ:H3L&,PoO"Ŗ7w\1c=e>7pݣVuL .פVXpqG^4{uCQx|:焅)aAA\X+Uc}{yX.{>`7!8ր-5Q",YRXՖ>SW Hm!nBz/]1!T,)qQ*!pT]CVe%ʖ[Y Dv+Ry2SAœ+(NBYC:HkXd u SF@ec 抩Df#IsJá:y@6@ #$K86$R`M&J#dD;I[y9+YUHea6AH4:%,T"dCS)I<[qS cr-)-m]L eaJƧӜ#$;0pM@x JkI]JkG 5InJ(Ffs:% r{gE8gb֭[\z\r%C] `5:Z$R , ,M ^e&0ek~bNg͝J a759j2ݡ@H37"~?մ 5.0d1yNwjCh0xLu 2}ߞ*:ixvl,h-}(XH6irb |ֆb&6T]|'PŘY E$5ehXRV(řPA,s縢D*/0k-f` 87VْEGc?c)7֖B Hij L3:2B0Bi.IF<6J4q:mIҜEUW.Q}X FsC%t.VNvc{N.s&6͋S>(m9rv8e_Ҋ &3ξ| ߸J,GL5T+5`Vx?z5o r s1'| mhOOیx"Wr-o:w ՗,qo<>ݿ=?7K?9g{Gw߻Wk= 4S` 1Mt!tlh[^ȱX&[v3y.'ǿmde7J>wm?ο^z;8#_`ڵ<1a:7l6`U+aAE}==}J#BKIv`B_wg~]_03=Ekn3~%_Z!+Jǁݯ6UV\a.M%`x\ce=}ZOOO#"Nd %s͌:V<2 B8 }37#entGr(.崓5p#YڭI@owG6vvfyBc<^JTmi֩Hg*V, !3%{njrp!\ H]S+Xw2:[-u?.)%wW]uCsɛ<1*ud *TTA63Q,Cy!) V`x ) &HaMNܙe,iaLH'%FNdM}kzݘr?Ztsce|m+QH6=!,]K$JE!] sܜ`>tڠ\&31J9191VxRB"du>7%@dJII>g3\rM;j-!ëM?) Ơm)CYjtB 6-#,< f;C?Hކ%Mwp@b}Kv?\RP>6,[4I/naݺ\RTc=˺:My/ZY櫷62khfp TaΔsyTBR%%oiZC䑌*}ӏYC`;MeC'']_Hc-vW;<1fIEu]r46!H$`i`ʂ=ͥ8tM2pT1~H.7s,p0p(nM%x zE~Ⱦ\x-Xj20InLh&Qm%,@W$c;| P ֥.Kffsw3 ᥉چgsV]`˛ -,ŢU]O,"s2Q9OaIY#RmÓSL57}U%WCI:)MG2]G7p&ĖГ tL52406gRz"Aw/Mj(O2h!,*6izҙۊ9~qgE G(Y>>pƒI ]O?ygc{nxb0}R/Zio~\-Os/q7s]/FZ٧^Kv[ɲ+ݹ7|<~A x-/MA\Gm&'nL o{rkmcߊ_ɶ"IQKe7bexF 6h-h Ұz>g YէX![t:|?Ƨ>ol4:-žb3,P$ty]?Oo>"?4ABN9Pnq}sv/ $MYzJ0 NG8ybns59<72n12FIrMP@4gX7>T ykwȹvQvȰlb>X!yorb:J-A},Jf3xhİqFsGtؑ漏1ֲLw,%q?ʹGlg6xg˳k)%֒ P $x"BiL<H7ɴ%O[t $[eS\̺<ĸ5E' ?[UpQ+Ң,gc S 0iFYUyoY-C]rX S4d҅@HHreGbh#g* lVJHeIkuՌ4bkBW,*8̑K V3rKA%uek]'"wɶ3;31RX{]Ce5|۝X =B"' er:ev6Cf9/nh09^'N4ƀ13nt'reAoͣp)ٙ!!,3-dKʑpMIFiƣiBv!}@ eoz_Nݦssss=|ӟ8'tk֬_522u]t+K݆^$q7WA +L BJrlxv`Cbni銥p(BPE2mt6Pk%g:5STBHob˛AA ^d*),]e\L仅!5Qd],`#bڙc-Z̙HA %$I ၵ#іVtʯbLJCn K#DҒXK竭3_uhmT'D"#EHn`{DžhQAx}y-!3HҜZW?M[A VF.aV:MXHZp*nckòe2Nh%3`pcґDa%.CQ b[: I3O>[q.WbۦE25ҴMVZC=$낶ֲKkor ɏ~u5wտ]J$=e`W@d̑;#bnױżowWz}N4Y{Ys˯A)'Je΋.3Ad疗ig^m.ҷx0>aVa=gS `I,|\GTX֏jryk|P&N4ێq|A5>FCz=G&iq-2%x >?p '336BLv,KNӱ Kmj댴O 9l  xM2#_s2V~w?oq`fvfedrӏپe֔`k5qtMV^Z>D<8wϟG"z8'q6+WN<㌲/H7StaSjD/vaVk"cjfn ̄!7J2,mC\;bS695 U!|fctΣJ=銡hte Y&LNB5bC+/ XK(_sW}%ovy`IA89kH@ dؽ^;Q8mW'Wt('{dz[cf"y^W3mL+ڶ K]4G1MIT@gm:*`h%ޫYQ3< MGߊadJ#uo) gn[:ˡ̵ٖv!zed$ㅆ{<̺5m^HH;ԛ"(($ipS,~0<=%3 Lg003<ʹ#N;N?pN_TxٺE+FaXIp)Ԓ&fwl Vҽ+ s t#[0֭+{l1Es[Lh<Ǔi4zyp{IC@$cMjcIӴ eg&єq,w,0F U$\/q=Gk-a Yb/:.?ϿnkJ E333200.֭[… $ަc ^u)qg pK[t^a ݏxECkbqcX$H2f:N5C]>R# B#,%܁Tc>XhiٍYk-ժ[KV浕@2ȑ4yQObN[L6KT~u)vD:,%R -).p ,YV'CK;[\"2Ν9^/f gN[,2޶H$qpnfŷ^Bj@c饺T(M cҳ45 Ɛe.;ݟVPR|?D g~e9;Z>(M7V+Lշ3X;=_ydڲC|sَ!!3o<Ɩ,"#DBj, %Kt W# %ڒ̨B>AdX|+.a3[G}8_ z]_2% j<}Y Y/"9tex(u&K:,X[Yw _Aq~?}B:;ޯ~vOrNNBI RE0<`C0{DEuQ>#6@TTl0`H/Nv[k?Ng^3zϽ_WN~Y{ﵾ53m9'.M-? ! m yZ vny\8vq7}hvbPeJEaaǜnSNG& ,֔|V`nNmͰlT4nImrgk& e09ڧ%I5#=LYܰZV嚅c*ܙ viᘆЃ F]猿:w]~{!ݼWa09ՒJ"  o᷾FXrG>8W~I ^g?iG -o:14ˠNVDZwx&rz<$! Jza8=ZUV"T|(,P@K80nGXXbǛN ˗Uu4ZМl STB8%U PQuRţ{ù.XZg[nac4ʒMK@,y>q1p2j2Þ ljMSt2KmlSА[0qDV$B،,1Q "ϥDZ9R,)AJ>F[ɍ'@)C)Rݼe=j|&*(C'9yxk.G" e+s-=϶Џ=%5-q*=2<_wҹ }.uUϦS /1()J>vb_`&P'ŬpK*4aRhh_np(EF3,:Ok* %d;3Ƃ5lxCGR}7uI][|/$kn9֙*ڧf v+ZZqF3ޡ4wAJY3| }}[6 4ΤdC4r(P`,ܺ-[\ffͩG\V׿LLNN{n6}}}_#[uͩ#r|XYEk2 `z,l UxD#$MO٥Oz IDAT2qpq:s%34>:kDK #$dHIN ky_Ni,5tJ IaG,RQovTo,Y'$)AHhr(BmT%w'~ŝ$Pa*zQ8TDe`Ȟz'ik) +69%7=ba7~|qwr)on+}5HUHu0%kܵ#vθFgouh͌[˥}f?4F6?FmigƲ,X-yt0+|OkM 0:٤Cq@5/<:mXPC C[B(Kh%ZViIHt*{I+1s3Y{tc3'(A(;'7:_Q,YKWg "vxrՕ_A{~qb\}ĸ@*J<欲Z1X Z lBv(d5 "Ն>g ~{j0…r9WvzBY*,grs)V͉B[ K_"DG?cu4uwX'%&wBy>[p)\zʊr`ʊ%W_L݊fbh&N/*\+ u vLi >|#ӆȎX(Jvdf&떢+@"XXlob{wTaTF;7HWnW ֭}ovbSaCFg4ZڙC֭xhҳ->+{?fJɗ9RP99KuJF]p^|w:7tXE]kG]q? 0S|)͋ iѬ_ X#cȭe [pl!R,0\( ̵%d1Ĺ |i%<&:IIXHa|4*BX,]e*qaOSivR25rs0) 7B7;/$IDwH|z,6O1cHKNK]PKAn|6QX{q/=;KO?O:~aeϮ9w Os@clgtp?x-?$ 4 X֕%#̶,Je+^[߮9 /_l=\q_ox'_{ȃ*Q6%e#wɑqxp*gw?XQjvMzK4mϠ5%\ʩ|6Ps+xp1>UϒgfTCCUY&5>/KZmK帕2쟦YXm-,*8ԗZKg11#xfTL$˧9gS[8XBJ2#A<+mΪ@%juˏJЯط 9gxv <\XheUcް}>,-1+ynR- ?}!-P=w~+;?ucDNc1Hf&\!*Ҁ)\IG hee`y};ȌayD;kI(A㾞آ kHbdO]uLW(()LsKjnyW׍eŹ&-.ga*18muxK )'nco'L&E;2<F!PbmcK @bpgR![4u7_ⶫZ̧k%ЊJ yƺAxb!&x& w=,ʵ {jIҝe׈TBXc25yH%(%(Ee`14͛H!V|Zm9Fg5S 4{-M3uv&ؕf3 ^gW;>kij4we]6E;3,RL魅kb0ª,Ն$3m|u=%LЎ $Μ5}Co`jVbXC,m}0BlNȌO<([JIs4y@9}nsͤ\]:;ZhcY$qC#KX^$I49 ) mK-Kamށ%i؁6C̭I9 zL$Cj{eAh³?Hy>dl(K?6WN K'劵krIȧ0@XF9J!8d|?*ݒ鵱i]9QXܥ8Y.uܸ4G4btF39sCu7=%~^wxR* Aw팹qօ fb <%/D( r8 Ơ!F6m`Mή++t qBPtՇyǻt Nmgv'xbgr^u%S ,1^WxwÇ좗8Ej}^7;~}/g^t䘦#Px0҆Z*B2ile2(PĘt `,X7pbNfM_?cwDbO|oا?O,9Zk2iL₸<7?On4IX>opcy%gm`qqCOsʐ{C$16S\,2V? ;$ۍȚtzQVI r-/9Ϻ^cwsĆS(iܾ辌HZ&3NXGHxxkFOENB{Yȳ#;tVklmujY^7Og٣tV 5plsm_KEg*k>YW4qQS?D dX;Ѕt-GrƲ/1ư!<-/E?)>я0l"|xbw̿|wE_~y+yf>ԣ&6J8>i9mKX rGso{{Yy )kY8rI\H-\[jMt6 m3Я!K,rf ct)龜mQ֝MK3`'Y'W X,_:7"exˋ,AX<#D"#iL謬`זݯTjO$IO:74^E4`&:za#7 pt,6jXtupB^cˤ< %_0R׌s:J!hQ \CA0xv ] S=BIT3 L"jOM\ N >/슙n,:xβ %~E$7>Ԣ{! :YҬ,W.i&Yh젳$]aSĝ=sFOYQvgs~rs-M+Xs̚2q(TՎ^yMU`}gɩ&Y'[XvP#sZ!ĉ 3tղ|S;Lsꈡ^L9BYk ڬAgu,.SCJHs8[,>z}S[shAdhɂdaҐ~z҄< T[c }šTYnIuI:J3Ɍ5 W 3V `+ /rX:q[`~ gچK4 Dy=,+Bu"ɜoP@#tW(rRV}sNkњz\)%jՐ}9q#tBs9nOe_ak#dJ%t#"_`G+u+/Jʾ;r2cfQ8{ir%]ޣ(tp'g.Y --˓m u_ Vu9/5AgEK$8hg0"W\0NED"U|lٸ3gӤ`T6t@f!T}T[0܀Ӯ CrT&P]ژ-7bTt#p/_uǸ5u6As'dsBw#3)R,9fFw<׾X 8Ώۺx͕W~g_~_u9/YJ {6g"TKtN$`>s@Q$_G ɞ9A w^1KeUII|%}j&FGXwC|ƻg陗2]c6 lJ>̵-Hq~MGxj6yj,R:[⾚C^ƧjcfadI Y<6,t=:zS~ܳ7}f e> tkKWrca:*-xz0XX0'be3 |& C Vnᅶ4gΨC[ʒ#j}Ye=\!Υ@2Q1g=3wn7s&@ Ί&:z#sȵ,qlqAm#Ei% '-<-dt6Ǔl[ZqN,+}ՄK)dqZ(n߹NsZ^0Z;sM)Th+5|E(iC%r߭c#(h:RT"崑#*A=4&$JyÎf@b}vϺЗĒĔ(|J"0Mei%@VQ[b˾"Ih8+`C}B(5%{L;{j 8wdFX;-Lh?|Mӻs6nwq໵9i*} 6h D+2t\3G۸E~LQ Ϙn8Vб܋06oeTک%Dsy ]ͅǔݰ w40u$5υ\کkXE!cxx83忚kahh;(\ zSY!>^u%3=yuݣ)Nj @JAuP"e^nZrөKoEPQgtSCʩ'd$<0 I1йlA׹q>wwx,_m:fpA@ jk*k? _u1RJv{Ӿ[%Jc$\bT;do&\sa óHjʾbQx. JOn*J+)F_mg_.-[-YO^M~\r59!~']CԄϟFSBS)YI:k! 0g moܧGm_[n{>%|E&4ZM~9 D^p_eCwٓ_~.o v } }>'& }`!T9'))%ȌaXJ^W_wqNuT+ <Il%q36;'aϔ@ctZHP5Hx*i'|SCIfS<}Wprc9ēo}#%i<ԭ/3aqmӛyQO-óڹhg[: =CZלy~0w`!!tpeF[},}+. ]pt`ABG[AZ'\n&"aZkY"\اj5Q =ܛ2UǙKcHiKbm#hXAfmaC[C1G<5v֤>Ѩfm1RHc6'SX9z'ikZM=N!" ʐY4pX C=' a' ]YVc씬X(2,'Re 2p\KQ2udYN["礗K34,ȵ)`Ͳȡ5;ߞۗЈ]ZL[ٝ$a$ 7R!Q]}_PF԰eOR083967)_GX=]Ϛ~Kw6R#?z)%RH:PdLlz{fibBϒ,I< ,E:kQ :ж8C[Jdy`3rMy;qRޚMb4bYN%ݒ.DҭSr#}1&<3'7ɍkΰVn1rA'8xխ"B:P1>k75]׆ xg͏~#reP%5dA4Wi7gVER*y ҅%JC'Cso!rvv`Ppܠ39T0Y m uͦᬘ xiDV':aw'ӜYI %P-)KLaFr ղBk[FrRZ1ݒX[Fdœ^43 ':zXPu"ch"5@3 6ya2J"VW(E9pӯX8fO4:>l&Ӕ*ROJ睟y/ZBo/C ȓ6Kh`TD+i9O”Rh jB`Dw,=M?o^EhŻ6~:‹Yx Vl 0^7eGGdE0+zg^'޽k7rc2'' YeE$(O?#{h]o!ηHs#Jj5:Zc9훟g-/oB;㹑j`ٺm'_!Os"9nU,uhej!Z%L%S I3 #scVu32J§Z՝{%R11^)љeIAYaJ-e% 5| rޫ/O=?0E/G?$Fiz(='()vL4+_O}Ctvu^O_ow7ę`Z?sWMsBd38Wrƹs9#wb{8A I#3Rh&ȣAi4K?YN4Oxr h(sNݾLFkǴL[;,Utio咤w3\lKp68] b]+F;'m-+;uT%@HZJCY!>Jўa:v; YLơgJ@$()l%I=s֚B:ˀvdPLdݲzYcYgΒdeoǀC:}-9Q5pt3,m[:J44S35$IG [OqgJ=B]s ?JvU{Gcp}1py )v;Flº|oxR<Ҙ싿 K]G%%{v+X%raw K\tPNF8Iڎ*&ɹЗ̶5%K֭Ѩc&mhJ%0:9.!ݖ|MZpnJkM@-,wϴcXv&HҜ4=ecWD^n^Q3ngylFfۆztG:Hi&dkEgq~^׎.FHhBڵGg?YgUPf?}n˙-W@܍7 ]sUiGj="9Wï-E$9zI'k{8&3%1wWYam:=R"YL]l-TBs'-]!n35TC7 }H3X33<:UU{j$5^&!Yj RxT#Aɗihh:+4,J:#LKc%(W MNSktYe9s6j& s.:l%igeO|iȍ /Y܅`&3$yz4G`UP1۠J9JR2cQXaSsNQ.\{fswo Z@JR"ɩ砤6ο=Yql ʼn|!JU}N:",W˒#_7}#P!@ľIg'_L7ݳ`q$zXl5Gcd>< 3익bdV32 >ͯ(Moclʠj7en{i,_2?Ƀ޽7`(NH:\J@W٭mf\!gE8Z<v5]vX %A:aν5y품ٖaQ_H#QtV$'7`b>gWO2<կ+! rma7y2IiډCΙHSWH1W4C4TBvye"l3OVNG!xW`5$kgRsq*ȂzP)Ic 0&'0I!Z)~EnRxJPү R ]Շ~kKxK^W_/|[n?XV"@yh6?)Kʒ!Tu0rC!$rdx>,n[*fÒ.~9 a[Ls8uBJyIq: !AkC8W}Icq*:#HD!BHr2wHrGBau43t<wKvL-%$InĂ5,[]>Ek7ȄLJlM#CC)Pa'j|3W6'ap!mZ`2޶T[)B8`DUzDmݤpg+%Һ\wp!{Ƨ*h4E/]&\[԰Kq܀[ [2$JЪuR岷]oys_v*.]nNO}#v.5#~EK'?Kȇ>ݿDgֱi=o;oCH$\c%t4y*O=t5V`G+1 *v1 ++\EEMDA -96 ȩ9W^31Ώ1N|Y?.bkw܏vn·{% z$lm.8T~}{}~1r{R!K$W$N;8ֽ@ ~ժf$cwmf:К58b%98_\ Ye8=} g|^]C޷4R}ۙ[˭,G\c|/|;++%˦RdL)zCgHKX[^ܥiƆޜ En<+MANh %fΘFPז MݣLPxXL =ə< x1睹F5"W|K? //ӳ[ UbJbty>ï}4eUy RY򱰂0@jIxICeҰsް~_QoK/cOT(RV8i]݌ ]=J)KO|V.9^Z*Ba9ȅC7qx~Uo3g3B ﱗ xGQ Ҏm(eo ֞D.*k:6B=y'h!I3KjA?cHRtD*A3>])JZv^wuYΗs ?mLC"잋lE%$oQuy"M5bb%/Ҋ#ei$$ivK  M-bA+2@6| KKl"ֺ}8eH)O Ẇf&:/HSlK)KJ2kVPÓlN><cό {clvd- zwgphF't\1]5s')&&q1}Z3ʩ/ qB#vqS/H(- ;/>q jt O!ACB[& |_0Z63NLiwm͑T30뾴8kF!PC$9Kwh׽{\7?=\V\z%e3|"RPZD J44ZUvWRJf:BhU_jD5%SKՓ ]&o.dΙLH)+KW_HۣJH^ qMZk>icu!=LÏɊ$FSL)$t9|c'Qȗ2(gJ)D61`cap޵SiSAF :2R ʁ!wmfLcR뮹nc;:Nus[v=:sr/%K2Ii@: Q-䤥KM76 ,m&K |XX=7VX&3Y*{S3qT,Z<yٷ~%B( V| 7xbc-,wMDH}Ag ()6v;v:BKRR4Ifh`Ӂ7GI 3crqic"B^Pj&H3쫸0:m-kwWհܷ>|!(HC4 SH965/7$J @27PSF8iv8r PdW۝ut}Eu0d rҖBЎ1y~oLfJr#r ks]AvLS\rH@wAӓSm(P5dB xisJ;K?k/?wI;ӊXˬ ߿]ay:Fz,V[7fBw%\"RX*°xQOx볘Vv!/EXZ&v PoSޱv B<* ͢I9*t(KqCacxeWD+N \w@!F;,ɋ(Zaikw Y͞ RbkRX5VR,![PxWr;dJoȤ>Vxik[k=q :lnBz ˟OZ}ow%yJv| 'LN1F#Iܨ)mR4-}qA!uW) o½R& *u6ud˧{Zcxyy+ [9nvçyl&W Y!Sr(Y'Xt_|XB%,:;xaEYQG%~+N:G$Ape?3!hƆ(N }.]`!I (@a*^ɭ87}Iˈ#|&Xn?u>܆J)yrB5`LvS7+WSO"sNRu) IDATs9\Gp K"#<ԓzy$ƒ ;WsaӸ̣ #o}V<1vnJ>_+o&*n5ІI>6~\v(2Pt@ $NGZ>wqGŏgos.>>z 4&_,1̶1˳;bT-ӊ~*mCUM9p$ $Oo!Cj ԲBHHzJ1Vc m|,k\.K$s;[j b(~^Dzo|{Fy޻1Տ O&N,9C2>Ňwe -, m 2sA5uńPirw, |X76f124W۷7a_vr<ֽʞݻ(ʜ~9|{ax7qsIw3/?ѣ\O &QCY|;>ȕ>~A{i;W'Y3$-ʮ)Kt狌" u %\H\RXXc+r9J9Q_=ElK#u&(CeHAk * : hZ6,];Jک%9b#5>0OT0Y"Hu%)M\Fl9h-GcON[R'|0lOZg+9tLWh vX\u%9v~= ﹸʸ;h#64Cڱk54cy`d?eY-ZB瓨ǐjqM=S$P3[W(@ '"{F|7@2޶r qjVܳɓābaIvD 0TXO|i3mu _mpE};@wIkMõ+z7a఼%I_w@g9ut7v+8K:ʊ|R6O=wIbŊvcccp ^o'K3h8jǖ1SׄK̵Vls㫜&jߧr0-ֺEr fbTkBW-NqjKY4l @rEMIb S.9g?[X#PfNJp"atBj%P G-SijKLa3Wܗ%/Ra,6%hf֟wjn9qZW ((h)V P TƙF2x !}7!0'3ú1KWNPOf{!EOӕFL,Ci]p9r*4Y!{. 2>ByJR %%m2֭26s$b]g=HJ &Y`3!R^2 h&.OcB^|z~g̘5Z׿E*ޟPir eSϼu׿BDP`]W1XPnhk|+ƴ5,]q| Ǩ419OU^x( -z}09~l|'wuuͯ}8J=1.?"Ah5II6mO=ɊSOcdtӊ8h 1|Ax㛯by}MH=FS[C, wӫO'yx!هSYt9/z5O9tcrTbݍZ5B5!\|;㾕TvW8nNG<~cy˫W?Rd4+/sUof Ig`oP}.^Ai>t8+M"Bu(^db51k^hK9qd`~^f'0䔹!զ!/-{ *6$PK$RҸ渙DkS~G}w]#͔%(۾Idfʼn\BM)L@Q%;C  ˜~`6*>.z[Ytȡ Ъɗ$80㔙1|wضi=Sr{;nGObs t/koȲNdq348뙳`1F IBbWAG?\Nμ=*F2jG J9c 7mB_ЗațneT.l*c 8 UJSRL$ OK]unEeƅyJᦳ%|dX֡x :vRd _7e_ՙܥT1RS̄0%֦n2`>&ԁ9HGnr BPoh-6AvܑRH-uu刌dVy k}9îJwfd K y!ֆ:ݢNY0J1̶Q Ɲ?q2[׿-H1{beY|`熗8ovʬIؽu}ӑLi8Ғ t`R'3}L($$g-ɗ[³k6p˗NHPJiI-Ƥ n>7󗻿LX3Kk,=dνV0G=-uogꗈ'{YcHױ'Vr'0:'o .憷_Iǜ{E\}Օ8AV*NRk( @:9:CMi[MPr< fr.>2kJ&|zW7~ByYvA]p&B!I = Ǵ|LKG] *Yg3JQ= 0Wy kؖPPQԠ=Kh ^ؑ`&O[H`~׶͓51 >I*Zewe\ZӅ6"Ki676dž]șK9IObZHb\' .#{xGG?sy=ow" NSfw[_fÚ }XXvHn|'apCnahy$r]&7tZxexR*mm(j){L(P,I5qb US@ņB^1oJI9v@TvHVkH.:%uQSm8֖ٸM.+miO #g )0 ~gzZґsɌ6FhÍDcqn!s`S&цF?\z|¦M('kچN 66)J"Mo|eWʧغ};^N; f͞KoRerH$ӈj+pEc wTBa6lيw,Z{~}7{nV&\AԂ-_\C2w2^\L+ vT\x]>Ӥmo)Ӧp 'RaU\Pnxp}sIscj\hCug˯$?oi184+o8,,=ma҈FۮsXnh\GX^$Q(54k V7iۘW59ܢFʴY Y?3ҖY0ڄn6`FNrun~/3w7COnq5.ueǮ Mf֭T14U~%%2㑡|9>MlIY;{y(?ef[Huz^Y)gqG184>G(<ʽSmUnHIBOfLotq6m8KY(N:lNϟC^Owo};|2itZsӸWw۷_Q9O8{}ٳflaܸ{w@-2L -'&X+aEQ=їhhdJQ" EzJV3A}9+aɍꑥJ$Q5_IuuUpE-݁+}iiwPYr "B3rŀij8R<2=S.,/'HPM\78;'aq%utcFԽ+)͹)E n`$S$)Yw*z !-Y 7$i8p oy%bڍ:n9e.>2?=Ys%_1yBfJhUņfsy)=v} 3!Hevdf=J%_(ORP-N6l*&nVzqkv&4 0&:uRi4y&?7 ݬmr6LT Ә>} Qb[La"KFpxO&?||I pafר2W"\b,(t+KV^jx|bQA| .xǜ^#&x\<$5)Q~q֡ CMP)%>@mM)wMƜŜ6(DdM,'Kqe-qjѩE&"rMcȺY7-# Z[,(R*B)>ʒNrFbhkڡЃ@E ]}-q(K۸jݳL51T`ey@^%'./>8XqN=td֌--MƼKS%UFJ4x內9N(Z̓O9yy7Z׿oLwCٱy#,^kE]N3bBY: dY3 R)Iı4ؖw9Ny_hGZ>.y(xAOy_7P }|`eTFxÿgqGnln@j%Vž +516oС8e6%s׃Oio^u_wQ -%1~ZZbEwrŰS|j@gAWP/DiQK<~/;VYp߯8okpW?|+/.9y;hR%Uo~<~)J-;? X$;)Q$MR6-qP^ \ ˛. [G3,ca( .I - j=f!jJg:<`Z-,iC+afQԎi/:mN%NZAd$[X3ndp ġ8c"aJrljFZR.3i%ZIJb}95AXBS&yEuv׺ڊ\8˵~0I&Oub9 ֙mmK["v8RP/_m/ 1uFI͡NX\ko͚= 6M7- KL(iю3Ra=e&er<DfHv{A*l6~r.|oS I mo?Uh4쩀t\]`CxE|)jڙ뮩17iƘݫ9A9Cu$ lMM)ȡXZk^f߾ V&̙lC IDATDTxdaiZ`њDK_bJwCh 9ϭ1˜)99?)Y;bY3n'aSf*)E&c2$PUpIjx|hY)}i"8! ;8-Q5cW̐I>$Ɂjb%P6vo{85Jw#I71N J9C|OqN~pᇓYj:::^ݼL&rFUr8K-l.[@I7?[mu}% (/IcOJ3x™ %b8q h%<0fRәDq{"l~G%ҸEƗ)֦lF)A>fhBR]KTIy~s8JZ-vtv2VwpZc[G j&,G]g~1)Z 0"ddqrlu wt!< P 9,Q.&kʨ F`F)h&nz5ɢ,Z' z,RT" lbͮ1M5X:E `j  >q)BmjI3(2 4}9#7+up.|t"GD5%ڿu׶@6>1>mSb&x N=M{],:PnȷEnڿǽ/ I ,u]hr8o蔬o@_)ÿvAl6"B(Ag9giO,sM*FF`UU5ʖ2$I9g8s@C%o`yȾ(|?s.#aCY7O{*کnkS<%I7c-CNI<Ɋ5S}T\I1gϽ/9_sVFzz{Rm(1ٷ(Ѥ>␥Ϥ,O3ޡϿŋaEs%4u^x;ŧ౻#3:!s4  ]uiE9tRN;lv=w:Z]H8 Z%.Vb' '?84T[5}LF0azȄN&a !8dt ƣkBl+YWs~{9`F倖qJ@w^_:2h)loB1le0KfQ^&Kv5+P 5G}f>/B:j* HQv?K$n]J9!ۇRԉz:T S !)ubuf=(PK^fGJ!ROs K;i j`\ g%%̈́Lj`qV~k+,lꝺwt'!ijY b5Jdfujsƍ >$k{W(}Y7 WXIkssx5d{5k83d\wup=sNw/% 5+`MyvL!L/H铓)ʰGPf )x 1Ҋ |m6Ώ# %6q` ^)4OTaM x*Z쉒[0@!'A u a=E3U1C(Qd(xH5Fn$SΚ#<&v5+$2%C*9{[Vicy׮"HHQ,l[6bm@[lŶ66bQT"rk cc,|u]Uk9לc}~6K2Րbӻj JCT 2c3<Ewdĺ: -nCӆbS$ZhY/5Z V ]^LFlBYi* +~ ek,)uƁ7"%$t2RuA4狟6JNPBb|Tn[2`nyEr! Wc< ^~+Pc]wn۾Q')'K~:8lN?FG&0@3iyJA!/HO+>5W[  yt:,(hSgzbǡHe,_ a%*(aXCONqʂU ,h 9A- b4IW_9IuڬC (Șhg\Vcw 0HjK'Q% gd6t#9B΃ fF,S@YHS3&⿼I8PIaLҺ|^2r0d XtlL:6WB)YF *Z* W*I;$n[ku(EFU<>*"Bf)ZC#[$.-ZBu<<Ui43y,5|)B_aq85 }z=ĴbCۀ+&3u%\17g3S{+ 'dȗ(%i'$4)9u]ڠY[ %)2~$n6½{.{%TfgX8wӏfJJ=s+z z"`f$0Ӳ6$â<(Kް\ ӏTS8Gzn&: J%7LP9"5hd%>J{f'tjrS,5XE[bzz}{\pyN/BZ!TRI1ϊ"rSނLy' 9ؗqO~fg)9Wsnߺ5'˯/^w=MW1Ǟ >yU?ow=7l3'>/Tv@ٍgDC3R501ҰT+cOZW+ kVV[ow@ ACD‚sZ X|/@GRiL܇MǹG0N|&ٸ&@KI- 4 ANҴ:>mmYY_Xʾ\h`܀si6{~۾q`ZF pGA- rx~J:2xfǴ+v#\(tq~E^5% =>JXSM#K5#KyoS} 1/obxnKMos7qމijajd>E!KRW]C(n(k׬&yՐVۡ* "@E=%֖m3+Yˮiga"Q’,ݑ:tl+q]B8iL/6F(* ci[FPK ƑL&s(<ۆ}k0 `MəeBPlr؅y9c"?Kc4cSmUxR4qɥD*jII!}%0*`g^sT贞'w4Qt,R/u11^tc.yC[QLQynNci 0l4LM'Vb=?rN>\pY|Sp~L٠ {j`_ ~Opy8Sr8u' $TbxVJtK?v%_mOP{|HL;~Rz/—ɬAwQRSݍ^ĦaJ <++da.J呫n724%kr4m\ {0' 88eYXP8gުye^.{ߵ׏o=/"On''=-c_-5Gx^Eaue[a( {xJDXeYx"+גE__4:S-BkMekU~r;btZ-ycٶa[o}\-~|{?aU _Y\Wnf]3OpP{ w+ ȲKԛkp_ حfG׿AjR}Z%eIR 3#Ey_f:Hs'g/ ~q&((lKQBs|{4BzyJaǚ^ v&Uኆfg9T,)[ g]H!ȅ!tξ" "MykX&5Xхhh֚$0m0jiZ.wz"0Hʁ۴ƙ 3PAAS~-fQ9(У+''*( 桑&NZV iEIxm/}AIAwQty\EG%}=q0 h Xք$*>xA{Xh'hIOCZPOӢAamG,h+.(r+(>AOeBj{k/Td } F!+%1qJֲmẅ́B f"SCi%sLt{N&$XBVO\!+G3Prtd=vhd 42fm,n?o~0rfWS #C-:<.A,Kl#Sg}NғsbbrJS`QkX.MbS W{_r16n ԏ<\2"s\ K=%OV)`N\yym GCw5:S ==I쳤2F$Yc g\Ī%y"?TPgBahL#Q\C)<} _$ e}޼9 FɄ:$V H3x[GTSHv:COd$&i) zJ=f[P,FAe򩶣ٌd)W4ؐfhlH5'+zx)EOgi3 8fe:9'5qIĥ!ɇCIA&$Ş~b`G9芤+F|ӌSI+MswZbHrHw!$$*b#(s`JJxѫ=}j76zVב@I̍%(P KN/c7={'yo`>)FU˗wdvMS,*~DųBBtp#sy }H*'`[]R͠/'xjGy`+-M#1=W |/s..8b.[~8G!o1my;hٖl:^B|?ԣas_Nް|3'2^u_2;/~#tnC^+6M5-O')y^{=ݽ}s-`޽\uU\|/&Sܦ $etm3Vֆ $S5˂.ÊpzWX JNCK'Mb163z(#`n%/D}L3Qx}gY8$M5q^^qyCX.PLV-UNF$ U' י*V?ј+Ǻy>徥 /}%woKs0ci{,jϮe `y}y@eB!9YCjF? z$2TRGX FIWRzRN'I^Is4##^U!& dLN/]sغ5|75@qձnd; 0 Iso.\挚v&rsH/h֫숣?=mx/^uWy=Nu_nluxK)(9_*gHw^/8Gv|g5ymc-oCDY3_+q97_GTުϳH 1`[oHHGm[,6O?>ۤ(*X/Pra9f*d`IbO-TۆjxŅEq9,Y{<Y罊SXQ ,8NP"O7:|cC*1yؿg7ou=Mef}O=DזsqGs%$/'_#+>nyns;3C^BXOn(eNQtEԴ^>d&a܀9`HOn c^Wu]q*,-#P}% ~B#wkѤ Gtkg(6e3ڔy_zfuGl-R J`_+B?xX)Z+"7i"+\G6E9~~>rZu,v6I%ւ閤9D0Pvhj^0tcuo1q1zUBYA1PBch4XhoUX K\Юٕ7W_xc~>vJ՛N۝!XSaa[dΤ 껟ݯ<z^H[pwCP*u٧۷p1EHʑ|xQw{0G)|j.ᇇ%oy݇~pq/=IJnrrJŶ-[g̯ .xE,X4ļ !0m5."txm I&3,O~h6 7RG4e?"XB"kv=| /}.):iR**&*2׿=wm<;pM57ZȲdG%( Zu "gHFeKsȵ_wko{`ъ59ҫV .-{k5K4췬_3/'@btZU>4MfUXz >C*n"`RY\!ەs^)'h &ӤT eDL<+v% }'oeR@Ɍato;`D4ۚVjA@O#ԆLC;vEͼV-ehq5ߡJyY6=; X!sdsS\:񒋉r{nvկrWBR?o D2PׁnԾUZ 3pD[c'\RbJ^4ȱ#1$eIaCiPo[U)e., e<@G.&M'E  dC2[7"MS<||/P$ }dsZ'})+VjBPEKPR$\p/OCZ 3YMltޱ3/ YFW\N:tNMsCW]J ]{ mC7ZmHb3ay],G5Gu%otj']; 'g2p%8i^ fӪl_Q 14i!90QS{\|E$áDf_Kn\o'*PxOOd(L7UmMf,I!s"K}6cl¶ws)پ)rTw_!u6/ WKD3^})~ߕ /ƼsgWxa6E 8cs/eӳlٴ>Ͷ4:8BHɂ D]}`^+8ugЖ9֙hn=<%( M3hpOQPenu'w=?LП6Z m`e)ж׆ y`bSW/GH-TǛY?~Ӛ4-]-/,m٣r 4pc00o)۷nfp?|g|? .Wp9wx /?knɯٸkyz#>/ߥ޵oe0SI#%l NCߊ MF{ɴ:Їn$5Jyrbv2YtY"rX8 Gd3R(O0ݖL62%.X2 ISP,L-Г(O:V7hN-}_r{v̛7Ot͏`&6Xmr mmjj=Ů7%oz;}}Vd1ҴJApzZ"986{B_R3 i{?SUxu`fr#'jTO}۴ IDAT-u`@VEѮJcC>5P/$+V3L7 f==J L;PRa$K;ؓ{hQnknچ(-{-ݡT~ϞzqsK7IK_Yߐg9* UB[z7/aYtypRPpc؞WB ( #]$̥)02R gf iV071p)mS=$3sh.Gق3e-| *g*0S˦?,GvLLԻ,0Tʱd8$ *J \ 0V3Xz.AH6 vް#]}HCwib휴0(tue?}w|9uը8FnH2GفnxӶp^@F}qNu7dK%@t%kڛ[:>th, :"',ݓS$IBOQ !X㻗BS<7-{/2Ĵ-gpVK>wd 뒺,A5@EK~ ^]) >wt~p9'}v|;ss 7]{~ٜsxəgvbx&N:p ~24hTD^tfC+V!8vEL]!w3<Gw"T֧i^^plLBq݆%QFy]p2Vr%NY'UcKHRCGJPGvf nwHGk};%25ǕYB($McӚFw1VF{qwGM|5(cB1ׅFiSe cej6pU4ٹ}K/Y|9[IKvBW;[#h|CDzE(xr(ij;GEB,D:!Ru7- x ar wWGU`i)u}s߼B{ӻ g6};Y\Zs5뚵~miXxRfgF*k7o.>C(6":+׺H0 XA-'`lt0P] Vb:LPdMrM̝-C+s{e^zP%"PMr uI5Ł#u5*ӢN)_J``h6L&Y`MQ* #TTx`%GQPDgCw>K"`| `לo6kaWÊ(z@_{:ϰ߰fjymD( ᐢ]!8~=|_ɀhpv,ֺZi8d9ǫ^*."* ֭cxx7}~>ǞɄ 8kh,ysdPg5%pK{moD"oo1yS. !F ,PCı1XS\ LM` IplӁmlY/4q(ƺnBo0A?</2 mWN'#WSy깄LC-.O(RT@PA*"\X6QG- (rî"k]s~0>bc!HJ. i& %At"AH5zYY0zb$o7DrペܡeehX%Xe}eUւ8zɇ&u=s Zi7wy'߽x[5\-܌ !eLT[LYR@/K˒6}vc^z*ǜpG尰qR뗿i1JQd)cFKB|>U Һ -A0˛1*y`Jeg Ja@Jl޺׼,|AnFN&9_ϊ5ky9c-O؟쳛/]Օ?aDs ju fZNo1i/?_B8욚߾R\)g!K-ǚ_2"&(CYjˆPl ]rާ/˱' N9ZMʹSV JBYEJ8`IH_,4-5 zȚqA$&511Y/D@(ckPckB6>2ѩ桕ZkɈ4׬HFWOyv(((8#% iƚ(؄_igOs;SԚ[xG<Fy?{>x>s'ygr>+տ(W]y ~3 wuWY讯zzj| _`պCdmRI`K$R ,`UJ9\ 2qXS/\Wfbk3 QaDā$%кkc LG {Q|ȥMNaqH_NB%Lv$o=>B u|G]Fh+ȝO:0ehfߠQQ0CE92q x6L7)YNHX`*9aurp5ؚ)Z2Nq(D>x.5vdIJcAFKfl* 1TEv= (A]"iƛ7"CHIz⡈Uٰ(łsG,c`ĒHA#iBuTMNa*֊.CLDw7k(4ŸIuoNRC+&d]{X Ā 1o@*+W99Z\|&v\x/lj#:ꕀ^MOL`DD JI_ x١dǬAŕANֲFN4nfRȵE Ȍo`B/gr:1 EA$1gyLW_}5'|_v7so}-W> GqG.:qc5\JYW gLB~^uPtJJTi!AJN="Huf)2I" ikr2L:(0yN\RB(,01EF hHĂefޛ-e*#s#V?,E8 Xh $UI;5(!hf8/nP& %Q\$ P~+g _@:9RdiD'%̐]sh®Y>R0\ ,9ׯGQ椝y:9]42OQ/91IE}_3 C#|C翓>Og?Ur{: E}.zBGGDȽY1׾jo?Oٽ}kp3Gu4o;ُ~ rxǿ:뺓(P2S ) KX8Op{ص0r>̧>!?&8c I:LNL~Ǐ.{ȤѱRөo3VmI/ ,ٹ(YN]aBpo2t,;.8 J,m =s>}%1ߺ%Y8v7D&qVTNRKE ^=}}IX=L3qGTWq|Os OTg7redt%e||ℓO_]+:||_TYʡvk]~>O͇3Mt])kuw>9ۛ^8\W3|AFgCpʘR +rFWWЦg(GP CʢA fRߐ dBP }eBjI G$i&dv%!cfa2>-5/Y6]#(UO8FeyPp^vk`YGrbԤJ̶4S76 ת=ϵ"Fk4m ]9T$ Vc^}DwyN,9HloxvJ2&pY!̣[FGC&fcИzF^_"4 H7!sX¸$ފ`'V$nH鉙IX ^oϤX%ͽH=[Z:)AB&j(j%AGٯQ4^;|K"/󏫐{ڙ]Ua]<&*Iٜxsqo,)HBZ@;1)r*rP. VtKAQxӸ'_Q+ z.Ds/| 'F8*!m_Uw5:ɵkmcI:k! %eLSS.Xb"YϚ^ff:ybcyA<-=DJBz{(w8ů߼x??]ϻx^Ƌ_b. /n믿cO1["J7^)?>RخFџ%;HE9ڥ("ZҮ^tx Ð80dc9Olj ֿc4ygR :hT34,Ln1KA(=26R8B I,B@4Ip@O-d/dj^N^/뮏'.@*(F)#S$ݬ/31IZYd:F=&2?.ByG|#JXtj(@H#5ʪMNQh~ 8j6 qF5 *ivq(d}%&2@M0aheٲY 8WߓaL#,#w1UޤTBmiuA$ȭ#x⋒c@SXΰKKEγ00-Q.|S?7:zTJXdmu7h A’^@q.x{?|DAFt5 u J2c,b@p!ؙ홨){ >SO<κoip}o~n,ȝd2[a}]&(x&ݏYS5<9=KQYUw<1*\KK%nw|obByh߁ J*B0:JKl͛6qۭrM7-e+=o}9_EQn6X|C\rwO扥#ki|c"M&''X|?GьwǾ3Eo/Pp jU_A/27=E:BO-^-Zmi4@8pg )€g'/~;̵E`ѐuT_Q84+uǟտ4߸" ]tRL'"M Njt'o``Eb&3}Z[:C CЖѺdE:ܻMS=:gQŦ/nsrfcY#iff7dEY3RFP=e5kpNH<*AH #"'* %* IV8dHOXQs<6g1q1m)8ퟳW%/3 PM"k=ZKA=Eޝt]ltm Wxn>gm Ce[yn.x܏L;T0ßen}:'-Ւ:O^j$>﫰s7/%˃1 (6LxXI+"ԒK;ۆ$Vi'Ą,K5S449ZEMQx\ Yh~Ut9p]_g?p 9:acH1~}gK,xjk)RA(І4/< E_ (G=TL44$ɁKK-Ǝٖ7B&ӹ{Q>s _tpl|(m{=/jxS(IN9v.g9re?WLquq衇?C/:{O1QՈKBAq k5JEt}fAcRTP'JȬDRP }~l(fr`?`L"/ hg~J J$$\r?Ch?%;%ю4vR`)8rᮧSo3O)`;CRBz 5k4*Ig Ae PQ-u 3Qv{:i7jpʘ[nv;Mr'V&Eɛnj:YLB (&Tv'Z ,-s-FX$F(a)o)X$-3Ǹ vϤL9Iu G+(Y6wdm( #nOdqz"q{H@i "б0^\2%o*ȥ$SN%2 |s~~ϓ~[76lD ǯOA 9~vW[@F I'ǒN UmY 37 Z͵A\Nt&~W+sw怃~}K77d+PY0'40ӱa/R=}3+Y Gx9j}ctzlQ('K|{-?}ܧưel6|⠐w|s$j>kw%54;}h^th$4jm󾽥}$tQ0Z\* 9WQ"OH7Zإ1^PGmBo,F޾T L2M9 Ľ5ʢ`aiƯqFvlkHxdV GVܳ='/Jkz}hIԸJ;[Hu]D 뻤HaAw\;^zxCXg(W xhKohɼ!>3␼0(J= TvdO^GWcco_?}1jʑCXԢ7"|0P=`%1oHa@kuCכs)`x fT^JVp;G$h_D%bQںkf5Kz9*߻z'2: uTT"|s=%\=(a9ti@]O&> $#CYs ͱG1;k:OWV+1(I^rs1 س277|!*,Si lN(P'(dT'.1ru܅+,ȓlO.9 OVű9ک!ӆJǻ!|eՈ7ڏ +ǣIW"Y`LY/f $r>KEѥXK&TO'b=]V?Ht0Fc;;q $BIs9{EQP.)+`sͻȟ[ĊRA%?rcsAXԂ[TJUz -FVLuF@1N mս)8F*% V }U+zKPdj쮭pGGq0q缬SN?'QT۟9sӵװrhN@Nab4k)S-Go~:牶D2VPB#\vKR XӫNbE$9D2eHȍv5NL4 ~Ihx75'v:Z' ^w6Ƈdؽ7{O:o˂' n/h3MێGvyɮ1:RD2`qlk9"nE?|y")B?y*ɀT˽oցd( B;M;f4lZD ΟpP6mKPVW I h&͎{i*5ƌ@Q/+O (tbE) ٲ7<"PoOzJ'b^/lpT}  miX[%hY$BH͖֬ɜUEO% 7^<7|_4`M-(BG^acg:X+Vđ|*2%f ,!R P/WGvL+W{f&c CO*&+<)it+M -(<̥"pˏ)r\wNr1]'{dG-i禋7_[gi%9 -?=4GNR{B-m᮫V!m= _?fIt:y=cw`~QifZz(eJW&2Awt6MwH ZZf@ 6L]޴lc%̳!YKV'-$ohE'\O( lgvaa7`,gIȵ%7 7n+[v|Ksȡ|G&XQo@r1ȠUƘl]vTzUCwLN$))?3BkSP/PcǼcuNBㄢ)bBJMډAJIo5fZ1L|H_( x9'VZ1Irܛǩq`1N]1 (V55=N$@K_!JfO9KrQ{1 O eH\kroҌ0VL&_y4Len@lNSJt+%ӷ7\>9o|x_6skyBH/YKj׹U N(T<9mH5TG.0jKؽwsH 2b!sLLMs-ח^ _3 Wt$djxAlk˼t];` r{7%m,n1a,5qJDʜ[ ӕMˊ&†ל6yAl~O< 6/|%v4|cs)qsL=y;_z5SX|%xܸۙ ) lXѧ8@p۽w5ok4R+ D1i& J4L@0$ mlؙ2tM"zQH C5b"gr@j;F낅|{؟)Zw[^_N{ Fn~+y%z6c/$ FV 'h/h)) Vd4#]s+ma@K4.)SWմKKvr(ة5۔3s'Jʿ hdJ@@A[+Peߠtڡ#";,Ԝ#‘8 |x۞ a)4x0Hśt[3.V Fhd~m2gq0ق;SGH±bX1\BA O\J]/-Z~ ^]B\6)V@Hwс*v|ĻH7@;w3MCf"[ s DN#sGaXɛ_Pԗ_H7`)Ma(o@" }UA}D ٕY!ȳJmJ`ҽy~j\7"ޓ#QiRLLwtlY͵IHoR*jt] c{Ҧ{N8ToBHL#D*㘙\ 9U$aਗa@HI 뜟d`hwh&-y氹YI ͵H3K.L&i]X^vNq¨9ȰֱbqU"ӂ yeiU_XrHnn, [Lb@Q7-&Hb* a# bB" tWWWu8c.J{;coF/}T18_Ⱥ2%۱׷g*&@H-ݽbV*x*0I" ($c |6k')E g-~Lb`NAsL6A#SyAoфNsj(AɃ9as/4%ҝWi)R92(ǡ)gS:0\/O7џM~4&\Dv0m(eSrk}i4T,pv5Bn-}uJ(h-;r2x绦7ě]HYت ώuc 3Ͻ}ηqW^5rqK"_[O.]GI+9|ZFw`Fa8C_eD-A^)5*as#7 ; 9 *p;Hnu}LL`$BSr$C9GlHe# Z[Or͇3ˎm[Xse<͝!·)vo^T3pL{l xS`Gpo{u.9pz|5C̞Zh=fHJ9(p!Eڳpv((V-|-h1YNv7e*1(8a0e~>9>YRxyXSES&4=} Cc v<bs>F<x,{Y[͎n=wp\~)_G_?>@)C M4eץ"6r3!{9;Dk4Bovk:{j>c2mH!\*!Oi'2R^ڄaFK^/ *H$L$d;Å"ц -3P1MHBdAJdQ5w@:]lwgvC&Q,lkvKurp"!,Fq|q"M֠5%`oH%, ۱|A!c;6@U jS-(đ6?G |iL4ƐuklbXP=*d-[(0T5\KXt4)R:d3.#mz4ж$#Ts,+Gұ)ڕJuwCӓ#"mA AX# QD)=žg$1`bڋk;ygFOP ~ ڐ:J Սŭ IИQ/h3JZi7cvMN xJb@DPKJ`fA@ DeO,/3$Sv(jw:f Bc!x r Zla*eo L334hNvzMRf-gt G,qI&Jn)*(vMjuE+Քm)ZNs*a&+F]m)l&1;_B-ԔBF6oMi}g83?_{x[I1^ZU,d")t0+rh9{w|2ad%d3}z@|%Hez:Q2׷ eZY8D5H"OQ;H~~&ݴL$cfí5Kjښad2Zf31FS ]g^bkbN%43:܌$-s%ECBTO(X)V9a:8=Ub<(Gco .Frͦ\E$G4>r/R8tUHS3)bP.Lua sB.NřD$ A*l8da9va͢ڲ']ɶQɺJ؇X`xyODhpf /5C^i4'"(„5}ğpҹ)_"ȸ9"mX~wEd*$aƍӯf=ǯVYL5; )HFt:"5S5=PǼG=G+&ּ>Ʒz+o|*9r|?C>Ͽs_:@wkDQM Jچ%RXVFdY6,oΞ^>ws;IKƥRqff`AĚN_NkBhQxt,\NWW'υ&PaOpsDzh="&bw-pSV-g}j.;2Y޳lAhk.wE8Kew??{`5OlYݜwsu,v: 7:1k{vɓc?a|td{'PĸLaFXh;\C>?O~[oadetZLu2T9י!6Շ꼰#"is;K3Ajt0@#x9}s'Ys²"m%6&[T l^HAwA#X]ob.RmӉvA5ʢv5B9!R*0v"(`~OCjF LӰlH\G8J,h#*y\nwh+9Vkcݭ.ac$fբ +x]g]SX@Ƶ5C}C82i6-m1X ^y/bnxۊ"B4 elOdHޞbEFsä6tj唓 I5+ϱaq3䭷]Ϡg/WϳPcx6 7W_(<7|3VۺqF>~;ozӛ(=gG?oۧUW]u]GuY\}!رcG}4;v;yL`M qmf6HAj8%a45tIc5=%%08֜-vZTc! 4Mt,Wj8'/cJ >-*`oHr ГL&0^͡ݿ~<̜5?W||HDu+هv}[ %"12E>xݵK Ih*&:Z B yGv7;yk}[rW )x>$qڎAVt 6sx3cu eWrOμ^P*h^~/~4vյi؎틅ݳ,SVIqwާ-%'crOk  HCCbxp7G7 O~~m>19i"xqDa$I8\ꯓq4]Y>wp#SfǘaxJr=^!vl!+A@_F+XE/42V p=ɲf0P,Z2QiJ\4t$=-Yj%4l0= 捛ЧMW[CN[[9sN;'~ WF &;Jp'>W.i򙏜Ο-*ebhh8nօG?[fHG.E-֨4b~5ՌckgRJH`I#[2N砃˺٨=7U5Uի8M8,Y{Umsw#<D;/0LHt#ujWdlև(a(2M YKگ[~9 `P͂J́JWZH4lO TDOZZNp%kĶr%=- KJ!t@|FĐ6/Y2Gk A#Q=zU;3I~_sSOzj.r|AFGGsΙ+nzK.dJoo/###\{zꩌ5kְaz!n}0ڊLBo+k6nٚzR%2![ g$,IPM>Y"D T'lde#H0]#1mmRי٥0Xx _:L'I ]%h* IYʒNoҹN8 %y_%$& JYG &lKpA蘼 (!YN,1 ;Fb Cz#9/'p}}}y~!yE<}y-01>ƊUs挳iA(\N'_< u w w`6pť_c$V&شaz>{/%> PNNy,[UFkh3 ?#~,+/ǞLg .u"r Q ,+)u9DnF|C0ixY33rFi&*6_rp ;SvKi)vѕ)!`v@^3<}c~>\|vm'?D!\ҝUԽ<9/d`JXԏve$ [ 5-8GЈ:$vHӤi'BJz}s-_:4i)5q} 4,.v,*;n['_c` q(*;r6<2;y2NXO>Jc,;48$DQSd\bhԃ>EQJ6%x^J>026o/h-:f:*)E1kJΗDLRky0YcTBc\h+իtl|j;DzhJhZ3`vF' AV.)Z"Q&afC#1TJ 9H-F AɇH'Nߤn޼b7sF[{|~5گ/ ~=)ml!/$ f^` )S^ռ^I9a0& ^Iuhq\|}06$.<+3"~"4tꍄÓlI a#Î(08'[/ MZo֬# +۹u#'u+'\[W\d0,nQ;n\7)DS & |k 5jJ76YKAgAiC:s P <{Bq3d쮤x` ɊՅK Nscen1e#6*"M.Y>uІz2}Mp_x{Ӷ86B9feBmWC4Daq" 4=%桤0dbܺGF je8aIƔ#0RN _eu~Wmvb(8I9dY!t+ޘZx!qDH5L|T[9({<ir$mHլЮq"rr@-v;33,nx2?`5kokc QeVZ_>0'? [lP(L+WdlذO?6o޼M`S{] UM"F `6>sT{Fl$ZP "6fyF؋u8e] MP]{& 8m]4)qR'<>m/ ph#~4fS7j5%S0"{LVa 6/O 'l ^ r-eШp'ʟ/PD8A'%#DCl,Ʉ$qTb9,:KrԫujjjA5,&5$NhTSN (EHA1g͇S*PTpM sՐhAD%z[jL\E AGJvSh<T.NLHeI#AvϞ /(Ppx] IK(ױc6H.i ¡hIbčAuv֚Q8f?Gm[pbSg8y#XϾ #G刿^]Z–g;Ճ98]5w}{zܹkz1+z^RSIkf?bɉqs՜Syxm:|$sh {4+O8wva>vXChXPl/ xz 厗cPt]I)+YyArS$MıF= yiP2bd-!K ca0d;Գ/sКQmWg_q3ǟx _<+Vb |7ЉfJ UHBMOpEWu 4 Z#=hh¤ #uMɏ~_%BT=AgKgF ΌF#A"@s|6flug$ߒr,_1ZYtt{L%﷡TGs\ve+3[F#xr3df i"g,&qJ$bwC#JY_$q -oRmhu]B%)f-yII JXxݒ]e6f 8 \Gm,IJ $/TCG Kf<^'!;Dkx@iKՄH9LL$<,eAlSZَI8ktylyaS$N3H #5Ѳ&[ʀ0FRM桪}.y! f{΁:+:IbpMfaI33.; $w FC-  ͔cFU' H^R$$1 [`T.v4"+zZadSD[2`呞CQJi|d7EDA)-\h$ Nd,!g0%BLj(唕i^Y1 xqs8ϱ()tnVK |_kXmjA[AQ bφ|Pry}߆7 r2i 96lP%aLA%$Y?.&=\͛;8 >OpB.rj5VX1]UUJ}T*166_/JT#=4@A04&-"5Dp#uL*'k{,L2 TM5^iBAs}q-+[6QB0a}f]o׭f|" ci)q *_(=Ny!%[Q+me,;&ki6Ǽz"cǧFROyan Ww#VPt{HGHiZ cۯTaEVf`P|T@9{"hng}vh 5B9݊ u$F7j}(rUWP R6$H =m.C)6 f,2v_<) gRW IDAT,;uYG֘'"2 }/\%)9!) F$x J8;wN/ 'JG [DI`yCtxJdj l>%E%u8ᚯ]΍?O}\^}E74O2\(ϯ_KD(=0g WkT87n'dvb@ڡa6&vZ!A>; lym9E9{q $_(N[7c^X}p=Ig|eZpч369IwV0U0Z$f|(Kܾnn}̛7W^q9wziE.8-o=8a2(7q73ٱu+.hanXa素;9m}+$.cr]G8)a8g|9sj͏ZS?al^罟S?<mXS۸9 x|Yp8rÏ&XhG6c^}ʛUP *ErT Q#jaU#a,fv6pRC 4V8} K4^EVlK!`ѧ`FdSY}B^7tv;LP{wJ$%IfI6)2 ibdyj$Z/V^Y'$TKF,vq '+CUmah(OMQjia΢l<@Pg5Q szA$:,5C10t<|\y&&b|Hamk Pj3># DņMfzt`LR8ճfsOw3Rms.`<$SG R4SRNm1!MJ.c'k<(Gx{1qwpg}n+G}'xb'}1p饗wrEMV((rLPk-ժfhhT8hfz֡e3K XSAmLֵC[{`@Atd4ш0yjr,+ T)ٴ?zd hL5u >dPzݲ3 2(!bˤ\R1YQO#$IGY>e,-ËnLDTVc(``v8%hhap5P㸂(JB: ETe'3NRO=2u;m~{ϧy^Vj+2YFA5yGkfb=A5G-!6IT:ɻ #4Rj *")G,y`A)~u|2\s;uL5+?a!+HI5X|6l9LM!! ULE^àB0NV9ahn4č|;7lJk?w#A¿? CayGhgHpWokm[_YNOt=%dSN/y+~D+V 2;Ev+Kۮ.RneH 4-lQdGj<m`)0X<4ON[JmM#'sWXӿ׿=o7wc]L!W/~ѝZw_k_w9_u3~ tY8aZZi}RsΊ }]p2_9װfr`NKKښ3c&ψ|`:X,Fd+4#AKʕW{2po:_ox7Y[ n( 5Io"ki  L\ /e`Ǟ C279ʒU}G1WfdK8wZs$-'4]%%ӱ˔Rc6<>=ʏny=ta v-" >7ݲ''U#>Ey8a|&Vx*ѢԐtU%ݕU='(4`IډTm9qE)Z[Ѡ™keL='3q<ksQVP$ۚ OVBXm֜ # VDoq׽u4M泅կrm̮]|Iu1l69t跸͛7~z֭[O?uoeppaFFF8ȬXeq\wmF͍>˓.X̡,ZjvBpQ@#i%v[sd*c!m-͂z֖ jJ]=I*}ْAcF~BfΡ x4ֺ~I BJ3& /$J H(:>ZWCmbhgeEW٢S̆5M Sh)J!2U1MkvidQ=N:D!f'WBG(vx՞\˨`yv.'H4GO>+Bߧ,YԭPd<\POR K+ f޿5RdKB-r7}L5 L;@0Jd5K|&2#(0ʙ֘dpѸHQBe|_AHɟӌba3xɪUOoeʕj+$~D7 oB 26p2'~&G/qK.c"?)!v>߿]|>`ţ 3B-=^~|˯8`+'6>[W#I,d_( rKJЙ&3ք_4,ݑGxV[7ԇz}~O|6ӳ→/S>2/xi WŔlge몡w`w'|"JAoUQ%l:,.)8۔z ?Fe_1Q5 ~zV`Q$1s .sXRO9- V-3Ӟ#NY3+>=1m&&L BdTTc)S} V ]cI26X=Pf&w%J(“"H45?' .ݺh)8ޝ%_2(Pj a=%Z&o{޿‡>q߃GR Z$9T+%z+z;fc'HKn,g G 2KlR6.a`io`7 󤍣[Z<ƺm-,%Ns>}:hOt-ȑRqy~*6( kVBEWʡ#E`ZI38mzVB' TVg޲Ç02੽1q\&G2Ԫĉjdab1V '<tL XvB-V(n{C3)k={&E[׌L34tϒVjTKۃ-&LֳztY=:axxA=gL6G{Yxs1{eݺuqW)ZrE|}sq{p2[dm y>1`)>vQ/k`ϴ!MF'm-~Hj[{Ah F##M. ؓ!F`<:)eҺ `&CI70ڂєUTnB[mrcuڕ]x##'񄠻,ٰ')l]T*46YnBU <*A&2qL '%#ngs,v( a ( ˑ!_Ϝeh yGX#ӚQ((Zhp|I } =]8pwzNR3Zc_=8DAw-B:LQ _Sh0ΰ6рG=R|nOJv(1ik ,e!}K^,]}(a_+̴5 >u66) ,mm۸p>`%ucq ^e&b|IAo_/]*ChwUpY=Xgx>Sx߼|s|➛KmyʀZ\y'L$_,&RppvnKx].'H {h[`KK{[)KK=7dI$F. R=fc%a) [)x[K)i&]$ඟFe-{g.|]2|QndӦ ޼[c-n>]qp)N:u 6O5ۄugOaԬ^yEϬX>[Q[ז5ɣCch*.r˜)q=] <}t Mh!ß/\_R27~phNPn9%N,u_[xZJ_dxpɧjz8's~pwiPh)$,6 M.7z< DQ5:TUCUz##5,Dvh2qG!U>z<~hRisO02L/L4@94U#$IA;4֖fmN-$)򂦵 8S7kb DA@EQP^,1!,#o@iwZ :v[2Y p`ֲVa&גmm(}G\P=G2\yPo4 3( +>gE;jH3)_XZY7FdEB=|au,h_Qb &9B(0˗!nڤ %)꫹ꪫE Yt)7x?SN95W^y;ͻٌ Y@ 0bcucu((9Q,f F[}XT32:YЈ 2ۉNml@)K;lٗa$ya:2-K<7q. 9ܮlQ ܰg,!8^^ni|VT#YMkУ\ K[,4,JI$u[LSqb*Y65]cK =|$s !%Xaqxrfl9nb$״ [3tw>ؒh7cZ@L-{|_j@ڜ0EJII0xs1/_pTHqI^<,?8{T&![Ha;.7*֍"%e*2(am3s Dj<X-m4Q|s__k?-7\3Mϋ>Y'x)%m.b镰:ٖ)k IKASk 8% g=X4dRs~њ%fw<ęx}C$7xǮ+37;۽_3jjI_UD܍'Vܡ9"*ΥΓ;&KGs뭿~w5ə4#h%)%p[ IDAT( P0Xe:d3 HH){w3384 <I[qRowe(#;~)n.k^26=D6=gsW$F^>`]AZ(dcŸ?{)=aIwDA-s9+| Y'k)x1YEnɜD {$ 9HOڜrE0k`6N8j$䅯.pdl/󊍬)vc֭>7ˎ%6渳_J?a>ib><{go|6ףPg!yݧ ߡ th=}\gu6pƹNW 4JBFp-)Jut8m AsgB@e01 m3*H`qhI`2x{Y\~аG1FFg=^֧6yVy ]jL Z@wr6W $a ci4s$C)x Zޯ3C$9I O*R11~M:iLgZYO-▒]la]C=WҔ=Ñty 3C ֶ;?#<|OXC[wZaģ۰W.yt0\Sk;!AJH{sҍb)M Ρ?p϶#0GJlyd!Kr |%Ȍ$ܹ…2 Hdno UH/n~?q 3|1RW{JShw m98| e)+rcBxɆ?{MHʊל~:QL-0"Y>08wfF/LԝVH5dcqQY* "Zmlo[Mt$׬8<ÕqٻɗZbkrdǖy|_vfoWkEh*L"*y4 Z[@4RfΟ{/+J}#s.$PJ@7cĝL W"'/Sp`G6Ss#E#7 =\A]0225x4gаQࡔt|kA*:rCC@ Fzk^8sam'<9KŹ[4>t.>8VpX!Ici%C%HKCffRwN(,rUpb^0sp2G!>Y'ڣZKH bj.FX+ IyJNT [IA6Vb0F " Nʤc]!*Gqʲ~ͷHz@JE#0>YS|JHOhOTPAڌ4U9Hr8Ƌ2#X0"=DŽ_:9PhmDˑSUY<~=wOZ Ɠ7K8[ZJOa =xۅ"\j)BIB鞷d!zHd/zF:IJ`5F~qݜ|ʩ/o's={?ccc/^;hǝg!/q™/\{^{!ϛioG!ﻗ+_u.w}j<ć?{>1gxv-+Q;I_;K.x qj9E<5ӈ-uJJ@ D?+y/{n~'e˲}Ng ,,ĹEII; VpH:_syGqĹlytU` GS6K(CqT % (ΩFvbhŎNg%.}݊\Z%C.saRDŠ56ͷ4,;AL\ޒ;O~S̓Oh#B@-(2䱸hnA*ĥhB^/H pxlM_-7~]~qӏn61bfn~<W^IK^2x)$>!!R½JY3 SV03P"Śk$gغm c|PĤyĉ3hT薆?\["+\"3BQC&GfVDU9giB,_1>[mJ2@ '[yxb(뼛ٵ;[,92OjgZYyFcJט9_g*s/?`i5ӊ5đez<.~A7}vlys nO+  .Y?p (|%=UOpڠGZ=/ ÁC{ʁ$-,f~bM31%o<=Հ3Ekk9ߢ.yێM_vLԂ!M')e5Slu' JZ[BR+ hrBϒlâFG<011[((2NJ@ ~LᙌXJZ'޸_3‡>\oگNwơCx˺ҭ-kp`"BAiXBFŶ'h c0VpPp >o0&ߋmd˂539{;"vkrOnˀR%K,;NxUL ǎv]31 74.xG GR*Ԁ)R9Gr$ vN:k{/~q+|+p|7p:`DŒuuťQ%l) ` 7=ٵwok  @WL =זQ=<~$EI!rӭwpi.ͯ[o%%O%5m`K9ZKf|\r R+N_[ ÏƢ%KY+_ _sf6wH&xY>&˻,$L'M`ud (A+5xҥprNX<7~5!ND,4E+ v' ]Kjzb3^7~r;fnC". Fgp dܫpףO0dl6?L;c&?y>Ef;t|;7lubD=mc'.?9ȊFbτ@Z3@ 9,m߸S_76۶m_&g|o]w>.8One͜}иbGգm#Fm,_/-jhJ%bO&̦&J#1#o@!JY"'B,y.x w?Bہg |E+r(h5X^x6MY'OGO)tBe<_fy(i,ݗ3䁜ZH)pVJ[zj=~6/x D:80JDIA) xH@H|J F>'՝=ZrI}%I543ITfņ!/?ue# + rDGgCO |[ΏvC$8I(Х3IǟЇ5W~?{O9Ig)Ǐ(tKbtQQlr1HY4V 7xw]Z[f*zJЯ6n=,) ]dIu3#ԕ}$XF)JrzAX5ta}[HE` Ic W#<:o6tnpIPV]!ؾ"g;K|L\dHCxd.3ȣ+tZi/V缘^'|#4YG>Un^z9V=sю1:^dH$嬣 #7]?寺75<|tNzQ[HZV j03K.PkEKa^xfׂf*s]2[!174c N$$JIp)M@>c>s6HEZ#$;T@Bw0F2݀(Tۋ1z5O.QpEO(' )že\V9Υ?ea I? جa; ڰSHX@N wf:FBɖ] %KTwuq{V KE ٴ*_mqha ٺZiuHjYȵ+JVJX.|wpwVs*qqn@I_kr~  f[xN,R;9'fc j!z yXX&B kIqZXʁK*vQB8Vu=|/k>I3h,qf9sp6wɞeyNBDk2xJe_OexZԫ>FCWTsc/Jk5;/ҧX'-[C֌o8y ]8oy 4G IDATcqU'Dw : uK71"&̵ DkdKec h 4;XX0lRq/F!'[4jCJH3K(kC72tcg\~MϤt#+4ʖflYj$ĶyL\s%+(Gˊ mtdM4VB3uZZ+ |__"_1$ Ӟ7* R$E6Ug ҅9u2C^dz{O}Sq]{c\r6sqB_Z EW|4*=7yes/gj4# V ,jʖN:% 5=H0(#s7yx3υvmnkb143b)Sw}yBq¹  IS W-[}"4f +%㊭4|'ɴATR w U%0Ct7%AH;NnFch;MJ(q7e + xk匛3_ Fkk%p[ =8n9R@f9ྖb4Pso.Q4e,`Bh(8{&7} ჴ(atdGi_Q>72&igR5_n}n]d֒$/xށ|>EAbhcK8#nb |-Nu,knԉ, c ˲TuĐزf1$]/-0#$̈́nj`%FP.JlWL!enb޳R t~3tN%a~@YHţZP2ٽ=>IV`SkHrjQ zX%?׽?q"M08.H }k=̻)4ؾZ kЪe&{ AAts(hcX7q;Jw(hWl$2K[mٵ.M(%ab㲡 `4yyOZQ.\KdU5F#9ZK|O`D@N .FJMGl(aY^~/CJ@virb>GHӄfWAw(}Obr#9S)Iᾃ85 BIt :OX=܍~mfOc<֏ph6#R\}Af+X*.p|QiKc18XL H̠‡m!q(ՍV7GYR-&# ca50'?kIsGh@IA FGE~Kb,^P! ,9ĥdK7Zr`]EH2y ]p!7u O#S3XN VǍWt'8 mHy06]F[dz=%X|!ТL j2cQ'Iswq}w~5|߾c'H T.j[㱩O5Fft'wկy/z).\K^*.jt0BOF2+=Kk<'4ˑ|F*B7sHpsd)bb| ݟN. %4|aW85l .Yxb r#k *u *˹Kg/oiTдf]V\'3n.`bd Uν/{&7n1u턾|w^wop'/},y[NG;D`j6cZY6NqAGH@7}iDIq0@ha(7$9QhLCǖ\P!'3i;Ko9'l}Pzb-㓬XYp_W\ŎnxK Tʂ]cS]\N$=Z,Jn 鈅m[y9xndr6v,T,wOkڙe1*1R1gQHk$!vm3𑘩By^&M΄q#=' geFS\u]+$7u|?|6Q3CY6:҉4IRXF>'*,r̐{}|Wa!c'e9vM`wAk C*ge)c#z1E)(P%diLYfNMs7#N8:e(%HRP"N N'qL-GxJ s&< Y@qjĀ`QC 䐏/͸B31 }#x_f$s/FܖBk'%E7vyڤ׎X@B1rǑ-%}m]4\JY<ߍIo,H^a A(kP>S)J7 cS(O"9>O?*C 4 暥u;m2ϟ:lrK,XhTfnGlܸ~?l&CqL2RsR*/ +™iC*PO\+'[X1yjyS[رPd?wz( s.?!I<%e )$Ȑjypn,<3:n}%H 8)m4Am ywDP ^׿cc*XBL5aQsѫc]{|}SEBw~'/oy-ǎaާQVwt ,0\/D΃'<~0uwr`MkAn +kҌV!ab3J)ၕh(<7,sQvĵ]=ay ~/` <~@=dxģ*l>#}>ɧ=,2XH =e&r՚TH,-"<'/",x3VoZ*%WH0@~wBMT!8޲R/ VXhf }QNa%KKs}=f]]dB!  +9>FJ) A)y4+ĭdxPRr~oI [Ep=hdž/0I5< ԧ 4P`1)K%I3xmHҍ vxJqքρSd]  bصg8:z ϓ̴ sp% t 3Kpv;#M]"qIBaHsjv5_ҍ+ t3pknІiK)xq9!$,dke7`lܭOTjM~Fs(RxXljr#'[Bh6mgbZkHe{[`=15LYښg9]Wr# +!.Y*{N_Xhm0p K%p|SӋrdn7U,{Hϣ+>t#[I+r:}):CjK3yX-a>9jiGԥ;C$g=iF$Ӱsذa#Il0Pc >X,|x}Ct/E(22XU03[_B0=L5nx x@eG9;&%:$-$$ K_q#rӍnVynR^ǘ>wy_6_Ζ4Nfi%~ 0\;oa7vQί!-Sa!wFPHb9]u]BdMؼi/xc73Wme(3.%L<`ȭA{O-hpc@ 9~GQt(sr(хcB ce AAՃm^,U=N*}sIpS!zQLYowJIgN*?#'xVYW<*VS -\- eFpk_oqϽ#>J)ܰzc*8kg*۸+-^~q*h8DЎJ(OFG"IRF=R0P( IP9 Fd_b(Ƃ,?RtaE}VFX(Jh4sF 1vuH%4BK- x|ќ}ɳ YHxt*GܷՃ Os!ehNXeG} B)=r׿fﺀQ&aL'a:dxɝ'%:eYcF):ipq6םp 龻Pq[_MO ֭ =ɻ4ggwYe;hZ5J9Y^8HWR:݂v N Dq+1TՊpV%ڸf~5913te_rΦ c#!۶vėJ%W @\9dCqd߇@9dk~9'gdN񋬡 |N `ĸHK d#k,d Po5}MNO{43@Xq!),,˝($'8sIUEmY$4ֺo/uAyihRr]pm/Wy_ņ{goP t\/T*ک$ZW<,f_nٗj 3"|$&NL,^/>䉮a%zKaex͵Rű^d5e`l-Cy_;SMoe-? +xkȎ.?)_`z.bH8.hGsSpםw~_u5kY=>zDЭ1;׸ ?%ɝeO .^"Z~LhGk=Dk.C'J8m.KS1 ]* .ݽ+]FM ƁIg$%b~ޅYʁN8*!Π>y){ :3R E;kxWE屇jʃ0E!y#3Nnc- .!:`J|U|瑔<'&C:~kNTBDZ*D^An]8 "/H GK+vMJٜx@Df*\K2\WBї_Kv#N-{7!QK)%R>E!CI$VRhsR+=f9BXLhq5DF'zX w ]WblKGf\ⵧwU`ktƘlW2Њ<'?#R`x"/J,[蒤l8b) #"֖u 8oc)WH iW7R@^ʾdS1{w5p!E:/c(C02Qb @dfnמ?o&$RX Xg ,ə !+)cxd+y+ _yQmت5I]F5w?aϹ0;sRM[xٍ!90Ab95`i T}ɂXlC Նg>Z~E/nx ןu8tz%(PAQ,4π2r<T/d{#Gy3brz*y+S`H2?7!ԡ%r)*Py,'䖊a=Vpkc'`NjJaMn(u ZB@ta`D2XA4Cpci&% 57YyBcO\/>Ud㮯Ц *DQ2Un4WZ T$Hk pjYN.sͣs) ban9G[,VȩXhdc$(bvx!/;p엂W',y 0yz9_-|>͑@>YB_P@ѪGVփ(A#$Nj" #FhMej6%]њΨ[n.AP86Ψ}|`d -ģ9]b k'B‘SDQ'-_<6(|jk."_ JhYa@`m d d$2U;fSwe\[yۿÞ>%OR $Ւ{КjI*RR hmP v^ɋʾ"iM3}hZ+$I}&7q'xMel X32_Jv^z!O_HRIT\K~JR}!nOo]y?ͼ{jHWbY*~`鐔A&|z)vy(#y>APb@F%g) e9<5yiiG>{X~'׼O;Vh ˱9$3KjVaP>t;n|qD:au##Nt|8 `@-c)t˒MCXS c2r5הJu^#$Y詈fo7nl!d %_Pd{Eu龿9 ;VR)GrdY1ݜ4t7`9Ml8D  N89IdJJ*rՎ+9qù}_X/zFjkO&XirvDFf,]T$%R!lkt?){yE*'O0`b)[9N2.0rJ)9ͯ~ .CGc!7c4`HvXp#K촶îOx*hG:<1C MDw\-%s\Rd($ql0($Q8U9Xޖ%[߿01:3ϧ_2PL4H: `qt<5\^ιhg1;Xv{q4PJ[V2`f>R`rR9ь(A1+L֝Oeֱɓ{Ȓ@?sDXbձ'q7%|&i)MC^˸{xoblb>%Wpޅnwɜ{&r͵qyg1H? _SO޸ezvIfxG6ǧ?^ھ8 z'{\;as ɡѽL'P)t ~!nxjNky9e&-[}?B4\%(8M\zŕ|a;"!hgb1,7t>/m,\b* `i"9'0i48Yےz҆ܳ$Jp&7ff#ˊnA#Tv|#:21d^CW\|Wo\ܡHL3qFvIsͶgsUn}pwS|#Tfjbgs6`",ZĆ^>'搥7ݯxHUӜ{~3g26!̳e(zKf9M?V7  Ҳ` `Bh. 5) '4Vnq6#+bC^8Y<䱯mxF8g?93!-q 8˸Yo.na6t/gu$*LhWkƚz+Z AS B%2d -_L5F*>s;r40cg?&|㯘`k6TCɈmLir F*X@KA-r(Ir'n{>fFi{4RA=Ԧ>zKt&̥I?e>,.خzHl` }(*rp-t%kJX0tF)eeԵ lR((('(Ww#% Kl2[Ai>γZ`rI3yiuR]]>ǮpDc\M,`k(}N;K/YonOLʪ˭&KR y$NB`6WGeAƎv/$^>aae5(4߽ L$d҈Ru~ǚa%܋TOo{'śJ_[E IDATiPo6A sh,9jZqSesh'D ~z&n),(*e"ǚ = J4 |AOWL\('M3R G_'qS)GW aXfEՋZ1&M03vE…}csк N5qs+|%T4+*\yJZx0T8ceȓ{c~p_j0H!ׅ$(| ?V ,>ADX ^!-<RUgfK$Kɽx;c3\{ "R TyTisrRRrX3}G /t-In) GQ TO3x4;82ҭͅ`qE0ĮP0Ҵ.4͉m<< w37q?? _a)*< ov~C\>)!Jc!OS,ڏ8{xt1Be3zHeAhV1\W^E_?GF~O:\9qbWq㷾Ncnc ?{|={_ /NX(r3_ xagnb++^^PZ_Q%|KآST m( M_QeZlx4(Ol%]uHՇ܇Pne7e+Vp%3L gR@eL?o9(=34w}=f=}!Oز/`^E*h/NRscnhFS L,(~xF9h vtS3P?FXCX(go~;Yϛ.8?misGr|+z ˒\Ř-2əjְE1{ {g,cc4$@1Fz&I-s*hRXLogʀUCUr Swg?pHP.xBdqFnǚ<|S- d9D9ęeet c|{TCM, (}>g[f%Bw<2iQhMR:9/-RtT Gvc2N4HhkfŽ>'yj|iqq/t+* Z\<3K>Ic>F"Mlnv<|8nU7]ی5sNQ8ybwObcGͨ3I>N[NmnH)+?$sx"s;2'ˠp\0:BH[[0O_[cvZ*3ް "Y[džhR %[A$7K +$iJ#x V/43xEƟen߯0& 1ۖ2Ú6V1ãVQR皝g1󗖘hO:BHxHPoiSUqNIR×U5(PJΜ$Jl~3T b[57A+v :OR]SInovdcǁĥuԸ Ͽc$J-f5:#sJvLF4`ItN_@3kt \Q?㱺QŠkaXsi^14#L#`Q0MљBU}F Gb˒OT|͕ l?sҠbiHK[IH0ՂrnIAX*3]K jyCERoxցx~ e{DGt8SoؠL9^+X\l-qG W]px9sm'aq^~5|kW~<; ]py9 DV K{ LN NY.+V披>x"{ )|&(g7u'[u_ /λW?!<f3Co<#L'+os8gdD{ _chےH.P`YѶOĄ1k(IUo x3l~۟Stas)|/>7}7OmR7 kf5b` -Ìb씓g7ٽm; C^ʎey_pc";=ç?x=&Eaqy>-xϓ~'<^䏿゚Z⒑.mUX|khlYjLcdo737͢‹;icBeҋ 5?@4ܟqԦu׾ȓ?ox "BH~!r2Fzn2[f)-.=E_4/ډvF"Vъ]22J*̶ _@3WY{LO-`IďI>Eײ?D:K}DgyĉAHO*j}eЗ̶=8ڝ¢ ,Љ{Nƛ ap)iꡅ“z;gۈ#diFęG&Sک;YNg>ZH0!EATB(+)JǗr3db_AϺ!5 -mClm㐤}e)r|qj Td)tȝtcݡ !~?COIe_ i0o{p`I,h#)fN0ӞG#KXXSbIϡYyH q+.ǹ@OG4Cc hScc,<\Q !;%ejAP,HZvlhw3X3CCh5ijɼ/JJ>VF +K.c8X8fYefRGw1V_aS1ij3wv1 }myep1e~q5_naǮv@,fj9]>,3e䝤vc {قЗLfmk4gnYҴM_OVDs#Im:XKo]%Nqw~uüO||<>3pl9$ CYkx2xR i R .(65( ڙ{3Ykskr,@YQ=<ߓ|KyiWz21(#=DMV-+1r8FAb{:ȌCdߧ?gq^eh"w/ kd$s 5vL w@TR0i@ ~>wu3E2N\1yL!tO221b+F2TqE;4YSK! W K;N3Gkrikd3[t:lɪ2,閴tfnhO%+܁a:(9^zaX;'$wdV3AlqU%=J$39ӦJ1TTk̹<ц\û5Cӑ"@s!5 p[3Ϧ@ u|P!E K]3( [] ږjlLOd08 7_\ķuN_KWt<>׽wrkHߊ\r9:DLAQgvlb~W~CL=r)sE(_5gX233ӌa`hbppL$`v6%# ЗTYd_܏=oPTƘp1{U/?L=2$m,Ey|ٷEL\Hɗ,Z2W" w~o?8'̅/#,>,]b-j) Aww=0HzH3r8`pRF7T=`<0fbV7\rŻ>S6/xY=?*7|zf4oĥ]l~_ S35{ivˏݿB f6|5ea5&ksTA=43}/|[|ou=\p'v:k7Ņ/w]47~]=L9Lã򳛸7s΅>S fnb٧o+Xֹ\C<$c513e-,'~Aimb~dńT<04 CN5]h ]\v/=US}1Oiѷ%=L4P!#|;ӝzL --SVښZ#d{ͪn&gr;A,'+Q+\2 nÐEC!tXVk,]EA%4e KnVa}2zKRQNr&MA#N&m#I(4D bJ8nXqhy.*R}]nI* 0yBJ-3!j<'5,=MQNюnd9U{t$u$KTxlΑ 4a'0Hz<| Az{r"r(z>ӵcGnߝ׳-7PRNZxdynh F""W|'8Nv5Dq34[-X;#vFlw;󠹟iIǦgS4u_ZX35Ўrq͡ŋY8/#EkGTR0x~yvGm,'JAï繡hdG!U'#(,x!FGd |eU%׮`>۶=f:-9oå[@;XSET؋Κ<籗FܰBNV(E!W2*E]M&Xӕ=ZR*xdБ;nCvhƮy V;|(8L7>,'bb*"x[@t/O%,J0״0Nx-wl!=7#Iȴq @"!Qog̓d)`uOiԙsc CqI=2̵,KM\Rt$['pM6`O,+-<#} 'E3ȲP"ՆH3n %!"C\-||%q͐R GױkӘi5dZb 4h'.(3X W`SXs\悘:!fT ,8"R}2(*Co |bs+hdx]fg8崵,]7^6nM,]jW7yYk> 'T((%>cqŗsik#,(Ifbhb *4mVۅ $y֮brO}gmh>k7ū|-o~u,1v -#-;>W= /[~⌥ g f1$ ;k/R;I:v>6|ꟾA.Ǟi_m1+ﺗ:BZb+% Wm<ݽܱ .Û9g7/q3hLofm=ܡػs'۟§>xH5SSC5=Vgg1orN?Ux:"}a>t!4/tyVWz;v0g[ʻ>a{zlALVEOo/^| o'?>]goGg/P)XP $Tg!ml>c%Ixf+ral-'je(sUVkq`l̂Naϓ2W㖊ͅgVٱ'bl&CzRAP =M7 [ӅJ)+K#*$^aSkClcb?z R@ TH`ˮHtUV7 dF\N;-K^E eQEr&*HVs"sY7Y{ }:CHfk5F3a,KǻGy~pd#<'P74m}=61yE.>y!RHRY"dח k4;,rmLb9{ ,YbHkДWPH=ò$!*ffnR 9eeco/{ ˖׼;n {$4ជX[q!GR۲Z;Cb =%!SMA<_rV:u{iGm&6k5E:,& P9GV L3uoz ozf/+cq'̹\o|1L9̽ma*5Z(0JSNJ"u0<>74}ۻ R* p;?s.a}ػEnf3Xt9<  s+F$gv>y7U各| GoovM,\O}^L%2T 65ծ.^|vvNjTd{?\tk7jmX/2o |۷QT؃|[~ʾoAnwLL"`a䲕Gĺ~Ԇ#pkL.| Ycgyq@&A:ce3Pe\sܽ[kNu9SH<,cHLSש* IDATfEkGy5rK/8y{? O}׽V͞폳G^a`RFĎrin%n*ڊkImy۩dtN+Z4#uM% #=KML"Vkep1wbKjEG{MiF . +iuf_sKW`yh(GJ*zNsI$7읊HrqCBe)qƂYRPArR -zJNMp%vA )\zyh]D8 Ɲڸ,(wҭK9 ڹ3k|~H37]g]iZ$Ղ>ec骍$iP.(z(ƥ,_`ߑٔ1rQgi(Lne'XP$QC1|.yEc$H36 I0LDa>0WJ;! ~OnarI;?TGRoāN#536;fHO 8u4()`z0}N _UˊLETI:^s h4S<X!L=!Ks aIαVZ iQ;`ƹg#J`PC }=' o= yϵK8fYwja]AH;J9806udO`o>SYsnhXWz!6VCI{$ZE#L,J?}y0cl>Aƥs1w u6gA,7927 Ǻ7 [`X;ɡ\zziM8RAt=U=]ܱ |r#s/y63XXRs}|!]%Au6nW*,)X5R)@`{<߰6qjkFh&&&ig-!,*%7sq_kHsK! YPQL4 -r/ndauFUd5q2"A=u$eDb)Efɼ>JfЛ12=Wbc`Ƣ <~-6] 3[_˻Ia.]k,Znh,ո3%.)3vC} mJ>0/{|{?f!o]|YOVu~}_ﺃpb6gy" 7|Zǰ|*NԞ}%ǚ_f),9{3̈́XI E2Jioz(z[=1M쨣Yv=Qը G9'8בOtvVyalfEf&&9so'VkN?^L&9wpwT[mNYxI( T aRZ5X)/ޱ{C|Af8n}N 2 ڙ>7 %΄u> Yf'v2@=w_r w}~/pWb~/~/n.Oj83Y32 ?v9]D:Ϗy-&{{ijΣOnv`b>GEDQFY 0Ib5!aN2 mpKov4yJEI). Z dGp̲fS=9'VHw8gR#۾rThX}(3S mXrevMٔv8B)5SP[ J׉ݽ% W\Wf\J[&mRft9 Ȣ$WSN'1k;IZ[c@*!,}t2N@Q̐ig CB-h&R((')0tYGʗl[kh`%)~HbI)Ɍ%sERhr~ٰyr;_?=2VG39&Ӓ0IFg|:SToc)_1Wu QQle Ksp ՖɘYДtbKOLȗLX,9fWFz%Xu 9PSl@Mu>ߝظQh%`c:Na11BFtD`5E&OP? ?H;U3$? =בk4ST)-q{L Fr@X<<xRҰN#P,\H9"«P"'WMS^F Xs?b :KU7 ]M/~×x?1UoS)1m*'rDZ%xfBSnz\aE-|'0]ca5t'}׫O>|+Nx ?Z*~#ֱ̪l:֬[R{~{8H~ۻpKw>Xg?91e֖X>_CVRT7Ǔ=BׅeYw]>/]&.] Xo)RJbmEd8AgwϲH4Y3HU[6=n9\}=0}'%Ͼ7s:z 3ϝǭZt\|⥕"~5W~Z)DiT&'*~p?|# G]{$LeDg kgpgq?fL =+.=#|Kq'p{>a6Gt7KS#I ՙ)mM)цV520 DCHІ/ J}S5jKc8tljk>pf9hڑaGArddyp/V%l 9ZK'/xaŮS#00}&ZCbXvK= Ǭ/8~G)S,Q*pĪg% q5rQ!N /Rw>Gih4 xJrP @1kth'cy }es䂜ЮDX%@ ASZi3`dJ2 >v)-l- \qruX6:)}n˛X9I.^ׄtD :"|]yLk]acH1zkؽs;r>zfFvA&R51YNRKN>s_k,- ^f\aL>3!ZȸKmCEM1Dn<1/֡_ݛd4ҭ,:hg,/+&M#ʾ3{Y됇YWx/7-ZH"q/n #F$)@1'hwh<` Gk -Ħͦa`0GSd$aLONdtbGm2uv{?˖)'44łLyKN'`]EZz.M:I4PP,zl"e%v tiY;:ƱXAy)MԪ12+GwRqV'"Jݶi*VvcBFGK$IITiNrV`o'Lk!%3X?¿Ip$2JH K6&BO!BO"Cw]X{x~?^n}&ʓ(r,(-wڤ4qVO:T'wwB,K` . XK`Q\QaЗwD[4SBqP/lѴPEQkY{RE+|[wOӪsigqDZr\sƍ3=%=Ry?ǭ?>\}Gi_)^rz|_O@y>>GxEm T8kTּ|,j3m oͲdOM3hAAZCNh\0zrsjhY~rg{!|=iw@*9λZξ%"ḊeFHR 8 ^yPiA.yq A.`_9?qA.gvʆ%5=Tf&@C_NKCzy;>|%ħx幯e8gF(;O>GH9nqn1H~/iAMJNzx獷r)gCJwhK)|Feu䴅Z&,Mqyp?Eq9pŗ\APd|cB!-KY?PskY7}m`y!xY}΍<_HSz˹lp.َUʿ\{ a66o@%/f{/餖flDy!I{+>;816(r0SeG<%f; ԰}R3݁N1+>N,nQfi׆2H$6  w ]pg;1CLE Kc-~$4U }i95">ʒ$Yqu!o9O$p=E)'I2(inאIF&hyOvq .A,;%%w"9u}j3,s )(B{#N ϧwKBƦb yE_٧T CIiO1FK9St.lt2NL1T Ѷalp@H.ELFxexS$UdiƖԸtqa#$ CB:GZJ)'7Re;FzgC oN3ɜ15'qlR䶘3~y= gwD8b-C}T[;jLM6k_^nkiVt;W[ᆯĝGKF"tĂgP*ZX4m< H)| nv"%)B%nkyK{]؟\d"!}Z3ews9q;uR^N~+_}1+ԶCE^P42hًzԙx~4nFi~"h% M$i,SvS&m2IӖ6bKONG`pF*w*! 1/ m<̠;Rbu^^=Ŝdfhg<.X)*yIl$9$f!9hl|}Wsǿ;nJ^YBÞ>B]ś O> _3P&#Jy7rTZdyzLs5Gk8|E+|V Rs@&$=edѾxIRc%C>9W^~i} LUK ժ&<$Ig-"TZ,e٠ODLG //N&*$Ȁ"$HX pkޮGXk(Isݽt5 סUѢ;nlG$_Hnj-t IDATtbCL) "ibJ=ѥf?@KI/B,# $CEt"r?;4z}d筵>a( };;3ra6 -B\tFKS+EI#,"M27M 6hceGIE^)9N&pd7BbdW Pp+c3f,X+$cs14BE'ugR yQyFsh v[I>8jD2q$14XQdmlz{XAz94 eJ҉%?uF溾RDiiLlYh%t(`p޼c_觜Wx4b^ғWDĆx=äq Rvmk<+Wsgc<}i@9 ّsݷU眇?pn`xRS  K&} ܼ0Le>B.+G Ք |Yf"*RNr@Eu%RH{'bzK.ѥ{-Ƿ2x1C䑇aLNޘYEQ!ă17d倊ănC $yAK1z2A!0 sq?|Zj-%8Wcf*y^fkLűYki@G5tf<ܾrg`AWxBQ esA[ sDK ,]FVE])8XemE"%Nn2Cig.ڗ u}-A`:h ) b-(KWcL$%f u(I :]IZ>XUzc Γ 37EӐmPPMɬ /9j}#>+!q(+\:KHL'2^Y 8VuݪV".Ō@9`*%'R.Fϳgө>'(]w'8bt?ŏx'޲5b rzUZE \ADiȋE%pu[g & *C1Z# ArS9xn33ʵ$xCs__rsϾMSȊR<*^:L45}i_s:GFϬΓ+XZ ɌaI?_xO|Ey׿9g>~WlFb  ls qYï-iF %gph?JK}JOYv/lRX, S^%+e|wi| +>lE7|ro~73iC˺e%3Su,v BfIb_,Ft^vYo{}c{8 [[萘jdxz,`֭mk~ޫ:v4 Ŗz-2`9nßNZ2Wn[6S*kn!Rp<6XO29Mܞ*Rv @.Is(1N+#󦘧_hN1?[>L*ǫ {~O'jzGz7?d='iJhG|ύ%}ZRǗ(X`gq"=9=A#4'^'Ng]Q$7xA1߶<όgęei[-n }>F<X+B nN )njYW%Y[o; 1r0{ ?jdj`B*GV>(ҬWsI'`4#M_޸vY1QS/6fn8aX ^+|>yC ԍϋUn鶵Bk3lL2^ ws)'/0R,^]۷~*) A-\W4 Acܤ@BHvVak0 <=1Jp)p 0om;/~A |_ażGw8ja ,+,3,[>])~ X]ó_.w=]8=O>Ǿ}G㞿G|r>v&MS,Z"K=H$׷lۢC%szC#2c񺓸گQ}ѥ>u,Hzl8%Gp3t9C|9Xwq~k?ȥo}'8 9%/ajj(tqk,ƧKāJ_o/wkL nv#4S6| ]H G-bQ"5(lT .QۏZ RHa;ш m5j%X+h43FʒLXBp̺Kt5e)e6Pm1&fT$ B'VDAK rSH:6v]!ϒŜ#AGH2tKkm((' Y;s.Io`6$ZZ$R4.'"/1PNUIao͑4C'MT؋1Qlv?p􆒥=/禮(B T;!ݴe٢Z; V_^03SĄjWP ijB](X:q4ւnLt ֙!qf 6 /`#inB|?]qPZ`RM+sn|?? V?E/\΁t T+J' QfHRAd414% [9oO31E1')0[8gkG-cH_;=$y푒w酈(STz skF䜃O]}5g\x>r%-T`%'2H6y?pR-/;tֽh>kͧ?vN>(&C侇7PtCI{$ya#m ?| בf q=}wm͏?ǟtYzջ$I e) S}qURP4bC! ͟﯑o?/o ϳtZZ:W\v5(p?s˕CT_~z&eU\Oaxrv7[``pW/kom۶׾s HI!G |s7%TÊd mř&2$nbM/F[V<~sc|{?\R(iE 8xj̷\¸3d.kӶqWM(+0a͒rN9|`CU.ye/Yܟ#=r̨O;3 ,R36@ʠLit${{`k=y9%BBd 6x$v8vNM8cx~cOx0$$y}荜[^[R/*UTmW|76 hNq Zt |a(WR I,:gGS4QBut뜧gq^8gBb!ԐKOvBut3c(vĪ,(oXr w{^م r.W\cL;ǤI>=IVJ;vƓ3N9x"uTO v :<ϗD6CC1SM3_DJ=g DsWr<6SkZ \tb|_296YbGq@g) Nv(jP92IYf;A9+T62@_K >+'˜sA/~3!FJb9C! ZH: A #5XfXfmG/3@I/@;kbspɼzQS88-xJ`tUPĝ> %d²+h8cs JE`=/=yd)EWW_q&lpō7/-Ϥ<H,]) h5뎈ԪSK, u7YfsSNt|*R_Xl)$fwDIgbύK͸1qwY(RK;uc (M.^D!abd!EP -r8Ia"ev_Aͩ^i2?;C\梗^貕aK~~;ٯd26^y o~(s|14,.k$f,PKs=S302ĉKX孯}%KV\ye>CV0۰|[㬳sp>^$㩟nc(Oߍus,s{xbW8yE |0zXOь,>bC u4B*m?C,5#0]]&g0)+!5.eTӁjHl~& R$.ᲇaq(P7{12w-G9lщ 4tb`@ͣBƱ˥tsd6cǑ#a Ͱ7Mt;3I{| \E%ހ02Dfz!!ױnQ*ÌĩAy֔yHYHƼ|Qqd:"ׁXZC ,)d:CI hz3:g)ql\XAɋi36.05X|Or1f#J9%G8: T*>I{ɚӻhݽeNZv뮿ٙ|wm6Vnz5?O8eZYJ]e#*S-E=u櫉cwEW|ʊ+,4\Σf$QD4)G rVkMS^pgSh?zx _B:R>V8 a-yaID>t8âc3ϋ'7itam+& @Ƞpm9IgI4HDJT:KY2 gayxja:fْ ӎǗ~0 ñ{8IVi#͔ZS]hv6HSoW"N3CϑT[ZD!ΠT)bc Ś9cZ) ,E5VLXh(yk $I3$O Cd}"mIqJ"MW&Ooڛ^|K^ATfҥ ,=tuw0<˯~C&_͟aȻ^{=O 0^}o#䣜w8{d -^r!\tLh.5TGu +9m; M;Dl8E޷ ~=SQoC;[4c>1.*gd~]e7b/Z΃? +y-ceI5ԧOO?P#Ki:h|c=ܿ=wbj&95̾pŬ|}z}~T)$EAu]ThtXpƐD; VrNnZOi'mO9w=y~0H§;ҤH֎zq/0A{(`lU*ڭ@Z{! $OZR+   QfhFn30 k5GC4 rJ,nb'AZWT+:5G34@Η\6DͭIQ J"Bd)zsG=&h0!N]qP \@0k\,(KbDJSJѣ( FrE.7jwgvJ |IQ,y E'{)t#j!G8Pȁihkb!ţ-!cE?PTJNJLEBU,45qq;t#MƧcR %Rٹ&9m10Gͬoz# {x9ĠG_WW8K~dQ69TQIuCwh-Qsmᶓbe_|_vin'ugaFw"99U2%8vPZgf`4s (P N`yl&љTKr` j _郇Zsݔ =9w[L μh=;~p:O:v/ ɁkR"%,:Զ{"r1է@W[w(I\.KXmX$OfOqJbjAP  ]]JB-4J"a`S=fiyBu<#J FQd`̏$% "aBո\spkw/sV*֏0ArTy0 57IՃ2 Gv<8Y4J8#yz,"snc-[Gn#gqNhg2v[SkmZuFQJ26TQ2q XZFuy/ƎGgȲfZqh^Jy'<:TKy=ƂYn`ޘw_8|l8+9ʾZF#h! 4:vӜo{'c32 x_1wq~/[,p*رi q9x&۶jD=2S˹_%=}Owǹ k^5.qu7˟AG8m&nMX,x[䓟g֜sb./.fmry%0dSOg=BBĭt;k֟EWo=>dڂ0B>kPP*ik-f3A#v _?w>+o}A._⧸|c^?M/π.-}-2ZR:f ^KDdӚR8^;|Wڳ6d)Ѩ(KOM󉇩ΑfwU~%Wf0Tcr>Xh'%1Xd!`aPBR s\{cxÂB>s8Deۣ},bQͱьTrRYf3m*9e9cHDhˡ3mWYmM W#5;8T8<1[P^T>Zk+̕CG6NuWu2A*'%\|J+ |LڱA-H2Tb䊿btLY eehS&n[cǴ(W nW9PreaɢfM}@8ܫYրRl\3]7,^\ZKPOO\<w6eeJ1~b Y8 ?"f SbpsY/<'G ls5q޺>m(#< cv.U sOSX4UDft$F2tLJhgvk^6 ~C'"^8R F'()O"`7VZwdB_v#yZB>hb.fl-D혤5erl"+BN]g~ϫȎgزNHRKo!,ye)\} +=gQ9Xp P;z/$\yXv=NZ.&^ISؓHXtr H.x!N%KHp,.EMR&RZeO}4;yRIRH ,q&@VNzi蕼2I~13 -Z}xKJ<~pL.Jnc dBAתWўykRw+$ЌOf'ˆr>X>B _FJ2:|kϺmyko~(n=%IJ-2(֤m B)K:JNP) |cu>1^ӄ! L7j-J Z:# W|QB3pRFx ,` |8JƇlC5*e8&ɠԢ͌4ȩ AP!ؑ 2h2PNJFTts<ؔ]GRZFhCwA1єhk(-EdNYi0DWn`kFJ6sj(j3E uZqBY\Gm,]39!{/D-?scs)@P5Ij1u+r:")%>" 5kHRTj"E4[qAt5,Z6GNˬ )Dri^LPiINIRPN5FsK/%p[n}SY4CK΃9708gv]l6,5(}s+ecw+(lN?4B._`hx3֝/}rL |/}_ѿlB#.~v2:8Hne#|N~o1s0S"7wg?7܌y< *=yEyM`mT+tTP 7(K;kO>_ĵDٹm+KX &{diP(ƛ}J٘#{12Rm )(m=!`iͣ<}7]Kc\q6[aLZ2?My]ֹ,{O"͚e9iQŞe7\͊uԩkO]t51}AiM΃$O7J俿aN]C zǃ\AHI_OH?64@Xb.Os@4䬡Xf'{ $.qb!e߉zX&ļ%Ӛ m9ZscX m:Ys3'+u:!|a7GQ$QJ4S' hQXx?ѤaٚwhX(ρ/Yj),#BjhpI/Kqx3qJ fC^V$IB^.z?񔥻hGODÌ.Ij f=?;=8B0tj8uĦSŗdV2-qՒ熱#mv~Գ,QTdyLulkUKOI:Ȅ,) &n*~RBwO/_x[\m_X s}|3੟}</p1ok,S-끕RK=GPKbO0~~N=<!zzY~Km" RU}4X&[o#xp\{mxvGgTP>Dݥ"VnE#Ԅ)H&]dql>б λ~ %hņT1t *)(J^!uLqƲU?8L\wq_=wy'6pȀ5RΟWo]M] [O? rX`3GrP~ 唈a5\} B^q7{azP2K`Y_ 13l@ȀKV0T[XQ8UB)GIPh8Xj;X?#$q0MQ)+ͥ {>Ҋ bWؔ8Id' Gg5ն&l61:v<+0F{r`g_Laa0>ƫʿߢZo)''%o߱ GyǞy( RBf8sc0 Nu-r>@YZ.^H\h͜h9~/qpjWV#? ?\DÙhƆa NCZ֜[fX~ $ԢyRP牵Da>h#iч)Ec5kT ӆ%3zrBנ,dh0A7qU'f2k+&X#81!k{ԑKhfLRS2W>;Gjєʒ4n!M;raʱ{ʱ39yŢB)rq&#%l,l:"KeC7c2mvWv 36͘nظ'6̶ /G5l~9xէK y 7l";OQk6 Nxû>Hu7YLT޻ ж\P,.nJffX\O;F|Ŝz\|ɥlg?5K*HXH=K@薖hx]u?vWM+75 M&$'/kA)/(%ѶD[LLƕ7FO_??xByb˸f?\)]lr?gB*}TqA]s dpfhab6z̅3 #~l4{z^8"5۞vReSM~(E6'Cot+qyt#!Hl/a(vʊ-]F*`OA2IBg Hʁ`.EiaF+sQb0e9jԭ%bxm%е27چVl9e8`JZB ̈́4 YQJB5웎z4efpƒ01Uc4m\-4vx OT۠%PP ܽYęEFNE$8_ AOVm^)4)#p,vMqd|Dsh&fLA[ѕV@ NcIGC&53AW)H=E Ô4nW K5OmRKZH |YCqk,I\NLE\iњbs4F+] Ij#8%{ъF A]PD{=F;g@YMs$ 5Smڇ~F%)bMOYqbϱf<$L rֲPO{Vs FY($X1Rd]h6cף2 P5\vjyafdZp̤CVCO{GywޟNJjW,r/ƶ CLL ɐEf!j`66"jeO?O{cVfwYϟZATkwu/K.~77pv}ֵE4YWM!l_z$^H(ag .u+8rpMnaqptҢʋ ˭_gF~w.+lٺ|),$I$em8ɰF2zl1TRnjV=\W#s# z DF=w41>$M im̳q8oL-h!-/͍[unY2g(W@9|p__K~1~nN贖9|߭*bH2RI#ƅ]2vLgd + Cn\hCqƠe0\tryNɵc#\=YM?e ʞ# P 8uS` B%X;ʡ(r:K.w|N8#v \ ]CZ &'>ΐ ˆ$˱!=ClAh$!#ޥ; #O"d<2t BX[h2BЈ| lݰzNgBI.۠8uş=V=9T')ȍ4Ѓ(<;Ѹ_ 5WH hpɍ+7*LcrѺX-iD' 4BPQk*Dk]mr]pް'9H2b!Pt,G'}"cv7UBX] )4bAE3b\3, T#28̋^|w|6;λM[1fsT{ }AlfX TAgCy<ቧEyAgٸy+\u?[L/5!2bt]'lf2]5^rifǏe4簒'鷰~KΊsD.y9,GٱF+XjgeQﺉ)4ݷ0?E|.<A'd&D% gG {j!H`%4m:LٽTbúZD kI򖉀] sb&X#X73HکaEN`)ՒtM`༳(Vq(RBg)yv2T 8N-y]:tRˡ]|v,ӌœ;0_= }e3p0N}sDS@]DAoYߣu ɋ[%XljiA Z~l0xL 4:CFw@I Z1V+ >cϜFc!,o X--i:ÔHyy)8҄V?OCfTXvPwrx <8YvnZyn%N]Gobhh82HtIna(WCb.N PL\3+RkcȈ(8t 1N/^W@FJ˶F/s,ȷ1حDAr3XKm+*2min^+ۼ-%B[3R2(_҉sZ~]1G %Y-4 /BF(<)x˅>_}?:bhƮɧeX - f] kJga`'kfjhennZ5-ih1( n§Gg(J՟!\te4G;Lp*RU0ba8?M@R6sO|bI'Rq_yST -޺ ,9s]E6iV^ëV)67ra>'wY^P*9t`/s'=q&׬8EۚֈϑR ']>cw&mwmru6>n KS \s[yφM9‹ܴ 6SX#|RjƀNbhΠ,)([;͓j@m/ C]g`'Krm}W1u9p2HigpY5*J3\P䆁r#{2Ce:1W/$n$,t'hM?@(6L\oG۴{#eCMҒ(ʊnРTpﱂJR=^~ yQk%I-`#hA7,n"_,%mZg(mbpZ9cevCÜsVg]ΐ^Pd =6#,(m}%9+gN qYZ`@Q@Q-Z[rE<7z(]N76<So>ɡzqNa,9v6E%P$&\Kk_ ])3XvEmd;˜R'{JER_jG7Ea)E *Z( c 3aev9'NMPx9 ~4B3:'%.ЅvEJLF,fbz&䴤iehk{)a,gGXSZ(XgdeԈiLl9'496c!O$YhM"DeXFh-sM'.JPhCavbٳ??dǎF~L^ghN뢥פS`ѬDu+#m^oF\HWʡ@ gr]#)W?-[xǻ}1omI,EAY½|ϙœo U/xF)Gˆ*ť G,5&k\$*RCdkI Gm\Կnb2qeb'. ܇MkI}X;,^L6cxuK7GXႀ6fSw1,.fy^SHbP$0`gnhf q+Vп0L`z> df[J\jXgnIsmmuR;#Be襆x%Im`nA, &/4 hMsK7w_z De9IR "݀L[C[&Fz) V$4ZHky# FRdu1x`8/`gL>Vy"ѩ+m6|O2PvICL7׍.VA]pch2(BR[qUI/ |΋V0szj80di@ԡ'P|d0̣zX5N5+$6e5qf80t" VL^k1Gy k\፰Bx>ft\,w,o(bt#(aji^.9ѩNW$P0c ó_Oh$P}rP5D;t\K4VPw0(ڹdyr+R| krjQ3'sM MQ=$>9YM(S9ݠ@:ًQ i2$P)zZaHmc#APGRt!Rĸ&AZdے uH!XkFi|^tKx/y!E$:#g]LlLC5?P i͐J K X<4,zIY>S ʓ#/W?kWDhv lnyvǧbcU조<{k/|-IeEa)Q 9g}Į .j:yFlh˨U]aXOa\!DIӤ:! )8  /^c)%S$ˇyhwc 'P53.X=2¾-R*tk`^B$)81Q)INص|ęRa:Hpt9K8"E3M_9A^mJ.M/Nj.Ojc\ Xcp0 enPm+5NQȈN 'i _P+CQtQI6lRe!2 d0XsR'OS\R 3<)x1XF9{SGZbfGyN]"\Ъ01qcKDK L^?ϙոW 2YV3_A r"n:nKC<M}P`?i_8˳33y!"wJ3)a1R('Z'@@zQSoiz_Z݂ٖZVLN8|"qa-)}3`8Oe84EI7( f.)hGyM+Ιo~z$rPErZ?/~MfarXED ##H"C6 92SEhi)NR0J\(E׉ӂ朏hG!HT d4 "g:v(WkHSvJm`x5J4Y .d`*tQyqJ\:k3^Sڭ& _1{vct6v^ayݛ;3F/(׼u?~KT"IOf  a<seSE/Ώ`ވN''z|mRI!av)w~Jhr $Ȣ 0\6[ X6 CgAzx~ڕUG~v( @Ѝݰ[BI7ӤqZFCGVJL#vAN"Xn87@ե(6|Tܨ-TO)qdA6ԅIS ZœG !ŎGzrqfR]$m-hͣsgN>۹9r(b[-IeؠG]0>2N'0:SNl<8T!/\CC>FNJ "%3qԯ$5*IF+7!=ݢ7qjѝF|&F˵&[vNR$ x<؜ʑm,S*|8\%lclMyBS 7xK2c=syBHG2²}}B@SiU+FG}tRQ{iN^ZgEK4C)EY78t[q/h뚑ZɥgA9:\ K̢`x0@ Ah=@]cys_C:='FA$'ufy&@wTR{5Hэ5^Xgآ`e?{7:ͯZ5e47dFy! ٗAD]K4]|i |OP aE 8XrxVsefbeȑ؝_$7(ΘK4Y4L Z\N2{'X50\x91h#8g}++NJ2e;axAc,CpΆpD CGs |IQ\9ԓtYFJ]bhm" YR S4[ a-Gb#sAmF#)E -I~C:钵;h8C%1 J DFM憑;ԏ./HfOS 4x6O !u@P*0{}ʨw嚼 <3 r|Za akTҵc5T"pEqJŮs|vt+_`'u/7^P'g~K'1H3 M'/i̷M>Op'>m_*LYK5kHeGشmoߴ0~ky _J6ny?\$x㯾Am/뮿 {xͯۼ_JT'?*,:Emrs|׼?Uo@emNyAű=n8K ̒!GغbT%xp a{na _wR>p.gx_|+ݴnb:^701:H>V^ej¨Bw9~x/Ӈ~ʾp~LL{8veJZQj'o)aYWSzَz6mTr|w+W_#ˋݷlCKJJXdZAksG#Wʕۏ12n6hm kkK' goX^u*NT5Zh$G[puOn%Ċr) IDATh vLm! ^p?/776'=B#ϻC# BbLL+h4rIbLB}XqE`j_H}SHh;ZOJJsCb#Qdw7ΛhLOљy(4)^%#9R } oъ >PLFi2TUL9>k7Ԙ H CB{JǛwD2!  )N& tc  x) O d9tG yn(\`L& +K_ dy$%#c7P 3[ID6r/# /1I;JVFn_._TAbq&x5ox uۢxu?t1yyg%}9x-WYkY~TEB,a5JI9ZsBA2L^DZSHҌB7y-*%Ⱥ5%$Tlbjz SN򧵓s,+Lh@$Q>ED_uފ/0gW}[ka;v5F#L! 2`p !D"80  $@BřHMν~ #{){>VMMՄݻ=eF]΃);}oNSO"Z1N rX#&ͽ/btm6',D*sMLgLOgejd:q #>\yK?eˈbK =+ zF9doOg>RǛ_u9.~}ѥ%$kk} Gר(vxDi7_2ƇrXcQbɞ)ɳ>p֖Yԣyp)g05 RyUUh3u]暎Kq^G5 (c#T5{'X|^ ϩO%jɥā#a;J0,ԔѶIBQk6HZٖ #9qs-Uv%d -|(_ad󚘣̡԰cSB_ anpl@I?g>16F:hyybpy(:I:OF)DOYm]hٱ*xϖJBAo4y [!шŖF8G)r8hmA*AF$?o#'Z\ƽ{vHyx (͗E(xYunm%MMKp@X Z[t7il (}rΖeQF4*bp oTiMPBi]J@QR8,G!aPԣMۖ.^&9Q#GC KH21n<⡅b y`(t!CGVx߹gT4-ɧ7 dFQ2Zᑂ[>}, M0VHQ^s.Q m_)N!Z Faazy' 7ꄢK/utRK(_ VF>%,#%|Bon hlƒ3hj4uM!<)n{h %ՒE TA(a10Esv49Ƚ44G!Q<)EkG9::DX:9ĵ-^qЈoQ'#M}٘RFa F.,u-FkohXyJߒ\!@DɊ9p䜳I 5{ZOt8؈H֐-Ng:de8EYc+S#9ߺ7''d]v\0Q&c+JB8$d]#КbmY{KΡa^=/嫙=zQD:SJʼ/MxքcalzA[F" M=BpmwK_}sMNw/~ڋ{YM8N%>}&W='sJ"N8 tSx0zS 'I3Ӑ{K| J"ӳϸ׽~cJ= ~ɩ5aΟ0|nQN*_Mq h 4K=ZlglھUg:;؉R粒jt•ѮG( Ր>}gP$B:0`l$bq5?yؐm^"5/h"V[9G9"[RRmKy_Kny✣ևܷ yrWsGSy9y #I6ML?/|fAidK9Cs9D0j?5^pF<3( q :3l?DEF~zhƖqeM5ǒ\>[>unetq8o}Rf9gGyR(p֟'W5QaMΙC\<K:6ƫ ')of (ft gP1Kde9F!KVxXBKSK(ZM* HsOC*%BOF E}\K>們cǺ [7V;Y^Kf[=#;6PFYQ+trAh!dvJ!R8tߋ^SΩ.sќvXUq3,(iD>>#|odE2F%!c1+)?XЁn1>Ax;&Ymt=6n[ÑC ^(6G@  1{idA U/dpz8xT 5S> C:^~L|N5RH:N4;|'c3O'er]f cW2}Gf|9S*6ITwaeچQ+ m9SIц4wL3GghdJJ'3U.CA%pO&KT& =pKVZ&,U& KHڭ QTɝyJ/omP rۆ{O04mUbI 2FgL7 漵GWj|NK>yaȵ(ޣ9o ]1{Qp Crc2J _D*eǘ_IOJ1VգeI7T fPpR\sʜ%a|ay"Zj0}?.&VTD)(Q%[:D q@1K&stS k=~7ͬ+_.(W,Ν}oyM$s6Ln¡iFHcR3nH@86<2ȹ{6#6̭z1^+CI0BnB+Ǵ=%Vչdysm_X{>@2Y%O A ǂ0 YH%;&0Z<0̇}⏷O/qߑB [9C9W$d+ُJ%վSAhF*9bc`h|něw}e8FBkuƙc m-9O* S2W| ͈ M2mh$!C8 s˖u!@i?qD@U?$(W_ѪobSKv"cܐq.c~.|4799[R =Kg"N.dRA^2=Rw=9Ob,c.NaXeeLKyrbY @[G{?`\1~hSAQ(9sk;,# $B1Rj&I9 AkCϟ-冧]8̺kOzoqߏcqnZ8*ioIjf{@Ph^}:?8/H!uSPϕK‚@$AHߌ7"lK`(\|fs(q%l"sknW.f;ɁTHEj2H/?8+$}@Р8AM;0Bk0LRT eRZeG |XZ5֑(78?$x [ a 5<}fH&vfhh~-~M]*IZ]HDZ$ Lpy~\fAzkʴZ9ݾ?,GʊdvP)K>26:f:NbV cz?dU'+0de#Bd?C~}މGxLeo2Yu>!`g-ҺʑgCB7 b EaH@(kYq OJcBgɭ`{RrSgJ L-1Y2`{s.1q ﯪr8) 她#1l`{xRJ׽{oa5LR Q B ƫ\xz}tKHn3`n`+߸-|2~vkRR!"tQp?u=y  q„M% HSC/XG*Xna2F]6I,R1X̨bc8{}{I[&JpeY_DlO~!)X@R;7Yn?x#&MsbѴ$Q J@MXA-V :)s)9.:3t0$}q$Ai.Pҁ-J8NETt 8hسJ&kKt@'pT#u['Idys hpںG8!Y:jI 8Z'ٶf Ub\u,IP*eMX/,XA@ R:3uK5?|k;?~$߼avfRb. tF]Ix*7դ7ԫbukh'~ʖu%Or' ]hRó9Z]*a`; (~KV5![&e߰r&t~f8}D"'9&[T \j" ӌ*IHW.8kBff7;5&' ΀lNd>ٸS)`pt.z&cCr-(YGX>3پ T0FaY920+BN+rmF*ڙ/94`kǎd!X4̱8eoo̕HĊ,7jXI^X"`3zʰx (N_v"deWJ)c<}LT^(Ao>)B"<3qanWmV ŚT >*#Uf4]oTy0/Q 2 8s{{|~e)%jsƢ6 dF2S-`HZZ+i$cDtƧ_Kak!LXMё/H"9o`q"זsH&ĸX vOcl|VW9w\K`*PkUt},t J2PL-r`) a$c ԡ suX5_Z}<9Y3q)'3>|t6Ya߼;3Z}CouLNH1~/(G8]m#-ā{ޜY%3rK2wB+6cܦ\84ݙD<鷟4~vş^9o&aleoxaAbc)e LtrH-Y3D<9a׹zl}k^x_(+ᦛY#Nx(=t oh)X4+,*8*~e骠bqY+(l IDATJpu M˺OVh&6g`nnР3rc tmg-vFҳ3A&H%U>LYO~BQ.yXZ^F!*t{'hYqEab#pע;>Ȗg̶Xu?ݟsݷrG3::Ή_Ao0Tk JIob %A J2&MSH l3BJLI C9(73F3/i)\xJ`hY̷,Kˈac ^V\JaakؘrhHss'BBb#.#qthb7[)|brz 󞉇iv d82āżP;GWM?Z﹍~^5)Y!B)A%}*( / 3uHT\uO%嵤i rm,*F*ήЀJ\xSrG/;z;hZ( sz5GS;+%QA!BC9kn'!,8uoE;GV%plTl4}O9_ lO4o 4MѨF\r$ 7= -%߱r3gq%EFB{lCEE3)HNkH<ꌴ{kYn1- 3eVZ#pCeVc) = ƕ5k'1Xƥ'4 Aj<=+@(;9i@ ɇK)֞̈baV~?bf6y>\)%e7oz[Pdb>[7Mwk7RRl*m6~73ϣ\M}Wވx/Gsٓ_\ݯ#<.|t&^gsOͼDqN5brmh;w7`Zm :*KҢhB Hpl!'L'<ҵ q}sd&/jҼ)Xh2d۰}B3#=To7)B=Z@xRe&;7MHMR[H|g?KRԱlzQTՖAn3$%ի^H$)58gsF4+]wAV^/dj\grWg* ō˚ς+RUb^QP"tN9^( c㍈RxX3QE/ڄNA|gJLN !Jz\iHoϷ{vY7䩊{YnɆXj2Aj1BIi$hK{Z~jam yoc-j$6[$@*ffjMaۆ:IIK*$J$"JB(RXxqucX]15|+A(IJ~fަ/Rt@WD:[`,ǖ\[aZ-6hXFn?eHȬ!h+ [Y?!A]J'z.S Yrﲩm;8_Lp2 *C8hB$ؼG(@200n(-gf`"ʕ RMa p>q)xڕOg!K~8No[U'>v"ȗ xt9u<8v݌ Ոug ~<6mi~7ƃ M0>1/o};L3oyl4NiR 6M(ۖJq(H\Mٴe+zw^nğqpK:rp2$n?p(ds~v8* 鮜Z6]ya\Q 쬈3DOqBO|*\rطg/84EOx4k6`ׅ X2U"Q=yx֎$S;f-57_.zxgfz=[\P*TkDq챣ō\rk=PNV klqe3""sZ#["N̯挗4{^jUAw('x]=5p׉ފjNh 'е$c %A,AQ 9Ƒz}RYbF!!' Ƣ鲠A$c)C4A(pÌa06QUBͱrdFvCj(, SALT*c͎e(>+99oA xycEY ض‰JNuoq _Q妟́ X]X'֒grDfF^ 5nAOtQƀsA:!2%#eEQhr0Z4V_#5(2Km&JKKJF[ B!:ΦCeΝZ,uwqC:3̂URNxIĴ# `C'|J( Akk_c*)^ԩ\ XY:~L" #*7,XP4<}ԉ ɽk N(r`ѶC!_8frm6ȼMR0xÇgٺ&BE3K wz~rE?^C[D*{7|- #Ֆ,H`*ٽD:zpln!B@IJ_eکol02bXB$ ϕ*[H$-I&VA@{SnAS|  +ވ-D /Bx-ɶx|b iK*%<6gi@7Mt< !)=KDDTU!UwkUT]ڽ6BS)IIT"V< э&g !pd%}^&(5Eь щjY/6z:B`~sZǚDSM3, IjB[?j6G$ÆR )iTs\GuL Zq4z$qNP{C4ϞVE\Wi<:nHw-gr7>g<\ײ㌝yg?.zڳljㄗ~u@a$'nlT٧G$Ja Pt6vn³zW+^ƥ<[  s3 $ 1X>ı\aG OCsP {9|?"?ѬĂڹ NtA,摟l?}%s%wslٱ׿| ,QH]a}M8EX4oEWyySz*̚u3.^>|8,_Tnf8H%W:hŐM[0>qە/⍯x{L.b9C\{gv*zdJ4Ǿ8((/Eq:šwQydtͥoh/M c2PP+)N;v9Qqza!J I|עe:1BPRR?{ӠMwιg]H֭ȋ pBB0"08H=Iƀ2ؖlV۳Yy$S*OT*]e|L3 +,}`^ۢO?b@JG\]kCe~A:HH"_.'vR2bkhI+q-c*  vǞ볶'"H0*ut+ބŖkE 8q $F֨o^G K# <zoyn =~ALT!~%]%G78k-YJШ)8D7Oq&U=RWrCOUSZ;ne΃pFGa7i]G,lo[M}Ja-q {gc`y :NJSwy^)!b …&脰317kwFi ?ˠ04#@JT<ë~cg\DU<&헿qkVGpmuhT9AJo(&G[ $ O˷yݸ(LK7Sg>!BeYA=LxpebחqRLK!񇱙]}ΓL]ﮀN%>u9ʪb09}Ph6 D,M@8f-&!3ʐF=ӊح`L݂a ~cgjH1̶B*'Hp c#FЮ# |C 0KRV {f{'bp"Jo{].zη ;,-܇!e)q[y=]j.7jdE+vSnf4LE^;?G}vվceR؈J3w t??¡0#kY[;Rc>݁ɎHEwTO56X3{ Bƞe_B pl,1JJ4;k_2N]kxó[+] K4q62=f>)E?:xt0[Ws'ӊnjQ??U;1+BON'd%U':+\=gLHJ_}aWpbE/n }TUŽ|7{sό@#9?6?kxdpxZ"BɧV~=U^CJ^zWֿ?A>dOTڑJ^;jlmDCAC_v~ꡥUW3\Krq91Dѫ=H:qAZTkZ`8BMyζ tӉOTT D K3sڱ:ڝCr?cThXOD^fO`֭M$g.*)C"L(ioީueKS gC("FDYvq蘫cǸߨ?๫CK]'HPJ2IBɅN򙭭?Bѥ, 0vJPoQP#5{jL͵IbO;01U\ުn|#X{|`fzNj8rho ZORJ qVs\Jq?Wd(JHpbzѸD0]t59~s "qݕ\+iNwTḳy.ED ᇾscIl9 o0JK$\SOL2fWs!ͮZTCqb114Qh8z"O8uhiZ,&7NV4YAgjAk e4X#1V8oI(ӊg"G*O&+No.`k=B~c[`(!XBvsPG6ThmRO$im) åFS0>s&;#ΐKץDqB٠|W)s{^9KT_ k+dg-5b`zM06Q>`KUY5~47r ƅ`86*`*FY,QԠ%ei|( Qcg6<; 2vF(n1^AT,5,DL(f~t0PaeC$d0A &IXzH9ƎV b?lFT2jXXQb":=Z^ M9I m+OGp8BQ088IΖ6Dxsi$ 4;Wq:Sׇ@P۳So*Gb%I"֞"TkF r4H"?5OˌSD"C{J.e)2 U1 *O1c%m㡧yQiJjwBRT!%DGgdڛ*#0,vrɅ[!qjTrť҅({Zz2. SInI3Q4^M1^c0gLKX13xl^>в`:0(ZAE@a$\ױɒ{BYέp큡Dʰ=r|5w4ȴcNG\]2әFW%Y%g-7)-Bb#N*kA QǾ|WO|k)"/50(*'疄j,X 2krT>$RZ1 2ͥQRm) KQZ&RY/TVD:%HKMIF1fop9dvՍyQ>,` $45XX[֟{[6뿇%VRK_;tܾcdu`kq;~W~)yQXUp,mVS?׽sͧXMDIX#M`b3ǔYʎf+@p|&`75,N)JHb 3P U].hY'\A4CBJ{|2|(eFyCbd"v3T/\h *,v v1"mwq`~վXM-[be2H8j4 ')ɞYiQV)N&j:uɠhӘH1h-%(_FQn,/^Le ?3}"R0iίqmi,ow傳W$D:ļb?W]첼3 ?.eenNV@oTqIï XYШIƩ,`-)+G2Q 2NIQzAL ,{:GG\ (JP("F{).mlRVP@BPU ]gڟΛXl{he&~ m3j oZQn==IHA,>xve޸ȁ˛9TSUj BIT[pxoB^\{IAյCklu+jF(0hީvTGX|J-G[3Cxd_m 6 V , GZsRiu%΁,wߵ3iܵ/ᅴEYi5Cc8#MQiGYcJ¼IB`o#Go64`K c[C83>Iȷ,oiZf}V"N((89X"abBЖd7uB8f"[Bg`{iP}BvVy'Jux+')uP F1I}5W,I@ 5*tr (^AÁ=lfm'x<€~jiB*gVl3j/\1%BYգTӮ ‘$5Tgύ G>geds0ٖX[ E8\__˸5BscQʮac'Rz 'BSpI!3"am*cOcJ<)NA=DΞQL5#*aOb\zq$Y [9\Y(` 'k#joe~_acPQYG='쎶ЕLWSZbCiRFu*%M3.I5X0.-$a[ B7ݨX T!v |qw1n\^]cŧPIBֻn5=KPM-cJFcw{č2Z(=֋$pt|>Tc7AբVr'|# 8@oɭB]Ѭn8mVp=5վ&/-#1׊WzP $`w&b|½$2'T+ 3lt3%h%0脂!,g1yßkŃWa%sC:Tm݂ݾ& #RM( 5 ?rg4yuF }0?kt+2P:58:p`Bl WzOFF1gIn7YHu1cphOD^uj͔ZRwcfB}0-̠r0h&vCMeyX^qT7\rzO cX8[#Piav_WSHx; RQZ,7l5N NR݂N#$!4c8}jH"0ԣm4YГk}MBPo ^NeQެ_W(!$Yi&8X+#?|21&Ek;{rryD%177I΁Zarre]g8I{9jfdxQG݂ HOz񸢖xDN05*mZ,}rÛ>︆e$UU^AhwyFHjU=if( ޸b0.j3W:ܽ7_|`4?~f3zL$)@0tioϝXOtecpЛ?_!>ɰ DLn ׂ J)f[~:҂سc-K',l4Cף)iDphN1H}gQj^},!8W[ȵFrNJ8&t"sFg-OsV2tSpiÐ~㢵 bgThq+>%/#',4 %NP ԩ c8 +-: +m4cFR%]ni集o9Ւmźө/G0"f{T2v #Yi5e99-ag*Kd`{ "3WkM´\@ܞ>{?S?G~+*&lU*7}®|nC5N/ = |@Qm5Boߒ()q'''|)$P0yy)5RE(EVyrF CbHa!߬xvGuGE4\_9NIS6O!n:u;zxk_ZPڄOxǏ"}7#ZŮes"YZpn~;_ŭ7HX%wbA|+_/LfPQ@|_oÌ ut+7-:5 z侈g64Ya2@mԹKtSAf1:߆šO zsN(SޏpbL MeI((bXʫ0=M"4J pEp驴) Μpd)`m$=%,_4A JA4$Rj0l }dQSԒVMblA:ڠ偗X15BVjHr%RJ;Gе^>˰tL50&ǤV#$,v"Pj͑C ]ۜ Wҿ&P#'rHcY䅂aa1(T Ƒtl SϹ>&-}΁ZG;뇊iv#8w- 28yVU^ 8G^hJ0d[.n8N+•-* pN g8^<"CO2%D1[‡'E^qZj-q@=["*r2w rT y߻Q rv2]I3Co`h7ͦߕեݎhBP@Ip~52>C֎WLBvziJ*mI"7 ȫ ly3Ê*T%ȗ5C~aPplX 필a@8 R" akf#$5><3Qo\;~8_c+yM_<;hOSV0ɡ_ IM~}⁧_$ д*ac(L@8\N<25,PbD`*dḺRQL|$ ʎ$0Հ}5)Fϰ.8Ȋbjh^@X*At(a8 p1Tl+L7%Գ0\1nE=)3,u$Drd1ks~3]z?6Drb_.ehc8PW+1C- xo*}33[㓇cVv+k%>JD,a1F7ݡQ2a1]c:e4X2.RzOT(HsG4ʑC IDAT$ML5 b=yS⤎c̵5Zmi.fy+Cv3nW ϝOIG@EPY8y]&>wBJq΍bpdž+XB?ceY4Gnl# (c}߻LCQ\Kp1%c@ғ4쩱QZ viGd\?oi4^?+g.`-o $?L"ِ_z8xXU<٘7n|Ix9K"|XUsL/΢Z3F_Ve<8M*I_H,ģ[dtx܈q;v = |_ud Sl Ǽ@WB llqpwh'JI:5YEV9B)HHKKq~\ӧd烙Ut6~f#+os[6KS! m@&HBFcmG<5×ܡpf<ޓ}&497^]z#OQ)O $U:JF :4q`_[vg/!;7"V֘ ֺq>RcT =اjWPCefHk:y9(>37STbmhTKXK$Zkμ[zN&ô((KM\޲jPV`')SQ;#_TVp`L Ҭ gzc/ $`ji:)|@skAHK馢B^Bm{7eNj&^a2 ?4)Yru%֞&]MW鵧I~%!{_5#_PZmHDPh@ZF;a2RO(HyŤ˅zY xis .`N #n $֜&l3c=-M2'W]C5 4F@HP yPꨈ0*"`6t\N;>{w9kϧZg:?\ﲁ}0to2< cxx9s`oat8Rgw,N#+bjlΠ7X bL Ӂ*a 3']OYl/*SEXV!XJFh" MV d@Ctg6}A#QDJSVe)F#lYAŰ0J.ڧZKF,*"2YnYT7w, 0 I?Pj`Y2ivabsh7n P_E-^L&x5[;3S{p2AҔaW5 Rǜ_͙jI* QD 2,ŠQ0PCloy6lB?'3a64g7,vSjM9}}3EF?/XB5 ʊ<*yrݓĵǏs5WqG>KτTRqM'b- a[㞗 bH]YpU%xRLkDHKY&lڤQB#VL7Rrx땳|vmՙes|A(FN@4A+:%=0L8P!Tkڱp>O~۶'}s+A)U ^;{ ?)߼Q=ng%yiS,.T?$8oxV!o`X*J| Xh2xbI= H҅<q|%!a=9NCC;5dp( iIDc(*oU4FR &؜=S% wyG2p1z>fs?MO?U>Iٷ|w:u-a^,r8tѾwk\qFk!,y_m4G]}x^+>1z&a}ha> n2 KiS'K_E刔@f{A!AˊzfE}mZ-U=ţJnޫX[FR( eiOU&N%PX&!B8=(K;i)N+.nAytqV<:Rikz#]ufgR.i)Lhd҆akV#NkJbrzC|?Rm6{{GxӌrCZy3*@-p$j-<gP x}xHgWgqd0 o!ر^d;b+|8و2_8*Prf)^n2NhyޓG)CS]ʲYqzrt^^Y"4O`SI t6(D0Fgё (ሴ@UC w.h45R b)YSU0A`滴!Fs+4N3zJ+3ۨX\o{Y_hcHGv|B>\Ĕ&/d\w|?ݧ 1r_YG$FiEnW=T37dcqN߱0̤zɉ%G-QDZ)(f-ܷgYdXOZgS +_0^2H9GЩ9\W\{FUJgr0!G#Vh!i O$=w.[ sRXK}Ksz]D:;&>_ L;H!}WFu:B N0UkBp8Jc&~v6s9 @okrsHR$Z;tJւQqHX"5p)x 89s{:~xntR]Rxw?J+{h{On=G4h\Gz5dB%+r=A}Urj=7Z -{SVx{>7>w"i]{CAylZd1`݆"NR oz O 띜p/sVy[QsWm yh5&^͛U%ϛ:K)?!~￿ !=B@s輤E'ǍH$VP*MHOϔQ8w-dL-zfo{!5Tӵ$ ktLZŭ?0-7NRO$\1B%gFH%x)/ylT[RZs4"KQTeҊ8RL']M6$w*XZ?ްLshGBe,qRC AiVBC#V`2NJ24R& Qg>c)$$"Ғ E96$' ˱Q$ ?Ƙk噪 (Ѵj1UeYE c-HaL O*$Sg $lkEtW[눵CQ և!#€/(K:[%ٰjF=hxchfÆ m1oy$H?s|hdx^qC͒͞Ilmihu:.T 5~H s-iTDvMQIb<N<}<9=͙.[R}KUeS4SI%V$`EȐ`?&oV|-nbDFyIsf'=ϽƎ!{xwZ/y*JZNZ^z$bZ ?_ k Zd`XVmB+{Uv4iP-J~k98U4ܻXQVw3$pZ*tk9TֱpW8ſF0 B \x8O>Bn<pLB&5jIDYflq0c,gbIUP!FhF]$ҎȜwnwvgy~პ?m}vг{l…F1C09tkE%1UZGVZ0TH`ycߑ5'c+X IDATvM7#y+KF@-;}T)AMZLE꽧#7xH $dMrլ`B8b:Xyve)8pWcsUk~p3@ץeoyoy#[8&az"m(Ϡ )ڿOwmo$QF3A)A4PR˂{Ec3\}A*xhhC+8Ve6m]qq/97G.QSkmS|'sfc)?s \[ C6d6D=hݷ +%6 *& 'Npb"bM#\ζIEW=1H|$;&VQZ7Vn8wJ pŐ jmg=.TF1o# 2vZM,7eNe]͖C6r|AROV50Z8j$lϠpar\W,,fX`0( Ղ5+LsS Ta6Fk" f80lvKjq s&ݏ|z8'-<$Ea ,u$\};Wګfi$!0ݒ7'z]yM|5!yM6%{v$4ѿÆ#%¡: {*_;џ|wě~$9Pr'4mBkLqBMJ“/62Zo1H)5A0LunuZC3SgE7>k'k Ajo {hf;w$bl҈{qnF㉇ڼyR14>ID:h ߭a~*&R"Kͭ{2˫\s| c,`rf `Sf? +xa!(_5N``&;HqԸa@Ԥ:'bfc:𶈬 )a)iƁ EEV ^!1U)ɶV=&P a>'тut̄ɗuIq& kŠnlm,Qȶ(/ދ~\ GW~J }xࣛYL٥l{g}PDHN1ZzJ ˨l`T:>{i%XeX"-p@ Ĭ4RF:<6SXT6 C>1F$q>?waY ɏ=e_>(%Ҩ8/ɒTK*$m7k.m߾27GJ~s}eLV8hT-\w0 aaMڱ2h$t~"* x9A-Q^h 0h,A52E^umĵsa+=;zГցX &j #GY6lV=ڕ!d [ڑ@cОG=qв!"NVH\]1 wWq33&V{| B2 ^gyyn&w=%냜//IC~M%$cKar$pL*grD#a(n"Y R0e=[CGfDq .I0e@iۆxK8J2q CRAQז|ϧ,Ħ5VTw?c:TUY`ľ7=pW?à '7߿ߑXY^$-⑁b]By#X\8o}VJ+ gX2H [KgY6a*L`"Ԣp +An0 I%uRk;B@Q[?RLmWy t b|f)GٺGWyuvp՞|3_Ϻ' [llUDry魇aTX$`;1I ;͒Zhg"[5J㸰\䦧ROn,3Q'wlLvZ^KQn%h9ӎOj$W\ɕ7 I4#Ra;i^$/+݊K=bנThjL7Y0ZXXθNodS#-`8-Ij^Ug&Ja䅂npT1욉ZeD=h 62 ^8zӭCW v-?ؠ)DK Go w0ڀ wNXD2,<44ad#/+ .ȰgRQR7dS7鷿,|ޅh{ [@W[y0wy)B#iIH1D*HA~Mh%ik̴j,m=+k^xM0(s1ACYYU߼@_Unܧ!GC Osʓ≅ Ư!OE7|szdny ; lf1_:mXQ1WJWRkrO ^2l!C(lARHa2< N_2L}|/{PT4=#/|ky_-Y\`fz cX[Y loUS0љc  9X8gJ=HcI?|KL$~ߕLyIkI+<12ap92h=@1X8w/c4spB9bchֲr`vs svo/ؽ K~WSXfET"idWw鄤v3hhUD^9.Lg*)iנ,BvIEYV(.(-h' j 3=c`kDX(aa;ݒkGYT#/< ήnc0O-pl((*! 4Q/tPM_- ٩Ɉ/}i2K[8u52j1ՊyS:<&ekP!|៿W>d\` IAQtIj^P հs$Y.9cKQ%xIgf2XުmmYk_:˷`ߎkA0ŵpdR)HJ1+h5w(*g1:Wx !B8zC0HqMHfo#!FJAڨSir0rEir \q-L;G?BC$&m -7kyϾ`=u?ܕKH-Ο||Ϳv{(8 Q0:ց cCQE"#gWC8ȫ2 $x: nz[~hXr#Z 4) F3!+j8kk`i`#Ғszy( l"gwWĽw#+,1w=w(><$@pH$`=|> ;!Ts^$N=tSUrK[c笔$ rR wpyt&Fŕ 'TeEWH-Bg@xuI#m2Ͷ)V&kk&B/=ւ^)IZlJ#*L ky$qh D)#6 yl<%ZPT8ک\0a8ZУQL^_SMMXRV9+AEI&k$`0걵|7— A0Yx;FqQXF r594ݞa%QȥKRw?3tEF)).J s%U!InSZp6$ǂ'eK~f$ӱgq$Gh,D^)-+&A7NMQ:S1,e@5Cżw?z{)MCRia°;YR58=-<C!Ȫ e+g2)CzNJ$, ]Q7}0ȖV2kLWp 5y5w o}?̓}Օ%DϼTsZ1K؊"tGflg'~{ps_uOz ;05/ޱ &$/2Luwf]y9o fFْ,K%8+c )b/Fp2X6^L]f.` ƶ Y,iFibtM'>EAm?TT)Oğzq==u2l KZܱ[T<1gN 9LSH:lx@o`: _2_~+l# ’#atSlPγ]rN_η#W\=A/Ԛn}_`c'+]epɬ:)==(xG^k{^ ,%f{PnԘYY8h$p \m/RWXk6ш#WxθT' A 1 ]w~cWY*eZ2yy^17/1qЄP qAVAK:ѨBGdyA^1@ohi꩔7e3RC%݆X$a(s`5.hv0(D:4A10 SKktian'SƅCQ Sg߭?=pNШEX/d{Yӓ*agdJG$"6s&1$ҚqՐD Ϝ`y`P±+<#S5/SUXOXTUtwl?DhD$/QE f.6ԨFQxgZ+o]_ܳQKavE ل|<+k7\Ōf+B o0ȂHF0Uʩ1 3 L1 < ;Jhf'N06dSiz&PT&0tW5I;bXy^z<Уjs㲓S?9xnɼ 9בtA:48h`kKR#A!_^]p PLX% Qm:/ `-J~x9t@ģRP=lF!G-I@JI3Q4j]v IDATDWAPND`bLKY8lUnE*s,&ao %ӊѲ -y|{+#sqTf]R!i44i{oKnag`1>4J*4ڳk(TR ,Pj:Hp`F1 ^mWh(ϼsЎihƁ=eJ%8Hbq6EXcȲ^昭()X :Xo!iᖣ-%đĚeXz.] C=3K<ñQSI˘؏`LPζG?{8c\1 ^qzyV¦mXx$rTUϽuШ ZQFh2s:RfdiE n -Ⱝa@+t$Hgz𐖞.8~>srq|rIWs^ 1*=;:(ތӗ·U0OoF<<(1z%=Jx䘈Xh 4>f nI_`VЭ  ?=6\9щ$ugMnUG.C: EQ@y0p9rgxX<|7܁ GX8w+A4jp-ʼnDp^L"_ yy)`D fcw{S3BHb2A䞝sZ7f_{SY*yϽཿ›5lmnO/q?xWmMg[Aa=g>qc 3 @kɠaLl/<9wıbj*f{'W|+875ԍ BR<ЂvGSs9OӚRCU:66 kHE1ıFP#r[DDIG]`w-&왉Ñs3-ezAZu-LjޡeC1Ȑ/llLBCAZWLl@(&d;g51h&Dxukp1>*q%,^H zDe*X'("P6GkLb낱eoHaM> CōN7`SFU1-Z!l;G99j`@ZIlIeq3K4t#|,(6 Fe1v3;l Fde "TZ XE bϰ몸0'y83`{QXhWiBO M:Z5^vE£* l4 / s7uVqV+f]26!ZV!\ެI-9rIVkqnuDeM/X7K* s>~ Hރc S"9#x_aLϟ,tSQs ylyzl q.|X%;ih[24Nl,+LHYK2dIAQD#DJj~eq5]= ~\KL7,Ws4cm`wl#AZ:x/Qm2 j Q-T_FHA?|1E*Q$z0# }yih¸qauLiY?U:0 +c(M5aj&"Cnc}7qjܴjΙ쮡u=Zx:͘(h%g * ݩ*X+ɐJ/"BRZŸl@T9f[v`\3')}(V" 4v=‰B(pLua r|®c+Ȫ@] ^yѭIi@oh%'%NKL? ޱ_XσWZs xZ6IF$ްRr*jH?ECQ4+#PYTK,cm0/MN5AAu>TjXJ!EX ij(t񗳵>ohVBcGHPm+ej#[_a]~BŒ,XNwܐ&M%={/oe&\yS>rBZI\ִgTے0'q"BKQUϰ3^*V2A'2\W()Q2dh1 *Jɳ!y2XwlNQ9QMD5$*޵rTsv' R\1Q:iIL Ne$SA'xEQ8(c9!-<.9)G-BnKd䅡LIfꖢ)l8mĘw-A8`pU=?]nxx[B0eqTCW[`yu9ZRX*"H3=3ͣ % 3@n5Aɾ`{[RN^H8!eJW45 BEM,*;Bs*^zZ2g=>G]d-<%_ 6m||o6'}GQv,y~bkih"G6,H4\~ͭ<}N\c+C=ĒO> }O7x"v*GbɌeHKO ٙFM0.rZ3JxM^rЪ&&KȜdeBȵtZc+b9zK2^/q4L%;9^`[n6^*Jayb(򒅆%P-:wnR>YY]'/ S.cǞu:3O}*ZrF+r1H6Gyx5cFd&Ipw4zک-ƔZ(mCiUox!+Z9 YEQ$=EOVBU CR#ɑb+le@k)\Wq1ZiD8=GgpK.4yƹ%RE᭣ي( C0<5D tG!ʂɩl\;3Zɩ*IQYz%^A^y^,Orq-HsϾYj(aW!u^0xM8DZz1n'Ih!* L$CKq"ɲ ߉T\\ϩLXD WNԾt$joP(hی)-(s >,ƔԻs•Te\\%/7[gg%{LϠbҺ^@aSXAy,rJ׵z>.j6r g#w|a5H3 Wd٤(+MKFGI-o8YJ9pŁ:GZ f9ŸR",຃oϝbh,ƒ 0AZb!ao{3I^*>a~aJy3uϷ8}BВ,MG +U"nϜ*}=!lYX\#3]]VU=M$P+.Ai|&'7 - k'a37]<{rO0pǨ(J!;*p@<82ZAn]`yr`ʩ#uـO<ڀWgOOъRq6; ,v"VѷXra7lR8{.l[\%N X{oYgs@%yYk],t 6eMtx.A%ރ66 oz.ݛڏ]cOzw& o{w׽u|n c{5 0ˑT(2[to7p1.<2_S^8~sX d Eq+!v8fPsuJxjՓn"H+ß l[$ CYdu' [XkAe\Ej8vNZx"3b}&^eg Vv|)LAQQuzM޳0Tz@#ϥѦ@Fdߤknا8aБ$pd_NP+ B](G6(+OoPl,i.akIVe: #X{QVܷY8^5ijʑ$bbxi!҄ոlij*j䮛ZHbA. =aw\}(-R0 _.'-E'z%P\< K XooXmc1o5ˏg4g"qz[R̒?8da 6勒re'7OI^N.r&+r$mAK1Jw $ݘzҦ*JV/}sO V,Cz'P5L`]?ؔʇݸ6 >O )< .-&d浣T ]"΃T Øi,hyk7(-Rl0F2D *H2jcrUSʹQM9АBWY&g,v$cGAxZ y3pr( t< K/Hk$DОkWYbkf[Ud0D`#nz^z]l^GyO[^f;0-c7v(,ufb.l'd{KGpO=Srb3 /~r+"lKqo#';g_fkעDIWLͶ.xXʑBa_QVH8mx/(v9sqL(&&c 9}O8N8ZCѭvYZ1T#1PT,X" ?!]~ =[;%;h F|[B vR7lELkCejH%^C JOH@d2ϔ6I,Jt[Im} kix^B03eTlPqkFX[18gܤ(+f8(9 _V#m;RrFrGVFϽ5Lu#vvs ؘ!,QR,S4r$VɰETeEoXR4 m[B]}5>zO~嵯}?Z aiFIbJšO#<IhTFL# ,/~(ieR#OSl !oqΠeHI[ =[OG%&$4T6$d=f [ |m󒙚RpxPL) ӆ$ i%[Jb!+* ūMX^7yOcJL3:!)3u滂nC2? Af%P5E<9hqjdCTrac,!݅.2 aVdl>2 e9b;.lG GkHYάz]38k, I`>#WȊ cin@jjQQ5И' 0]GQ̥o18ј3jH,^000xO/ &uϯF ݚ cC`mg PZ4qաo' v<) pM]ےt< cyur_D5zOb-.^(K96yh:Zq& _d1\<dNsܳ!*!cBc3IYZAFó} xOhDpY睼rzO>JYe:&[q. PRҝn Mz0^XJ+V |M<kg CapL%5SuI$sLiOC-X7VE` a^;0q(@%h_MY#QZ?{j.!dK]_IE}K;`Ip"NSϞ¡C/IJ=t[Pyl!Aך~Ǜ=z>A7$* RH.iG rˣ?ʙ'ѫ!"/rGfN60,o!`gO1pA}f=s"4ziw|Nozßsqq2ݔ\N Aw8(g;s(6/Fhv3nGa,yN~g=__Cng?I 8Rt i԰[apΒdei&(C,YaKDH<:Ooc.nhEF3fZ[9"StҥGt*Syaxyw,wv/q-sڝtB^N"A-ocřNnA1 Nʅ/gq3:3  1ÝYUe!5ֱX|ſ$]d<1 B7pRMJ\@+GM{nSg2Q -<-,ñznX͵4q=bcPCذZG_~|kk%ǖh]u;=׿zqfЍ%"KH.We\9{~5řaZG牓},6֔\,2TH`Yά!) aBžݒD ct¥t A`j^DPjEF%ΆEUeG63KWкf;a0x4{#]s _ڣO4ǎG 0OzN"SC踁bH+٨Xi0V#DJB*@`zXҗ뽿W˺WٽL$IBB P#v@iGO@QQDxGQ"b$@()NL2u̮*ϋk%9/ٟ=ku3a[}ʓ谂UWm!'Qӧ!T> K[pvDIPKQ s3z6K8[%Bɔs(מ5Yz2%8zbc Qg"1B\u%QաHu6%nƘk+b䶱ֆ 5y0eqNa) -QQԎDC\)f3TfEֺ  %=i,OLmZ /iHƜ^ D t]V|883.bafor\hT|wD#b<; I*%K$ʳ4"Em zVDEm528 }'_x}T %MR^6 PtbυeP:r#R!Q:Q=5T@ Ba!&HFu`GFXk(J3R}\ჷrPՖ>&_y,$i9I3 j =b- Ҵ|ydTr<KĬHӉFQ:V^& 3g)"$߉$0dmL6!|202\2/C.Rd"%&HJk (x񮏰hC_Q3Ոy-8Yc}"h y4e"7Q:LRI4 Z緽kC}}_BF_\{pC2oo{^HtǞņUKm=Mg+x`|GD1O9o'G}k_ˎm۸{g<pY{7x~8YSY4g'l Eϸykg-"YPp][GgAxzc˜CcQ0PU-#0aΓƊnƚѸfbt&R vAj׊ z)m'Sk vӉسw)9q@igzbD1U͋6ӮHA^PBRVAaJ48tb5hX+HrÁ݊lN:`0)*KhH%)rCᦫ5/oJRr̴K pBI 'b<!V^[}v.*3ϓ7xxeL;SEV*#Ғ];4">SVGbĹ@vBxl^_ck Zᨀ';9GG0a3g  W\ڦ߫Ky-HjϹagkL"] `; s Q:Dq*Dʑf1{/{_aZJV).eYp;Z,”=$xY 6;,t5R;95z5uNE ž!7Q }8?p ,;KKYcet_OGdd`rneI"<{ږXæ?B0*kZ-:r =#{F5Npc!L-5D2RFPV ۥ1Ϋ>OTht6XZ6GDp !9Z'6h"jo pK=G R1옍ji.X"/ґ%SO}$~>Qo+TkhzE)6Hf 5FM,uS[afNX), 9tǎvt:MWUE2 2-S'gT.slL4}PM 7e}֣[Ȱ 휂|p_•=w]Ցu<̫,-</Bv͍?Z>XZ) cT[i@ ~pI{?~o}{̶y%|QmRtd-ɥ3qΟA1JPI>jpMF)EQi_\u1$< ϩ,ՎO%1_Ri{hGq:R{Zve4M+rʢf}W_uÿzݷ\L$Zܞ=\6߼Fq接d.qC 6 C2,6j.Ux4fTٌwIrC}6Bjua)w]$y^ˈۿ}8ӤdTXʲc9f~6/=D Iܘ#n~vB1q-='J:Sq2.<OQy0Xmn{,=Nv/'ızѽ\}Ieu_;?K9zC˞N[lDK>:B8$T#ʲZӮ0Ҭ RVx1*zvJ&)OzgHaF?4DJgJV/)KpPy/&IbF GI˶c6 r2lgYȘ͡jEI~eK}>axpnԹ1/{6 x7ta Kҹ0r di*\Ϳ{,Ui}Rذ"n%GO 1Nr[}ù͜{i4}<ʣ|@~UF.x=cSjb2H∃;D 8 4-&hff"8k˗"*q+cdc b>(u8ZZۀ Dc'J$Y׊&s1ex@Bޜ4cGanɚkD٬ X(ϢalM{ ےV)-jS վ$``pVHe\QPa28_D*\f[!4v+OiRh ~/s=CX#Byz?Le^i: ɾ =W5@F @2EЏ;8~d\dچ`a>#K#:AFs+K\1\364LhJ#fhoW!eQr#:iR)BGQ[.ZPBDDo\sa ^n4ֿ|+vA2gq(T" H"/( OP-$qıd%2#.BxqB"g0͂KV6g/lqv_1?|sLvsrX_9$_ʠ(t{F4Qayv'+`}`q^&F#,fښ_|/8l*̽ Jpp. -IS՜&i|AC(nqi]1*|zDa$Jx"I1sY@ ^xp-e{5|H?QYI*RsϢ}3 Y$ Fx'Ysm88t`<HJB.*LkMJG;z߰> RaRGR. U̝xǦI)MEm=g| ]*Y y$0$62Av%+8VpOVnʼetfXlӇiYdb'RQTH? ~[__WKy?c%>?)&H?w|˸/zJ)ڝ)>O~'Z8DyFV6SWQpPz/sۭ_f|3 _-lxj7du "edhA-" i9qXwqjd׶^(z Ե!Ki!ae= "JGH;&ț.j v=l'MAb<*"nW`VR0f3)A| ,ծܴAPZpF5jǕ҇caT:5HFRV,u ĉ[:\cVI]YVh&[*%ys)$ <m 1wǘDrJ2asTsǟ^ABќ 덃A,Nkg{wbZ%uC>9^/˫FZ-QVsMB_rJ(bA&!q85TVThLkڎM0zGG{.cV Fro[Ƨ$H!9xxC_0U?f,=g|_ĉ]@C-7^oH%fa)΅fʸM{%jXR&oKr*'_tEe{رVJ6 a:4T0j1$@q[<tPLY6Vo+t')idB3p> W6+N?HQX6f6xI%¶.HAk~/:(U?%neofc.XԖFkF¨fG{2ӛQ@ٝ<$`)'Qv]L,W Hhx_ ?.oM3{G='jݥy?rӓܧ>sW?o|֯5hozF8E_?ai: ~l!xVjb-8ue=x?˼g_)5R^)ڦzQiSv+M; vgV^04"A#8fkĵLOpC[Z^{i +Jk@ %h4 \*XvH +QڌSyo%2tSfrFEJj*\u,gHIf!/<$ΐMM^޳s2Leq՘I8UR*Eh77`gl`a>ҋ:uSLF#JX[PE]3'qH ,Mpl 7+|*xRAYWwa#ES/IN-@&\T$$gmYO+WF hTSFũscr6Qh55Y9LUS׎̹1]L1;bD4N4Q3Y(ei&1d<!FɱcZ|Phm9l_ IyPxFe\8O%;\ņcɞw "#/EhTTr$'Azaȵ8ruK43Z ͧ85#Ǿt kJs<;1axlP2.E&b-pRW2!RNT JOQ:n?R1,6OKޓ5@7R#$2Q):OҲ0bUEnqT)\gF44(b{x,Ji—fա 26ְ&c!sT uy^LZ=jyA-kvm?4 3nRAi*:Z Z'9%'s{F^vc;

=ńtH<>xAƣޠZHEct7{FH5cݠ7r&M]!:zo=t[?n|itC2^5J@pu`'1S̓+篃bѿv#ڠc:q J cX#`w ^<'"4-bݑiT06w4 4ľ6+YA켣? dYeHkJdr[g+|oi"|'{.?߃+42?·W2 YU MwҲ{زšQȲOzB-K^~#+3Sk[5S!"ؤdKWa=Oaf:!n,!dfs`{BwPw43IQHزhi4[BLg)AʃSg[1=#Oѳ!RsSƹQb8$E$*k4?[aHuOP³֭0֒&fĨpKVI$az*708/R2mzGP\3Ë ~Wd~*  4E^gȜ-ǚF,=ь$G9mQTglIqNJxR?hLI$@J4jcuښ )%))b&҅Oύ4e۔û@Jwα1emڱ`-N6X 'ME%&3,$Ͻ}l;L+@| wt#􇆝 1BW),7No;9WYj[pdNwPhd\}ϱ]]k,ε8\szBс4 IDATyC]8(PU%Ӛ@PQJU-r! #.JB^ၕ;DI"ر-,HףӜK&p3\<˕:` 'Bcz~Ah(*ƕcGSsd(hت|#|O_`s8M Z *$[FPN@^VDҳѨ* z 3%ɉCKt39Q3 ı@ B  r x|!j,O<:EEfAf0\Q p!meyѕ Q3,RX}$<˙`1+|e^jCBYCyj3 kK4b>և{i$ZIw$zak}h3-_~ )g6FW<83O/-r(bmcM7=CB F~H֧^ߡ n7'M$W2MijS2T G9V@Nyf2.砨`38}O{Ԁf 8$$Ek#HD|Q:H#E4godiVЛkma/\C^I_jr(zus!xcT!M $A3*`}ǯߜWϕO_EИK\( ݀a}\MY#ISr,~*/pxr| ,"[}3]zs>vИ9eJO+HNw4|_ÞP̵C Bbvk.cJjO,ce*"u?ZVyo>|gϞKKv.xGOg9:b6AIJ8;,43v OS\-) fGAB") JJ>Ppmn?6͸P+=e}B`*rhW7 n<-wMszdk L%$pS`*#jHQ8FVOsy[ ~p^tzӜO yŔ, Dc(ɍta:bB$Vlv,ah .#}.vX =@pwJ# E Zdk%︣I 4ss5vjXGs~*:Z8GY͍9+?r%!_ƒOl %CR@vK}z59ϥGp,-digj _ Fݛ*STr%0E|JB9!D [UٿXWy ’ Kn?T#L>W{,+0jCDžWڐg;|ŎGG8 1WdcpqIV;] &PPZK^8 HJ[志 ƅG,Y4'/Jj|'?w>!oh5v vXfBa lmTd-CHݰLC?sC{_s!Rk{őSOqm1L-#gIcovO"YIZT}=.3]ڵc :ṮW^. og0۔8\])yrE3U rkJ6(Q~'(K%q@VV^* !NĘjp$7e0尉,D0*|8m 1Zc%Ba?}>{%UMLM@DȰ؊Yޥ蕊 S9vu|3Xɫ󛥟°)愧.\rqgCHC8^"8p؞G_sgV-YVT1w XػȠ MsQڻR!aRR>iW Lz#M3&0p>C O\Дb6 KOs' 6JhqU:ɨx2Ft4j1Ά9pDkJ"h*sIZܠخ[tS?:ßӻ 8864$TAHF1nF"57Q|;kBd/o u_j.Hv2ǮV#3%ЇJJ2{E wU8EnO_}|odyҔ~%޷}Noկo#<0j29MH7|E^ysܑa;gl2Vv!J rӯEQ s3O;읍Y)薆FQ8OͱJr;}=o<W?ϷmXO={V@- A7/JT@ф҂~eTt`QQ}$"SuFFתi|jQ$ґW ;@Mp)#%Aӌښ +O_}4xGi;GØ*Ci|(KH4XY0zq C3)_yaD4x='VI(@Hi )$d MJjDzl^{Kf=SC6vJD+x g2ƥ,4s1.X;o94r`K+f;TX$irq=ELLE}q HFk,3XzN)øzMQoş?#u;:ŹUMCD' <a(A?E>bHc:9 x6_;UI~/oXNm'2Sc2Ab.$lh7q9@wwq}1=aOX˨L7$1ՎQX6vJX R8ǸP:~S1._*HZ~E&e@ kvRj!#¨)}1'TLCZ敇)@*ーDk_*ݔG>q(T9RdΗV O$<Z7 ׹K2 T5aE9IB/j"7$2;Y:.w yC%H*Iğ@H  *0`& U0I0 $빧gWEu:oz.Y,Ӝ<ڡ!}u\袑yA=|gv©1=P 'z2F*8i9QQEN^dcAIU` oO 39ՂQ'/T]rb.u\')cȑo9Dtr™[O ŸɵҖV-D,7.ype*KbuG ϭhҲ;clkcӋKcdQo=7$qUaoHv0( k$X6fzzdD/ܾ7䌽 a250l*tSA%8⺡]g}40 :c`pbb-a۳֑; Gk#ZO|!84-rXtPPB`,bI %/9۫ghǚA!ؿ`sǑ9EV:H 񾯹vLv˛Arq}RO+9ffN[xÍu.nVuKcG]°gX-a o ްB[GVH,|cٹEov6wqzb')Mȓ'?gKHG2OPahE5f 4V$XL/<$,ݱl.B ]TNR%Ya94-Nc ,e{gL6( g-ץ ߺǁV 5N5Xio}~ba{g)1aΫ=?ӟfH !;|14c8,)*Qpϔ:UC{5E=gt# N _2 F8$Zfa3(7yP{ɰPltǔsxw͂f3Z0`QC_KBMby>;hc|.ޝz,62FcML(@Brj5'./7ةbBcd}"cveA-S3 (#|ą+c\>ɑ3i@foOQ=d<鐍4Y&~CG_aclr1P^Bd,,LX+Nѭȵ%MÊNƕ5uU1q9^k.|ާ0eSJ)NSI&"|{/8}vm54`4.jDJKfG uFqy߿o?O>ɉ #<^JCcak2JX7vB FH7 s=?hsHccB1X=8Wfkk@^xtݤ 0aWa5}]EF~kj' U mI`K꒑x5B*(KR(;[IZ( U!mIaRK@4Rֳ r}KK |s>}8lGT=:c7d$ayAZg k xq0(JSId@.BI3Q'ڛҢuNlSG G={ k Z!ae7]^I xսGmP$I17~oNr:n:2[,D띅dgw2KuW ZE?TZS^\ŶG( fɍ,:+G zr콟Ι'F֛t9.L)_g>r\r'I#1:#RUMCVzJߥ7i/ _ey?s5 kQe)MG*-'zG]kZrSfM^uΕJ8BT׬`03%k̞E -䕗KGi-nkrcZc6ӻL΃"r;:7L5b]e>¼tJEHo !;njfLUo T1rlu++8)0! ;^CJ9Էfq îiɨ, ĊM^7X`䥵ANg yB T$izD87>n%h;xoˁDEDW\{j[^Y":zq>~hjB.3>@[XhRf u _6,B;rr>#W8J$e>RNcJ)(j f'+b֣|3Ftt K`n|^ۯqVEIXl{Yf #e, 4眇9P; sl씬a@< unvDo,*Vm IDATy^M+6D:h\ Cq5X,A- 1.y_lHVst?qT2qXJ2ʫ kJt;XGF<Pkf06tz8>@*5鈏| B6gTW޲qE=uJf@oX!OW!a4H! ՒK*EoPQ/gRmJ>u]i{~^ǿL%bff#://$ Ov*}Aodk;G:xv=/=2v4BI{n乞خK#Jbv뙾_\BS k*JcP#yvm}sj_0K5XK]AYc❇6qnO~=S\9N搕-˻ӿȫ~=3qHRTߜl,TԒةо[%7%Ai.3[=BKkMw 8 d5 ~%,F}C“,#1BmX*3 cMZ qe(+A=<(F &E漢g}7R+VY= g{ʱ5!+~Z-8QVWtQ98Ж,&+#OZEdP:FPU صOuF49X1yU9T!|A$ Js-RHIʦFJґ{8`ckD^בl^zpkⱄvVD6Źc{Bcae5,8MCҲ+h7*C vf4O?͜!W*OT|]ʞHBwJ0PRʱS(RwnhHcIl20TxuOז,%s I#Ӭ![KX(K׾He=^1 ↚ggc-y$փ~ÈՐQe +6O! ZWtG1f#A(k uW0HM32rx9ds'# 4SDȩK%E k0C|Al+DWmAJ~nME"OO-]3JJ.K9}y=@kz '<ƉX^@rl99AcL#v}o?ȗz9-TOW40'шQi m=Ej[:Cvc4A2WZQW+%#=0.R 5j{鞍vڲw@P H60|}S|퉬K6d p$q@z|a'eJL-&AY#TޅWKP6DRTRn=LѬ)FB)z,S5̀h\# [f/Uɮ9 HAW#"AIUL($qV"Kq(2Yq:rb;"ۼwώ8wn}ӂ$?c̕=w1uBPp<`\B>r?{ )Ύgĩ䎅kgRRTpl-" !^hKJB,p&8 sf3Qs~9I߼B U$@Q!p§-y\@4ѐ_QMʡa\YCÉu˅Qq & FPıqy0'w 2NI-,"c/*晳K-ݷn5=[Vb@bF R\]Y2.asnH Xm(Fumwi!;-I"@8BqOzE+ DB=`0B17"Lb~nid Muu[j!̘iDiϴ8>%%)Gcb ,FTl=ѣH!n1dck}ß=g%(A,놖ᦁX;%َuKztԍƶozF?αC _do .#s1Ӑ@@Q:9No>0ڱ=h5I/PR]pz"z9;Թ+%&JkOw<ں[Ҩ Έ҈uW uvX)^vLkS0Fؽ#Tn3~JrMu D jҿ(-JJkM4Ŕ3?q=N6J+98`y>byi4Q4j~zXǩX?"_ R( q2B,5,.m# *n8797ҖrG8/7ECOYz7αGV}JBB|KXZyK_HB C*齘2U|v3YjIN vӫP|-FHWHhE>[ k,y"瘪{#Nc%HPiN!&dnMgh6jSI=\%[+7W77 W6:rp2 :V)as'-R=_9R0hO^/B01soP]X [{]f X "}E'],,=:TpJ˦^F&EMVEѫ{mK`gPRHѐW n*.xDh0AUM%2&Q%qM2t3fT%*9 xWJ?}1N5qdHoV#"P?o}/N`lDDd:NTMEB*9? .\a4k^ne$I(irhІ$H7 8$8nX^jTJ~$NJ![,mJ!d0Ь kk1KTZX7h'Z@GDtO>|LURΠĩmR3g/qtNrObEʠbAVhh%{IG{{i !( w쉸]<{rȫ/ jyŞA!y}| -QeҔf"[F^{(CHYV [YxRE-6%C3K2 6-U%iG0{BO Ҋ43MIwϑ*cTcjVoz{nns~?4XV ƕQyԚM_UIWn"bs+`GOvҲgw-y^2,qaڎޤ, BBxSChpJΨlpʕ1Q+kC^4%w2åVXa އ %~ZJM"u*Vc);4-jB>UNYv/u\RmqNb8;BBJe$q- ! 9->_ōϰoYL6ԡ;pqKg.bf6b4ӱ} R[6 mRKÑG||OSKQx*L]L35Aqrrq$(*JEP1%8 >{ŢN Ig*n>ZF8'";{/њBgVka1G9's>@G{*>F iH/Y鉣E95k\w(xR.mj,DYRpJF;y[AdO=g$%RdB(op籔 "tO-#CigcI-N)!lϱPs\1 +&3S#

=< 3;0)=MOX\V>zw81ZPR73^W|cW_c~_S-ge =p?;cm!W8OMxݭBZyYm:ֆ=Oп0 C5T0y@k cDQ41)vsݮà4/usCG1xY8?ƑJy_WV8)*ő_Рo"_Ugd2{[ۯ%CQR# MnbS7,fVΕh/iwR5ty.f}'k 7ꈩJv-ybcT /6x\kRZg"S: OhLS CΨ.+Q嵌,-.1??[nX>8Sgslu5Y ',(ϐg%k/5|sYoZ;o'x?xDQYs$sEh⤊InGU\-ߕ[ַ =vO =6\-b8@wE|>%Wϗ?>,_pXP%ΆtcR)&-MC=vĕmo X=z2x52xrBA5 iQT6 6%x{QXM顐JSXH0xzsUL |̹5ͮNL zYғTpx!C?ėXO-"OC3M xKk=T[/9G1$ckb9w%c 6vrFG{TT&l, s4ے­7/-sCWx%q, JQRL>Bu>t*?U4cO-a*R&`81\LsdF"ؔ(Cۀ3.HG!p'/ [I5Ay; 8HXN,2vۛ4cM,z"cfVhtSԕ<(mU|9'Knł8xQiʻGϙԩj.xjJ:`b}&{r%Ekǥa >)-=qbsjUwij̕ƻ`(yǝuNo dZ{w4pBX IDAT+y03 ʯ[r#g'+o}_c^ E*O!o>k4Fab7.-뎬,6`X#E7 wU>Juz2@kjnʷq:)Hy- m s:z!/e7,8p^,=bO/pLDVyfGdU8tG Mk@nx3i>ŊuF/JB$$gc$t4&.S]AppQU vƞVHL.c`OqdQ/}5^7)"0=ۊw~a?t/5OжzM74„g@`l]4I_ FʸۖomyGKyH#yt3N]= X逸RU":G5E"P:IKyN,z3}"3pӞU3ǩFƂI,Jέ;pY9ZM SݨmUǖ\Z/X#q]lr[Re]| ~$NA'\1س6/npJSCQzT\XAoT嚝Ag9,18T??uRaeNp:Zv!`q.bs}1_fQXj$i,y;y'0ւ-IcV<g3' OGK~=Gx.yؿ+!s  ev:vhNvQincwm)P-FXTl 67!#T*LCꩵ T6b!9U.5v@ƥR̠x874;i-[x1VmjivRPyM"!qDae@(M걧4'"iCLv!̺E{0;Me̔GVm'.c\(iXm"w5y\u˶1dkg!mxOQ3ʼ"/=hJtHp^Ci(ZN, 4O] 9?CLfes9jZކ.C'h: ,zCRgxVF"G"ULY6b,dp(Z&y0W2GBBULX'١`ͱ5 $ q +C;yekbK26E uqA Tc !1S;=d01!kGB fS!&<@*\6BG 3L3Z?w3Ov):]v|TrW:Vv]Tqh U>_o|-^ŹSaUI~ͷ)`x\gqR:ôx}h9wr4GȨn)[B߼^~8C~&&}_yĝǾy 3ķyZʆn;n\7X'^"I~ӊP!yf4UOvٺtH X=s՞< HĀRu?9v*$,H& 'w&l`.|nvJ)$gWK$%B9WySw 2=r(Hӊ Oΰ9t씊\vMS?z1K(Qpqb|Dτw8Q088׼̳u{c.ls;.ɳݻRwuz$X)* r;n08y(i+_:|#agxSUh&;Ym830Rqm^1ݼ/&BǤ\qs;;g=[ð Ql!c2K *i coxdL]2u욑WudU_ ICq>/» p_7NNdԦ"!seF8 (MYڄWxu TƱ]2.^;*g't{糘ZtsWӳY80PKPT҆+[*.gk Z&X0(YiH#$SoElAߎE?s Ktm,{'2- )q2&RQY>LH8Hq9.{vw0=ʯ:wh>οDcW]}'e83|s'ngUofy͹L+ܲ=߼;Vb|RIŖBWʇFBV2VfM l"ofxPiC+(B}yAB{O9qbAQDRوe. $+ 2z;9*NH6N;"4Lͤ ?Yjgc:9ݯ˯_&#:WtL&oxT,7XخB*VXouYIu.mH%Xr bv˳4%AIeԽFpMEUnl b< `kܮā=-4:$/5BweR ={~yO^zNyXh^:'ύ !p4%UHS%Qcl['Ҏ6'8giNv @`z$Z 2ߕ'_BĻh9{v51:x>PB[ og]@$Ho)(}' i<Ԑ]x}/$ؒ`*D@ Ki<;taRq![/ 4J* Yߵo>pҊ:U!Y ^9u:[ee#%D*vE-QTɐk`a&H"%Jqd_ل۳>aǤ 2L3H4)1.i9xŝ׷ֶr&;ۆ$uf:a<*lMmQ9.]׼/a8*Q"*t''V$h@&u8JoW<| &:  }薼r%bRڰ5pV"N_d:\GY4bŨp(ǖNsCY"O$ -ll "!LMM@$o>On>U`!ڒzm<-Afc*x]mQ YP:xG%"/|4^(RwXz&Z{_8d;{ch5JOiϧw(|ҵ{ngU2Wx8̚2 zC g{ܓY$QRujC%6e`;G;o?)h-O5e4 k1X5=(T T:D0P6x݁nv'3#.9+-Pki _ \SER#Ý 86%]SS/I$:YW?OC4yK_:nvWe2-deiHx˚IQHwr'?;^|a8 ~4L M;/Y퇠IMѻAc08l`e0\ESW7-c!Fs]/kyop8MΓO~ai㮗s-wO}iQoŮaGLC" R0ے*cgK]0 lEqi)m}NDL晔#a1Ƴ9 ^ X+ؓ.B#le!O$tfkTLt! ~fk ;j!>m(n=:lj 8^W@2KP]_"<']mIvϧZ+I#K,a(oL*+nZ>ʒ ̍]a%*Ғ F=Fس+33iکkZMv, r`زO=DJIgE&z_mߓ0q?|=/L6M~)v=ǗE(Yj*k24Lg0.hȰ-9x gFMdbL\Qn*n `TNqXkI 9~Z֣+&D$$t# v1=Zڄ_c6`E1B^>kh҇$g1FJ orFi0VS$;y-H+£u@xO$ 2 lfHM328F@ HW%ɼgM,䶣iH:Bf3"T<\LxlFpsY4j&tДWpl_Boȵg_m`!IQ tc`_X8:7_`<JLL)% mG?SĪ w/O&ܩ5eӮED3Yp9k{'IC6AЬJ:uAQ':k}K03ⴉ1٦d[曂pBЊKrf<pvӐAPBO\Gp̋8uO55%i ;#"DJԙiFDBcɄ= p"e9BP475ƙd>>қRCbuaSRӡ8bڒT>&=2 ;2/}-l) /C4 v-f!H`3N0Y >Y8jrO2H_-L<[cGzw+)\l R3BzR8Nj¢\s3k$W_qWM|8[ੵ:)˂Q%KZRܲ\c33\{8_ȐO6[1J(dyC#TB1{nܝ1\5dX0Q1҉ST { <˳)[A~~D6:^kZİ0_3ctKN])3_# tŕ )y-\M=aA|*I o)˸pJ*9o: ' f ?ǰ,?[_9]0)x e K -qML(қqfA>쑍F'@j6Ss,J5q^", hs[9BpC*rspsqLUjf1T"Xo]O1u !%;Z Te%O B /om#g =8V{?>/ޫ68ǥ_ʋN>ϙ՜s~K9Ocy mHOs;Ou`8惡7.?-Bnѡ+3q4A+LMw8퉣:uք ^S(%xJHv&99E(AZ{73ɘ$-*p.Le)4+/3\!6Zbms.Xym ,{\ƹl%g.WYA(RMo˚z\!|^.a7m඗_G{HMylH  w粐j=I0a奣7 5;P&BA!(e&v8`3KTX:kCK8gX jtm,A",JR8YGfs\cˀ:>tnvFaVg4Ɣ4Rƅ.8+9$Q+>zOxf1&~8a.vl=;] ǞfDKzc(WP,j)&UTž'&ކ5Ƿ/:>:?ӫ@8Nj?i~S?Q uj@jF"q>A ġ=4"IpT.hUH\;aŭ 6{!7"=Fs,l#{BPv<읁͉E53X$Ipe\1fN$4gY `lJ m娡 J0%M^"ڞBMY$IO…ȋOdx)`''f{cj5ōwx9z+󖷿1Ξ|>w "E7S70Z3ٵ{z_?wnٻuyۨʱq9ّgb)> $L& G/.>)CINJ~6vn!DfH{eԋR[S B32z.C(3(4, Ue0qӗ A^;q_H!XJ-ؙOwU8bNIDpk%d(V\ڬ߯qrNH9rvհ8NN鑝fĨp(|B;ؘ-dqcBňj8Gr5< )s ŃՈʠ(!01D*Z7[L,7՟ !PeAdT8\de;X8TS2ctHO{^`H*i"ǂmŇ_恋0Ias7&MT?A`OG0(bR9"%0^`¶A[HG3USzαݭxf{LI-Bu d P`EHZt6$r  ]8(ef W.PL'q6H,sϨZ%TC:BuqXBohqހZ*mt1ay.; Q`+'>&sW'lt+{"U#d2{`ݲM=|;A[RnhX2"( $,1L H$AI  @99N7ϛw\a>aU3'I}EH$,s-n?<3Ȱbsl +h$S*nbkmQdK@=FYϓkCO %VJ2/4:[g.F*K +Yk(u;ÊVKh{gΟ^38WQő;ky?C h~6W6+ǖG+~@H R^q9#X5{CsnWWc@V7O]oyG^1771Zפ&Vk"g\sğ0;wfɊ (kRF[P!^ "$aP*k0DnlI?.[318a,B^v(lH;F6+ ݩ`hoA"B;R2ˆa F鶔[8KNⷙrĞy @  Y䖭 3 F7>;au;%VCdg@P3ŷalq_xn]\9*L O3ygc%i#;"NJ:ӡ5, H#ɱ-<^1* ʚ8 BEQÞ 5#qx̅-K 8+I8 (k|*7tjgH6b6>)f:Uiʜsg3C~ +2Ëa',Yn^wRtg"(w'GDPTvߡkʐ嚃;c0\aYO4D2ߍXO-\a i yLFKe5̴|?`_ + Xkuц5hXrwѰV#$#H'!|2_ 8pl¥mf~ӿ7>'t!T!5&g<"V%%%ÌK=EoЅ֚0Bc(" b@(ۮ93eA^c U J>쯰Dk FaB^3|6 _dc9q8IaiXҜuѸ&*G7n=w,z]NY9?c4H!Myk%Q־d|{߶'pֲ#ie[a.Q!V[M&ccYyh;_-n1dsS[.`sLղWƖ4 e$ ؒ(O*a A+ y;+f } Ũ`kLU#A!!޸+cV4:#Mܴ0'Z=Q\!E^!?+ۑ`,.9yx>c}ÞTP)o=G|̖)w>r&sMra`p^i)౳O\$ 79^sd_sy%Jml"w.oII%Yi6Νo> mOܿ'y=%v 4`!#P4 Yƒ}mOryXE>_CkeM~DQLosN,wK;_gGmoWs\pߖ%lD8cBvzaF(ċwPB#0R0(PRT,t}g/hj3 rL"Vކ<4'ϗ~G>'HA 7}>5km!u= h-QkPd _?Y๚`4 CM)!PxIKs'?E^XemIbBCB%EKl W.卷>w)G ;E$ aGY[-v(8 ģ '[p fKK|+65Ujv6 +pHu=⡇r(sϢ1! fr',(.XM{B=73CJq0L8;%r51S]Q,=Bz;qe_RZ h3s+~2P4cq⅟>LC$ ,yip\ꑤұ2ʮ6螙HóHú` 3^ѪQTC˭Hrd)̏,2*yB/_{BK$4|#BCJ a՟$mO(B-Ei>c+_]/] ոCdv_o?Tv$۽bU;z'-gK"iіfNٻ+*^~2Eavw(PUqQbͱaE3Qh: E]lV3z7F=dJ$9Ed_7[vk)'9Ω KT(1eUV"+OC8_b-wl$ʯ1;T{13J l|xq7ZIѣ!%~Sl^90JpL c.mW8 ei%4yjF!h~n&$ܾ/a#p@(VLI*\H”pi%u 38$0=ڜVĮXlS/x :RKf!t *us_(j0)K6=)KiKR)%;04]F[Jv9%QĈ' 9Kk:jU]5죭PK"DZ/[a[* MO9S3}UVpÒ( r"Bw'"YipXOW|L;NjHjOLyχtHmsmrYͅ-1RQTݝDs;_F&"9@)r2!yYI;ڻWp{Ώ̧!Hv0iZ6:˻~?1Yrաj7׿E.\.~C6*,.os3$qXiVKJG,o5KIi=+c螘L;p<\zg:Mwt]Y?|^іՔVSȝXQhٞ׋iuMU(@cn$QHHwO GzL`k=|? <1gEeh " cZ'XnA$kvh%!󝐙6Jt^Ԇ*[g7Xݮ) YX;w_5¿ˏ_! $co5#8 VSz00{'lfR1ӊfgf>èxAXUEX\vb4~xN"L $EMHEt!ǯE'(f=F㒹cRDFtxKO9>7cu +jRgg. #iH$9ޝ-ңQs}  gӴYKߩ/U<̝#TnK%#Ëuy m^+5o diN%{4^?e4eUK{_T>C yӛY-}ı1=pRQߌ]Nї-Ϯ2; a@z[J}+4՟ѤjG-RH("0 3=OxBqPTDvӡd"ˏDID)8+9_=ϷWV*hEإI'iL* Nz_:QQn$8'dAi,09Wv N"(|o mI7!Pllhmy˫g-.l:㺣Yhyr,2uwrRθp\PVkI5XV[@m);<*EY皻tm7ʉTڱ>bݯlӒljs\px5&qqt9ܔrvJ)i=ji6gZ|9oo\HY 5Xr2⪝@3*tld E]P)2.-p74'g7q"dsl뚅k:{MA*KYU·`kʒJ/{^ K } jc: T@3\0F͸4|.&+kҜX'Z[3KܞI$fZ;Qt嗑/cfe,it=ׂ2g7*JY zZoĶ|@UƯ+mHX װ@A 6y.2 Ug'._D*R::rHΓ&ƑY1@ 9OAYYp ;v*)Z4Ie648 ը!ǂ2Hҷ;r/74/z|C0.bRLL̄VB2$M$s3 _T@E^Zj#.e׬ y_ܷC*)2:&Hb*~]{6?ujBo4|_́#װ{Qm_{7_DQD) |O>oN~O_Tw*-oQGvD Z4e(M IDATIퟑHP19dq*6;؂=ҫ,9ublbb8m.>, Lz ]#x~{31~akvF 27\uBo1sMXz˭$ X&8dkBeسh6BY5oϕϢ]: (0[Xm-Xes9{)cRs,-DV\Z 4Fͭm,C01JkQvĬm8j*mޞ5K_E̴5ZuV~kvHUdR3ZcSԵK{_J3(x?Ogq '~aIC B*/+,Q'{wc9Ihv{yQY9# %+Ue1@v#`s!k[uAXwWӣ)iӗ.vpL!3Gz-IۀgΌpR^0g /4?fRh!8/`cIF%VȏݻwN*=!?dM pa@5 6^Usu(;ڒ&D"lBnE=АL2Ȑ%ͳUދ\N9 ~7z'e IY~ 7=LCs%=&T\+ynceD#b:Mi6%`Ϝ⩕6dž*.m\2 \rqPX5EQf]?_l7x|%gO"cv>gbU%<6)뽊MRֆ [!9*qv3a(s / /|!/ciEr6EYH{:UP8Ul4C$:g0T8'}cp8RM)/~8-B9ަQk滊/l&(Yӊ%N;|bRIʪbvکX@n9Q8w~ZMHutCRճTL8K^p;)23Wnqef63¯Pv~K,eiYWl+DN8h&AXh5X kv+6F #Ƿ. f;S!qf\ m~]d XK LТu\0pF ΰ騈8eTT8'VĞ% xO"h/) ($QF&y;fpHTV0Zb@%&YA>S/t\HзFRd[@l#X!_(QbtBK.d/J 3 R";QjBTr|gIdwWpf_0)5 JJG#\4,7a=GT~IraCc:v/ġ{T{}mHKVd #/0WpuSJ:8[X^Z/`?gCOOM~?>v_u>?>GoOp_kkD5:YŴ9 Cv5%$`Xzr;s!H[Ah ?'Sx n:~gW6hnp"ѵ/@-hm3s 3MR5(k}͓'F"hvEpcs>ʉ=5 SYBAcf;UsPi$B $ $-eI3RRbӐ O?wc!5$'NzHY{qyER{J{TR[5k< k V$9\禿K)YPd2ilUEYC[=s~D(k463H:1-sXt:Mf\E^T4yY!ʸT*IUsӗŖb" VzJCjcS?'tbr_H; A# ͑_%?wWt%Kap`MMQ*_e3 $Q5jTY"HY3#F(ʶЎCgGj|˶Qjm4p'?wf*ٹٯyZicȴTPkE%yc 7-qƅi@?gHQ30P`wi%IJ;J39O<;ZsPjX<p`!bkMGJX9D Z^sf\9G޾_9m EHTmN?A^JJ`kǑ 1ÂfP:csX6.a(+2qE^SlgHB@+Uyu^Jܗ= S%X@%(5✤ .ʊՑ[D-We^ l* _,#0Aq9?Շ*G !זW-6&n||ӧgp1,y(o&v@7η 32c;M#TNyPBbL`h0jn#mJ.M@r]\4\,$3lLs NqH:JW S>=2liJM+-4w|%8L)R?C \.|첔X zHaI4g2cĈR 6L@vCDSiÕ̰ܒX/^߳mDQ9^7`eCjC^juXp~dɄ"pT;X?N>y-][|կ{Bo}7F6X|~0󂫏]ǧs49`8v:v˟}Su %Fi(i ݇ٗpj J!n)^S;6KNM8y6' o×/hw#z XZq0큑#$YI(J*'.UZ򆗶iBnv3gUMq(shѺ& F05%対_ Txc8)سb촛D!՗~@@m烩v= yixc̻n'sgT AU;8fBc <ӈ V qNfd&u s\:گ IQl( -A? Mڈ+J[cb1)-JIjbU$/1 qHg1SK᱑"p𺣊ӣԗ(%XZ!0 K^;&Ҏn<@;Ɂd%&]o_uI}(c%4š^n/:0de%WqŸvzP:5,*!}9r/kkORa-WN}G/wjoKR*,t+H3w,z!0Ğz[HRg윑F2<[Ր GV[6+脎ܲ]N ~+Q['~l"sR["i}uF|P% Yԁgk0H%zBC }. ۿydKPac4SVRT]b t7ܚrff}m[GX9l5u1 x`3Nw ͘_·o~Ď߇S5Db[Ҍ*ɓ$ p)?/pc|O׿½?~(5]eɎ(=/ƅǟ?^G>P5pβ'0PL\H )1ުyz`PIlS04{gYimdbm Fyʦ#uiV'YekVZ&F,qbkHqLǵVRZI{jWU;ͥ׶7ac%.T޻+i v$y)k]iCgV+ $^bOT)c}:EETXsƲw)!3,usY6V6JC|w\ȉ# TlV!6iX21o/CbszYC$5u]Sj#N#0;P5N,%[9l K(J'Rq+3f;!а1JBF!n- )ܱ5|3gj@q&/iO|gIM6*MBJt)['OqӢ8(sfRBoʰk77b.>mV37D@DѺ" =tGp R\а `p-'_VL[:%o/"EHƙrbk"PV#d%8  BJɝ{ @i&}*ߦC86ǎpev7$ }hڱ!R?BH3NiW n'fBII"*Sl.UY$N5 a$])clN[MABF$9߰Bľ7`l5;"d]Rך݀InɊ,)m{4+_i=6!${wL .URۆ1+NI) `v+٘@fB(5 _{zںe^>1=lIi R_&Pb!H5foߟJ &&Q@,[Â'M$^H#M3OYKUDdg.`H]d%GTc:aA]U[= DSbH9FL!4<(&T %;fg Ԏ~dM> %sw Rn`dij5UE2ńLrBaP;2X_Ńk\ŪpbY2dTư@4hێذYxƐԎ AKXt3G5 z,8Þlz*6 E` |'I0 s-9=|뾠vIY AkuNb,4,rp"[1ϭhP+/dU\JUZVrQBJĪ%x\)b8BSp3aӐ̆S <|[o*fg|쓟m>(&|4@p箐MpbQ,XLLJfML׽4p<_ԜҔ.JkXޛFkzu޿=>OTJR$b d De|q~yi[De-cb#I ̕R9ug=X{Zu>T=ッ}] U7#<+fJO3 "Ey<5m y!>{tszc޻tQ:kK,u%sԹ} L %W4K+l`Qh]4g p)0]G :# 0?IǾ-F4B|4hYUvGFXR(K v p2,;2| #$:O=N*{<)юM h9- 9]'XVz2eddˮ5JKI6kݒ'eBbIc>ƭUUFUj*ETi1l}B♽> zCMY8Og\p^ ~z*Ǟ<ƦoѨقeX.` Se98H˲8gz ʪrbc߫صv0*4f¬ .#>#fYs'NpzEsbOqvrm-O)IR/ Klj3ee=Rw{JxWm~z䥫£pZ*i??BЬL0k,[fci su)S9Z-wm^F- ) kS}(+bv2j GB*96Z5hPP%lq&BHڍDžKәPq;=\IoƓЇ C4d}GI.&%gJ=u4L$g>1`®Z\a 8()W D H' pZ Jxu~5'`hg}TԔʋK#oPZRTְ)0kRX?x:Vc41WHN@9~&v Īձ"-N1orIu6b2›___^KYV89Ble g7*bq p 'd+1p!%Gd 9UsJ<@f*P85EQXʱYc$98R*ei2*RanR$@JO lEԒf=deaXZB>msBs1rCEu*ɜ3@֟]`(K{0]nyRleak)DIG %_Y 6]Uhmx'䒽m-o\5'#.Sg}:\Urў:ޖՂ4 /ly DseК T)TFfÑfֆ#PN pcY7pt2+ZcQ:SK$X2􄯼1 <$XSƝ8k44SDBL{łC! ǡ8!Y\\$i}ӿwn;4қ lB(c :-6A:2=GXBvݵ*&(7." '8\-fA FTH_`#`ΐCY'Wk'"`v8zbQXGҰ%*TZ!A)*6K/r>g, PqdCb,mr4buFr;;Z{MiirI6,7K43,H"ijA D*/MrRbЛF;!%!y!hHGdjhtn7EblhbJ*m1@;_p xիϭ|ӡg\ilq] ֗@t*$7][ڂC庡W C[5z樴'Fo\)F; @^g~?b_>6*tOrocnav9Qسsss\xH'?~}/hZ~>1}`G$菘l4e-XW~Seqݐ*AZ0֬~7\pb͐eRm '%w41Q^zOgRYZyi&&gWLe=7>y64b7^ ֲgAp%5t5 o;2)8F;}Fݳ\t \SE2ʼLG4b}o6>wWi($ <ĩghطPcST+-E)O'jc^yzB"ϼA- gvS熽jTVϿz_p^-Ou۔EA^hn b5bOc^((S 4QF[,He6ay"Tc@aƁxvP3;!) M"A ؓyj%R7):䰰L8FWHa1)@s΍kMK!7| c=V w{1N)_a:x ox[?t!c P!NH. CAhODd7!g`0'kUeIkHХ!3qq U*!9F|&w)`(t"!%q;JG (j$}GrZX\-$0*ObLACCNKGf$?ױy$!I βQЈCY\[/XՂV101riK"%JWTV2 !D '`JY(Fz c:vϫbɳ)AzE{y8>+7g랞}6֦ߐۉCyrCVq>CHSĉb&cXyM zxEeIf RƔDUE&tMH^M`45#-xbzʏأ: ( PAȎ Q20m7\交o,(+[cqeŃ Ɗ[uBRhGрX +kI9>*Y1Sd菋* I F k-\TE6Li RX&BAL Hy{~W=}Ⱦ .:?05=®]l߾wu݂]:XrC޷vxロ߱|? ursy/W_˕ϿGoWyJ:7Lb\|2( E҆aT50q:'$pAt` D+^|<XX8 6ǎQ ΞA6?Kv7OV]SpY7]t9+??zu\w 3_Ç`|,3cfS/o_}zpSXLNt9Kf=(-I8`r*!cuR&͑=g.ZNe$JHn_g8!E.jK؈JCYeo2Hɖ逵+:#\+d! fV3҆.7ϿCOX(c,њIXDkL=tpf%GD_$qQQ.&Pe}S=~7'ˆ4)ZkiA-r^mgXU[H&ll x왂<2@.`0d+`$)46f=||@}wk  z,fk]U#b8'_MɇDgz#s/Ҟ .rCw蛼{_3OU-h ETL}^5qc D{{1/wopL^?L;\a299`0o| f7%7&D/"czSQ:ġ`m<lzTk0svDI޶iZfp4Z5Qg5|ALp*T22c~"ƄZ #-J\7fi2Wvc}62Ar eHvR䌲! 3? 7 ǩ ]+;{kFwI7~G!0 ͑OU  %KF<" 뻮S&A_1:LO&`M1-^wR?ьRI/!}7&/,X3RIҰYbOL#AhyHP"c Mdqz]iԛ,4eG_+m¯|2io 62EgqV0,51m W+J#HҔިFr0bە`U?] 2k(Gd1Qz$QS3]foP ?y%MJf 6XL !*l2?gJ4Ԧa. A H#M2QԱnYjBx/|ܘiJmxJIGK.?,1!YZ+yvbl;3졵ebe@_}~An1E6֦9T''vχv7#u !88^8]˟(F$茼o>ui4i+rG '[jd6fvҮ :}bddТՀ3vnTl#$AfbYf4 mE(۫hc;n\i'hn]`>:fH961F|1=,LU ^Hٿ+ۏ (5,\YCl ,y #}l+vDTLI1 opvΣ/NǩFQD-#mk-hҠ>m;8QZJq_1NH;~7y?K^2굄nN 7"`q$/u JAVP&TK""PԖk^'s^TCcjUE /%R/k->)9P[kyi%07藖Aie猁L=29qDT(,$ci;c4e-$P(?.yPpXgג&zF!$XgK0xZnS٬2hDLzB(sڟP~~i-ϟ?;ƷO *G*1Srrp1x~@s p0x8kDQ)]+'li %`H#r4b%DkGn5 ui$&_F8oVJ@W#?`A$n ntG)1B{w|5;S>;/sL1ڣw)!RcU+Fg E; U^ $t[a,sJMS _ #%<\ [wx*C(2#+,aWKRhy@pH'U#R!(e`}j}K97}ۯ?c1l.{+Jy+NxbrԶK.ய}u+g(˒(h68l,HȪ=߿g7FDqdd|pw`%xصŝ:z$?k Кk=l+4cblGWi P%)@}BrSz#H͵ 9c2$br:QH)W*Q%PyFaԥD.v4# $:]&S(!֎^-O,m. 5";:V!qdr0Λ:d ~h-?}O4sRaK'j4R JdDz5e;:=aBa01z ^0юpr4MVP %f `]4 R@4KUf@#Q*j8 Oa(:`bBW JHBe(*mx떎vTLľd ",I)J #ttDVsPA3_#LF50**|!C*SG(D G; gt8d\thD$, YY WWlne)ܿMK$ңA:JR%9fbf( -c8gȵ@8$O~k\yt;j5qscGsɤ rKD` &.ljj5JI~^?|ыԛ/ˎ=7_ܚ 1YS邛2-[Vɿ<~ ׾?xχپc8q;8~w_c|]Lͷ({%~%|t$ˆP!i[po' VP:G,<,D ȭ╯1?٣G??b8, 8؅Ȏ2UXa NÖJfG%HG O<=Ui=/V78pAֹ铰,/,yˮ穧*և̵lh_H%%,~E&qVC*&EDd }_`LHƢ;7Vlĵ2H( iJWǟ},v1C8F&;g#,@Y X$>hK+vH$ XZs UJDw!=hSxOG*Ktv#䊣8hOwc:MW_̷>D_jF8Vqӕ)Y_smXu%+@sdrr ܦapPxXZ-b 'sja86dUfX71)〰}%S۟3w0F[0;1q)DC[`(@RJCC#p p{X|֍I,£e(( k -?PGӯgLr||AKIA{&@G4M])xX"f͈0Q ٳ#etLȸRR9?ʝ`xbW" tÇ| 缙2/|ɶܿ]C`9#g;)3D$`zO58+(u5,w g S-#9#K߁X(%LŖ.xv4hÖDH-+3ˆٷ=Wd:)9zjJC ui9C5&ā'YʑEl4ih 3\8޴t}ިȍiF,H΋/ezr@zY-B $*P&bED!caf9b3sV KPz}dFY(g B !(@Ypyo@>{@sz~P@-R7>#Ǖ8r˟4hWF0O-,zG.@Wʲd[qGy=P: D;gꠍ0Aw|̡k_"ć.>yLJy̟~?oL_['x Ng ipnI{MՐC+ҍinEu?ο_bay8!yPs-gK"`ih黾ti!PB hG׼p4hưcxf,8tq.a^x蟉 \+bל$=/bgK/7?іz:jVuS%ǖo?^U[j$i@i1{puٜar"FaEc.bS [vgf"€;ZOqtV;x4_͇ 5.jE)%O!M_1iku{)BHÊq:^RT#̤Q |,%4T#O@ckY\ c-.$E>`_ 鏴7GKDy$Z;Kɞ%?}RHEy~h{z,/p(+ cRsTRC#LmjXXgM-=2=<|ԩ)52R a&AHAķ[FP[DhhdRAD#2)/"!`2*UT:Nzk|hWu֩~]T8Z c(GgH)> <, uI0+= %uIUnOpt3zb317dqxt)TaI|%JG)t:%QҬ7̄!Ui6/ *wZ (e6GtS̈́nF12wKUVdX9`l%V/Ug:$QE Axh3,%&_ fKHKZʘtpsք^P_~#y?OWLMZ隤W K t/*,EahG}_ky0{&Zkm}ΞxdLNARB1 JZˑSa!,"|R8"L2jI_;c80 2c\`HIBG %#:RNJ@;=*֔OG9JKC ^L$+ƅCR&[ k <zs=r/m% h2" zwrl+Ts'9Oܕq+RXۑFik{ 6P3Q!Iti5:3>.&cэswh$܃39{{( iu9 KВH/a.JRMxn0HDhc.Xj,'{1w>ڱ<,I!etDi$4ϋm͆mʌHA7+΢ )JQP,KuZcN\^61;ROp,%xGSz:U (%TZ)rE2~Q3zƳf(t͡T0E$<λ=LDeȑ$n梌V~b(cjI*9Vr*$bS!==EhD}㯿AK&V)%r`+܆PЎ2Ҵ/ScSK098XD1% Wܹ&g/Z"8zVe< oFTQK]&g\t|?~ tyen9{߽H-æ[3-A2?%YX.:`h@HN_0^=°kSHn熧Ln?4a0GU ܙG렸& z sl@%)'N<18AX8,*=3³g.0/"lJaabaRys_M^J1Eţd#Z"DH c^ݐ,[" |l~}ǹXL1Su@!1A064LZhv]ֳH^QFXRA^zn?O~槛5_kImX{XA (KOUZ)`NaЯRn'lFsT!B}HIK$ , R f7mfbG!͈RA7(HHރWmPYl"g(BS wVw:ᘕx[>1V;0DLۨqX#K}JS24c~ o}˛M|[#R Z0Aʃ `'_O" [Yl3#qRd.}sXzf?:橘GOVQy2BYi7´p(\(̌ǣ@F2l^"1yX(d0W`*n?YZOK O^Vd(1e ” ıTVJЪ7i=g=\KF@QxNq>LknE DزOC3/NU_ /#$-$CV :9Of4 ]mG =M8kӬ*.VZZ !B6g/hw|׷OËВ(!8o|vHOe<+CZ9fa^*A9H^o,QN %5α!k64g'gY)^YVZK\6e=b(K2)J.V0' K*zE̽.9wUG6z uɒTmCGИnr4zSKDQ8w(`Jq||?y˟t4kƑR[>mw,*4sV[uf4u/0zD"5} D+=9S}dCw-TNag<#DCЩXX첵&yri>Rl>M1+羇+GbPO嫷?_rEWk ?w- 'Nz.8'tjZ@ZB0Le(r. ʣFXW%R'T!e^W^rW[ni.+c'^eIMcSe݈$t2{bHr#i4~ FUIL%Q:bXhv Ɔ)E>Bƅ1 Y--b4ELe &s£#qoK5ql%Lu<d^cIc;nD#!R-3(h%O7DaL8IL5K0! 9շP ?>\B;su;{U@I&9ŷO:(%H$Df[,xZ23r!3daB*lDPKR+5O^%BXtNPXmJcJN9{C7~S=Vt2KZT;򢢕%8"ZbGO$q[ᠢlQ-,ϻh'}hWOY_@yS{8 }ۉ&kSǖ-{.C)N?Ȱ4}iFODG3 < |mAw-H)GcfM޴s І{/E ډSU Î LuLXR)*"N` iH$"eɽGEEV!wdmd ?SSÓҸ'ߺuÛx+(8y8?+&"BrCD6tp*`:L3RL+gL56t;G숰D&U׽đ``7\08U0SԴ+n?j IDATb8wcb:H6Vw-7 ~g/||뫟iy[/|}m!,$㭄a+_!> #>F4N`P_2i-y EI8lXVtspn W@x ްD7@):F3]S\]{9BEwwނwOH~Bw?~_~l "lo5I? TV"j+gq= ȟujyCk-)',͆s|!#}:8 z#@QAsu\>{չvS0V4b8Z]st Q9zr6 .fi`2\6l+AN==R BkS@ ORzIYH^$I-br,b}\))Q mKՕ-K"-d8[Ē,3!:8U1=17q~ Mp9/ؾc7twӝ`8BM\ΣGT֣욍25#8vE`|6lk$tykMBIH!EC0=3;]رnsc〧w^23 y?][oa 5XZDR:9հ1I`v^ebɰlW\t3g)μP=> HF"(cC-D# V@e8i=^H^߳ԅN6w9e"*"27yC5H$3-E3h1n]BE =wK[_=?Zn|!˧ѳdg26Q$(KS1kZ-ǂiJxumsKm{d$M4l{Cðrt˘tOã\CG iJXX9'98ܳNŞɠ9 NU`g%iY[Z-asKKC0^$go󭇿] P~;$R1oHb*, CBC˜bء29mM:ߢLqR}{5Z tXa>lohBrU#,wC6F03e@HtaВ!T9[ KM/S96OֹIҍD1R#do*6{8qxnLE0ajzbaqxƚ*'/eJJpc!J՛>`g8Z}-&ȨM$!:I] K ?m&.GD˟{^q;1,-G2c$Yx ^9nM[W!mxhrA?+ \(B0U7D G[VW9w#`Cc#dN"%h4CG}!$^M 1B(b|‡B*sdlY/. pal9u֛֠d`pmI|w@S2%%&sSawi !6ت+FF5܈:Ԛy2{o"Ҋs)ԓЄd!`95J `:՜u $ln>"ID4A^zz}Q@`Nf/3q{c9CV\1)VUtbT8R8 ZQS = gh.@+dS!&:EQx. f{gyiO}=?߿G9 O[Rǻ& wIb9J-<)0-Kۍ:VL<'j g#wAyJ+II>K'wtMK Jϱ4U/]#F ;xXN4JP5}kY'd%tv#3Vb͎»ܶf){'!P-Jf qף\A*q\JK2Ca@;z3Xgx 1||2ig'!iv"8Y@ Wl+) c@#OD`sf2Nw k1ؾZG15%iGD"m,M#Br4mo gQ5Za:qý=nNJSXæ E-<7*z,gdSwZ0;f|j?`06xV w$: 9w-x+6%RHҒub =i8Vo'r"ld$*K|K)RnhlzF(SBpZj{7iT0קwC09fv<ݕ Z[gu!<ϾɋnEkttO@R,g$-۶Fa21Md@}\S(pG-[:_fܹ:8F( J.JHJ/BR,ABjs*{vrr2Gj`aY sG8=_qVK-%z"I`GR]tk멋z{Gɍd< X[S寓9B iBmmt3MAU HH<l RCzGcZ:bS\{ÛYd%V|p:2W+=T1ӖIs3mO; rǺ|huJ<ޖMaLaHr!S}gS;Z!c8pHHv=(G E$#*3ikq-gNh LQZ7ӁZgZ$Z2^|?[.1֪)V]p5|@#nh.ՠĎEh>[pʳЃ վF!e7Sg:cM6(M7N$&c $CY-&c#w +Kt 3ɣ[0ݒky?s'/ طU YM۱gwX࢝ b$z`54d"lj(T2o\W.L8EmOM:Cgcǿͩ? !EJɱg2 ꭩCIMS ffy/# 5/[̏ CS jRP9E?8_ǹCE"jSoOA9:^Oˠn[D4l2C]"A#?YxQC 6)cӔjG5FN+QK)Gq (;bΙ=+I]AoPଥ L< E+#pq;a]T& sXm&Y8PT&w`ۓ/gGpC^87.Cio5q|ʆ,*~P%bcqޱe$zpVSjH}Qx;zOYA=:SU3mod=7aJ?zxЌnwq .9;e%}-.l8P2)>;Fz?Ͼ ZJ-LNݻ#>9y>ǏX\ʱ"&NR@W#YEyKo#>w8Yn Nph=W@\Ki5$bi$Wx9!Xm8b*ǡ2@Yc-2z|[`Fw(XzN%J)ΧYa0Q &lTCȰ;jZQm de</oHg̈́srTBy[c8͏lA4xݑC(,us&`[7X<ĉ 66J88dX&eVbtxTa[0>zx}H*:TxVAc5:L@U'J<452HRʁ0^25qg f%B$ /`[Zu=X Mgj2]؂VT4adOlۄ<vN)*藆(&h±\f  `TJiGYBұK*Z/'ap OnA,3)1:LNE`1J[;j h'jW#`.L^O^tChOH>őaaqX ~ ^6g#3u9p?2%cR uq_ \!(F RW]}/0yMe˼wiHGՒeGc;$vbtdX$I f(B' y!@ !!NNs\e[lY]Gvý%`wa>e$Kڠ*$ !i`~u\9ai8aN'Ql넳6N(`G)X j0q<֧׼p֭UE;?QFy~zsY K5)T_ĉ?G$Z |`ԚeΑ+E $)@F1:IXT,DR:+O2uCaˍbA=3I:XY*Yf_꣄g{'xc& DZrzҹ N8 j<_Żml J+9B]qCv7GD`gc B$y>*9!{78lxՋ8svç [,h'}S9yl~-5i诿N9W$|aoB؍ڜY(tb x8T5Tc=NphKw 0rT(fڒ?Mj~%3|nԤ, ^|/d\/G摌T%8΅ !/`I?c{Kތ9_./zBpJh\LمxDJU4jӿdeSWM!oTZu)I^>ƃGȳ,lRIf Zw=0M/tXRcLDQ[,vXDQ!hd2oVq~ݲ}2=)#D[)Y<]aE!t7 *u*nOT&Ço|#sss;b3ш.݋3uG >7pTKnqH{ B)ӌ2Ԟ'3} =8gH *OY$Yod( 8kCb2ޗTmY h=AY !45(ƖCR/E:KA0.hnf^*HD`) ev>ЋX8&]GD"hM=, .Eu VH@?sfzuIJO3hZiԐjzBsBX7#n/*Ѭ^ \MQaan0a+Pڠݮ#-;a i5ch[ B '_0ݐt"J.҈$eBiY+u#HJ |?{gB .LK*`yFڿ.ǫ24KҊtgtDyb~bDD+ kiq,WtID|\߿Ιj(b6s\ó6r$j]DD680fXؤc)i ze(`3 VJ7~A=݂a#َ`X֛f/3YJql R!6F@ 릢?\;%[2b3$K90s'z#1)Ht:sc %#N|x~.|]!15蹳"'p`mItJkžWw%,n=³5#VZp`bː8 T <\9 6=D"lRvҨIY ",r*~;]8k( `"$UdNQy6k`yr ! Xډi8m na/gx\ÒWO,iE'%q2t` ]-5X9/z v #˚qBhhdC{bF_iErVS&[X%^f$A9H $IbbHQAalhzJkddv즪JLe+Oo)VN5 %IRL(:0x %fNDq~BA3Ub}3 a97ƣ}=7<۹34-O⶛'8rr$bWlOs|`ta-B7E@e1Mw0;VƦra晙D[x:N ǟ9qx, 2TЋp!Ui5XOlraQ_z84ΓĞ{?q/O~:pv9CJH"es +%4@I lxwp2rҥVϱ8=sc͞H1VV&7 MprɊ@||⮯v9Qg{E&/%F4`ʄkZ7k7a"4ayeQ$ٹ%birJ_0osQ, RgJ :- }9L4Gw}݀W䡇N3Lı%52sBC]Jd<<}9͈I+&c8MY!4pDLUb_@e*FQC՞O=`kɣ8}Ucnhyޘ49XJ Ix ͈V$ywRPgO98'/p9r RQJ#u0h](D53k!"Ka㣔 +`d UVu$%Tֲ1t K(za)J01ls6rV/414 ŽqA|"XBlD eڐ/…fhdM6XO>KU/!w٢ O`',vUi$2( x^LHT|Q f>, Ϙ9NJw!$c(Wy:s!C/y3!mU͎IVR 0(Q%Y"+Kƚ lH%ܱ: U$OlXPh'B r֖] DVۚ%eHz{adfTY.Tld5.f[lpD>?ky[wxk( ȀV±oErIV %7A:\hhOJi<șIKΦ\7hrC{b.1^D$ƞE$g&#@ `fn &֘0p 4mFJ&C Q>c,,,`ʰ=sC Pn+ERu)BZeR7QKA&bmHU8R|M{Ue_Os`@T`UN+, YGۑ"+ Tc|ӴUǪӌI+3?lߵ?z_'?'VXU$SM^gI (a|EmlSݚA4<*àI &+-uDq ϙrA),x[^#+$%ÐtGhRpMl , cg=cS_ckwQ&;o˟T;wq-Ogtv,]mz$伟yFy}).T1,RcC'GREeipƐE/xt\Z/[)@`d7oy'_gY[>|W?'8rl)%bk)Z2T&@E.Ae>Àgr<0a2(!V7H:)ٰdn&f[ag˘cfq<3/5ao`i : &"6zry&&޾:TJ|cB/U V lU^V)mM%NwJG΄몪+)cK%9#VXIVan0p$`Xy%<45B%ۑrŎunlg4(҂n``7&|CL_.64m8x#%O`s䭈q5(:ʰ֢EA-L6=E/T*h5;TUIaP"6pq~yk _C?Zy"Dm*#;< #Kgio-! 0Ո./<Sn} M=By !,0( H23X }ώ]4u#tښp5TۉNo?ȿ{yfM6[,n*' to^?Ƈ8iްoNoXHRZG3mF,!pF) 4d8!6E<$QS Oё0Xռޒ^&ъq{)Q èy! {y%Ǿŷז̟w} |3o}:Ɖ_vxz8cmӠdEi&1>'k(@;gSbGY]] tz`Cɰhf Ę*B&xb\x /X d_>|`T'>|8Os*+RHSK\G>P+ZX*NCL#DV& %Q έ7~Oaֺe8#kvx$Q@pe3w<蹒Bj0s`w>o-cGZ` U4LLMRxGO?rx= '뺤`̤"cXO3UTщa*mV,XԄ¡ MJ*c/y|g"}Brlq CEP^tˉ!V9QEvxfp`/ #$($X v3N!1xokQ0h 8-8a#7UI T:N%K5>$ASی;ZvTO=xZ.s'Cw~o%Tԅa8R-e:MX T41yeX LUYt:EAy2H ڒtgl5J0(iYWlzl;Ew7=rȌ TK#lc{lcn,(Tb~ ic652X\l`R0%:n6$?q@Q jmI'7Ia:,U5}Ge|Gu@a "[t2 ҇5v,8E2;{N=U>O߮:RGac_ >Q^a2g4{FEFQ,tK+ɪoxn{O_/ (, h&ͷg~E I VO[9cq4dCC҄6?ɓ|tbffC+|g,m:Ī|G Esl$q" N.[V`'!fAtյ7~孿˯v^0R ʺQQQVXYr'H"XճkOnLOd5wvo=WYZr'smtlxebT^0 #HR(MRszHblhQaw~,l/0Q}C0<1Ʋѳ,.W/:;b82ؑ"3l **FK3lHyuc왎lh>FmXKs~qp 8 "ZEGfl$""<8VH%(*pd*0©Y(@%\W_,`y7w{Y^3N(ٷ<#$TҊGTEܴBK׏lt ʼ?^{2wk1sXodK@4@K>{gm3!0;.qMEwOUOs&$Ͽy(RyA+ZiNź <ü~ߒ0Ϟm I34"D͙qdT6dE5RB!j ~\5q邓p0ǹ:*@_c@қ^mstD^9vƀ`b,{6YبHcA?t+w?Wi M(A.isFCojITq$KDj03K^K/( Ř^hCG5HS!)݊LȀI{`M#DиX$DR6^`Mb VH0$Zd0ՈtDA"!)CtcPcL5rt LNtO IDATA+Z}|1;ȠeEa< 6UöCIQ' w잎8*ݲ#"gYjlE7&EAkAէ yi#S9'B)M.$t_ HkiKO!J)} Qˤ /KA)BxH`ڽhny'x[wۍo"hߥvs7fqw*ܦcPZ6 O,DMPZ?9)dsT3 9f;\⽥ +4b=5$6JЎaeD A%ԑ-c b/.ނ˧#X,Rj.!i8|caY-P0",JDR$)׾?4HpDHTMlTa}|fbd&X-I`/!RH%Uc=|/gX 8 3OK|:l9Mߵ' u1Fن繗+E#҇M􇫀'd$|/ =}#(k|wM"n G U҂/p%<-)H%=,ޠOF<alttSeu}7s\dH5R|Ɣ"E<=;&"< έ8|>~oD`T(4ݦ,9KU 8|BIɹ`D Daυu"a%U)Yp%A3A^㰥@#Pf'<~yOb!,ӑgl"xpS9/q,vh;%|a8[ xGVK-, 2 ߏ9q|Qh`/騒 OY ؞G/# i8hP+ulN+yyhb2{*"%q }s1i6tIw&TD$4YVa8Ό0& >4"TNxG?0!%{b `uoEgLEJ.x{l0#[/)TD;@E-88x0UboĎN^O^wQQE&4&< sKC9y\5cocbH /`m) HJ+TmX$V"ID8b-i&1JzCG6xBJ2*cY+|ѼQyRihrmN84RDC\ YZFgX#l$Sm/Z")\FM"H[bJ6#w oVTBH1x7q66^Ьu)Yd z.K9RadX)~Ό;2 ~n9fTJN* +vG\=iiQp'\`|¨`""/qN296N,yɕY\c{ M vI0,-2xf ''(g, ۰j;ZN(FeQC'ڀon77=*~G_WeZ: DU(26XV-NɌrMnoPERB$, RdeZ\J rg.hr+8԰hoXf%J ɹ*֬4D@$#"bv|lmъ%R/I44fqfcA/:0ѵ\"g<bLxd NF"g84x /U݂kSjHcx>-7^E; E{sBre[@ڈ.AQ-Bf,Sro3o,8qx>> w/ '|<hM\xʱ6p|[)F(yK]é?6l'VFAXZSɀ6b㭜6FcELGqad]O~.RfA;3i$TWVN,^<1*fb߳L:TNQZ"4CɿСq_ _"~{﹗/i(حpX_ !3BSq ٰuiŮ=y/E7W9nѐτt)8uG|+3y'i$jr4b뎉TF {&5[F__>—z7*Hd[3dt_"dd&7tO=Y“ij(}&sygrbijSI'^23u)zg8M<]*>6g6=GV<ݍ34chDX+X0wa- ,l,"-b@)}k1B_x{2j;* -,2Jp@S 1-o`0VP8G+:εs1R5V2s +LnZ`eWGyc>܎./0e+&K$V-/lpԆXG;4DK:;g'hQ"eUm$j\ x+~cs#dو}5] O;8s$gϞ[O4[`rj%aXa= s;$:d&DJK/qŤ8 hQ̶-(h&A#5;Z9@Og&^FxgY4 =,/h%d1H}=o lNV)VQSY6J̌ +!X\-|"ϝ_YcW{NF|)%+e7#6abGe\.i_$%SyAi Mm R93L6 mߍ/\0 Sh>H6Z'/KpH&Q[~>|?{pˮLc̴λv$U)2HH`h8ݶspCtiC8bcL@ʩjk4}1VsnSaךsl۶I.2k+}~sh]bq@ZBDlxɟ=;|",S(ȭ(-* YFc$JO_,c&Cw7Nx;g>q9Pc<2=5 cNs { ַ3[Y[[S}4?p&/-WlY(&ͩ6F[@{2,3wWߒ^%37LMh3tU=ʑ'% §ϴgIDA#xPDKKilisMfs-I ˰dc_Qj(*O|c^0P작<\s'jF;+#/%3Bk-&G5A~ӘgWS0+jiM9`-7Q8O $rH8Hq"dsp1_Aw3J#mufxf_\?{뢤75M"kEN2:Z)(ٍi^Eݓ J/ܼmF1{]EZh8$*c& [W\G?I5B)xcCK-I(bRԞ8[є\t3"pwܵ}LLw̉I: >_K.#l, $98djfǾ6F6lA?`1ῷJ -)U J$Nsސu\{dAha) D؄*'YMO\-9F:ٍ $lk)faW_@pj♍v Lk:p24_'[5{EȍWyXX2FfQi_imP-$( ɓZcl? O~FjGn,:7yjmS ڊDRϹ&.J>ӟ8OswS111U\ˁ?}?yjx<+hT> ׮g/RSCuH!lAn+a27QC).aH@Ф!5Rt5?S^q? #䘮C!X$00@"}#8G[iH:\3ŹwLS 6dY%%ƒ)nKa|kw}|H4B+ǍbYZ/\3溽Ӥ:g[)\~iޠp~]7BosfssgϽ:/SUU1A}wRˬ>y=̱W0 YeqNPO$J:?Ol 3L5CM-D?ꉧ&&j$Q F%o JG6[3=>H#T1Uer"YiŨIZX&[ aZQV!Z6{п"2 We|xJ ńQk(Bf-ddPШrh]՚tqw,{?n:G2]gx0>U[xWtO1*ܘy"|A- k^s,]Y8Ř(%Ʀ 1Fu,j\ͼNo/r O4$PpwZtУph sz+S_̈́BIjt1*sXcڏ!vM?&.-!ycTĖd! *reTqx Z5}F!ØPK"YC{|aĖ6q1_0$>H dcm۷Lb"fӼ=?JҚ#91YUQǖŗ!*҂vCRICߺK#P-N+MzZܞlaa.yOٯ XVxCpf6^"KyJSV~䯱e@զ*#WL.Z yb@rrҩtK^6ǸKF,-CO :/þ];ퟺy}%KgxֳoĉDfAobi6RORO1Bdn .O[ێu°Fg^1,,~,́o,9`uʱFTTcg R3QPhf1jRLsFO1Y@NMokcϕ\?&T~]1ܲu29K1A*xrRQOI3Õ3+z#0 ]=3}* %pY7<{#Ñ#ݗm&"+ (@ LXZ/)ʊ !B7~A>-ar m y7MI/}:>  Wyi8uz2gN9(q8.JPq4;|C{6i$I$_Hϵع%OhD8T[|zS˕p=3u5oVʯ̐%?NLđuΒƟD”'e;T$WX*'w0jY9z<7bߗ9O&$$IB]ZfPh<>(=>.PDDUif&CFNW#/*M845.(7'q֢bD;_|?`~A?[uT,q)H&.FA" B v< ^_Wĸc_{m5X)$T׎JA- 9}dY~KM@i) D kǕ_YoT\$H(ǚߕG*d5l7.>%5}oEDMZuC^ F\{ +-1*mA6#gMYaqb~/# FGJ^×rTk,mK銱+ Th$Ɔp襚xDE(u0^Q`tNee(# -<{'X#l~J.dHX3 Iyψ'h'r8xHUh'0F3c˛e$uFYtCmF+jL85dcZ[cnq2[ 8IIԆc"R"fHJ]bEx3߼o"ﱚ*0($X1ی ZSوF"ٳC23% t3|Ќ 'A 7f*~; x͋ ) o/AI'{9~cqf\ g,+EA'4-l̗4c_]Ӕ h9ǡ0Ͽᗸwr蔯olLS1,!Ě!vJ:늉f@Q2cd]m RIJ&ɇXk@#Ià!8J!|-FG- /L bn;Snv!Z Znzyx&#0ղlKm![=MZ8y6Ў%YK-/xٵgǏ\#lY`/BYUa_*Ͼi.Hpne`Afi *CeZ$+5c/yniby ˛|tI$W_pٖ+%ac&jҍǣ;,#3b,񓭫vŜX@ :5A+VDli*9\+  XYoXT>mZnec Q#Š?Ұ{[%}Ms~IEZjgOڢGëV@*/^!{f#zV#`" y*J3KoPv$ f[-suV6J1|z$ $,d|Dza:IoόDAxΡ6oxLI{B9l *ID߇w%l5,GZ›'$RT!}pnSsѶN5()+ݒ95Y]cohI,^y^ptP8!2d.$ L9yΣ&|,- SݑfTX6Dj\3f"6ڃ&Rm}pUyj$(qnbߟL5%g$Ğ7ߌ*GohAZ-RVcq`|1Ԙjhu ׆kkFd[[ #"HŸj9hJ!p4kk|>^{FfْDerlS;_p.cS?Ho!Rl𼩒B;k(s T+&#" Nr VP9:8kaBES#e7vhv&kI5ި 7RaHJ6P9_4+%i6XC5=Ҳ/bvlDFn'^#~/-$0 %k|`Za%6ڠU̹#ӂәo*>gI"cɹq†,#Oش6Fw4?TkfGkNɾ:޳FMpe>< ++IC^T$c֐~N @W~jXi~fMQ2/m{lR .WBB%nܱliII@(gOq!ۘ WXhI&ж}DJ( +GkV20>/ h!(!u\jC^[q`Rcy E|޾}ǃ}R!4lrUeiEiƈWsT_:uTDpeȞC %o%cNMpzvRo%$ە?ݻdxj$0FE~-ocG8А4V0BH!ԼlfP,|hD Τ nj:eߤ: xt#9% *Jr0wD~:Btbwvj {߷׽P;p);gɇ'V.,o{b]t Jj4&xEx]>spTѨK͐Z$V^mmAJ*b9R5>uN?c= ZKƇZ{a+4+ c;I 1cx@^9z]- ̐I㸿|KKB%sևZ"ÿoHx3FM*f{T7kJcn~i48)} r`K;)qlfJmgḳ'sF&%* |;wޅWa0S*PV qs 0wQ( m4Wr*“cc$IdFJ5gcj DryXZyj̄"K1DR[8k9|rfiЂ,A*3s<]pE ӻT(ݿY~<6fG}*OcTٰ<Pkyr17BKwB*m$C;&ꎹǾ>Ѩ  @8@q-Qn~ A/qz(yf5sK\;tDg(I0L*҃ǮP'!Zi難& Fq󯹾?x}3G@A]<~NR6(oD'Q&hz5[fk܁qHGot@rI2pc j[^)ڌuHq^kѵ QpPzf3gS7[?gqi/%¸ *B1Gi*A/x|hwڬCC{F$re>^K+z!%q ɵKN$ȟC.4C?^LғG鳝y6X;1cÎs2\KҞa|c8JyQjqw]=*+Jd2.A|Ͻ3{lzdV"f{\v̱.QTIAdG3oS#f㱿1qnS3,CD' iĒpfQXQz~~J(Utl6'3B%zg=Ma`yeP2'R Sإ'n9 ` MͺK{_}~/a˃ǖX5K9/T'&Zt3ч؉Mj7!Z-S4A#{A@{'g m5஄t,u+CM)GY q-i'k6w YjP`$FA@ ˮjs4jx0O^$|.ᓟ?νGI4bfyx͊)E[|UW(EJʐDueWXbv~EAo8~&ZKO&\Bh%CiB;#gQJ"dXHB_g$CJ\ B^p} P(gdFQxe)kWYU8(T:[!%A8ucR'Ž TC˽6ys1O$ Ƈ]7|r|`Q޿<i= +r2x|<m|?“N[.a2q#hF0הlmOw_5><`*l!\E4\4'g:`gK"woRyQM5E#O=}Gh5eI;$ %"TgJ[# F7+0NkrN;6qBb̶0Q4(RBX8sdvE*jlTHSZy焀xPBG ]J@aer/~o-5KPV7gѪqPM6Z%Q#g^(DLP*ޘ$Th% $* c!(3@Mץ.=JIL]!YSu߽9BfRE0[t"r-$g f ZCg >۸9ѕ>q Z5)E=#IҨ)/H$&Zx=0Nw XC#rFP1.:^fЖ-MfL?:F'vlL%ylm$BJKi=.vϤbLWu_\xLzE=ObCrt٥Dq3PhРD1X'h3׎(+ö76ju Ř=^Kt؀>n|źӦtgY[|lIqº|sywV+X)g63JRQ @08pXKsZ[fꊝ3=gjW+ KZv(K[#a"\+BDypWW8h%,+6#0I}Ȗ b)-7nX/ky}+&?HM3Iw@? 08Bؿ"˫zx_2-o~N/׼;n`i)D.Ì'c=$Pda&N@L5^c.hKFU IDATň s4gAw*ˑ%C>g+# U@{: $S1DttUj4ca٥MԀBW-SZ]HYҬ"}s:M- xm&T% Y xޝ[`d3Q&H2B͍Iާ)x  ?wJZ7*+Ҽ*KZACC͙#1*`זle99#vK}>= n3l+ cl^g_{ssp꾻E ԃpx9/0aepđ0( E CGZ! T3]J-|!Fm}xTl8??9A9&&@AEaeR]5#{]4j%*\=&$Ya(*C|v"C6c{p9NHA(P c*'\dĵ7-jB5h#{^̨tE}P8 iƠ}3KU#$JBeQb5ƶ˜d/t|k;Bx] <+˰rO"Hb}or쇰HT/3NWy׷y˯}R Fn~ދy߿!ܰ>H=䙞O}S+(g.[X¢ǒ-tI\Osc5{2#8YaK~ž#'m1ʏZ3f&Sā g7*óce͏ߛ5E$֐ϛ<;#*;o kY7p<@LfZCRVZNA[Aj9rkGjɚ^iuʡI8QlgPV,MQAs/6zhF353c=xlVR-*?UqNX'ZK #SGJ<,>@4 $8K&]U& [ $3/#P? J&N'~Msq59ȷ1x3pQֆwc!j:e~1 {'+ ] F^&18OiگxZL[goDC)1^;dv@lpֺ'dyՖ(TդsηmyYrts@j'ɋmRV`}F{pڝ)j vHɖ}ϡH|QzĶ@cs{ NU9 Oox/H[x|# ,dYϱuEbjZ\\[#D.bp<950ķrXxGYBQNp+ħ>(geWy9WĪSrP%HXˀ8blnwvs9blظ$PJ3sW{tqV9^ko~>]wUNX~~xna M5.ɵ7Z.qs!@Lio}# Էx1eM-SӃ&SI !eVPGyY ɠ>Ǎwq)8g=7iH3l+)q5 kTP1D!LY%72āK_/aC(I?sKx,=rmِn6Ȁ:wıBrZ?/Z,GQ%1s(^[|H\kB(oNJJy)xt)Ta9shx''' %4H 4(8MBI"疕+6,5:M(Mkx!@%eGA,ߡP$I XҪ(j[sdHDc*Q@$qDe q ZϾsCύxkC&oka.X@lma[s"FV0U&~cXbmhXTLV(p㎐kL (yI$ 8 7ƽ0`ݺwkJDl@"EVhB \\Մ¿H'$avTg $zDE0̅гAaQNSw+\$zk}XP[v1Xҷ, 3C;t1!D~v BqVsۃ@PO@=^g,OpW!0\XV{,EUN1:.w 5o|;ߠVo'v G{9sYFiZ CISu ɗiN,{g.+<]ocnn#O?9n]ْu tU3_,[~׾u!7-7P9[GO1rI:TsGnؘ=0T!Dᄢ^m[V9o׿E~g\<6'kCE!kpݬ`aHs1O )kk SXi '%o=2eT*zJJ1mLOWKSqXZ:\-Ҋ63x}宥=4[bEfzjDJG)$%z&nzc`b]Z`ܪ C6wu*LͶ:8c[;FmԹf69/#enؿM5kyU^\Ҩ'DA6]a`ZՎJEҨ%lڽHt[$LBBs YׂSK>2zm !˽tk="IMZAR fSN_ 3C%TlޘЉ MX5wrn9# JJ\y=SXȱ"GdeThLsCL^ljH> {G- Dd*y$̧W"5c i6`iJ3;HbvLɌRIN/j2ySןqq^ (E%aFmk-9lzN}7f"6Q&9#2o& +ZBcrc U|>tZ"lFdEI5t OY]+ƒ4'*eF%Ql?pwgPŽLn&j ?L|J02yIjc=,e T@XDA-;TslOFr=d pJCƪ&?bTX>^"DA |0=="OGZ51?|9L [6,ɖB&oB`7SME x"9U E r잖\` o>Uʍs%vʒd^Kh!6@k>X0}en] T%S qPbI >%Y(.0xq"QI Acn2>EAgG#&7]7}c, pf%I7t:l)UjKu צ0J5֦h!*wYU&uT$I Ɂ3V-"'9RE{ˎ]ܧmd<잗r﷽KY: i^pq^q&Gr]{eڷ"ZY]xCA@}滗/\!亮i#~]?yLjjIXJ^42+!LVDsj]!g\^1왖Z֊uGzZ,Bp$!6$\뉊d,sT(=-yL49 Ɇ3N$˽7K)A^gY*.5Q#ݿ~[ŎO6N21kR[K5/h'ٽ{/_?9}0ox]9LTXTkɘ^^ ٽhϗ͘UiuF&(R&/}K pݔd[]qivI/IρB(J 6jAJވ9q3yǚ}r}86V{W8>No'Z:=gT0bp%i<{?o˿;=;Cr]W|a,g5s\[2dtMi[$#r$R TSCVmus_-_du_+)Vڒ T v9\&7.3 m4iڥ7֧w2sR*`1:H7@t+#Bk2-,j f`F H!hpR(%N.w|O@xdϦ+(2|R%N[O'ռpA fA",RZ1~:s4? g%%¦ )9Pq뾛qH% *)ޔX #6.\8ã|Y3-R`a),+7HbL1Ql0,+;FظhLFI\29uu%봗Prضk7k5;r}HYDQ =Zμ49F9,]Y2/"]Î]{ضk/ Iq`ߵΠ/~?#N>|}Mڕm%> A8U( Y"b` Vs56-\sXPrmip$2L9yni`"!I~t=Ъ#-TbgEAsb3qɋn/A/7:ҪBUC ՜@ ['6vZC Ijtc 'O$oh MKa8R4;E8>?S)a Ɣ#=*ԩVr ;%JZA<|䛇_s&"tAG[&&"\crWPrld09uDMQ䞬..|8&2W(B*f H27zb\PVDRVtIˑ`%زK<—"W~ )?SFDMLWBQ2) OFnyKO@kɏ} fm+CO7)fPZ_+rJsKk@ysU 'I-%ZF&jvszKp4!چT%Q\FEiqV7N]Rǧ[NN%Z;jR TuJ=r6P0Twn&&njYXTbXTApz%"-QgW,FF";Ya8ر\S|v !L5ᴀIrN!j˂HIsxs> * #y".I(&7T9ElZ"vsnG{Moe>eҼ`L!]DRh ":#Au{^C9ZEgѧ[&z *eY295ͣ_K.#~Jpo!K K|W's6|gHB>T~Çq?FD+xÏW@-jX, =$ȯ9:|̭( 89y?^4)x|2Zծͭ<#InKa!G[A-j;*|tη^WŜYPOٵ1b[vǵK$:m->8R윍-2%!/sJ@^xp45$`0.jf = Rzlw槐QjמpF^*u2KdB j7cFFqm9T~dCBweMDDFiiyĈo\ɵ&JQUdϥX:H6w>Urw_K{uH,6ر1 ;7`8׌&A Cɖm{)s,cii'O|;v ۼalF9jtz,w'Ul:dK waѼڈJ(PK7s;Z⩊d.褾c kU:Z+ |SFhO1P(ᮾ'- ?u0|}e5*Fuμ4w[[RA? [~~@xML"Hg?IQY8bl W qIA59S81&p"M~tXM`usְNo( B7(YY+Yn8'-VltArrAߏغť}OY#Yn16@Y?r*BNSB Pv$p-N/#V|eaAB5 @`PqG>~5Y*@(OqFxNz8kSk}G$5!RyݢֆJ a3n>@+FK%z(,y$Quζ͍;fWiKQURBFX"W JTU1LÐVnWl(~l:^ZW p*bF%\%b0,rRL6iӁz懹8szvt /zٽ?|G= v<$S#!~W;.uL%XՂ_|HA/đn˱(jNK&+;4׼,I-P / J{jo=혈{e1w}ϯK(K"Jpś}΄I(D)S!lX0ho(J#-Tk֓#KidD=bѪzinwxA) kPIfs9f;ԧ72Rc|ӌJ s%*P! Ъ8^/7֙}f#dJ8|"zɆGɮ2 dHV:&%Aۂ>~ 4ZJ;;uU0Ξ5%IS(TbY#75!eNa\%PcJmD0fK)I"?Zd6+DߩĈ 2tde6`I{m bSGyd]>d5#ϵj҈ؼa3/^$B7}׽]>4%WnЪGdK>LAl۾d.~/ BIծѷU Q5P~\la9SJO` }P0 饚4Q~UBPzSP\%arE'KՈf2*,@$dN-ֱVbtFdXR\Z㝼?^9Isq{S*5\f1@j#v]*ƙ5C;TLUPt§jhCq3MZG!Sy^Y꒢D:W2;aM;9qzQ1I j Vx˟XK-OH== E5=ʄ@EGWg P S]Ox*S@i4ZJ'hxepnakb%#V+I"p$Ҍjg|~#&c_!,/Kl?pN?u.oiOrrA ׿7KD1NQw%)ᨅ>1,ÎBQ(Hz=/-;aqs8 oy5GSP8"8+rpC JMuxj(1(FTCh%Ց$elkՖ~&7yeW]Y3{\J*U $!M""Nv4j J;ۍ(b`!$d*U!UuiNt_空ϭ{g g3*/g=U O];'ҁ P>51] $ 7JȀ&{Cll1sL6CڽF$8Sp-6)G2"-=藠v>{ipЈk9~;b.9K-+CIjqBbk"-f kJKin5k CB-I]N1k&Γ7YM|s\)ɍ+ y &Ň}q.cPd 0'<=lmA^*ګ m֒#Hnl sEQBđO̍+bw̄aʼQV҈Gf[`-BI/u>Msra2@1ì jE dEYMt׽.AOʼn*-qBm~=\yZG>̛\ٵ{QX8&5Sc G䑇~ћn/|TC",#(id{ZEpŌ$$ԱFQ0e&H_o{ٽg/癌ϛq<#121ӵ#PR"`6҆񍘦Lp*-T$p%_C%0hÈ:AHrF lbF 8Xĸ1IMu%J8&b o?05LOX+ˉ.uXt&`3\IMl䓶-F>IJڽ'e#nH-ā72 -V>/T$o.ġb,h f(hO :#?^zt0lTo!%avV AgYعgg> J*)Az,~KZ%mk3ls~Xzֺ9!7}ǔds`2"ѹBh69ghay eevc=0 %TXQYl9R KÅtԽ:NhƎsHQ%k`˜"-A+0PʢZ _}'R[-.0ΠGʃO'z ^Bݨĕddtn 20Ɵm8#>[V:tIOoET+&Ͻ~9GHT?M?y X_V܅Sg/AγD+9I+`B5c3dqHAp(2i*7F~Zpt`w@= )AzM>Hc?6ʏ}? 1&DZˬ@ꐯJGaKnީ|1<2nR? `tǒ9.4Fl)‛khYdR"%u Co8/i4 /VB'gcPR7]JƝ (K(aP^+:vKZN;8@ҍ^~JЬ t &O9. =j1$K FJ!?C:G &>KD<אe9ZOF|>ջ5ڼesm 'h4h$#){a~vjQlpp^7Uwq X=N:/?#ZO|\űGI8?Ϧ UHUJ.;69)[0J$0^.Q‘YV*LE͑E8KE:~hAh 6, qD^gDQ(?cOb(癮K^2ZqΟ9ru)>;~n?0wN{Շٵ5⦃SL.ͩ~w}s6c'rSO°aCWXMt_<}4yY}/s Wq+^{JGAS Fdvf2(2۬ҫ4#$>=+ H UIG)7|_bێ:|/*O>/ 7]=7$KsTuIϩa9 *LVA y4/J2&qX ZdAiojʱi6PƣyBʺcKwNc ҴR1ET즘T9UiűEo6q VS0qf7f+zP*-B͞-!Kc{ MsmS @1WއȯIS"ط5;+#AR8jg{h!6 qru{'Q4cʬsÕS:8Ź>Yfffr`};Ii5O(^Iz]Zϲ-q&ٜQ թyco5|>5;+hĽ'=I+-q(r!,shKf`!%Ñ7fC|[ĭn79=fWJSЕ*( ܤ"I 79\D2,@M[S_ܙIKKXk[_DSfh)\,hh=Z~ rr}aPZI #gu+䡇eXLl[IS!e@cd6I–)ŝL3(yO<0rd2+ rzyWB/l􅂑A(<9*hA[Z!2Pe|@' (9+D2GKUS6rTVHG#FwDe"(-$d9 He3!%2P#JXNzV2BH4q7 +C輪ZLƒЇ-4|gV2bM?(Wf:&8ݡtp Wm%-Ϲ"$ |(Ҥѥ Lγ#^rXԅz,F!! $kkC+L?&b;[>W.W,ݡ\ϑf lgys9r7eeK6ǖp 28{,Esف_W׫i{9tҹ,/~ٝT5N1 Wmd:h. Yb@F%̪%-!TQfRQ- 3ix+G7?{>wrY:scuVVT#Bik).BI,9%QcϟO#-pzTT(2fk䒙8Ia,Z~1-Bycy>NI֛HK0X>oJPOtbdKs̐`뷱qr9(<=gzW1Ϯ=sJL3ϟ{|ApNt^ZP}WmJ6DŎ!,JTdTw!X04+@9[8 "Z=s՞GGZ⬤)4s Ƈ}  g.x XyW)ٿMi<1fH8@qI B9Ʊw>BIzgX-h55kgGvMrv)ec| ]w QpN]: '%ALJY ^OxtS1EI9`%7k@  BMIn.I8C(I"eřPRy?1  A4Hr/PRRyձ@^u,2 RAVB{>EE߃?7_\oǤ@# fLp W|'I*!oqe.|\>\ Z!C(diJV\L("?r$ﻫ͑Ms9k]M+(o]ZFTC3B\>Ho{_ n{׆ć4ZӪS?вz#`zoHwX03C[xDuelJ &i#1"ͩǂ-վ¦9$5T`{Sq|#U_9L]2āB}'s "V01d BXfa0JJcɍBKnbBsi N( dw^r3tC잫7Otɬ -, $YN-ҳP)UDTey #MFVMrb->w4MB3R*q 8OJt4 !75k͞W5+ <-,!q1TTC'OhnŔ]Ւ/Q}iڤezv na Uq/L+gk|gjV1PWF=cĦdB:FR w+Z) ӂ24HL(U6z5!X8B-k= _h%&(@h)R򒭺BT*8Oץ vT㺣ty|h]tx_%!ZE۳k/}U>Mx{\6#؂/'^fWo>;v{owއʾ9T^[qf(ݷ4s7cM}{ xlza.EX cD:ڠHަyj$aعs'_pH拗^Ó?s ֟|3{kЄ0Дfz19LHNw >%qlmޡ"J`%${bj&̼aX G--M?*E=+jGږOSUōWӖkLFjqEj%p`oX.Y) _AA%Ҍ҄^Z+j:%ҒFpP8(e1-SXvJ$J"$aˍbUa()KG5Ȟ á3*p=mr쥔VC`_:w~xk^ߢ9+\N씠V4Uađ HM רmsG;:Ko d HBq!" YS#@*Q\x}5)y(-|?r,saeg ]LFw`hfSK%k ҾFQ*؉c-yy4BB#gI)¡U?o Ai'đZE0]4_/Əo=Zxk|#T 9yvcOxBN?dmX/BTmYG0u$~'VO-]0S<1s6`rPȱ-%,8&QؽS.;BPqnš[^=KYjhm;t's 6z%BvЌ.^-Oz%Ow7I&#Fi? 8oaҊfQFZk Re^RJ7qx{9!P_=V2՞!7̈́_X^!IK28.c0hRZ};UZYOQ  D "?/fG2ia覂Sؓ4@”eIgY::3!5߹K H;¹7dT0-LVY[RFQMeJiY G{eQ|;_=(uݓ<$ieEĤ튗^i(UC H%I;p0TH4'&y},[z*{ށH_w>[@8".\U%D c IDATcɆ :77"1$%#[OK[ӡMW`L@XWI™wUxcT]HOrZM|s%9_?K^h駟8" LQnEgԠbɲJ lާLG>C;):q#œ̐>@=4+'G sG)Mj6"yJhʱo8A;B%ѨJV>o QHJ V}׼Pc:ep ̱0&diI^X66QҊ8#5n~o% $_x`5f_ [M\)Պ "aH$\PA ;ڃ&cLC1\}FxTEӮ7:Oq=>jd&D7,}6*e *&W<Vs?)y̴"tT_XkXh9(#Udc\@i".|!@)jŏ&Ǔ )ؼ,`Fϥ7Ha-R*2/JuY8)<I]x7]5LZ@l  A>Y- ׽΍Mc~(i.959:3Fb駎>t+8qXVV  1Md%iZg?N%= W)ua9Iɝ/?HwT8~n7 jĩc_g])==1 ,gIrOc{ԲzaJ`!W/MH8z`Q 8d6o4*׎aԆހZuI p mz=ɂ`dS򢣟A@P]*:C)I}b;{<+/DJ4 ƌҿi*#cMfJTWt˒J5qJ hx oK˫`\(jB|#Bcڱu*7McBc+!/3F#éesgNnrzmf?e~/w~xџ6./z|8;Pq@.wo{6x@=̳)AIX,H}`ߕdmصkI["@w-92W\Ijjiđ&7bt@52K%T\8 2QNQu~k""EI?y(gyXn(a}v%F0H?a{-ȱ}X.7(%i5qE>>I-m-([ @@ъU|,c_pa{|32?5 OaPOvaJ/uyG[ˑFYV;HD8x-%SvKc/h㮔xjZFR/cC E YR RJ.X'9d U4. ;b_7)Ic _=!0+ܰSs6M8qHnRZ,^wWAEYfcC7H:a DJ{E`ˌ t%cYE*_CK+_j^/bv8q!e=kpH}tW[$'OLR#ŜfAR)Jqy!yLɶ3lkHڝBbصΓ[RB(3lDf|q'?x=cf=?QeaPpK=wG{,͡^|w/TVPIBE|! ]p $7 ynC4۶Tj%yua(90 Ivǰ%s uPY3(WP:KEI ' veK acei&%@В3Pȉ}۫!եgyLW%읖\WxPң!(Xd#dx16>ocCѻFphOֺoNʉt -Ϧvp;~5eq΃lDY,f>k? AJ(왎U znllR{QϒFw4|$YΌs˕ x)/G~%l-JȠ%P@;b^Bz'ͷՂ(V<&Y'j@RVSc<)XZJ}zA( *A 66sNR fjg+ :wryZܽ0s ΛDU`yṙPCwuNXډcBË/xn ^ThA%ӬD$  8F糉4bDS˷F7Lrdù0՞ւ#۪yXc0.djfZ;で{H!TdFqɫfȧDE+*sR?e.W %ؿ+٥S-RBaeJ$Mle;ZNJ^IshBn8CҒAj^4aX Ki=;PDDAHZey(a?`X/VX72V pep>* :e3q~ $#leږk{KH(,H<=u (-4eU :J!t=qApx@zH@eB[@MworIBGƎcU '/%Ob(KĩP3o:\Xm1=SW!Y^z&Ňg4Ϲƈ~8qrPKv-h4GO|FUJ6 ȱ=<|@hfFATGf^t^>YH#vܼ“Sk`q3ei ܈*PJi,*CoE1*=QCJ/Epj؜02*Ԯ&Sq\C P>J=EAk01<Їxϑ{h,Qu֢H;`b0_3Ҭ.*չ&t3nPAPG.uTƀ^gq10"%9UUWz;?ya*|9p.>U$C7_!!Hr?e|_Ko}gs\l4=7"I+k0d`hobu[3plǎsۚ:sS#?7;443LU\ ".d8dZc:q%)aZ9(Su7%OvNSJ#=D 6/9SJduƻf8}ɧ:Koj< BЬፙeg9yECKsA00 dNo^\Y">eT#7LESg2_x`HV¾kvG\ܬXn),E\ꛉ XInWwH=4bA!P0JƅoKc)+K+u"K0 -׶Ysa#EkK+t51BG1H< `v4jdeuFVY6硨ktf Q(F#xBlЊϢ $Yy7kNu5q\ҔYdn*`<;jڥ8w9%XZ5ߨ9qJȏ#-.lT)x" mH|WfTz晵J ?.cZGO o@IX8b07Hf QqǟLԢHI~MCvʓ2Q Mw"vOG1% p;`iyued(V”,ĈlA~oD+ZclRpԔwPDGEoBvu)Y6TWqOё)*PRL_#0);;%ݱGډe!&韎 KbK8A oӓCH s1Yȹ+3(Nzծ%IZhn32C&+ǫ$B(@I+%ys] z&#CzAi+vvdֱ6#ZmCUA ,kz?}$@de4p:Y'ϝ˩!J.|*dxK}V{ SKoj' YSDؒ K ?7#P9EcQ8'~U?+J; 6d-1 –tEe1j z!lE-z6wWVqҬ"18󛖿q^rh+y ;$E͂ yj&+;bxC{eV)l5/鰚\ʐ \˱-f]3d 1~Nv̅Ĥi0>Nl 1+^NU`Q,Y920]$C-\優G6XhRМ1Ju31c,Ϭj闂GFC ‛{<g5+5IY6rP"c>2=TAļy!{ i8[7@EEn}Q(omaoԧy176%[%ܲSsO'ϖ<~ PH(0.NK^6xarl)xރ6#5Kut)elw7!ssd(iu&RJ}1N=qwվAL!O)JƢt^3xG;EfH!a"\"l.M}x'N4[8Z?W?GZ!oy"A3k)BPXIi`rXB- "Ю93lSMoOBHUUQFIJe!w fp&!YGIPc`+?āGnflS-C>q\#dȕA؎N͇96 fk:J# ë'KGjGW6ތmT a n_ ب + ^jc pR{bTC+i5z[o]RA8-4J^ g{`zEczlgU됗% GMYBWOvERxR^sZPYh5|:E ?<3 hQUۉF D|Kt{#~/sg7(k)(u,4?y~/ #BPM@IP1ݔcО\k_*] O5 f@!)csMRګZ|ߣDQZJ%0_fL1|塳E X-)Jͥs'w+#pL _y؂$Y w)r0ՔFc.1YyĠ&IE4g6^$ÐP,!\\!b"JJV3Y z"TaEű]~'O+WݻXZ23W}t(yEhyB Ț'$Rm-h`e6^W N^Pf1[-S k?OYZ4#Й7;ίlm%?1)\PYa7#ίz ~n\7_8>l'$# 9Q]U $ȑWnX &%UY15Dm_}tc+GaӼ`Q7 vI勵u(C6Z/ L[#ÞGXą-4R^ucƂI2&t;= IDAT1ݔ#-Vv%E<lSvIȳgEo{LRo2};x'moӈ4i oNȓZC[H(w88-mᕀa@J/Mtc5B7#"Q}G>u1,$ 18?T u*ݓ"˨[4ϊd4 [Wߗ-,F JPWVvXI$yAiRqmI1v4EV9ft o>;]yΣK|Ynn67O_Y;̲2ꈩABcM2)l-r&99vQ' $ZyxjݰчR1ЎSQFLPlPae;v]F^s[BK˻h7jcdK|̏ٳk77v$' >W4j!M,t2r}{]1%1֟ SWNr7PىƻS@x 蕒qX %u\C~(W- 'rd ,O n[똎ʑ A-V\j*U)L4v4$?3.x ms ="2 Q9 =F7I1Ƕ:/EW]8sQig@5 N /3:mxjI+\Grd_ C<~N^JҨ+AJ>K tSgn_\HX(v/D\ZuL'b0ANEh0D(b6Oϫq$ inK<mY luc*c*tO{qW!E.l;/>ا4/~ua'lE9!wYkt ҈Q>UQvC2L`%f(NʵEđd$:݊R;kt)+!:JPiz'b&XiǑǾL|_W7S>d"Q%S MJp2l;WajHƕX]!"4RE<[ʡٻIەpnZ-0㵫ZR`ע7~7"b(n:t1:SmIFr׀oV&>\N6!~wfCc8'p*)#r5e|MIDQ!)esy O1㍟/y|}p۲UxG,ֹ0#cֱe|~ssrmzEZ: )ekTqdd#h7XR4kĐ6zDhS"KFE EO=ydȐND΅xJOf#" 7iR fO>Z4!Eih5joQŌXRN e8w͡˔"-څ޷=7a{XM(oNC}_(2J3.fɉZҮI:1qŰR«833x+f/\N|3Uz#z9i}G毞-1ImT8YlK1-6cBr0,˚@ KYj|[ #ERXm+6+vZ{%+p>ѿoa^_ȿayNƣKKK/>+?~ ~bxڤ [MR }-CKY pX>o% 5G Cɨ-f/ާxz͐Ԑ 2+Ȭ^TK_K2-,JI(pE߸n(D!ocXR#840**P,A }RvSENS{9F6u#D`1;^us9VBn3S~`;omDf#bVz8[QT^mЮ 56ܷ~/H x /P*IJNÂݡa%yl0g z%$mIV:VCc/R 3Cnp|EQM׳!Vl+byur> «?~mpvオSV?v(襁GL|uX t79{Lw`<(5( H7iÛ+â?nDcxXZ ەBK&F })u"2Χqca*ͮGi#QΠr-")roF9,O@ua/CS:;bRD]7(WG%Uڣ(̎#[l+ /rbJ'Xt̴ݔD[Cd:4Dd.4 s9Kud3UZ# Pm\ tkR#p[`i&Ĩ% -(h7eOhy2!}8CѨ8kfg?ˌ0L&kSp*_YHeoj,*SLspJ4OYYƅ#'OF!+!>r Y 8q>vYHJKwc_k^:E$^ő s\ʙ?>ۮ?S ۜ81 6+jJqRɭzoe;B.8`cP ?QEU]%Bj.nZ &NofZcHL!"Tm-^7l;%p,Jc3ެҖqzpS' -ԣˏs78qn5ac^cž(Ozw$@:ˁt5Ԕc>º&4(k",L$VOrfCPi,Fm~_ =o'4,M(SIPY $Ak} 1Bӊ=~X[t]Sccl脎M>+&7Ҏ ?O< ǚJjX /ŔVxÍ1 w\?9=pX0|dei%Rh1|L=4l 4tZ1WKi7񖷾c7BD={! %K3xB?^w*Z2^ 'C֯HSv ~lUz3Vv AW+:;ЌzN6!3'[fj|9FD8 /9qj0V#Ֆ@--c J)^tl77t+7"ꑤICx =Ca@J6\$mE-C kQai53w8'!w|瘹u' ;ZAR,/D\ȉOmdF~K,Sn'*R)"S*#idy1?y\3( t +D`&(p#%]{^<ˣ'ֻ%E턌rϕ|SdqfPRp-Mή܌=iD~齘 ;!q}|$(+RGQ]'7`'REN^ ZS;/qos rC(?,"I{ӧRP->iF(l'⋛r̹@uQDVR;,i{dgfTd†uv-Oq-^pE#K}RY-i)oaMB+`iȰ N񟇃vCi@PRѝW7'3hnmBTm8TN0UEh^rgdf䕦ЊZi[~;.$(3v= Rȁ&~3<,;.h0L ͺ5^xmAP|%YjqAIO=ai:1ϧ!/sk.l IN",ŎΎQ:VD8m8`1cQ!gB/(,4}L] EVҟBZ!Ǹ%?6{E [43Xi$(3DJp~{3{!6AfI*AETְ)Ԏ5>ERRSֶUX3[)xgs꾏҇ 49VEUQ4_!_'X[[e,ѥKl? ?3S^h,_[h9[4Xekixv,H+/ic39::5z M>bg״ LdܕScq'c{[C_MB7s5?w5y[ 1̼خϭRUr~KR[#˾ŐX>gOY*Sڳ%C2b{PCXpiX!_\8ewݱ1\*XE`J- RXB o`o*q%l& [oyn_9=>@LΑ&}(A-\x|LaRRVBUְ{!{cمlgMw9 $4k1y1Q +TANj/c}WѬ%Mޮ&I"2>];X'qN4$,#~o|UeP1$ZA3aÊ@|"c|gYZsRL`)}M=4Fl[2N ^!~fP>ķu0TuZ+uw^ |tWE.)-rӱ:\ \0|׉GWl dzrp/+1L !ז5e/Lw R✣2r퓮3u1ل@8O* U\Te!^iY^&9Βk6 )CV$6'aGLOUah8ʱ1?;!qqBMWV ƙ)p$_r (kR:v-Fh2*1q!#%Q읱 *Q!Sp~R،Q챁EE|` )2B j'1 .g6vFz|KqtHK(Lw/Ӫ ^tjϣ=Vf mHSm*qa覎AG{)bB8`ϼ")g<#wMFΞg/kYuݳfpxAj %ee yi98 YH R;$- Eea(Ҍ~O|sOR)VS-@ia>i%pBژf}tB 4֦dpHn?m-#α:2J:萺:ay+:<̐Hʱ4S<$U'<9𦕘Qc$ ?E",30\3Ǿܲ:DžQ8,iW ?aEI+n\UQs$<|zED)nN?3W}ٻc 9şX_==عW{xGM3:19r/H)6_Q6SS.=U>?+ٙrMo~el믏[FIV 3#Q/I2n>+Y2 I%ʬN ptB<]A$pY2 Ac]-o / WϘ'(%J\UNS?PƆ'9$[ aA %F'8M7$X6)ıTF^湸`W(RigȭĜXst"[]pШGdޞ4x*;9M483w* UE(ғW3E&;kU6 ܶ';f:zu,+  ߣ;\q|oʑi!83]{ǾL|{_WV#ZqiY*"I4:G߼ȃѥF["i\5L{0_(TġIъYgnaAr㞈qaI6yg%qFJJ_3I=t*rUJw#l0ۄk%%\1:wa%$UD4z$RH!K w^;O.0o\Cmn2<{lH*_Q㣗 IDAT#S?"$ney:_B@Qr|ʸ1 9R[~v뫎S)C*pFSjm)0Z=@kG?q!Dd3.i.\ZeW) ƛh'2_;FXM5!R:1L$dS2= hNO҇E`~:H>mIӊ8Jcƥ#)f-sqʛq(K le,?r{Vȓ~RJ 4a= hĂs}tC kܻX<܈qC*A)foB ۥ#ɼJ"eUVq.CM=a!qcGuLdkPcl(PhbFih^Cwxq,'퐬cD]|mk9]m~n01ġ#i)T4#Ϥ^CVBA^Z.v79)5Qᘞ$y(I ;y/$9Xk^xdKރeiL1._hƜ)M<1>jʲ92ͳƁP $Lpya@Wԕ F@ f[5aqڰ0dYp)^Η$t3ܔb;:5Ai,Z{'7 bQ2yeX p^2ԂqsjhjˎTL$ gc .ڊ,aw[~/X<_}U?/z1a7s/\,?{w [f[yLN ׂ~V2ab s! +(mcvv.(21W!"Fp%xK ǽs_yu7Ta!XkQ_a"$RfX{-ۏ` W}(ٌNgKLYxj?GE`*4NKKKQ|43QW~S%inek" ~4$I #uAZ8nrnے^pEnj 6Bd ٜ Csf=.:ZI;͡rWWNթhQ@T9G稣ΨcK#e 8#rnnՕs9w'0֮F/g\sUqg?{uĖ͂f5{3k ͚xְ\%mw:Juk8wM TGh%ʊF0[8*_ʈIAqݭ"  EM_Ig5M 5LȤť>* O36ǮXzIW{qL4-FԉBME/ˍCc>}BڶOWhmWXCmk\YM@xD7zΈC/㍕?u`$/zu#M7"2J 5x7G^L^׊]cq-p6S!þc}{gd:9X\-}YpZhV61~<'Y "E>o{8V\Yr @-cE-5JUU9N4Ãe~gvB h Q%, sH !C R"QKZYsRگ["UtxfǴs Yn观͜P:&C}Wm_gskHXRS]Gcc-{v+|{6Q\҈~$/њ~n)*lI&#mVNdSѝSR O|͕u;Zo3fi$׎ܐpi0Pl 4Q\I,QH?5đbGk'?a{dKrxo,iq^ C0Vqu6-n]Y;zܸdPꑣhQlKnnmp`6`;dڢ8O /_z $>8QJI iŮ)G?ctΩjQM^"~g5BEi}a|lոQE==c^i)+‚o<(!np1^x&qHKOx:UV?i5ª^YnX8~ .MMю*b[8pR wNrq9B/*ol:tz%缾sF G**3ΩRA4an(ьaTB#'?JxC>t'J^Fs#*mI".q{VwPip~Q(88\xxl„-Z (|L@~eoDN;ZaL4]R-i(v+6SzNu;v CS5b%PQD0,n.~"޸(*|Ɓ*#leTdUz~{Cp\st,z-5-| R)? 0K 'XXGyay(ks8SNJqpjv")ם,4 ` A9&=9g|މT3OpW5=|sMg$Ee9<%YRV%y(e>A=^<|9^$567ɆEX19W_JylJ^F߃V͞frB]yXOsώ?|}WP> 3%L)[Z0.#̶;1)t Hfoew촜\)XW h[#lB̵C&aN}=czezt&1wMnđARm3Wr5,Oe q$r>윍 Rz,ϜP  욈8u5nx(0jʲ"C B KbrVsp4IQ9TQFM^2Ⱥ}H"]3M'4v |sS̢ *}OOܺ6 OUs37V{7wGl,xt-`TX1 XUĵk q(Sg;]o'z1/y]+&5R::]Mx#O@ܣ|'hK)(JyCǯS 2HwKYד:G$$oN Yc1ĵU͎J)eU+kx6%8A}W\]; % e}G)kTZaP\0yαag[LFD=T#lk"\ 9z%+E2~ /reT.8: 'K3Ao4$(nƠüh X\ RZ#$6rty8ayÓ'%a,x>Ψ' /;[lsϢ;x jS`Kˋ)N[Ɠd3$pi )>𺙄KCǮijG`QԬa&Lp+" c_mfZr,vt ^Ig['E 7&c,ŧn2^63wO𒷼lv9|Џ 7t0mWۀaP?-سA~|{={>ȿ{ǝ呿^}Sݜ6928bԎ*+P#zg4ff[gw@ZV7JXQ}s༏( Qpxb9q{C/| 3!ILPtktzlX$%Q94뒲r)I= KeZ@^Zc89K9(m ˆvbv⡯vwͱީȵܒ(-zq! L- 6ㆅ3Ş]-в=k4V윛s"#dlfT̹.Cܤbe۠Az!BˠP,Lts;aWS0[Q[! itk!ori8At%GlK$<⣏Xޙrc(odkا֛=yR1?34)˿ݷ{~esD\-wE(}v^2ի9bğ[-$G 6s>`+%2] sP{1>XZ8B)iN/ IDAT2~o^rDœ_yG^w襼ɇGUXQV)7=L7V,w*Y'b/Uӳ˔EJ3YnHsM6̽G/vT3`q#gVD#x!d-ᆀ[S!V􇆋K+CդвUQؐ2F54kIް"-<6ya$uEk?_7Ue˜Z6Z[T yLƋojpyBHyIq,AH^0O%r FàT<̀^ɭc.a%ٽ++)Z}"TJ 3y+X˼xNb[b'z h'/܍2YqdW0zDD^zћń_~S~!P9-G?^B-݇%6 }w,D@?Tڒmkl-# %DR2׊x+|οf5X!}h Nv"Pp:w+AQ}'Ҙ2D[dJpaxBHEt4BIRQoT"x$c`b]mEfzC ĪAOx\G0y6^F\@e$ۚtxO~6qs7$J*)kB.]9u.o88ܵcgcRJML=/_yQ_%fjhH[.y_%Xh$ C9Z`^P-GQRh0||ju靥WN !$8xΑ{g#o^`DŽB[C}@ I(aa,`,qN7 !Hx<5 ;8ѽ9O-f_o( &WL1wn^6 $;TbDfIBɘZ"Y6b&[i@Hj&zr'Η^ IE=8S#׎@5Dx`ebo!W߽[7tWΐv5{ťy,?o?mMr d`em+yFZeaLX>\flL1X.lTf.W;#t3`rC^}'Jf Kތi(wK&Bvw'Ḵri17R#n~qҲЇ/:H+RiA& c7S|>VoBU8<)%#.]qÜb]G=EZ:>~${!|3wBP!"aXYɩǚL%O\*=ϣ'!_-yeQ=/>I('FQ*Y/!Ƴ&k#qG-&(􁆵XԲf+s\0L$"j,I&[?°W %4BW[NYSH}ܺ29RoBk咳+3S1(9ְbu[{`Qł進KY⫗7Y\Ҍ[Mhk s !DrbNN1gN3MޚF-M5UUp`.  ,I$*m 5q,# |CXt(JRT0BRϮO&7^&`z,2H aړy vxޭ-6+wUz `2l'ȣk@&h#qx 1d[P{vs$ 69G7:g8_hIZUTT0#d`c'y3v\xr$vgS]ca5 вZ")PzY79Fw7K%yehĞB߹4hhonNrCllW̎|9N\\O9^QUg~vW;*G Cd+Hb3(EJʶE8JP9l$kMBO OiE5Ea›V$UcXh0 $a("taP4[!@C bǾ4EBjNoknEJmo/䆿|x(P8BU8ɓgsCOʘl60 6aqRP9YpѮ Y819su- J cAj+IYOrzΥ͊۽ LiGȞSWJїr~3!(7JÊħ՟Hy]djF#;CZDރ^c'; ss[3QWai"-,5pAB/tN B#} u &"3fPL4,wʖ@ /۪'|Pd: åft4&ynraR|QL$s5v J#t8Qt] 6r~YB"ގ pq&++C:pSh8|&XzE(d佯 85MV"dl*9DI{^yA{Le) ~ccrÍ73grzl_}T#c.5~'~s~1EG".Ic@#-|{O<\PfxM{fU?Ο{ɊͩH ? VPGF̷hî)<(Sv<{y+_蒉dB jxbg Z߳KpN2ސ+n =\GIsA@B W2AH0 Yt(@F0,QS-\;:yQr&WJf?HQL4c +(l J} ?4˫%eeh7~EsE5bY{N1 W34$=d2Du?iaL":X|n$_f},}sߔzu"y(t_2^ZO{CFIgXüD A-yo-r/q׋׵bB9c`ܳ% ǠQ VHHN(tXZl pl7XDecxǁ|y! H*ڃ @8'7`RB.s4Qˊmݡ~6`o~APҢfk 6և HXAZb |JEƎ׸Ubf^ijD!KPRe2aV3 M5cpt%fdo%YIWҨz0=_7!g D(G5lnu%`~aکN( Lf@;dnRbl ;'C1Fv= 4k=5o?X^/5v䊬 |M N/lm,+è؛c1u{QA@ JJ;BF_SCMU;QڗFh~{w+' k'~k6F~B59fWcP [ݒ2T I Op+Aw{"Q2 5ih* ~Y9sǯg)A::bmM$Og}CmZHBca"VOx]ϟ.HK 1VhS OU bMׂdvyǷ0㻾u~V$:Ω+ifd'7k R+8q3{Fe8WJ݅-˖ 9Iw!dqKAe/کy67v{KV!Zpc-$8g1UsaMQ([zAHo̮JC= ؑX^r"PJYA]zmNy&O ,-*w];Ak]~cOk} G83%NGVa BA=եYƠR8ch%C:FkZ1iQ2Fo{~7Qwxݛ/eDQ#?ȻVa5;C$b΅)Rkje,ougC)W{_ NЌҖeP^KP(HϾύ `Rml=!f~ZqSak@rx:#+c&t *#q#`6X :t0dmy4ş~n_%7+r4Ј$_zyT;`ׄdc(FEQX.lX._ȹsM:;4\7!再]KUaBe$}HN.Y5Ii>m{s 3W7 I-!ՎRNXZGv3D; T(XHBҌ-&}-LD47B`PQҧ;$ZHN[+JNPIC m}u厢T-k =ʓ' 6zUrRz%BA(j<?Ԕ&+3V3g+*cO8YA9+[V9Gغ0zu;1R-AXJT<KL4+u Z5A-fg`2QV0u6:eF,_ G?p3R0-HE:K[An Fصё?R!1FYPv@/#K4ɕ^Ŏt$8rB qV0S7wi^x=R8z\T'HnxPVEogXXo\3ߛ~#x+12ӦR`5ġZQ ʇ8 (2g?P_Zpvc@Igld(rD |I}VHQ$!3ȇ]{:,v;in~w gI"ɩʇ}0V熹^E;iNQ"&/|2zI7U 3Co;9P yNId{19\3퀯^,Bo;<-SMzSTpkFq)!UdP*Xh;6+XXJzq޷S=Acw=;ը+sG ǡôIބAQh C%|A]tTY74Jvūlͩ%/ݡai # j @0zN+ o@S^rťeocERkPBh5< w3ҫ>tuo*($Bm{nefM5nrY_VP=}{%lI^[^}wP 6K9zO Lh6t:N_JdCpz),-dX+`ch7G<ęҔqaBIwԛX@ e{CKBؿEK[jHT3Q[[ߍBc6 Ɋ="Y* suYe5 0+ n< 쐜^IJv6uUaX‘ djD2q_\Wx6ŧ)W;g2o,O4qsETO-;g\qA~wq׽Ŝ?Ǵo6qhJ+AL@Wd&.+"Wg[g*憛na~6fRJ?ƠCHBY8fH+ǵ[kuxlERKoB oes; X-Dp|dy82;. X -SeXxM R+.b<\A TRGXPyɉMcBR]H #ԧI?O=WO1ӇN/4IfJJ(b!#_[8)heeI=iJߒX!imkM%Yz@UH2r޿:F^ծK*]CWmww8q zgIþkE\\XhIg1FS9-4dSRX6 I]˯~xO~{DCeɆL(,;)LFc'.qj!k~(`y`yW҂ҌRPԌ TL['Wkr"saM@ï$raG4bIHZ+Npxߏ^]hpYzAmy_?ʜ+\R'ݑhm5k=8tV#Nu^[V{J8|Dx( s!Svi KpJ&Xc$2Moq BJs(籇Bx-⋓xKSɦ{nFH%XZl7na4\Ř'<+xZB# P7G]Y008J 6b÷ $NTZ3ۉ&ϟHSPJU#CUK}wPm>>,8@AWMK)H09i,f"T(HsC#| 74:)*d\@X!iNR8xe;-yngy9GI됙&[%E^qݮ͑╷#'f 1s 6/ivnMx؈P"u?Y Ea)CIj?JkCkEh?6 IDAT/SǙ~ɩШd#-$ B2A O/ B7P20Nb+ǍW68q@*ǰ L}[#PJNo?Ͼ1%V<6'#y&EaHcV G+ޡQ $Dynֺt呣]Tvα}ccUh.6饆lx f"dҰL(ϯR\x}!;p_=*?l?vv]>u'%zc}ޯƙ ^>'KԄGN)(JxKβ'9O?VWeEF-o`J2t W,J:N>ʾٳ} ?|+7x֡CkVZ@/pBQa֧1Wt(}E"YG/(4[;S_x 1M}7yXT/^[\U4B-C]3 ,j64ci@pdgKSȱfI2›eL$5KC ,/,ҥ832/J$8U*ǰ0|oR JdP64?bũ6Q$|:G/Ug^E~&J0Վ>Y8[H9Gwj4|'!|5%r~ơ<^Y;`~2`2PY쥌xZ{MEa|©Ŝ^j WY_|aS/F @JU"%/[k>P[Oc\Ft+kNm7Lpl~ l_A> Tk?_c% |x1L zANDwXRW@ ;H4/:إ)+ VNPkLċ/w2=Ʒw@rl\^k)%9HKo WVУU>B/z-2$nrxSeM8dS,njucui8tO"7w!x ae=迼IEs6vEe8~6Q WО2š,XqiRbX }{)-xXpT^' Qp\S-SI? %84u~}f}Y g,A#7BW59T1z(~n( _kE٧?W nz}o&G)E( 7}ҵ,#aF$s!Ș(#Ut9S|+_ÄR_NI) PQe]F.i韧˒"-}VEMOY_]{gPgSY#ȴr .HEڱ |}CrCKXf|H%5ti)5\q)H"5[#GtQ G$JD o`yeD3U$W&@%65:37]!vvN+?5)f*՚dl=BH`aJQT>4 %;\/S <طe JG02gT\=9vOM#2YwRsϮw:eI>m7gLfuXv^[:HUL7:gIjqzzI1U4X1dcA 2Ng/ެ8N0|;j74jZ;jrJ2ʈ0+,w5]f#/e-rN<)0RmW68l9RUX0;P#n-\8OGs1g+OkڬƒVIe,&~6*C Btj~fλB@[6z>WhLHZReΥ,-=_Kɺ89'g|53L^l&:͘=˞Yz_3L /kX\\N4YKݙ׍v3F08CyxD1ҕSOAR[T@s6 Em GWV0rO@lXa % [‰3Y|C_J7J`a2 ׎;6FݶvX Z~%2! 7ghc*KƧ ZF8 A"%4ΖX$+ Qj (GDmXkg/QU2\yaJQH0?{gsC -hqRQ ~vA.>;;7EA-*5 Ow6(%8cD,z9X%*{f#7o O/y15ðbX{~nn~tssm)ƸVg*ȹ k%r smt.NHa{ܐ{c$U[nPaPtsͨ C6KZH+K\xkUUu_A^8yA!ǩ재i}$TZL 1C%<$ +.$ RI0藄'S d}`8 eXbi<`EA+eFoRawВ DzMU[CF es*%*d(1iv" G0w?+*mYZ45ff[ b5$=%/+ /|_UWә;^'?|Kn,u)8%PO$CM?ch'RIG ا4vV|X=1bTy|>% ͽnߴy!#*7n+SI,)+h4)loqہGpyNԺҎ2p֣ݓ(Dg9v%ġ4yxF=AaKQj7CIMbίi(MS3g ͅtڂu9 +(|f ِ#}=EOrR2GOyHL=0ې4jQ183pj/6.A5Y"y.::O,rBȵbaSje1YwQfTIdLbP8LglU|?\~%^CDńB;rј7d Vm혟}4dK[㉒{< ěҵ6$`_S %m󊄙FȶN;mA$F@LuJNkG !,m`E(xS?D'V سs"EaPd$-kIDuNOz"5cDRO~x,n:?jOX]'b>]R2Uz936{IQAmu *BۈfE f:HsC'a(nuBFu5$"g~gBԢQ:O顤?sl5ƄdPJR_v =cZi-Ad;&%a Şg5Q~L3> E;m5rKw}SX;hYEHSK7:uAPfyU sBk1*rI/j)tfT+q1Չj*纆H7KIϧܱ/bJ a53vg>$Pd:M=ݣrdG|={i7=djd7qS*G6X:8njFC@ jp:op3S3ë?ZQe1PjC54k +$XR8@ M\S N"zJ :4x/EY˨HDFu: R_W-3u#_o|oGJIÈQZ5>߿C\yZ: (vN*^vm_ZmXTJcu}d(\\DIÞsMo(tucROD̲6 ,>u~M7+?;]] C/OuBAYֺj pր-I;"0,P[:;_ ɚ?) 8ԅhGs,-EerNj.ljYJ'OQD -}lXZV\Zs%whz$zc}smQ*b0Ҕel@N\R k6WIudF[~>8Na|)p]왯2zAz\;(cd8CSu0le"S#ZYenne.|VIKǃWe02:\3<k, ͷORO͚H;GkңUB/s`ek4¶^Xz/pՋLhmyH€3KIq‘$D0ۢ߿|e7Li"qY1acm5 눀~rVƲD),gKjI@pնf""EJjX잏pBpaLB&#KX7nQqބ,>$O3-9^qR/?VRN$(q~`։@)|Y*"* iƱL~*"$/Fkz#N82 )wz,Y Ƞ66k%`ڤ(Eh+'W [w Kx|pY51u)d|y4ht8Wn b¸iE Uq5ԃ(5Ң *燆$wsQ:Pu`MR=;oiÏu& %aT;(r*=ϖmMl;Y28Rl#=.,gfL~zWAf`-/gZ1NE7Lo0au)A= h7gQQHh7C*cxz"uv]c9r1CgnJ;\kZb`2YˏA&yᯥ042H(ٰO- hĊy.OA8d<@tz"cTj zߜamhq-tETmZ;vN)"e8v1]13B vLHA[ Rϲ92g'$A23VL˦Wzr|N2v~ckl(WmKxM?L,,,l޽ ˿ߡ##ysÏ3_iCD3y8j9Ge`Q{/w!|C [% ˝e ING!v1u$x_Љ4Mb>Ot,!b% 9iɊ k};QS̀+vՉ% IDATT3dtpY~iLMI^H9܇mT qF ?; pB _=2 $q+_?( [#Q] SX<]Vc enB!e}!aiP$6|KG;[ҙT8'dN(>8 ^N#`mDVHs*iOy5?1LvH3XMcF6PVPBy;[wRT=2⺛I"_pjqs^G\HWi1A5ߋsbfID0aZS#zc3nx,SP`MIH{ηl:<^7QJ]L6ChmLN6x䌦t" M74Q+o\@*Ź R EKvoo#CϟQU=z1L5nI$Lv:xkx*| dk`{0R闺E2fK'bW%W+o]4kŌzy8c*~G̮III"hc`kSrմ`X8M(~ De"k\3A;hlڻS7~e|#dfq(ԉ FҀAXxs'e|J|?x5O̒aLQZÃRpjXӌ*RV%E,Q>$+ n)JC# QB0G!H`!uIE@#6z]fStZ5dݲwKoc{*G|@09},r*٦51f1;ɖ&,a(0NrLCҩ)&f'l O5Ɩi|q$qIӞfnQuVR#}TUJ5CCa,wbJG/3 GWJ&btrlB8rpN qXkL3@Mo6F I2Y HrU/t'$=A<7`Uk Q,/&pL[^R؎Xwζ:[wJ*miwL9)9]W{׻~?o{y=7wÀ>*RIPash QP()mA#W8(/jrOer5|>*rm(1 I K]KV)c} h=(T3KouE3veJCZ/KG-LS{L V7+B% f'BkjG낗h aRO #7qvAP0sK %||R@hce93ۖt꒬\{噮 Qf0_8GL{?r˙ xk}8ъ0V8>懕[&c*XVp g6w[7111q~]8cYfBwqֱ66.)0"l`P0g츁k^MS'ƇŮbKZN"lE&eSts;b|QN.@2@|V=Z2Bk7c6(f0pԈnVƹU mOc9u"A&xEI4G>3G6 mZdI( 18Q aϤ]l9_WR?X ٻE32ank *CKpM(!uϜYY/pq'o ֺT_ύWL03>? #tuWq An$!򤋩G"K29X,3V"$D2ѩ53SL; - 0VL70&JY*LNj &jx^zk ?sw`u=犅g\Я?#EhD /C8I_FɞwК'ya(`yϧL05k 8cسƹÚ=@>Z]"9y~. P'5FRK@&l$I$yɹaz RV]} ׆S93ᯩkDQ_FSwbOA= *gsQZ$|k0=s~٭K%{N;v}(zrS]?{* Bd챬&ߝBm 0pnbat+1% V U옏(!dH!8;m,V/ ڼ&WX:Ag+Kvksce\ϟ?aWsc,/{JD8X"qL5<A/71^p#mMҌČrC{>Oן|z0f zsҲ }Qـa#$BnSVT*/7N!/ݰqrh+7ωdoiJ*S!eS Va;&-u#0HKOtCucqM3#$ '\:~8l߾뮻c/W%.R64S@rHvG3萗mvUB(@>&{Xsr_% N?cj 2Hd;fYx=g/W~(CS`.Fȗ͑}Tx{y63;G2ZSg3Ґ~ۥ %yd_^_.hKF?}%thn8@]dA7kYgTYKQDFQN52,Scm;JecJ(%|N{3qHZݘ0L$dt,ar]? ";w|>I^xjρ0qH3V YyRa^~Zb%THk!y[uo}wz=⼳k!J@Qv{\h4j9_x.8K9ԐZEr#l:Bf$xi6 jՐŕm--!'8)w60H3yOD6F19YhK~[7EX֛Q$#T"ɣː5):S=ͱԆ`yvOtzkȗa95zPX="l(J,i7}nk %6*YNN5;7*s`,6,{r:ŞkPcnɱ^a18lw&+gJix"*x(nwӫ>ɹ`J:J"*qBj%NJXm!ĕ[mQ~6̭@Xi-;_*瞿_{sy+taY]8>uuc!'V YQ)V&zΞmUnm`yw/mj. >u_NRD8(sADq,VJXd8dh򥓌Wn bIznihG5kD$$yB1b# $ANpFA(}akjH>{ysV8w}viJ/KǁcݨջǗ5=G?oQXz(H+thūXu R:A1yY6Wc)lFrݧpښնZ,hpTC/-`~#Ĕ倢In/zȖL̎d[&|0vX)G^`"A4P ΙNc" H*V)yiCz$׎fܶ?'Z h޾shlppV{K\ % Gj()FњB 0]gG 2d"HP0zZT0" ݔsPla~Ϯc:"$tU,jOU䖧=ciu Mo3֨ R2JT"E=2×]0H+ &J)WY͈J#߁cc~IjPǕT_n&vŽ<7x#_?qP7se!MS-yo-#gNA@î2 /#^E0'p4+^(? P"@~}.nXK#$`ϜVC y჻J=/*kd C t.c瞧87̮#':HJ-Z(opOXGHLm Yn, +Bq mhwt fg,f*<)S8x+0PـCwH -(rp&F#"Ig4Imf"O/%6uXZKr7 `4T+~}sϞr {oPk-ruز=i#ǻs4Gg5j8ZrۃA#mN0fɈNjϛPo-fUb5.^ 06NQc"ٓG#ƃ#ᑓV RwJ̹G,.t4TH^  CgyaRհ2Cb O^iԀpH O?GujǓ/lr9a,4 Ё}:;8m|/Βn+y@ DŽ1*:2L|bAoX{x&ӎÛܷNz.n)%?]I}bюߞJc%( I8 e}`c ggjYΞrG?-8qe-Vӂm!͊>[5E鑒#PPIbB%E$ 98P}]RXvGXVr+90e[iB{ Tn'޷fE7rH㋡Y<|<|귩ƊLá)h$-t5vֱ2>›qBqUPI) %,xj07&xtUiK, [4~@ƒtX01^UW4y#Ӓ֠ GDJ'DI7+²ѢKfLJI}CX{S2= VBLʠySo3c5I pNa}8*),iJkPŴB _ * Ry0^S^1}ÿRh؛nzW_ @^grr!SSS~׾eYFݦv9p_=IOь#>,,4z.bׯn-)YLj*P EO!:Ӭ'kEJT+5f@z&MG2J(McJ1J/xp#7frfHA 2:HșsC']@JJ,.a'/o\M'(ǫNZRX@''I(OhFPOٵ>= FZN02rO+|ŦK\MRжP2`# ;6VXhiz%/ IkB%k(\#o.3F4t@?pd=̟HbI-F pZ5e )OؤXY>Z`бV&i=ILTk!O8 i #l.iVI) YZ" eFxC%(駖^F`o}H=T++4+oYA#]JXFcҀJ%abD҄`t<涻( Cm0Ni #=ck( @ۄNגiGϖOgY˖uJ' nwu/;h )|j+giҧ7ƪl ik`ljӋtPFkAV85rtP ^;i~Qٟ~ӥ8#f*_D|=̯jz^˞`2%%HIUQEFF,3#r*۔ɊEG/YZ\䟿v=u߷ 15 cv\p>QBrE IDATc Jl^PNSUReeC)u(t'? SsCXSP%2J4:Mm#`cӣ=eHE N 5`}d-V%X |!%~Xr 6NgHdM?/EY/~,O{R>=0Htv.Hs_ TbIRmlgqə1m|/‘.'WJgP Xzp=\JZ,]p*_:\(9E']~%lX6nsmUұss‰*g\SNRWfC6MG9|5J R)TP$+}X^Vz%DM:.^bsf(x:T]-Y (~VY[Xh_GK669z{_xY?Kk}M5V4bbjU 4cqtWSʈrG O̜IrS[_L oi k!cVHI5RcĂN3" HH7 QhI^=f1G4 zFBLלĭ) F-)_:)y^0yVr:gUBԈ"-YB~"&'b f BɁ#)RykFHXEczc11[mϚ?}.ݻQC'?@7!,eiوGux`LqEb5ġR[*#).$? w94_ehG8XHNYjKT,v̅pﳹdW83@qL1,Z_ v Uzb$P!՞Yl#`*m2rr٦s&5&#˻XcIYB'co\0kE6G8`QڒR(;_PgshP>ŤLQ"9r|ჷ3=5+JB8A-]`r(bn/\P9L6b6V,K 3̺0Vqh,p›LCnس}*Oy+M6s^k^:>s|躷qW'>;nľ$H:Έs(8kfͯo>:qSf>7{/w~]ToNP896)OH* (/ˬ}nJ^nr0} NUI=]/-64c@౵}:N , '+ϙp6XwA*،@DOB@XR8$^.a+35ɟ_[EWBaC#uUM5hkD4c5)nӬf=R*T#A11{sRB r7O&^])҇xO6N>"ln:D\ܫfmh!2/`uN/7( +=pk9yGLTixqtѣ]t~pOZ)tS[YuPiι[k6;ϽIJh9BTO-k$jf%[6Vu dP޿ Jj qrk ^v8 ȭ,oMPVDy?HYZOz gw)p/!T% 0R9?PO;9\3n{xnade8c~HVDrx@TO>zG82hTP斑W\1gSUQB0xߧH;GVX:)~ _ pka uWl?(y\(;kk+5Fj-C|[A.f7~Fc }_#)Of}$OAY i-7 gLPz )I5BF ieAgK% & %ߦ[dY!%S{V-KHc$9\nGH2jHDL|vdkH%#(o^Ȱ2uI%h~~P<+NJ^NZ BFM"[ qL&1~|0ވ(,-wp7/ӧرk7/Oo}Fn|ezFjϡ5đ>g7v}8o/EۣF{*d=<,3;,,䁣'xG_l4#\tΡOO <עL7H !8kFs`#Q[!/Z(~P vLI]Z] )7=dd +N8d]l ӝ2-icmHf|z*yilhu 9-ytZr+hr9;Txѣ󆬄"%CXdJ>t *P>8*9T z%ސ{te$)X?5=37rϜ!]m`"dڛ`q&*҃ dI$Ղr 4b4>#n?cCu %>)J@8B17rD`iu5ekUK<61 -Ch-GMl yj,IB'sTel^g)cLB/|.yKL~,k=C/5N㎇R+%EiCXmP!v11VY{1iC2K(Exf7=Yr0CG_}dFpWsd^=ۆyaIi28M7đ#G8p/|%dN]wOٻw/?y֭[9x }ky{׾5^wkhB$abbqFGGz|'$Ad=8*qV3RHK@Ҝ?L-G#2pdIM_X[(;D iGFFٷo?RTdsȉ0mj{.`PFP oEX+QsH]ĭbqH%c' AE]SƯhL/{^~z=ԀPX;LftHZ?1X$NVDDF+n^LUȍ8A ,@{ .20 ` P}2X-yCy%Ʋ~RYX!/(Z6 3Xe]D^Ln:>V5pRhضBo`V9Ǘs>u*S8[đ m{,ֽKV2jՀR[z3-4EضBTG-pdm#=Ws'~'^d@czQsxWzVGPB;)|Td&VA*^)xCiDȆϋyx*yaXXf}zf#ii&'bA@%ԫς81qt>'ݾISpdT!F J`ǵobHqLS" "BaX_0Q`(sqs /A@P-g 2^lI$ w-%AF@g)‘zYyΦhvjҬ8!҇V6c" fG$ m S@Fb0(O:3a϶@j9$l Yh #2vѣґأHkj,IZ+>! @.: 3!k#8rUZ=K(3ph79s/iƂF| <)j;.Q霩шQR1JYaV13ۉ͢Tt~ijN4bV;OƑ<%uErlqTC1iCViaR23(z#F+6Zrl͡Y?5Kġ~ʡ{p#7~K2rߑ%NUU~( )qO8{ﻟm޽q&&&H?-ݵw^.BfF#aPa(YEIQqwF#6>=QPMy0_b0H0dU$+J$(KMYZ~W?z!η}1OL~LwXw"8Nq0h銡5LM9,(a`{_6 CE((AE1Wミ C$7$?Ǿ={=o;oO}Zzm0՚jstIx` I y?0JQynTBe*3*?3i8 ȍ/7ڂ1.}4&" jr&u?3޲F_u8\M)`"ۄnY"0h# :}K\g Wu!¢MH RȐ]ͨ<ʻo쀅[ZV3zӌZ=ÅgĬ _l'e>#eΤjb>J%tҌPBqW{ G Tb Jph7 ~铦@ DS#NjBQG/"/ccVQp^D5v1yK㼍 +&fq扐Cf馢힡8A4q$q2U3 JKZ 4#y ly!.se.ٹ!G C^JDeJƹ" f# #ȴ^<7~ֽk$ {- 7].I,/?}S*ؒ:QUѪtGbX|cBfU |$</3n{OLϺN>?q2s(QZ/}* !T RZ!b{?0 1V0%)%`j֏ Θ 8jx+_Î;'?'ٶmXaHE = H5'L%SpAZ_s% *dfOoo} 8k(JVcK.-믢eDXlYjU\ @ahXƅ'{fUZ_ڱvQHdDHCc0ccqfM`%P;wWuڵV8k?9>ssOs IDATRWwUBXQdk ~C#: %:9ۆQZ񴋪ltϚ(/Kx~0Jm&k )[8ITFUϟƧOP;fc,L):֎GG% &bz% Ո`I>]$s=N % )%I-f80L QpYf+RIg3[0lġ`kyÝy)q`?QHҡ?JR YZˑ*d|"am-QP+%g3I@ZL^r1ɝ,,oQ鉄, J@}XKrv{T'Y(XZg1J."9ul߱W tUb_sKg1B@#*9ZZs4}U.R6pkade}k" 7g)RzpUdce$>㼹Y=&I:CY]0 cCp+8> $/N!EH5HsT8?Ȗ=Knp.ҺCgSk[`#+-UdZ1MG ytI3^SZptD5 ԛ4⒙V@4MZ^O>ѷ녋֧/+=Pc{s$MRZ|+8 h.ގ T*]o"zCG^uz,pi~e118G [k [ϨehVacjdހ7&93va9(=zrǞrєdSzYhEmE[?~ZMI صIeb *1(*BJED3(8G9/c_: kR!ۯ/I1gMUg3Ig`k{%nw4xd)04w9?GfT*!F[1ߔRzZd/dyDYx iNT9Đ2]_RV#&"pf%]\=*x_Oi, v/./;qs)KM42 jU"@_},a$i|6iiEn$1Z05b9ڧ5eֲwwԐ6{׻s{B`&J^T 2|?-y׌sߣ[~ӥ}Z.[S`c . jL^,-wkH̭t[Kaa>9A\ VnJc7LKK9dǎ&J3Ţ$/|((rˡ]{-EMpѥW׿nxYV⌏($qb͎a}8p̳#9 Ȝ^TǃQ#G~L|=LDQL>w2F[}GR 9 ᤤYR8džRhl[A5 zC_@cR$0SN%$.d}|;8X*͡$0M5P g ޷Pkh.QY&+;jb5ƎldrA>=(G=I?1t3Ͱ' R$poEI‛n@H"{Բx/#'Q|x/<|O}s9/zk9q >g\-OS^fRG??|K; w|Sf"<9e,⛹^6Nњ&wu񢛞[Ow wuvGdm4Ssx'DӈڽTBI:J@@H6sV?m4ch!^?cGPV3% Ǹk $T2vzHBRnd҆gtQޅg_{ptP:fF` `-vg7-7I3LĒ뷇`ju`8x~׿{8Ξw_TcZU5i5ԫ!cCI ͐w=o)n:n_ QS,=tle# G~VL_ %[CKP$ n.h,5V'8!n͊`RYvOjn_hqc"T욫+`]BA%h]g{z&c~lю!t;)|x[!wo|6jX^.K%MK{s@ӦY9W2(Fk?h5J-({~} EghXnkQC~*mh@B)Ͻ''?Ii4$+;Zd~"=t$l5F *@؜41scL+`߶vd0Ԕ78uf袋yC/hN_6 Q@5hVD$-;`FZ!򩞌pH=G"ԝzTQ:15  RFƍ$Of:$ձsRQY Mx:\HZ((JB  w\r"[g bC)O~0vwq$91%xbmq(tẂ 3($k_Ag$(\ۙfu/:Qg|e6XCJ샻 (a7w0L+'c/=FT"V@Ԓ@k.(L b|Ԙ 'RN&&ʋ%U [ tx~L$X(3Jiiz|PoͣŤ&Q;>z 3{}(@B+d*$k@7S6&'n_:G'-Qqq {ta`,N8 `)1K"f""e1Fc"r] %2B;. 2NL# l1P:o_y$"{O]|{n:x<},&Bp}~eK? ~=E1SB`[i/+V-k{j칈țe?vy>u~]ro>)NsqGg>[JC#퉒Z#}x?uqg^b&LdQ&zPHJMJkI';yilFK?$8DcP[#d"!'[4+1A2v79s Jfh:/2% 1V"ưsӚ`FrjDR?UB xτ"/s*6(J*hʼ7PJi>M:BbgxMRXEH t1vo;Spb˱y1B:ZTKKgV2p‡\HK 0TZ]oc"q ң{A$zȎAX+8Xhq y nj62`̱:n),}򬐙͔daӧeK!C{cd4pNP8A8qc_Ŗ3c~= 7HWl leC|ӥUl}?5{&"}e -Q 9q58[ ̠YI-̃!vTCjJdߖ%wK ZXPQ9BI)G[fWQhIr Iy%4K?oJPjqL%9pH%'^`C$M j`*G!o~IɁ$[8Fl@0j4Kb# $Z@Q$|!#8gPg` Tw# G}Ќ@+nO%C,HEV¯@Ҭ3;][o9S0mR9ffZy.aPK$|1(jրb3O5uq.*%1oAzt g=%>YW=.0 k/:ӯSzx-:ֵO `ϴ J*DqJ/z*C )kE_O^uKE,QE6s'xAE-ql3iSv*U] `[8yekkanyTJUP$Qa+9:,wJHjl'$[R%. mV7;3~k~t4Q)EipHNq7O=oBHH:D)^4F-Xe۷7XXyDN,oiέS8d m 8W"$9#c!D}:ƿݍul3\/'"k$aj|/fm/?H8S)gH*&CzvT=n#7 `v<#GVM+Pj{Nڴ4*EήV@,^3$* ‘|()rh'qy1ͪV򒗼8Ix/x)/(B1q~kb*O+h>4*^]M.bke{#h)JK6shUIcϗLUPZY85g3L 8J#1.d sb QƔOi6N}Kj,)\( ^ 7T[:Bm>q§Ugc9o]Ļ_~74ōWiEtrpJ*Inc(v_zG2f~ӸkEf?>37ϣ`| ?yKn%7>ӇB~FF >WsvQMiE*_yxtU"̀b ZjD(Hl F8X&qsv|m=oϞժ'.Z2>a[Ӏ8'-28CWHއzIt9d&xxUzɐ2L5 :)>+) cqJBX{˥R-yxUvT蔎Z*H X,X5q>[:J7q Ziv0B IDATpġGDK1B:6,ꑗ֡q 9rNn[XhYY{OhT6lRZk:}M(D7*A`g%k=M7uX'9| R!U' R(_$??+}M?^F$)W,S~8c3s.h63O %^7,nj &%H^EAu^JՐ"K V6K6:t߻*#BJ(m5 U(:f$ 5(u59ea /9ifE2,~<).dD!+$#0UO!G>Br HYUE"Oj5}ڶk-dWB#&@OrW'Xp-@˕an px #2Vlt e%fpjȍ)S}lWĥ;VPQD(dmC>|uˣI$H O"]dnN<;662t1a8.[aa5hsD^Qtյ,8c**eh5H#$\{Ql`i4G%&yV'oeHs8I>NJf#Gc ZKjpܐtOG59Ƕ)JJo6B3`Jb~]o~klvK"yW4ŏt߹gPIX{B;gjCX=`o0ڐk8qԀͮdK+j(:C%Q,,ڰczK:`Pz3)ak?`LN4ƫ:?%pсXYpk )avv%r98C t,b, ޻[Z~Orhgfv=fJ:8*$TX'8'"ӎʛVP(#ONKA8'ɜkP}|H2|3w/.;Nv 9 Cu##:vV:)``UX!hNo:%CI (Kl$xJTDfHUl=dvJPorKC s!x똊$?}Y[5A(pJ(q!ȱ vIC\lm^n^rLL_-?m/I>?'׎3k%Js %󂅶a:\r%bj_|Wznr ށ>&6Z K\h7/[`vny|t2Kn`~,MgϒA _yRMbRh7R)TVVKt ,͊X ҂ p0Ҵ"Mc= XdYiR*Ę!l3`6f><@p!g~<}Ͼ3♁*E=9G$KK uGY#[>53ʬg,`P@Q$Cy pqNԤB;*cj$Efװ'% $ J v%xUEZZ.`{b[{/y?/Y4#ii}ޖqخ 𵆧`H72l QADCʲ$ %D".w48{1l| ;]_|vjQ": m!-$iaylUs}",¦% CI=QƯjph!g7h!Hki aTeXZ¨?H)yAiG~YhDb4e,֖X Dh*>C-FI`E֖fs WA 0Nz$miѬH6ziĎjUq}mX7X@UZu:$qaGm-+]YG`'cVa`.1azcvt+잒\LjްD,p8qkRGw.R&GaxnLKYXS{lu5R IxLfrڙs[[EAP;Z!N*~d_F]O QP6ТI;Lq.a"^Zwn\ڢ3sk60;S%ٰG,,I8 SFιlOLifUC Bcb"f:2}C3<|x@Ѻ g[GR6C4'czk-[Yȡ&lus{@iȌdn£J:g}FE%_í~to<=M0rW?׾)n7X/J&8ճP gKX'hAW DQhͶВV5v6JAt4 XayzO8\ō}R Нt ˰9ZN j%"ƨqn@(Il__E33;K|˯8*o?P'\y¹(?r3H>לӿmq,C|ԾMZox#"yu.cO<Ỿ ;lLa9N - m3YgWX![Z% #h<Lq4Wsn d(Lpz@G(\|bP"8ӇpLnޛa[Vʬ@$& |}k`A((({&bN@ZMW5h[VM1L54bJ{K$9.zzx~AJ1 c4Ўs9B)Ɍ'z rC?3"5ykf> Kϼj3~"J3ZvO(NOnD|?;x[=  5^O֖'o%s=ۤϟyi-C/sܸ'HQXQjUs`[KȒ2!<gg9]&uAˮb!Xh[XJ< &G0!|~FaF c3P:Dz:EV0֡a&1ܻ?q1L1ӄI G#P"i8!X &ꎴ0()rSZ) xhIq '0RUC7 rw<3ݚ,Jz33 $AՖEZצ}aS[zm,,|~^j(KK&bV &o~浰;f*8X]p^p][$ n{@Uw,)ML*y>$ S1/<K+ͪ]16羹Xu4҆HQRfś1K41e@AO5IQ I,JkH%Qv@[qC>}[_o<_:_On UT˜d9i9JA-r shU$ݡ q\ڂ(aF3oo:z.~%?OZ8"g7%(b< iU9]znpv cQuf5 o4tqk4*J=f0(dRpeTe7( ;4ǗkqV6zHka[` ;3×x3mHp;I>|iz4sMNJ]BzH$bzzJc ~^ _ xݻR>(ʥ)R]Q<\uۏ~cQ\z%|+ί-;@_$`*x_$y̹SIp%Rp'VE!xf͢,Lw7̌3+k(*J 4!$al  KYnlhdJBR͕UY9TN1L{}+Z~~֓[+#9}= /lyAf.\74$fZMy Nm3j aZO(2@)TJA#m5,)xD)A,@OiIVuVxWr=WrO頕JT |xJ)Xdl,f!kqau0xYH^\(Z"穓%:4ŘDvͤv\14`ʿbeAr~۲<H2y>wֻnS03ӎThh8gi{R" IV oXaa'`kp(IU #ܡ ξ,uV0f4bǿ&zQQc<1]#<ܱU 񸦞fol_<fcW޳R[Voe>Uַ-wl j.mTƎ:aMYμT'ڏ_jktm{'cZ{ΝsYD]Saa!UH[2Qi~oDJ픻ohU-vy\B=t:|uM :1gN6M._ ac.k*RC ( Rys9ݙjbnlq !;"I8O V"f<=VK5y5M5R1(+uMYH$n*eh&Ui$ׁ԰LɒۖhĂWPQ̇Ӭbkg%Cn_}aʗIplְ4*>.Hk6! e& d®F:{W3cF!o63Wےq:oƷ]Oqi3ɝp߿MAY~yRX[Oo~Gy۷7Pc> |Dmݦ/ l R?Wj5ﬣ'JwM5!LS]a}Ρ-U&%h'h$b_~Ɵ_6h D҅UPxdg nRbґא8V4X|ClX/GS03q҄Xz90-bqȤ$12e+?]ppFs:᝿1.CTUl;1Jx冺6t'YOѠ-R [5In6 X11IBʠWQc1^d<`7q*I$K 8lÁtVDo蹼'kw*TX_/X1TH+מ )*)(i^ [P֎N*X:\KOk+ ZQ :^E^{f.ThZJ3"=UTj# /|q66GxN}z|Xi)#m1 /9 IXXNQnLRvPºШ䚫/#n$ JYPk,SY@|]jM43Ra؞x҄iq8XXLFQiٍ[e\r~FIGfxQ" D B)pgG(xn -5UGʳkz^cO3z&:g!DQ Bxyx_~'&[y\)h6 ޕx,|rtwRX9VbJ J "i8YS uh/.5{5CD\N7%Med#ZՔgP#H"4  .mkRTc r9E TسuXh]s7{$8v\FOc +/2#W'ﺯՎqEoq^nUk` V\Y#=L dvJ $I}Wr:BLd^Jg^1)$YkY"DťmRJB;he1SaҶЎYBӳٟWۜwMsk9#||ɂ"P/G@"hŹ֌G~Y Y8暒ʆmHZ ڍF(hbO>HȓF.PQDol ]PDk\ٲem{X)]!~C s–plf0垔\|R!ޔٛL i$hR{yxiuLd9=K/>$x+:=)m4Jyw4фR+4C1یLh``4|XbF gv~?>ϓi+z]i6cT8^0CYkO$ZSX ^nS?R3) xH=LD ʲeM3NSrR4ע?8,_{,eXA9 ,Y 蠻fE<1C"%hDS!4BM?` Ɉ5Y YA©RFv83"bsʾuxq< kz5|ūȮr쎇x{C?J!"ș_dGh|oؗg1i .!ZZ0MY1aT:r2LIc-B e&!M$鴩1y]1I:a‹Xk/s-{c&ze(T2 ';Lz16PZ ,Sڊ8?AP6HYij$#RIv,&2_T:@!+Mob2A ѭMbH.KFV y jV&y.Y, 4 +]E;nMyB8wv6 ׇB4#2Ȋ/D,ą1 x ?]ɘ,`tpx)%hՌk#9busevƚ v։`yxd#L9zrʘ$DJ5`mgLYZLKݘ͡|7W! q6pS_]{T |͏Q=# PA- f?=8qfvѸ|;ԙ`=yiчlwECڂE4\pMIjb\8`i.=V@d$}]Y dEDp 8A`v6#QhR8;ޕpl0Cs )l'%2XӽrL9)I%!pP:jRi<=)[Rje=N($_Y ]{i7kM Q,SIM rnI&ɄfHe J;nZ z,(j\Krk]-#Z=g;z#;U~-Ξ>ɯصg:Ʉ6hDېD_x=?y~a0qT&1(E A!%I`-"ѵ&|mQnRb> PF95+JzNT {!߉ fW"B@EA`kf[ 9,`o_>i"ƥcX![bxrFI(:쟏QrǤ4"qB[vc67 R[NfqWiN_fb~6%[[qn$T:IYbDLED{gBcegb:ί3ǰS#z[&\64*K֎ܑ ;Q'%D`eɤ)sM1DPȆuT6aH\=K>*y뽰)z竺 c0MuH wcA{M|PHAC?wRS=ϑˆ(41bUg*1GuYPJu܌B8L>7Wh•ޘ'aRjOԜQ}wK;ڻ)!?qeĺ)b;-$ kز5QpqdR8-L_,gT$I 93\ȩjL#' I(Jzt9aa.b{DW4O>svF Ksi=Ź$rW/sA8%K;5&ۂCG-vxv=w߹ ?/̏q_1~#~/z=XX́8q}a8\ZF44n06$P 4#*9, 祹IeX ayǼ'~B,¥y?p_!9\Y1Q020!ZaKN'o]> z@##G_lceB@׎妘D!eGEHX*GXե֓`na!yf⽥E^4DH௞)gjT6Bx\Y6H"7k勆U$Bx6l5cOhTD(uҫ`)yqpqI% UYn,F$ȊP%"4ݦ;][#)uYnC"rE*lHZ >DDa;L0/ 4"o)z|RoLVʉ !Ji}h($H0Jf"J3L ao*+,waǟA&H/]^m.`_.u#N_=v3RBrz!|7c)xMgܔrR5/7_ ]XEQ  <􆖟j#8w2,O^h dD#Sx"Q0'$ZkbiGxYDby"Ʀ) >]h&za'CƜ{cR/5 , )Kdvf9H e&os멭EC-uYu $q$/ra/GDik$a_(x p>LDpJ֞aEYŞAxŖīN4MF{@0ZsO?=С@mO"*L]qX1;];~B΃AϘWs<׭|6ʳ3p2C-Xh+۔0r8)b F>30j@Dd&l B0ی(Xݪ(˒D E4"R9a\>!-nu{,E 6wٮ=czcwI>aRXHW5>_%&Uzcӗ57WL|a7/7_ңD`Qs v'1/0HA# &O~H%D(OQQBֈbOՌsKU8ZYo"Eo >EوF[q@ZAG~, )zNc|1$T榣mZ-`dE ڣ$aG/ Vm;Qy5H$. +ؙX҅/Ӡ,s'̋#{9HcR@aLГcgo׬dq•82#iC]W*P5FɽwRR%i%9t@;fЫ<k#@҈%r?|s\+X֐?0ocggo--ןZ ?7HB-Z1ʨgN[}Wq46YDD8)fX>~9 H0I v& c|;FVPihDC;UKS&wI'cp8!pӉa127T~E54[--H2,GbTn*ԸH*؃!W5R $X@)KQIs%GB q?}}13mf$QF*V60vSzsKCʼD#<^ j2 LEܰ/aBL#GmGutťO, *#CmWV(dm;cK;ڌuŽ]Ab0ݘjW,BFۮ馂NCq߱g/Vskq0`%`B_RX ^L7$0Wh&*h#iS!*H%Ma

Hh#I5ahQ!دiJ45TRQ IDATvp!$&`@djI&uZ^&D9E];j!25O92)2AZj17ZG4zya4ʼn(xD-xA5iBC(38^(#"L5˝l4_Pe`]4'v=V*sxSiXS#dL Wvù@VACk; Y:0sEƼ6/i$nJ&o bk`NYz͊ YB:1 s. ,d\\-Y߼H%RM?w}gy׷d3QW'yCE* v/%Te|p`c(ڻneK<{OUسVQkuGی\^Aau&+( oKp~B{Hޏ_*PgW%6 y>;w7n31Wj4l)%Q`Pz(Wdqx)JO)ӌ `#-6Q΀NxZ24يE鵒Ҧ c<ANBZˤ dBqH[L'cOW1l^~zx8v #,]G ;%Um^Ŋsof\X /B \R4ҐИfxsgw& Z7c0 f|Ś cKMB3{(=cDnfu\Si/L`$`!ܪyn01a"= /GlRȄ$r4@kbG]Ejmr sK " ?6 CR)|In>rg6H;[nxV7΃ }8I㾷r 8W\:ntX(BeD*lvtVnޗo>J@w%:99I/Ƭ瞼Ug=(j$H Ks_yxd"4q@ZaԖ'OWT6 4e,;8yy$KC4,qpzU4 YѸ39$Pansi0Dv ɵ>J(ȷA[ Jqy_9}%3&X8x`B19";MIymP*L׆a-0V!.P4 M%VD[ ^꟥"PIQĹ:lXԍ.\f{F:HY^mjk6> 54) ,?dU{cG3hmTQkaPg1P&dqX̀,Kt1(% 1&L~(u0X 9Em*mT ː)T_+_wB@"š}#c3H8a-L^)wD!'%qBߎyIi" ƒFZld`[qASgYyɧrN]Ԋ  H,0cE!d9IB5RGuՕ;~aj_5c_U9{kRyiC`l|RHfi bZr!/ }-6"ۖ-Fʼn.8Ze:mɘB_2Jeðv8`}O…2}&s}sw5_zJ7bg~Wy 2=S_i&^EplyԢnﲲѿ=~?3!7m0ulptҀ Ryi'kE+Qx4JEpk?;|gpj^M~{8g=Je+!b6MTh88 b7M4x,cy} ԆYPW-'xO4 ?#bHgX?,]0::AV%4$P6(vhm38'P$r9,0.]{^Yv4pye9Kx7QԈ5wϼbie-֠e3K$Y&Xlk-DԠD 4MlU L+AN%mB (R 9ЦmqO38"bvpvrkch%0#S9 <xsrHSͮ~/ek<ܺhfh`ᬗ[;S4Jg-+Ų%kjKGW ,ƫM5(^qnO^rB○/UY>ȁf d ,K#PΖ)ÉHLA[J{?z8*pn=!1a2i^0ϳh]-vkccVH|` ;;s??Be%Oyص(Zx8(`Id;H!"z#زk/^eoױ>ťñj!^<\p^Iё\dx7~gK/}"kdl.\I4I5:Sڼxѱf_E옉M8ieեW7+X \֭a8禤-ᴻ[:͋"?| ]D|-Gښ0V M(5#Idj1. dEƌ $LpbIS{>p Ҽzr)D^YT @XG:\Y+#I`<\+[Y~ysX/‘n=:aL•KYv{->hԑߟ 2ZlgOx)(Ňz JПO9;ƵL^3bFѠXH`VLCN?ڙ8eJEbEOe3D0INi=mifsFz5N-SYUA s-YnMdpD|>b[X&Me؞^\uP\ax\˥\Hpޔ3[3((I #]e}1f<&v6,M^3QgDjF21B-*kE)`.})J0o{*'nch0m y%&iwG5Z%"+J~N+=>Wq8pFï&HiHF|,v'\ؚ ?O<]0-ZQxA"O 6U$nC`g\׊zޔiJs%Ғbm0[)fp*?u|ushw2>XY\jQNy*b0^W.g&hp`b? YvA NE HkBwvc|aRA]Ѭ,.Lyk ٞ(IHi,4w?G֧%"$^[RUuBX1D2#Gw=cyx#؆6b@-0 \)VڅBڇ_SfB-/|yFnx:@afYER}^> uHA|^Vo;SKc~(_ƘZ y2 =ѣg8PP{KB\|Rpuٚn>*JLgs1F-I3`%(7J&s4ѴfkQ@aAY=-h/zTd_Bdu0*Sq㜪jxLKu$PA1p‰]nlYV:׷j E*Ł/|7r"yK];9"߸&9eYrl9)kOW,Қe}0+|Daf\þÍm"k_w(J|D(z-)BNK̠ O{Z),,bR{eb[ؗF&(NhjM$rQHRS"kR>*FiiE/xtTm)hl, qIx8J!%!4H Q`C q&]YBϢG̲}FL<ܿKsfiGL kP Cz$0 YilW(ۚ[O3JA#ݐA`B+Mj0R\9Ef֩ϤMOT9%v{VSy}5Wy|Lu :Pڟoky;oO KŃL'rbWܳakܰҒ" g;fD  C=rQsu,-kI0S|E' n <1/}' n 03l6ԍGk9lof4n <;)E &A@&Z5mî4rڒBJ:12 6Ӻ&Q|~g&:DPvuU)Ե4uN)ijJb[qhwF rx7jٍ2-%@h֚`Xsc1Ni0ONDJWQcT){X\ZZ)IɊ-{ڹڷ͆qEm>{ac> υ8NlMDIieTϠh\qѳ5g~1zv&a!Q3C_Z1: CEpoPDŽzVh%fb[˦BGxzYĊH'( (yg 4?v;o͘n_n/6(2Ìta&J gIrd޾iʹ,vS5%5-0ۈJE!)VVIl9d}oZz~[1ިy4O,\+2.^xwΨkv—o*)r#]%F{&YQV<>9-Eؚƍ /hQkH&ĤBA^~U9oxHZv.ak$`(={SB[ɝM{$uFiQ=E˄Iw0eg*߫N;!B>b{ܐ'rѬb.ւa)ODkȳTvۤ+cARxԤluV*CkX˙̣'_l#Y`oL"),s94ܵa\)ܐ%woƙO?ݒ֒!iv%oe_^c`6%IijL؊IRV5yrIru:G+ .-Ns-r:+:V {{z)E!J9|AWx)ZG;@I!xҼah8nLց# &܍Ce;63R5u3l[bRz#ml`orEXq\jX)b}ZiڍȳDZ>s+ٹ~BjesH GL*K<ǀBZk/ u#Xe %J/Uk s]i9񟸝?FMjǁˎq^گ+y-ΰ?Q JHק_װ}gm KMD,*z& ͥS|g7}<̓pY++] #y!,QmD*8Oe襊м͛l?n.ۛt{}|x7|+}9p4&1<#=-ŧ[P e z?ڴ~"\s۲f̧hqnaK}[{xd3fgegҫH+U$8HfE0Q|ݜflM,悐\dwC'q̺**ZQlhI?Um0u0vehjO;t-!c`;ud2>mEK!b䤚m`WLų0,=qRBi; c^qO\kbց2K'PHa*?}1vc 7}siiZ .Dj'n[y VJ's3R .T\syBB0tEy 57.ÕKLQ$ T89;3ʓTT$bN1zm=CڃVOa\Niᅌq-wSdV,s W\x}RTYɱX蟷i".Qh:L|ЙS=vi'2V46rRI)\h"T(sa]S(s ol3<^͈5slO2H7FUDkͧ/:ƥcgةB0,=N4cB":=kAR@%4v_ VzK70F4qW 5 Bk) qZSy͡[ +pyv 7J^{ř5جJzpΈQ &eam(:y Z=Lw68NDP$S:[Lʿ[y3<5/_Ϳ);e/=/Wo{h*qjS 䬏 l}ƭɟɟx'3?c%_<˻s׽/};g/_Ϟ4=#R8|7]75KLA KBZ†`"[ՖfC"D$;,I4g#:oFK hMu+yV z" Y4J>f Z J;3ʩg,Sijz؞z I t TQaFg+D Q '"0`*Jb''8dptwްL ȤO, {6ņ S_x _́CټOuKj "ϻqsf}cH]{ƥ818=ì΂ 9;匵dVG"eX ƺ E:95u@ H ijבSn::! ssk b"@ G+ ڤxs`&5sm!8(.v$F`B@Qli||{-c//~:z rWln7 }4 8\QY&Ui l.e)iEt^ƍAMcx-B87Z6wFK`k^~GO?=(~H|Że{x}~]DŽd+B\С{}x}P䙑ԉx4C:rHg¿6y$DmH4eȈ!ՊcEfFuxd9qV8E.Eō|'k_XGDɐ`hB֚fZN.i#C':ڒ hUEXH"4QL cP;nF1,TbT{~]0(s>n?qJɤYwR<1$F J ;c<[C4>]d5Z؍N"E.@"(6/{ C K!Z:;%ISN @'Sbu!26ْRBHc#W6NU5),3Y!優DߺCO]!Gcg}\qvjF;ͬBh{H 4R[X$=kSYHp8z4?=\<0\<g=C CTGB𝯿O=ĕG#+9NB|ٌ WMkg95YF]]sZIpVQ*Ҹ砕CU)66MNsם-.;PW|qN;7L*=9ÑڵS/ß'D wwؿ#%G-BZkktk=Ϗ￰2YFJ#*2ɇ,YڶCH̬kѡUgHpQ1h"10GX*X#TGX((kz k\ 2л]/"O ]˜Qr.e;MyݦbPn DBzbJ;Ut EjB.Z*r%48(pj)%B6@uD+:)&b8s{ e h_BtV7k6ڙd&K$3NLDk_u+R-4k-,m(+!ҝ}7&aYbx|slYsaҵZZmd>E4mK.S&[gK/@?ڹ= sX<%I5Vr5;k^X!4l% mb4/> ?؀դ}DR#U rNҰegjJV\jf '. *k>LLI3`hty-+/Z`cYіfuoNgsܸ1gFDFdfd&Ii"@BmKmk%PԶ-^Ue.ŒY@pdɐ $Ccd|qomwOSD8qb * uɸ@ZiMܞ;n3)+$$Ĩ%J)._IYn WH2"K|A8sf=fUZ֤hԗʊw vN5tVNlURZ Pae!aT>h?ZC^y觞i 27T&apʑ#*" W;OAr<@J)rڒ o%F1, A2FH`l5cҲܓB bbȹd40USL!,{\78-!0 ޡН" `Ϣa{Pْ0:wܰS؈َck,~( Xhj\0]'ΌXĝjy- ♯<|k1 ft1$q)%NR RkrQck^~Sv7xg7eXyN[;=fYӔc59) ٞ FD`'f0dyVILsK,-&+B撯TzOY)ƙ% VܲڐŎX +@7VtB-3מ+x cBX1}+yk^j<hS+\ܪ(*Vh-ʅ)6h7 <2W'KLuEq4O^5bzVN<س>tl-a`iasd$FHL1 qs'%J/ Kh]+L୫@70N3*  9p'@DJ$"u'Edd2zJshֲ>qJPPGhuC NoaXb2h"-ba9eD<ꉽz@E_j9l {\Okvw" ,0ĭ| hrlIS6y\l7a4uD Kz_ k:?UOU+x0_ :nȓHq.^2 ̳<4o-& 0nJ BM#0MiaY^jvA9zTeǴbCa V F;n]T^@N?/zޥR%I(M]{aJɋ<-T)=,pT> wpȗK`]9ZC#t4cڭn|e ьQ9v %@Jqz5Q;bk\'[o|üN(꜆NCxfɴb}dIs\?gyIkI դ{цF@&i3[Lx጑IiY 2p锹XSpc A⍷7#H(,O,Mٻp~X1:4֤K5Ƿ-}˿_ae^>wMi=:Iސs]?ΝƛneffV~g|$gnd(cXYyXkxwn?ĩo}#=p1?-咉gFMLN|믿Ws^"cnV(u"Nh;޳]ij=!#]Klj=nm1"nPcG0Ncgj@7[lM=JIv?<#hbULv@)±cf rel:G1_?x~G-\!aAij-yFy# aH5AU;1겦WAeD=-5iޙoa]%d'侬GyHByBTV"ۙiHȫVBj5MdJ+umKfbwrT9B+KbNyn21ևB6WJ&xڜZ-ƢՖGV3辐վF#+)*!UWlyV S['Z[LS$S+*\ Gws&qWn'"0ReEs'*"bkʩhf|\Z9X4-*<.]ܠ,y0FcpD݌9sa"-6 ~\%:_g%fi)kKO r Wd*^UP[~ϥ7~O<2uުfα,aFdV@ֽ|ra sL$?c'dee֯JC+RTRh#teJ#/Rxd; lYb=[k0:O/Cme%!]ՑJ# 5ޗ8eKyҔ⩰>o%YҴ(DŽU1C t9ZcZyO74^ԳTDb#xUI%_/L RYa{֊+ %qyrLqN:^ FJ&TB-^kF)1M#4(Ɩ&[J,ʠJi4 ,ris(AZ9ֆpeh%:w͐e9eQ#;9*[1׎Is\stֲ"-ԋn++B* ;fC߲Ǟ^>ļ5+$xZ"9!>KkOWΟ~Aj*|#>5BCZ86p0̥u/q?x+k|GeuL_z//v'ɓiNt:֋v!l8J[HLqbKsJJ^XXBwWC׆<(iR,4 ћ)bb̥3Wx[OSdV`L(G ˀ^ -IǾR=4O 2"0l_ϏcZoVt!&Bz X+Nl{ƅ,\ $O+Ա{&  hפּu`9SϤȞ" U8' Q0+.^U%Hs#F(WC;P I4\8 <0Va4YegbF5 M?EIؔt' A.=KRFK6Ii%[=rMdphGvX1 CO\'j\iEySRx`&6u=5=u\y*qNLI(Cv sk9Zy9u6r6XլЌ`X.*6{_3 pN# .oX4K7w ?M b G+ *=viϜ_fZ ,qހnu1MΡuNQiJROoq-L_n0fZmF%S9KZBRc->&iV{)kfbyl$61֋Vɭg8J=7/l y!ήQqy32!GSgXػ#Ij! ͝o}ǟ:{yb_S=Q(f_S<={wc\>} /|o?~|GeYbJ.?+V}<n&vlV5JCM̅qQMx˛x1w[1eXV:Kg[L*RLx1)h!@BgbwDqLDU4rF6.^ $DHZ_fP4tqjWObcb F*b__<v/9z[}8; y ?&/- AF^@Yb6襞g%UhOI=CK%!2 1:9G3TxE"XCٜtzJV,"2Z =5 & )½|󖅆"1c$bT#BiviV{-)1*0uj0$,=-ӀB&3Fd>=M!4mu*aRZRR9u2Kg*95rO頑hFq erфm *8?8ˁWPy3<#c6~nL/4N3 HKygw&wW(\B_CYن)Eko㳏TNi,9Ήi^k1ڶb0) CghJkш Exխ _*pV1wQ'!['hcxs`k`SZK..>#fehqb WVAts&y|l)tPg.<E-ܲ{0HqMoK0b4-(J^bwW'54o2T`$if%4tZӈafoJ;;= mI o:mTh,H1rW̍y%W9(ٞXeƳ9@ĬloQP8K;!i7q.~ah{;o9}%ǖ=VD6v5cFպi8:9hP3Z6ҐnqoRګOω-czbi ^)fl0qy$4Qcsl&%.?%0)"c§bR IDAT}Èr+㍯|.]`<آ;, > ;ecTrxlnw8|}O߿ =$(!(|7y-Գ103[?8Gص{/ |/sy}qiT1K:~S'xqw;v*GG?`83$fs$[@K"pdarE7WJ߰(Y(WJ&ɥēZ) ֓$2"!IϽ4[vY 9k΍[|s-6=2saԒYЖ EVAq{% "A@*føGbk}_1=Z9v{_q?IZy*Ww[Yy Vd6C7ē͙GydY:N(2hos|-x {w0d4Lc#,-:}Eä@tα1x%|Kݜ?;!<;ZJȐ(6he.S,WҥMYX+L;d&6}|k+y$IpO r׊ˬ0A#Xf,ˊ@t}e6?JUxI HB<HkŨv$q@h\6 ( o  $`bʲ+/ ye^BvP4?\,H4Ţyws/جf0lIDe43{ Ho9dçB(nQIurǡ" 4s Y7V cӜmr'Wz^lE %| auHu{-`cSx=J'=Prt#mcl4b%N}(4Þz)iFÐHYrq]KxԔccֶ+BX,sjI3 O 4uJfW(51%0Msվ-iXT!pbul+6H9M^=-s,5I3 Xщ+}ct Ox֞]841Y%w$iaKˍQ*Gok8K;<||/؟ӏ~ ,$B䏛ɏ9)O?3H:\ 4鴤(/DM S҉=FW/{ٷ:<_Gk*deE#Mca};9r8\8s^o^?c]t*)3Ȥ^:~s{5h%`uxɊH(\ ˭gT ly%D`D'Q&N䷯:ЍrNmbel12ܦE#P4JhR9G` 8Y-UbM"٘e:n=֒.dVf $1' [BTZsވVRHPL3B1-4h[[ŜͩÕN$T!mIC>OEs^9iZFXj(0)jEZX.mHcWsW?ؓVnxMr Ud޳:BAP ûHKǮ\`Fk!ɽ9=WC)+.c( fSGY:bvrձ"׾ >cf0[&7:A݆F4LSRq/j!Aʜ+(&0"U͗[!\V1 4=/ O?/rѴZSxٿ1R|bM@*C7:6P䖼iNd4ˊ(RP3p(Pp!fRu\KU* SH4yOZhLq;~#Z |=N^8[KDeY (WNHct|9E.o? GC熟{;! !i@,5G%n$-Ll)X.A:Gl]ɣsܶAE`|7& .h_q4{Vbv.6Geh Óg2G ZA4dBqw݇$7d=u ,L2gaHy!*\fO5ь )S6dN+(%3Gnl1 $VV\Ɐ_x w8*" ,f@Da8ql-*.O$Ht|A;VrriZHM1$OvpiMx_ϫ>ʳ<˸SYE$p5 ˱gySϣuy5zx F4h /ra8貏I E]7 j 2e);P5,/Ґ2bL DGW:NbNr- ބDDqVql,$QR!2(|uҴB]V} TH&VP6PUUIQi"AݤIa+4C0 J\kdtB:4~Sg6Q\YƅiǚV#xrJJȧI~VЌ-"4{RC|bN$z!<fǿUWfWy9WΡvEUP)$JCcp' s16`D4 *IvV\Ue8=FO]ka}*x|E ~ݴ+5h!m<@+T&ܭOz"Ѭ$@1HV%¸%zk߅bNR%MpJI TVcLsg$|fD)M"4Ycw: J)OV #75 d*0Ƨw1l 5XhTpTΠqQ8IK"s<5U2_A'U&t ( E,C,<|/ chg0H{ [E(t[#`'UucLVO/Èn#&*+Y?q[̮ՊcJ)QNY}uX/Ca$xMc]RDqMDX:[" JXk s|Iק72ae-DfZ-|N\v.15<4G>7=p-"aamh3x]$W\2ƷFc3O~)w:I{,MRLI^YАGNg3r֢?o=qgzO~}4%k%04gOtePdA:le=#ByzŊy!p1x7dQӑlHva暑|EH6K Ÿ {E-XH$EH\!‹ L$w^iJǠ?|UC+!BͩŁ8v1(-~PP7”cҿM] 3b%XiŽ6*˄a! j!T m"y/|_G;e($D| ЉBQS}mБ_þ j A$Cwtu%kYM|*%$2ެclK2$Qө?&l&/R (NJf#Fe4b!E8fh+j aYlv( 2&%hw ]t [hLlU#vMWm:Lq+V&P*TD9:~%BDҳ1MMSrTPQߝ 8L'V[1"H"&K_"!⯻fdvAŘ+z[uƂyN[f, /)о#˞[9QI>8mL*ThJC%ZiN_My'A #L!VHǯ﹃6*S ;"I&ڂopY)Fe8)BXN)IG1aՠ NA[ HF 59wa(")݌pR@k'Aiв&0bW!)tfbJE*nB>0m' kE4|FB0U(@=2DkK%T 6¤j|y ĭ<ꄻ:t#g*0z a}g>k~gp8JY5\t'x߬:mO)JǙs1Vl枇Dhη8q| cS 6V0ݑ,p.f*i$òAYZ&]S +C] 6>8z*gV"O v7aĞIJ6-:.;?GxK޻s+9sXJE,$b-qƳYFD0ވxˏޠמ8REFij48$WmS0eK:9Mટ[d_Y/>265F4}#Uc P2c\I6rC$=7]D!67nScM2Ē&UHPGIƝ$-͙MH7]qb‹@ ʝ_THF9X9\;qd=d8Q* ׎4 NrW6KY#o*Go1(-c͈i: EV3~0D ^BI#+N)%t[((#BwU!}1gJKn{K>=uk'׉/_oi4,Bg8U]s)JI\L^ȵ>Ü'k!n&ZX\u{6Z@0.QbaTƳ./1KY慌|'3sL$2R4E:"NHr ZG\sycexP)*߻i<2⋻ȅgM[ }$aI !]@D>3Mi6i=bhG4c4S+tXmFU$V^;]Ů+z9 uXr_UMRQ"By140svАP7, !$ P=88Mn, R g$_\u!XoG"&Y3|鄡%fay( O"!R)*i?`mdB^D FyzCX#L^uiG=hq.|FJ;Bq#̴%ꀭ"&S)kLx΢(A$clU3C1y*"N1j}x".d"xi(79E$Jh(I;^αUn)JyxI RvB vNݬu8e{+"5.5ܳ*XP|dXHodr"ЕfbIt[M<1jYhU+xΈ:r|2ivlk`ĉ.gfFXɺ~ swӜ#d84VgHS^֡4I)^#+%!%z*1L5/j{+7{X<}7\9'>OogϜF OdV6:qZ  30II7v|[|࣏QUNE$-;ӥ*BK]?.E%]lhJH[ FsMV6rQq޻1P ɘQfcP ^[xˮ)%|[wίW^|{7ÌAf e9aC X&Cωt#jю<%&4[ 8CAiɓh׼eG@[Da= ӳvVqoI kqf9'VA?\'"sA&%!Mx1Kd$$ezuF ^r$2 Ε.qhЕƅ|X]4;ZA|??K=̧X]_ 95J)*&2lggG_uлs!6 FAVsmͣǏr=!Wm ^s _bbr*} Xt?q?K?sf,7}Hrg~ՙՌ Ҝ':A`tX"qLE" Z '˘oJϴ̄iUsǶ!!Ia偭_K"$x ^ (Ԟ 91UA'Ua AN`@Jɰؐ)=DDIS!ցCTm(b6r(Y=~r6EDy/~?;/?e;+=zp5F5™2^q< ;KS kƚtYHt h֡vi9!ֻ !e"hg!kZL Ӝ/H} V8tlcǣ2.B`dܸ"mVpYWw%7Dl||z4瓮w!"i kKg#ڑO._;|o%+EIG)Ӯn 3dDL_|6 O%,izPGRc]-W(h5~(w\-fYkL&< U?(D%C3R ۶s>Ǐ޻Z-w~+xq`wg|%okҧ>+8mqHMSSr. =g*:ǜ OAMҪ@"L~ M!\۲& DD).}֫y|*=iu> ' N$m$~2qHk.5vJ!. t&p:ȟ8Г=#) ڬw*]!#+f$6$cdV-8VƊᙊ 3@Y'Q11,R}@ӶdY?wDF<;g$9MFehW)Ƃh+GU4UFIZ/sT. 1 0d{0wO&FnHHxuNaݐ 3KM D톢H*n4 nCRZy~܈ωȘkb*K^(1,-Ñ9mLi9s!=:;2,q];-+*`nl-B6uytUZ0A.$Dt7Ҕ8Nh[ղ*&rVr 隃e6)<(+}^Żllj:7p%HdݪNS4TG(R&˜QTu>mE ^p!0F sSBȟ 4ùUӟsk#%=?q6{vϥ~HJ.ݢ(5dz{q^1 {N)Icd7(gc OѤ*,SSFu$2@/4)J:*N([웖<$?3;(UqӍᇮirtٰg:̪c__:J#U=q~R% U?i* ?'w$%^d۞|'2E6]%* mPW^0Eɨ ^F, FQSGhc_i4BιшX8N):cl{] =ܬ\4SBÇp’Hjs̘b)կϱ f **^8ۆ?;[U@lTb&"v<بlL;"aTX#%PGG?K0ljF|dއiF$ 4ȭ ${smAK*kL5zBo\0;/Z|SB4HR_ץ$9)-xc#" 3-5msVp% F\{88*6I?ny/fX\Rm+؈d)OxV}OYY>hC0&H]S8ʱᩌe}iusa"%Uw¤h,xT0 f/b+7Jp#b[Meֺo~'$F*&T VΪXpzk-Cp4e;<ȸͨIYj*YE/JO*Ch!b-K/3:&w<@uF*)rCUo}@ zG7i3*LW_?'tn8I2CMkQQ`+O39դ? Vv$2Tp 4k‚ `P@E,aIV8&&3.ֲ=d2wՅG*p6G΄aHV*&V4U`i-u%G4q 114c;ڶQo P\|q3ڢؗϹEd,kmX\H bDH}TiRsn?KD8H/䅑IQΑ'}k4Ia:[AAPl"uzpDR2בdU BX)ȫ0U6Tb& bVᫀ8N N\I"!՞=gCa p`\RW3 J5y/377W\]_ ox_3?hbή M誈Dd-*{gQ%|pEiDck+HdM'^eˣ /BҹQXX f*XYpfqD^TTcm]{;=)HEPm9S+g6-h6< Ldͭ!U1 0,ցՆJ'?oWWk){hur6eBs2"Uڅ%YOV8ѯ,yx5m: 8^-z?tٶO+Yi|{xӞ׾Y!-=|0cYgy3nelnm;hQhx$`fjz5u!N!8Jb`x#40\ ,#O.bb@i:׾R?^Eп')cHbpT0(7,4%,ė4t䮙}IԢ"utCsx58u8աy쨵X Zhz _{BUAZ ޔ\+b( h2(-{=u'=>6o*]2,-;'5En~/w|v>32>ᑇ(FEET :)j)Q>;vj/*?s铟LSw}CyD >p1;˖dutU̞cKDq&%S1YpU%y8|=Qh<٨I 6R@ "iR2ʰa Df6ќ,#h*X-`Xj6M!XPA"}s£#GPzASx2 {'"S.4f궸@B1! 2$j?sc y{L4wDt'qzQ1`cw3G=ca1a.&Q|!XHVt YXҖ*(K? ~ ̃RlEpQg\l_#IO+ k,CVPxcDp%Z޺ 6+mѕAE cR+6FS3C< H)x- J13uH.+K sx7c_slQK|*v%8dG< 8 ME iqfѡJAp"eHq}& 665Dp.[ sew IDAT.ש3%N&DQYdW5 Ro6ʱ4zL\aWS V=Jg{ѿMvx GzЦ`ԃlJN`8 ̶#(@")l(rB$8L$ zH3n &$!,q2L%ʡ\pTv33Œ (Uwc!*(r*+x[B`br| P 9gW sarvάPDcnE 1g,WNXZc̳yӳOEL]Ku7? Rx E^yFC%L$x9FgiO12HާHf2j~ 뛛T:uGs+%ImoЈ`}3[)KgOfxDAB$O|Z"IsrP-?¡تB?wa|LlK wO9*^2)2 ˛DR XwՈCD:tC7c~Uo#"<㭿k[I!oZ'y<$iMO~7\r-I$,4%VP4,B`C8/ ^4%N@ Z@&8k넨'b`CFa*=m~aTضG%M(ۙ\Vigm8 mE:BRBECAI掶#Y 쨅@ъZxr/"`P@"ZU'*x9k\ SQ̓Oаh-҈aN\ϩq̈kn=`NI,q@~( KY竟=-Eē>XeF=Gԛu6O{<:ЄWȲ)K9ʘv;,r!E9 RuFdY@!$^*Hv2Z9c}{P3Ddq9B$?8kD 3G39QI"Cl/9trF h4jykk/G vl/6F_{BBRTX&ڒçs Zz"yƾ&Nf}ʹB>x~n_Y&HVaX4 p# (_if .J$߄N@x!HW5Ba FիDyT&A=#(Lj 2̴%u o@Kt\G'),Q*b4G Aq&C`\J"ԺkBeZp)eYEo~ӯ񍛿@?sAFlSF&L -f'"öl Fg)n&2^W{wHp(ٱAΰ|)23-msɮw  ;oHO_0 mi_$1ic.,9,s&b '3%;³8 5<9N˹ VAo&c2|g{!CT^/qЊ5 Q 3i(*9tZ{!IZe%w`=EuxPA ֎y @h'ajfTČ1v%D QԳ#%s K Î+Qq]'ضغmߟt!6҂F"<#eHRqS=z o=0O93 @ Ì4$/ Ũ2h"oE {sfs5"ElZ2֊O 6<+(ODIa]ةj _˫IecB=QF70D"H#Hijͩ r#,`8ʸC|OAi͚/ʧsQQ0{&^vyU3&!?lqޓehSXbضj*JP5b1GAru(o˓ 9;%gV-0NJ@#֒񆤝CWnbΰ vA8SqXT_z"!HcA!0ьHϪse[ĈK4yᕿ7KXsMЊe(bv6ȝ߽NTyJY)J Hx },4,Oƴ `hseR#9ӵx9އJ*CdACg`$?^9 ۨUoT1V0a?([Acuu8w}s %Z:HtpқFa92)z$a (͇ &Hf |[g}n8~x½+a*Ec]a`. Y"&W5FƱZpK/!a]I@Ej )>m&e[=9 3SSA6dSXt C*H0Lƞf=UiD]Ӊu~5'H r6W9uf7O_ag?BؗXHG b{444mC *p I]0eká ˂ %W2!XY}s^/hht2Qe5(>J'*:5E$]Θp`5>wΤH K,Uчϻ Tt,e{γ`-Ru"LأNG_\?9L'\X^)C8i ^zzNb}JI QزxLQ8(:B=~΍#FW<̱kŸOe6i5#~O~ ?'immp W hXLEc,,/:5$yT8-D)h7ՙ /#XGc$7Q'P)xBw^ K)%b4ȉ\Ko RṘ.M"gK,CIQEV B!L4[:! jP`e:w|eV(ABG/"b)9=LϓۈfFۡxtz0pRR%0cnX#Ǻ`gG21`([QlY-Ѣ%&[=:ØdrfdigaB6FU6rKdHn)VFSiAImpFȰ/$ eρAic0yP & dc;b3`:K<0pN5X!+s\});3&{ +$I6D0EhJZnjpZZ JM2̚gu3y}v'f)GX 1ݻF;$8`4MPʐe( p][OulFF%e ϼh+ÀpgNLM& Ւc s9C҂Z-&$l0bWp&IMT? `kq֓6&)LO *(YdZq%CZ=;~ V癪 Y:1B UQ+Q' pVyN(z}Oa/+0OĶqə^ scC=.,gတvZ䮧2ʪ%I^TcKe8xϞFq-1-shy{V2XW +0^2,똨k^8C?Fˌe8\Ѳ]+ 1&, k 0WBЌ;ڞxhw:,/-2ŀbrWLLL~>h(ru#˟:#ɠ-B_]2*`]q%RkL>1$y99"c 5'+~#81, cf"(=5ృ,bJ0l<Ǒ$9ƚ!w>5Ef,./(HRMi fs,%RԲee,i7%D(D"VAxwC$}cuՕ|o }>@<%g 0rr۟Ócm_αNPz!9|#ʁ'N<1i_i뒝3p?Zqd:(Y.G|_~زmu;Ǐ$֊^)\JZ"qkZ '\ ޕI7/vIsu$3;ވy˅`XyD=ft02E˓a3.<:#%1 xTNiNRa]h&D±7\҄Gu`ՐJ3@Z{&ϕu4bAks]p 萨;>B9R ˹5̫~X穧4Q#Myaȭ R0fyF;.y`&VI"$J qPzA9(޳Sõ1xWaE%Ϙ#G rdQ@{/X`BJb Y%^Xi%a}zC~]{؞+.KyWLoEP4 ):uU߂AXhUKKEyqcfk2,Aɰxq$a,pӂ~)#!`Mk bQHʎZ"ݚG\ȭrklLy,H E n9V\kf#3R:O+YN289_/ xvΉSIsg,h XJXdzD6gW#z?𓜉#`d yE#(,>"˹bGJIa<2j1Ql& 0& jho#DA+$o\!۷چłu-j/8.|&<و j MGMZ?Օ%Y RS 4wYm}yC|A9,.o`P 3.dȱ2LKsdMqKZ] aZ.Xq|(9ackN.ȡqN +) ]X %65bFkJs,ujDdK661t D/1e`pnP%'g{nU`~0_Z49J`YQ/!O}>`y;cO<'?wlش/=ػw;VAX ޲}>]XSuJ-,-JpVЃCԴg F9YRID] ay΄]g=كO34V13 s SM , |^M͈~VMiL3Ra0'kl,!R` %aL64LEƨNS$#g!طuT07 L^>swADɆ&l{Jqxq#Ft6D%d6P1̯EFfj&,*-Tl?XKYn],5𨬊-A'$2%SqN`%ı"d3HposAF45JDDLc ip?+W+ADpKĵf'$IykV0 n+@RRuǎΰm\<#" :YrhY3* K- ~rOVE?%2Kz⒗4;3$:R祮a^$"#<7u*\Hhz +.Ͼ +<Ғ ǚD^7w(*ܲ}q:cH)HZ)_i\wzÓO# , rօBY??0ٳE(mKQDS2s&Jfl hZ^w5k$zaQ$J`!/!QJ5 8]en/穅ZZ0RaqO`u3FX t_g?ƏZRyHnDB`%%2 HGP$+f&KB:k{%<((.~HYWf'h`׌&['Y]+[i=`QҨIt3 NNx鹂6ٻE,-a0>gÌ?{D.X;&$<3>5_Fሪ01rʑMtl@&B.2k1rd%%# W,&7sKȊ!{cʒ>i<ԕ!3R] s#&PB1/~KkuZ#OCC3RaJ$C)9Sh8]qդ?2R;kq^SXXU[3 ҚXk=QF믹gKط3۷~{pRJ6o>Sdxx56Lh^୸ p,;]GލRN"AKO# [Eu׍3j`J^x׾;c'} /x WҢO'^wFMp<`Y15RA_ 3U8$;)2r%ٵNϖǖCQ?9Z%rn_x+1J)kеZIK@gpQD/ 2$8dj%;>σU7x狎r)J4VEdZp{>ʣ2B*0zYD0919o{sb qzD[* H2S󳘢M_KB[>9^?ܲ k w+!(a\{\O?~݇ɍ@(9Ԕw9||*!wiA15[/wgAfoi^#Nˏ:#7ҳroWVGE? _JiJGsHJ\/*j^JQBwcDLQ]$S :ڧzRVVkק#`f9gx YQ($D`v=b  sTġ=u|A]j[>K jtw#I=H)h4==gyeD:ۯ`jq%`9ryݷ?,bIԪ'i#jANE]@#Ql_)褎Nfٶr'kݾA_ B Qu(JufzgW/)-kk3-BZ qL[$`LjGrG$ p>Z[ M F5hȒWX6/v`6hƆ$Y!A@;,[\Fy5+;ՍM(Wgo[o?Or&X)kJ#V>x:K(JlDRyrNX;0fz~z߉?' ]KBJYxTbA' lE>|RhG%,'2b%˫$(_;:2*PBɘ9 L4ZG(5Db. 0HK2̴- '{yO0`DJ=8:l<:Yxцuvd)2$ * L yap2Psđ/Ր Sar(ktxfdDqwf8Z% e sO/ | =٦+|+ϰ2smiMyn|ksߞH/:[FG!UR%9}Ǟ̽9KvUxjħn[JD4~{c3 ;_*cyiAucj" J\;e.ogsv.cplWbDe@N͵^͍_ϥ/Q,`-TCrL@Szpe%%kFjE/3|}'V_ O.) Qca^ 7 ,}m YtcFK"e˳Ks3 X|=Z~rܿGr`Q8"k/DXԕ1I%PH$v4A5T8zs&N  aѨW70t):8X0|@c[v11dts0U`' ӎդ,5*qk/>1ѻw#؜k>w~=\~9_OU8sy p ?1F%`b ϟ{ ꫈# ^>: 0$Uh>`Cw9$}FcX=Rwp0زePl-+ FCD҃+B7Sh|؅Jp IѬN$+򑪠qC|7;e$$Ce1JIp̓{/#JYo>u<$TNf,L˒疡 $+`Hf{ː>(w+6"P~B2C o\/y_Hnd `"(4R@ uEpx`s+b囷G-ù3 ]h@ujӠ1SeچWܴ%#k0pBc $ bi߹2`_ŗMqbњ?xF8ʹG}b!Qm)F+ j1kCX1>?u:a7 32S>8tgؼ6fd8Gk9V0*^+ٲ&" q].xju8^OVvWɄf]PJ~M@8$Ґ/"/)s+I;sK=&MJD#TވTa5& zYn[1lh4J[Ck'c'<?=?TpyUTN5fEP$8K}Z=C.#Ǚ_qĘ`͇*#.XMMnQ Rkv6s?%kw(tN/wM39YEIHhQ(n8\$C6Ӛ0a`XN}sriU10r$4dd 0ԏ Qam"08T n<#a';ӡ:윺߬ <#]dTc!hYxz4O12D:gg?OD:G( O?FZ.G/ r*A g.g1TU2\\gUhB$0XāD%#g\wn+tYGCOaii0 9K) G4=) {.Xm2h"bk) öY˲L`@>iMHK&f*1sBP L\tF֏VHB eXs`՚BZM ^z1%-ɱsttK}SzƢjrkK%0$enwHe<~@?Cѝ]6ӳ_1"-F듁^yܤ"m4p<}+JN:G~Ou-*(F" H'k29!N3頺LvHqN7,"U8?I\1GZXX"+}f.=C=sJ)KپmxvЅ!<7łUmgn֏pPpR&5jq~?ٻJlt8+P%Fk2Yt=.Ȯ#Kb%X=R#c  mMQdo! y+ /5A{8OΤtp.XS)I\eu(KM4̭+m"3+p6u AUOSЭz-;!K-˙5M 'zz@˂1|m^7op> \|g)}.j-Or ^&0V"L@y L'c BK/80uE3z}@IRQ)6";Vf褚ceJ_4d)[$W 6Uwp@A#Ta6YG30a8c>dM~*Qq39AD֒5'IMHjI/w׉}"+=KPeHT &)Nkz ?CDrф`c. dNW39%\_Gxyv@hH KZx/z2DhU5:=Kl;ocG,,fn5p/ׂ\j%/,Yp &FK=%fv $?FԪAgp|.%˽9=:3mu0%> LSO$JB/uG  ŎSZ=op2%֛8~VVM|@rxG8c( MZj,,-q2#{3:_-.#PAˮ@kK_je V_x\ V,G- cp,5?yÕ6&Mrvx3R;F. R<ÂSGǖԨZ IX; ;3ϨW,oI(+ -=5G#nܢ#+^/jgkɼ]'F$` ^Ɯo%-] jBQHf`ь©^<74--M-؜b+Rc>$3Π0خ?et!QҼG6j~-Îv&iK? jvfe`eDQ`eHfTSx;?{,CQɃu|-u) > r%k_Nwq7kW/zbGD^6pӅuv3Q\vVNS.( NZypmoerr)fgh۰׼W90OF[_4ā/.#BzFs(7ag>>F,~?KAHV)f'ֱ _~ƫ_:^yGqYg>eͤ=t766_"\N3Ӵ ܈}yZ{^,VH,崵1PLsR3-b0}Kgu!Kh--N&h'.=28mUlm0r $…y:= >R *^ỉпS[,tLI3E1B)Z漄Q_0`#Dd` MBRhOh Պ9L4$do$XSl KJL we@5\ze|Ё< 淸;wē "C:)?#^Wz&^x%l9L_5;&>o>pq?}nI%ίO]scawpA T A(,kh\Twi0 AIIB:6'Ѷk!0 SQPa "@ +X`7UW V%+ ojK;hcI`$w{FxZzPA9,eC_b|b+^uF[?z2^#VL6gjz[o{=獯pdQiњ[8 9Z.bɽ F645̮. }f>\/ӎ5[1D'T㹎`%=*F)6ıb o̢JpC_ M N *Z3.Xpp@`wuaMF-C 'QVJȵ7[<8?Λv0ӣ$!/9#fH]+*+{8HFXc4~ZJ1'MdNz?к+|JXWT~R[{*K_aףY+WMšj rYhoXRU#8Xw8x(8fF!2!$ Gݸʇ7cnC|2-npSk"%*r#Y=32#!rC8mJ(D=9Q$Ć7kek2YZG[/d'Y' )4Z;BWF%%!?-8Ygfz7:'*G Rtn)K*3:M ǁc>hغej$8c}sBC<Т_x ̢lH;aJ:6TBO5V8rW&WL_&C⣓{$"f^/*AZy[yՙFI bi֛()8t96HnƚӨ 9Z<-M~V#*i(k 3ǎ|>ws͕ײ<),bd8Rxb m*^y9TΡmjZaK %i+"t:Y Tlo( n*RLPIm5LT-kHM!PV<2HJ" *!P%|m9 lۘf,XM4FY˹WrB(v֙g{9ZKVBo,!αFӪ47k ]|bӏeUQق'~>ơs3W /k-;.^e @f~~R/%w{]\zJs'H.\8eFX#N)U:@q:m3-CҶ IDATd"i= y.Y PtЄ& `l2aPʹ-ݾC8K%jQK֛W#DQ(@B/ 2+ IZ\ZS((xH7vvy~J' 57pHWh* cu͐1XZ%+4A7I*`&( bΥq(iϽ/9uu7?_)mk֬au]<3~FEZDh.Br7|=3?"#|G ܹym5kş|믺?x\ YX^k,^ZZ@A 7nQa(Ry6V]8b k-‘DB &o)C!#pXT@;ĵ0m'h=FUc ?=$\A25T`Q ^48V#$E1S8sjHc0 Wdʧzԕ DJ e9_Q! xr!C>2ѐX`5%lͰX2cl XrF Ds/?S DM{1R M9` 3I} ts?޷HM)O{T@Vg4\0>LJZY\DZ;ܐaf8"e;O,W TT'*cs ˩;SH5ӹMZM&q6!?SJ-?U"tzں&e&t"/ W[gX!kRiQ@Uy CAb$ut!dӢe xek/{s+0ly 1:]MjuJ->e٩@ (uQI}-nOz-fK~ )*ΞAg8k`7@Vh ~2=Vz,Ig o|oC|_󶗟mC#Q:;NKITbk<:O[%+Y()ƱYn[6ռ1f=YX+T) <74w[$Q>8bX,5%9mnfay)$PҖ+(!忿i6HM(`}{^w7D0*:+U#l]+ٱ%`jYܠsC̡{~ĎsAV B0RPtfY=PYvfPc҃1c-`xnɑ[ }bl(-j$X=O.f<_o_غB|᯿1DJ|ǭp'Q@9FzT_W0\OxᦈeduL`ƭ$!><6lda߱{o{o7Xdsf,K]S:4 NCeۀ&QX)ZI-u8x^wQ[B $:te9sp%Ъs;z}5 2Zר!I5aA9Ni%'HY/P08YA8G'߱HBT|ӤckXhe !.xы+4 }tKk;ĕMRs0B.m'8|PrdPh?F3Vt2eG;.='GEK?s)ut[Jĺf$FDx5og#rWŰIBkXn.?:E<[+~D8"d:ZmO^L;lX4Bb20TI+.X֏(ڳqP +c˚5͐e8rlX\ֱo8?6_,謴\r੧9v\ǦG*eQz |ѴҜ`$m}߉krJ)'wB[?lü윗bOiHO!,I' A< 3Vrs~`'..P (|Clu5.fx:d?wvpf1y6^aXLD/UcC/\ ~s/k׮] V"ovU :^>$Й}gxS%#!Qk)g9Lq,UKZ0;Ȧ<}Ci$f-+K$!BB?$Dk<ج܏pE (^- P h]KJlcm;f"ӘҀGOO|0_San ͓!hAe°\K5R,Ģ% xj]#ʚ.ǩĒdeYh!7=_?Z^ 馠u`YTS;f@a,['B:Fpƈ1#Vs8掁bS+#EDDf4ɲֺQ#rj.`A YC(Ja: 6׽XYJ/]o7_%%Qsz3cPG.-A,X3hN.`tS#bMB2h2 Xc^lT53RyG>r`y)%uY ɳ}tڦ Th' 8 iq d>MrqƘzc5秏JBg)JT!CF.AO>tO֏*[g}~ C+ d _/[1l oa3$q֦^;v^LA$ BVZzb|y+|b}{yK.NIv]{sߡZq˛_Ǔޔ7_vjp57O7Pļ> #-zzvSvJ)>yХNzo-2•#kTЌݬ R! FwPJ!a=4;7[sRN( F8`fÐAHIHB9t+sWWz ;̇t{|}pY g-ե~}~a^ FH}`SKXyѶeǞ%о!Sb-4v mmrjQĨ4fXxz`Ч Vb蕞X;9ɭbh=NuK#题`++8n2ღA߼ bc0Vi(.QK4c58c õ!G{'5_cTiTKQT0q **iq}XCdIwoMx=Uv3bixsχ?wvc}\|Nw7eO#tR9^fh7eѣlݶG?%R5VcDl*κ  9"ML+Jy%Bcڦ<#+O9bKXt -.k‚C(:3kT+AM w3T] bҦ?u# RI# 'q2̴ +Y#Md"B.OʫGS^ZCXRMYyTL5NQ+f 8BDkg掽= E-L4z,֌ Kb`TI\NZ 8aXz&S(DAIpKuڰypQ+hŊ*hN<(*P<zr/{p@&F+24&w ?{C)hiisZ!ui\mSO?*O<<.]-$4dSmd/4ω=Cl F}N۞qC &y94il>ϟ[o .1y\A & AA.F˨sp3ȃ5O]8SݘvS9c k23net^ŹlURKK#ZMC[1(+ts^$"2-2V8~¨g;&5**A)[#e KШ:GnՈz'COQV4FBvxAV:&ڒ+yTU`DXM5=͚.xUVwxJGJz#@,( f6%vslbb,Obv"4ؒ>5[L~%.@hFVƛ4lPlqcH_;1Rx&MTwذ[F5jx[њ#4ǿ&Ji6grxR7'̹s^1^A= KU9b(3աBFEloe xu(>*h'ݝt O;|[㔑7eC<#cat@; >OpuI~4F#_36n&*e 3+=Jsh3YOkKǘ4aR ŚK.)7tGS4hOG J Ep F)Cs-)*][o, 6mB6CٜV䘟;^<ٗ17wSN92)x(8smETl?.Ը;x,ze7gpc‹^ 15=wΕW<سA]q{zKsv64NP|B(+Ge_qNҞ Ȍb0rXX8J3zIdNtLIKS}pF~&2opNF sKE:TT1ֆYN$Qse!xAu<&4-M߂7Ԏ8M9g{¾}cH"E1D!M4Y"R_ұcZhxXL5#JkYIMQzVRv= 2;K^bxfZ$'h7SѡqӶ֋׼JΫdYZZ!7mŕ?׼N;FavF.qe?/O}<`mife8Zx3)6V{cK|0_s϶(f#ؑx/YU XaS7Tu 'J"%M(0J>[>RhfARڑKJz=%A,)ډ|>JMĨ [51-=R97{ZCit_mZd]ŒX4S$6n:ę[ADQD9y[0(%455L)dndt2sTkp4@ d+F/]8i{ ,&qdYG%U7Xf?#vmhb-Z; D7v0(voNj- ned-9/@݁uϠB݀\pB-q;aE+ 7MM\58(|}ߡӨC +CK8ZKE^zV44]EC=~wBu\2)£8$dmcvM0xZKNkrΙc8Pړf`0,:r퐘6њ0ӥkap1*͆؜V6ʜrm?Y :l7 ~dQmLbQoIN4ӈuicz~#˽A ʢD$qG kNaZ'B-b`Zn(}׿ |oGzkY'AB(elC%G&Ύ\Hn|g2 LNdGoN?O;kw7=2mP/?_z?`WQ0g}W\K O>8N8̳(ڝ1)Y:c]fg7fxӯb\ejܰ{6*EJ~PQL55vBYɨ1S-W\+N< cJk6U0rJF+Hv-xz†F~v*MS29J^STP xLҁ4ba8lY9&[ #(&mvCsֶnCq&^S4XI!qV p5,/yN's=xx.ed#Q?4r:9Dixoz[&{)gaak`N޴e;_֏xK_m;֟o|i^ӟ 7}s UMy~-[S:O bW$ 0 Å@U cȽBaWՁR = G"j:Qү +q; A^T 2 9G)&RTs ˔z3dY4_,i(-ҷt w޳;/㦛o؜~h&^=뒆~ R2w>_B|w$|?d C%"Dɴj8kkB+#Gu찜%fcWstM-҈,`"<.U(MiέS{ڨYbAk"l'AT 3j=`6*8}JZ4bX\Gi%dMP|k_rN&&".J ,*E#iYgM,h C'PI4^Zt'nFS(mT[{_ I09|(a\Ioݲuiz/\!x:"Z'lx =j#asJwݰ>LN5gCǰu&a44+ q/^V#br$ZφQK4>ܳLQ:\ eҡT2:#uUmw7ޱJe |$և6,r G/(ޜK=f:bnrS98&9b{}Zbz&[9NGFڮiEw)Cb5(@Uҋ> DlOf˦i*{wTUhdt$X߮h=x0Fبr0&Ak٘M=΍ xMkC W IDAT40,EOpXReqND1:&=ܷ{՝;*;l{uazaHosDSMb%[1\ۀV&M 6L{ex3-3-0/cm@ /p \&(ϳy*ۻm0\rRhF!5i"ݖhOl23U7!?\vk$_[ +Zi;oFOo[%mMlEdYģcl"gpx[K{f4$0yٸ]6; j>(oc۸BkO2湒;%{ڭ)9jVqD-OwZj<,CiYčYFeN:DF(hHP2`ha"5h-414cM7*6Ň[FyVFtuX:KKK'ޭ[6q>s"<ˆq͙[J=*<s ^w,y.raH˸1{1/񥯬˲3$7\vmh-<(w(cyH,|[TŐkQ9f3аpeJʓtvGn*k(dC[Fx.ef,b-TN O:X=-7|zN>:(+ %i;&5g/OC:YLd x+ cTE!^/P o'hRG O|[;暯pH E\߲8Uܻ#mof}9`1FKwqlKCOU KA<9ZM!aayx=5~TA㼥cAKXTC[C55ac0l%kcW.]+hFZy"gPʲsܐe5"VfZ)}~s=DXzHtӂ1N̴ ü <;hQ.CxWm\bij8r5xG{,-eQ뤓O\/SS\& Ε|ƣ$ ^vo>.T;s;/y|ɳvE|S_< 3`tBk6Ic_fD8*u"/\y_yի_y ZڍazI'Ӝ3RH x;&);qdE#H[Y}HޕXLX#ڼ\G`& F*kyҤ FĨ95#K.Ri%v)&zED 3R7tA4Wۿs+Oz#sǹ끣Tŀ^n-~zWIDt[$܄th5c|{*kQSYo7"U01$cbba_Ξu{Gr˨v2=Ł'"ID4EdWttV\ vÖU4#I/'7 }.b]WXZ[3T,#O^t+b%jaIa =R< XkgF(Vmİ ӎe{. Gw34Hh<<"M6 gX12kکa9$ SSSMg:c)*KCfX:˲i |c}E36lnɈfVьmtegs`8iB]R$ZmEO~N5<o>߼iZxs)ז{OطvwӶj8x}N _檫?yˌ;̘&M-B6Jo$hEhY bmDF1d @"ҊJeĔrT;2h ҁH Jhi/SbFɥc Y, ʫ:yZf)a{}+>iP9h@3QT0"2<h|PBhJ润kU#IIiXyWn^OЌCܪ]z"ɺr!zuu;g6fv?0wkE3sq`M7/4IYqBQQ(NŵgʓŨ1KNە2Z#of~.QGl6ό39ih-/ lLKO@0-ydRPX+Y4ݦD1Sh;ɽ$MH㜢7 u(P*&|k+JK3,ޖ8W͆}%+C>;7)_1Iwe|75"C2 挖@40Fq?xGTsK9'lSܐ0p<=HAh['Y'i A Nu; ͷ?bh$gKW/ܧ_ZuO$o3(ahiJkAIoHY'm??XwA XVWҎ~-`0icbǮ́oWՎ7!; E3$VDJ >{DaĪj?r5w\XG*$%D U44#)?+|.w?[ t.7\.Oʳbb,3ί!8zᝨQ/oTaxd[jhرCK 1m3X]&n7W;,V4 @3STֱ6Rh#GWGW=H)+|_{[4PA9 1Vmj2{cz=KY:V@oczv#[v l۶>F601H]#u1tndTy8s:bG& yv p$Ef)*4?B~?ilyy s#~x&oaAuebS7ڭ-d+KjOǴZ; JO%1t%.`oFj,B]* O*7q/ s~a.|md"{i+tlgrOQL"IwDrҜ3)D m4DrR#:҄Y+^~zٺt3{Yn?PF~a_{hZ&Ɂ“jXSn 8x$4\'x j*&+}hJ+9VGw*TUߦs_N N72#{GkX ?->⬍{ bpՐ'"c뎢TҤZu,^xp2RIGcסr>:tb9"nTK,$OD1J)f;QUaYJk'َ$pEi3{Pf>&k՛ LNaaigChFE U, !QO>Q[ɦDqo|a#?Ň@i혵G$p" *TDN%*A#V'usj ,WeqTYG֓%r"pe.8 L'C.!2Bd :[Y4ISVj@@KfX+Y_"cEhϤ4X'%1&ZcPԂbCJĬF(ɯM#&`KSP&['blު F#رs{kx߽ i>1 v̦4K0(5VrOđՒY,!b3L"F%Zy7 sEYAeҷ{ְǞE}wyKSN\Ec~HHj="=a(#w1#k(ʊ7<#l߾7֛◮'nnL#vRpd^x/i 0 2^_.8I/u󭯳6w}+a h$!I33'^o &6?ߑ|E_p!|b͖Lq=Ӗ {0}#q8o6˞, XH%vUHE##) ;Eu*{}:X+,@'ԈwrYJaLL;߄0n $lN5֕|W35F_EYN6IۛKv4Jityu~~CyƓ/'hף<]͖i`2kqLCg}䈵j[w4{65EeSyÎVieZho|۟+8:t}o 8 Jxֳ >!j2X/=,BFkp`/3W8Lr3iHь+yU{}@qx/dJU%R#-5Nd4<*"cY1bU)m4.17:T7| ;[A):4&BkZ uͰ D2Yi7"mnv Phm.v/õO y6=9߸yW\.QkHpu,YC`Ҍ/_=#v ц <v6k+Rdž4KhE|CpE%] IDATO^Xq?ތEΨ,NSsJD(PZ|}EGg=Y^g>I-Wp9nw('{eU>s?P:[V`Dc"h#&86` "# αrՊa_|c1V5y%py9ˮyW)p8PVti4o {Fƙ1r{D;Ө8ce\rWNJ,^_86GliVNhfZ,ш{RNC`<54U3ܷ58廨`pK[A$pfs"*L&psHg塇{F[9OgNzwQ_g4.?L[SUA"UR66m(lcOǃw +}e鉵) = il+!mHEP qA2|SOG-]Jk8=pSN˟3Ix. ғj zkye򎉦ٜ $qcC+E[4NbP%˅Y8|c ґҲ]>N, ѰaL2NI3ēPNB"#E#Hb)yDV{P6֬雷(%?'&uiTCTLҔm &iDcTEZ5Aj@sg!/PZq!0>D1~Zslr-#yQhU ==\LjTPZM6z ]R#s<_װVEcUWyvNPF+!Uh3S>FIWʠGK+>I&cv<QᕀC• "uRA4)#L3 De|&ۚ{y׿moW?kg(K_?y&_L~N?_#;wn3֭ ʨ%T]:K)^7M'}KY򤱢h1U[rJS?<\X;Z?1TNnRbDA5BE -Q.[ "z:buh9`)AÃ(+ 9>j*V^Q@:z0Vt 8$HNҥ2NwP2W 1 'r06 F+N͙;'f=W=JpOe_,xBP,_\*9Jx>D:Dd4w?̛/y`%я8c]۷g>\.PN<\% C93u$@ڨ ɽеD\C{@rI|~j^ [ul*+%iZ @ &R9:-5)Vf -EUzԑ{I29=±ȳ4l!4} cγ!Uyj^VփB 'mTnw|nhYg<:-M@䤄@k9SHC12,t-& sO^r4 XM[X+LLR wj%c=ACj M_ jH,Ȗ2;i<ڟ, _:P8%+xW=F}ʴ殹;4S&DX*eIç ݒ-a+U_BG"2@#Ѵ҈վcp SukG E q+]!&6MN1a煏ᅗ0 /8zCrKdI%* lY !F1&,,erTgۆF Y"vN{+r.QgISJJN3 ìtE:išiGkMnaݶP&glh$tV^e G*[OT-01DJ!JdƯCmE1+*MVDֶ8M:1 Ms[0:Nwn7Nq̰l;/ɮ6_{Ż>㖃vj ])򥀉 `Gr/uST1Ftri8ypJ\UxX:E[~7\ocT1=Ě1wz ik$]1)Sm#v$?ЬØ1D3t> ۦ>Uv>l x@3misqQF;MhfxH#ؽ?Hf2:ScqO!XIg YgF<&ǎpE"W\lgg\l`XJ|ʓgw-?dHQvW0ZR}o_rγx h'E+-:|[n4.pko}k=lsMR6 '03i? J1VXHu` ?]wPZOP"3ԑ(VȚ]S-T4 ';Kϼ5Ӈ+ mij;lY…ᣩᤪС#4U "Oi{|/xtS[6d B)VY!*rȑ5fw͛7s2]. OE#%ҋr¦šM."M4cO@hVbuefCNJf3"ID93b|x4ei9-rY5JTQ74 dԟvZ[7JY7l)Ox> ԥwN_X֚Hj/+ h)Vw Wx(P39V{xw^&#M%{1A0q"T4H[gMr愻\G.VOA҄2$PZGlde\G?/ -hURwRT9Ayډ; #iHFQyI C5@"H389kG;Z{ ?qrM?'ϻu29kBz;ވR`κ1|7}gǜƦǟmNr =‰[7j_o߃ q^8֚={vS1m ~_{-ϻsRwKg j̈,a^p01 <2_{ǒmQ6A̐%gbtHw!D̬;ʵLQUC|A2tBo闪\-I1SYm v?x:<6cHQ*S"%u4["hZ%6IeLsp@bw_'b"X+8iӆlX2S'+s>ݳ&МAc^~~FK5]gLTQDgn_>z/g8>{Tm!"Ap1Oݵg_O8 9ǢASB܌MLaC@DXKa^64 xS\TKNt܋ZӅ% GR1==JQ7VC= mM;]M4o{:z^x'NFrx˲䰮‹_DETHTF9(r+S{NI8 s7MFO;2shA~z)J#F6 d*L*%dZEoje8T]Oe=gmYXB+19?%9 {Ԁr%RCCVjը`AiH*:SCSwuڌ Z^!{.<,N;,zS9ؼy3gVo YX%‰ Š7d*N^&78wn X~=wuF{"ii&!/WCXU!Px!'PC)dk,+8bS;%hޥ>{.+KQx/Y h+ ]AIDʑ|C!Ue+)|$vOX:&G#^rI[h/$V+ljyx){d1{2줠iD4^G&@;IE/,|֓ZTm,Vpk:lm"pM% 4>5"xgD&sڱA˖^1pX6 S ;u2`-xgsza*غy ߻>^?sd;i+DZ{88^%p‰.)HqXyIrD Αl0$dSxBYn < IDAT뾱V0P L^67%O䕼+i.++ϙѦ Kw1􊰦0&2cyi3TՐLK6hz"XHa[ a@9i Rؾr)C@Q1ܗT_ TrQV=x4(=ӭ6ݼKJةٻ"+{1 GUsٝ),XӵUʤDZ+||Ʒ$Yg{+D#Tgixߵ<pZ<2`yAV}E!-:b fA4JZ5 ª ?*ff>_C&s4r-8RʳڳL߹dqxlxӞRXYYfSUESwq ~}%{_>efix6o͌Wi"bvy7?1`]g]Ć-Y]^L>VVRzK,6*8VV ,If䶴=sO$umJspų}}RCR% Rp:ÖIͱ*ο\[:c=:",N(|[҆u#_+JjA^/=a;s昆B1'o8u4)ؿUH¯.pS6&WATw*q`Wr8ة x?s33uNm?1m= |/]_U\Φ8fezCx5<;Os#\au~!':']r/}\jG)z"J'xE)MU#|2=ufA6.H[Ok8%t?uTǀt@iW@Vǜ17, [ 9P1WSIt%Lu$Sܲ[ /~\磵fzzο_j~IX6]ȇj>P9/e^: Uqo~_r9} RSx!u E w<83DZ #>o=o-G)ID7tlB^xV+F҈ty0+NR%ͣ;{ˀ)4#$9|Xf&6"5lW,uAG-n-%=֞D|fDPy~q@Dl @)8!yth+ij Gưs fP`x}@eg=N}DC 3~qP:b ~]O/ #"cC렬*Q0Ez[* ^&0kGD@5w*VWKJ ѱ&I`H[6o~u7{le]ES1IVÐĚ^a˒p Gbմ'b܎#Ml@J cI־ǜ$~ь՜"s"GH`& (P]Ea5ZV`Q@YI"x3Q익 TFV„S-Ќk̛nŃ8i"F4 zhSkn^ E:6/`HgؽI`W 944+$ssȋ!* p=q*y%Fvɒ2 O( O p3B^'e}-/~p^A_[n0ȻM{lk8_Pfs"e|S**ɇn;Z22`IxAb;֎d\=n] KhS߆BA:4cٰ*okTx۰˴Gz4`|?gx}ΰ"֊flhKOdTܦiCO3:T&OAENQZZ㕒dvj'<1 UZLlmBatĄ [;p׏i $ԳT1]ϭFP^7R1$u;CZc"S64Ak{Y[ҴH*XI:|3FdfDl#iD<(_pњ8&A#}-m(^ KV枅>sCX-DA AJJ8VjP"-X ME77kEoe}֘L+6XIi9Zbixͯ5@Qms2 \ {j3?8z(Їh4b`}XLYʋ)lWpLRGHCZiL4y!RNm.G%*!M)p(E\է Nbj"edʖ g3}}:QDTñŊ+{`Di0\&1sTTuf|Yz6ZGT.,#1g_z>6*$c+ q)atC{}|rK f<64IFv-(c y,׷Y&3KY4qes8(^s6QlUad'_|YXBaNIT-1 ^Y9-'mH ЭQ$FԫMcC2|I2A4"he$,Aqϱ^9 )m(PE$Sb'+zmb&Gc/rλrƈ'hjdݨ" Jp +7b۱1زcuGvefe/p-c ?[Ѭd V py)BK)hzr9P>9/`ltѫJR X{*/D+8h%dUTRV{N>y_x&D)^kuzz+Ks}s<QJ>K++X ud*'N9,, ,QeHla6ol(P}%q:$GZ$y/,-;|Bdh ܐ@.R.AICZ 4;r08|}]#@+)`D`DmEv2Q0fZ()c +*h9B%[D&AkO)4{<*(t33Iq3(;z8ǢȝT?LeZ,%b}8܋رT염֣2/}%$^MI lKF8OW81(Np=w*0JC8_Q:O-c+(b  I-o};WEۃ1mPCg)=(_ú4Z2PHba ⎁cQӚ'oܾ @CɆ 8$8WA 2ԂX eJu΋ܦlRM} ePz3DL·J"ned] cdf4,ls j_rED΋a@2ɽb&j35:IQt: (EEFXU`j22 H5/t,PXy-R! eG)X7ԷXq^+pzـ[ÃٔN97*tU%Lk÷Ol{z$:zR7y9Ӹx+^ƍ?_m&/$XDX^y?]o^w/G&`HaQe{>'?nY ck=I1>ަ<& ; fkfqږdzF~%U#TL%[  KdfnŲ:q4_>y:mtaTIȲVTWJJ!mgrۓvgYp[x(f/!tvygOnG(*DcIMبZ:&s†lj"-WR%:&ш=ͨV6mh0 4)Ir{yKL<$iMS)3i-+g>wh~СJf 0h-H30嶻18*;  rK#ONi&|(!i-M3I$W 4{:_`e89cs(h#vNĚ 1w8 6I;@+ ɱry;nctlL E֚,kne ^On)_dϢ&~@xz#Y{/ M`݄Ȧ?geg}{ ;tMԌFHB9 KB $ et0`lAB$Q$Mܽ o5[XU)׻y~A,U~kŅ'R1MT/$2$W75l(-ڞA)5JHe6|︟r&^)藞[t h)PQD #HXpHJ:&qb" .I"Kb-ѸhLo*^5MBs-f₧Rd%GX Ir&'IS%MbqjF 򜥻L{ "p^"uAv2pÊ%_y~~ ||-}){ں/^r?v}0y;oRk^`_guԴ!Y7>]GJ/ /㮒+@BoNKzƓTҾ5C1YR#]ڭ6,('weR(  IDATKQyQ k!P<+PE隰Y}*~ gWcWڃ~Ai䵿|~ьN l'詭)9nT-Elxg)իr1F0~UMcar c2 :56HV,CHi0:c @`( ~|\}|_?'W]Pd֑ˎ,cOph/  Y7޵WUSӧ;}xчq3>18'v_ TBn X>k?~s |@֒! __% ƽUo~o=O=4>C)c i qсg3u4zʠ=9(s%i4dܣ=1P|UnEw)fJm9:GCKuDN1d(7މ'5LJdIg;DZupKZgS#`bR%Ģd(j-n%,m>R3TD=k4tTRZG3<RW 1u]mHIPcc~J zIg!RT0B  Onr+cC!kk2tgu*XSVZUR3zGBH f^u2Mz܍8P-+OIy`Iق_?b9 C-y&S8Y$JbEx8qfB'Kw{OgtFSK4ݞ M*-FŖKRyQ :D0JVžxÇ)%jwGM{l}cu 16Lt$q?]wMZ{&GN?n^Q%0:w TNb\DQ'+=i7>ueҖA/ZP4\[vIt0ecz,bkCq$"Ғѩ,<z)Ά@F]QMbQx._n͖cFؽMYV/fR7ݩ #2t5S YXi()h"#5n BjaH$\ e.yɗ װ/ib^pZY6Lh֏+n~lsm 5x)CJhc¶~'`۳f:%t۲u j"xI98,{1&\OTB/w5={,?NVVVxʱɛ_ %= 3;J*<L {`SHӔ7rM_1lYzq^΍7߈ a{<<,Q?adt c _ꗹꂙEp :y!(0 754vs#|hjpABX3,dy s}Dʣpt˰U*ː1D(ԦSԸwgr OX;&VO 5bۆma]+i> .̓_jXYkE#g)UCiXUpC1p1$8i-/%^֏jZvc5wfƧs~N8D~Q6m'd[΃q^۷s1q7l՗]}ZQ,fHk{%Q#Ei,!ulR I;kRJjit^!]8Dg&!h`p֢uPe@_.2Wy  )2P:E DЙ״bsE9q'܃s|mr))7LJ1 m puE+H[ $( BH sJ2ԂpބmDȘ~QlcѬkd{B#`j3Pl9\e!Rar5u|]60VN;DN~Uy9_ի3t'sT֢FA93wr6C,Q!x"x/lhԏw~{?~> NJE O~JX[ dv=RҜtғ[P,C;$i]xAF(!iDV9]v(yUCkmBgu P{lAKvl|I) Hs*ɽȴ]P,"԰`8U,-:4 iv6⍊c6G$[,D!7JfDR M'$B>L%RptufT-R@3nL )%aJsƅ/~{N;]fu وk0eCi-Lr/luEd a4Vxl##/wh4i u^8|p;yTrɹw,bڄ']8Əo^FxAYG@y^$Xq=^GX6i)˫.YxҴPJ1JA-&&+s},q}mFF4++1YN14"MhkqH& F*ee &pCc~1UxIZ[cޑPB*836,cѲk7]\䤣"N;B%P3ߵZp!ráڌ$iJi$0vi> ~8| le }K3̵Z(A s<~}% \ ؐb:fFG y1ew|?|'װDF0\Q눥t Cp׿}=]r=߰N'MSvEsh{isM7PnMYlBg}8殻]ayɥ敯|57ty"G8O:5,qz%yYן@2<) Sz 1Kw<6-(\ H!J H5Hu5Ҟt |RVKYg1{wL^'Ϯs =,vSXJBDb8*ZHw K<'Ktza(a Ͽ|i/*\z:.r>O#dڵ=vl[o^v6ͧ?>?9:?C?D<(Ҳb~6 P$e;QZn<`q`P* KrێgWB:4gB!4cq0R:^D)l@P|<29;F'm H 8GmLTIO<|JIҸ}zxazL1rLŞCKv) NX1R8r"tY̢(K.ڠw6!x$ձP /A SAyFtQT%d6`gP{yY[ɆY_]ףovyy UpK,w!{QSrHD0` E5+ciٖOH;,o ^pt|A 1(_ö8V`nȩBJԫ`ѹEhE?ӧ$78ZPl:'zi)b0>}uyD\!yg cJ >5"8 xw9g(ˀ(0.24b9[X=$YZ1t=:u 6 K, ,* Qhp i6MG|.9D.|eg= `]ڍs$|t%N@!:x,(B.AE klL5A߸*<8%K, wؿ$PcdJUۆAu0g#wldcTDny[q.|+ifbrQHEU"U0l Jj5źɘ{kA*}4_=p2BD!H ̭SP(U(amS6+6k|I+A^xji8_`*Z&||$'7wgbϓcJNGC ]+^1x]]%^Ee,uX!HkŒfkRkrXRUÚm HnU2$dgei u1`ltz'DZYlH32c},qP"zdiMPiž-;cOo1С(-H^/ZTH;:UWQ,qdClh{3 m %2:i16L_c 4"sa@xOg)0HQ}XCQI\8m0`4{z@n?diĂA!NX~x'cccoZˮo4-%'M)v zb@} G):Ix͘b"z q3[oaB`CL'9P"{#<׿[]JY_;-򮝼gYtW3#uELy)%9N?#G4SE)xZ8p,Iݚps hFUb%06*f+>}^zNy2yK,:] %S֔M`<2"yU$5pL'?<Ҭ)J2Hqcl&|RS[x h%#qtaZU#5F?%+-$PeKZP:)L )Ɣ<,W{( N;n33K0Atn5O8뢋9O歿=>o ÷Op tagu?+kI{_kNҳ(`;'UAwg%q d #TH )c5}G2jE:#xg)clH#GV%E|!,Xщȳ?MA$ψ\ !Tts`(Tlp HI.qAGQL$=OjRP 'GDUVL5$h~ Dq Q 0lg()ɓ0?.LWQO٤Wz AbuI)7?g%e%S u?%B-s!Dxp *:=2 .X* $GG!t?0V4_ @z|,XA4ݞ!=e *JPȑ3+wk9L֑Xb%h[:]Jxb䛿le4Y(C !إٮf|j5#a5+qt=%26OGD:4h[+0E,NAXo0Tsb%Hg&gurV4:Lg,FH]CۻxY#ޗȣܓ$Ԡ n.i5E Zق´tXJhUgP:D1R;%{Z_[Y2;M-5ۦ"nsyQAaZK0%Tg02c&4&OnYg _s~ *r.!ﹰ0|aмn2/LzzuܵXZZ"d1s9ϡ [Aqm7p_ĺ?Kv{>.>p)'Z JQɆ1 =IOb~A jab7Bo&r=;(]hpe߭ l#-e$Uhi9)\t񳉢e,crrod~~Wy1"9u(1~\عg|҆2Z)U t ۾ks#G~NN<]`(g_+p%32:̡\g#e)"֞=v=r|ȭs]DFRO'cߣVWhp vp6w!1ђAC&Ds-^p%;Y- ?t37EhT 'U#K0Npڔ$]6- `g iġSPY1 "!Hc}Ƴ%rhgs=C~_vIO![16Hª 뉕;HX"'ƐH6+L p{˶q4*Re}JZ+EEMc pK~91PK<B +]'#m9rſw70;sg3Hbn O 漧_ce \;SNc'HC@(2CD@~>) KEMj՝˶?=%``--Mfg=[ZaX<R†W?_5x&}50'j ρ[zR陬 P|v|L +`6Xۉ(o8qi@+)u_I'sy O9%Ih]'7`2DZ: 陎AlA>hU[>Ii@̸`8>~MDiHm$y^!|pCuE% j4·8LU S|:q} XsgSE&&yf/9x]9Wܿ>5קDo,3܀#nGDC( ZX:A^|Yxs Ei).e3֛#zM#gn>ިRL1j| s%iHbI- HtXl/MIı"Uv$fjz/~*Pctq[PRRC hSD:Y޹J Nɬ 3z5P1NJ+" 4 ES фV &i IiBH*zaR^|u{R쭪PKJ XbFꊣ&?RVM1:۹׽?}'1~/ocddo͘^q9./,$5) IDAT;LaK`]0*Ob=b7EN>I%N0%É"Nq=wЈ[ރ3W\MZf$;MWab|?cq`pRPejG\kC* q윣Yv >;>\կrY'qqxًZ{\DS1Z:e~-\sͷtt@jѨ7`Y`ƮyK$,_K^ZtϹ_Y)ێ΀ˬU/;{/sS"N3y\uo=|ܽgXωp㡩=EPڅ$0Qoi^П(cgY[H0xCȊ<1{QiFz3=xƅb^2:sɁg,L6  ՑuA 4( SyhƁ#o!H,}i<*g[؜zSfm-8c-68؆Us4ZKƲ}sXl![G,䰯}+R> =\I`"l޼=O&BkP T+L#M'@<JD,fH\5mE<빗/}ׯHW(]XLM^bCxh kAmBeŸ4ThEOV|ʳ7yo.43 ^Qb2;> ]%q$ 1(=3K%f J C̀Y]2YYQȨHU8ZPJbA4k#C8$Qr/ካ~}O̱fJe "wnYGwRR+q2ԈS.x|D0dvf[n_bT-Щ2JpSFX5p#TV3<1_jHF^DuQ@0E(C` 1r8:( 20X/1 g,u24N6%B`QcBq^n( `?mC~tRJqq| Z ɿۿ/y1?q̪o~S\~(\q.,@ 5MQݻ~}y;/5gSc0 s(kI%3.(LDk-=(yja |̿~9̧򖷽N= SI&QҠ=,>.n[]G7\ZXx"QqU/2׼g{Mo`3sW|䓟PJqy橗R5¸l n&7]/n9=9ovwiO;|>5:oc7?UwܐF,(sJùp<v8uJ7}%l%&!MTXpC1xvʺqfA(roC3&N'n2^TI~!w#xyϰ`So5K hgr΁ %矲5Xk?u|ۋa5A/QJGoBc ܖ()1>z֣=c[oC "BB BDz9>˨҄4h;Ehh l$&l) #pMh2lDhb$B!"ۆ8r?Gi\ gAӈaU=ej(!/3[NlP -Դd%2BCQ~Z9B?XkD\N~!M&~xJDa*+ PU lvL7v=j^F0CQg4 |W%BV&7RidVԂu٫Bb^9ϑ{XY ۣa%f]= d_fzz3UiXSB!k M^/f*lĔv\qƶgAiIVSQCIL+?~-B0,34izDۂ 4TƄ՞TZ*#-:T I,cI=V7&U } ȐJ7_( PI+džMRy8Ij5Ś-<Z|[9 wٷ{3#hQx ]O$%V,u#H $%`A7,}j]S{BaHRI")ƞ]~vpB DPhBckX+Y;2cm;4R>1&'Wc睯Nj@ZXo d֭WO vlG]5/Cn]Cn S@M85,qeOO-odrl+.w~o~~tc=bhlw,e111 <"WLı'©1~W ggY]ZӒIf&F M!F H(AʖM6bj ! $$6}&z]?L8/Lyg=u_y DmR6t񓎿穧N$VZltǏC;Qt ЋZhMҘ-Gxu)FvsT..,1^_'ox;Ab4/nS*fڊoOֽt$~<p凮cf<\S(0.b!,08e&f1}Ať_#vzyK~''HC}>3ٹSVv:k|X>X>ZȲ Á$>lUUnO'D6kEH]VB4h*eT__tjUR]+^f:rxٵxtX,bՁ5*zTȔЌLS xKQy)bsq(KDzQ~T:vxX zXEk sk8%1iٔ*~}acy†f:gO1#wEir-W(4\KA^v5XG7\ [q__BM02#WnYޓZ~|]$yozT(MõbTta#Qŗ+gwϝ?Iv%Z+n]zZ7Qb긁F2i ?;BpDYVҰ+xNǚ &LT##|4hW 45]őI^V@9G8B=h:B39!4*TGVKB7鋄E uC&Z9 iVaBIb4 0ړB^7dXq䩈}bgvB$F$]4t Q3¸m>r1IyYP:h,D+Ihr+̮nʵccr Y,Wkpފat;+ɛf%S@d<;" 5j'F(笏EbvG9Vp+LY tˆ)4%t 0>Xp*tGo]Q:vxI植vlFfݯOZ^02x'c[,?|$d%ONnRcneyၽCQ/ qmkak9IƙqqVxhSUb՞)9CϑG i4!G5wwddJ jGk֒"FErM=Z&A5c-{#T刲2!L@%K:${Y\,XT|daa򜗜sù@+}"_{/a]rb2W?(ٷw;Bj-pVs F&tXupY/ mr˜w?$&Z2S % E]Fz4NiVxKmgWuYყ,K'OI͆1IvV^)FC(PnE`S][֍ 'nrǝw6pd.8O|-W޾>NxxSWLLJ5 Nh%S>:4h) 'oW ǟ+{=,?lF j( Y[Y!~%Lb &5q &xGK359p*b {$J`U$ӑWEC詪7B4/ C6t4/zЅ4Dž8%4uC1FC//~ny Y]ssGs>Yʲ ȶγOcY^h1;ny?bL劧2=1p:DNho4;6utTic7:u e%APбlB(VT%(˒EV)Q (8}\20fmؕqٛâ}6bNU$ i r [r/tq&B_D BJ^KHnOҬ}SR-NиW=CQma符B[I*sfrMʟ~㬬)q4:vxޏњ(l$*򴍚LlUYS,uS?uG՚s6Y.>pZBGQ>tqу,.-b؄E*@kq=FIM![9=&hzo8h%#SOg멏碓SN8FaX9N9drx;}Ms5?~_{鯰ZrirX;INX{."yHg0y ͥky*?) $vǻX+8_ߩ'jVZZzJCY)j*މUl.Okq *ar| (vVjTN,KrpMѳ!`n{DFTxT)QV ~9Gqv5 '/aT,W[jE7ԣM!H4(+?rE{ba5"7TJ_"2 Hc?Zn+ȔGEHP\@CB@T-J7(%ZIvKRG~eooO?w|w}uU:-`vvwlڼC{wq?~P\t<^?dT' j AdAS ;1+-SCDOK5eJs~Wx|Bhx`]ΘLCY׌IJfԕ%:օ@곴Rmm&Z!8NP&%E+ `(1 5 "G#"2TBؠPM! D'VISX6蜸ha9 D[ IDAT*H\g2O{+5&t: [䍳+ORMGMQ2(^zoq51jЊejyberf}=XeP:%IrAD,PtBy}V2lBoRHU&e$o6+2{Cj]$Ek֍9O9gP&&Y2:{buq1'N`kNv;|k{ymrS`lzS%M|i[f)$:0n#NIP#g<'X]W~嗸[d֝c|vhu$V+Z \ttx%p?ЁT>25?ZsGKHaguvG_Ձ̊n%Hd}q/)kT39BL ]1 l{p$tKr cǚGfyM Aˏb/<~f^_/x:{|/PI^cҔ)_]M0JJ Us;}Fw-†J o4yI@ji&t*S͔ |DR1 Z۔ɱ Nnaf t#EGO!V8,IkXѪi4&h$:H` A)UR9{\gKTBLN1LvXffRF5GJ1vS&NQCuc4sLLl,ŦKF!cیd?SÝGźjhIn:C&%k%bS{MV[/=o08cN_ff\ᶛxϿypQ>M~U`qi }dynzL{ZAgNI3Ҋ4oc= ?޹⸨>TBV0ӖX+3k_Oxy`FvEGjln9 ZG9JiFlTe#V\ܕ:Vd_QҦ}^%Q`Ԝ5ǚ_2e'yd1*=#ҬM#ۺBW $zǬ%{ǜb*Q^ ւw56g%Sf.1dD&S2yBD).4HvDIhʦbS[3tr&'ZJ{nnǶ]i^phM2ČD T^vs-Efe3HcЯ"^%Ԯ,F4P6C/B>**Z:'ٻBYKdh!b\F(Ki,nCԱ#9Xl+i᧡u?9ϽǹD7%4 ųXk֍)+1'F*?_~Bkd5Y"X] lU;*"ӓ%GZR"}aQ↑=ba,ʶ}bY)&Tѐ&"n'9|R1t0XtЈ %(&a%ֵu 1 (0Z87hCJ&H@w$UQRR$j W0Aij<-wqb -Nۜru4ùQT? +dL%i(10ϧY)+OHU])6d fzo?hpVË UT.ٖpJJmCHS7v I`}Xsۭ'^̳ _KN'no|C .~lSL"IˁWm4i?'=bjf J\ї5 u[{|Ym<xǙ gH"h8|i0fINĢ\EPdXʠ eǎ3^zAi:gӔemJg C{lrVu jq4$kisxg?g޻{7W~J>p]1`#]BE rA1?tj =0upvF} ņj]f%{ xΥ>Gi#W׊?g|ޒC|T5ٷkx䪫'?LLbqヘ_Is#srp` 571ʎacI+\ TAM{"1#J +<<W=4`nJsN+6RPfvlzn)+wh:ՋX%9 IgELġ"Q|ɬ4L], 僨 xf;R\e|̯U2} f.fĺgNIp` Gv2,w)1 |d<,9 WAUdStQ XV Xb4WۉWԠ Z.$aP^OxAbĠC7-.~9eරٵ{Q'|{v8Ͽbο}?տ2j K сJQ38ظ(nd:0 :JOT 4(F7"\<H(L.`k7UpP4y* \As4# QUm,a!i'҉:IDRiXIww fb Tb$"mj-9 5-GGDJ[ O=Ȓ}k K,E!iG6uQ^vEߪ@7tf_jy}cP} j")]0(lJ2'08z5_%k`'c(k3k%ýxji1#Lf'pITfÈQ 2\8BsP,DȰa;>t%x #D8FE"cd0I'UNY/Rmau16 22] JPS5L QDU+$8>I@khBo -BBphwJM5\{SwXc-Jqs wjֆ G3(GCILOgϞh󤩢'`,pt0D_?Jу,;F)3za(kO2°J1XcuJUD cih7Hp6=mŁQW(}M3ޢ9iF:ɲnJW}5i⨽ۂMn9A EY^٦iш *l_Ox\Ʒ߾<7f'_f߻A>,vxeˤNk]/X.VGZݸL=r4iCPR`1HYY[dtK3pkdt36="*lIZ1;hc4WUZe-Qk-&zV{%/yo~y^Ɖ'ng_ʥϾ !(Rfa!Apڙbv\z E -J^ZrǝW6͚Lt雊Vsr|Mj"QVGssx׻Î;;7~|. P gt~uRTq%yEEcP}hB %S4($y+jYO/)^zNmY>}c#44 ű\ cMB+o3M=8)OG{Q!2šSl%zCT^`8  Mx/PL % >P2,*Gbu`T+pYP(S0]e V4(v6E&WFnRIrhOTX>A,iA&<43)b={![:5>Zx}u9s=,_|,9q6UW}+BpE.<^u$T+{i4 6E@!c${w"9~#\]^sղ VE{WjF}U%vTS 8F"T+ X{6t;=RJܼ*jYϭ:R:A6rk6n`@_٤Ř)X.dٷSɜX.h[X wNbIBQI1*QHx$lÎMRPձl_JqQ\(#( }ɴp0qޫ/􆎙dFɽUN^V`hGQϘ0VG(6fZE( Yff:֜'Y4}* kb|׼-BP9ӄY-k#Md,/>F+O&`xK~<$7$[|(2ֆC][al($4#YFKGTJ !‘#-V@\%-V4'1YHp)۝GnkByN{,kizhyX̱&A󴲬ÿxYR:ᥦVeqBZ)p l.H.F*:0R,7Jybmg,zR}U䢳;+-RKQ:6LX~m,g~fivX4\ͺdV~/dì}Lnez{Ckf\LRbS7,6.J#gP1I9^ HkiU"Lp?|ă%Vq"M`icܲ>tfPi2L98b0xhJ "+}ѱi.:zmZ+F mLXʷ}5v=3ᚯ}| 5lص޺䟞$ x.#2s?y_|޳ Xyzidm$χo;Hm#.Z%Bh;M]ģ83y_r\q/'Fcź "jd"VpTÇ3@[eťC˦%Xizix\ޒt:1ܣG^^g>w 2 =Bǎ$QtOk^jBD2hBe}0 Qz,ǞAɭAE/]DޣfcB LXJ%0 acm DC6Aٟ@7RfTְrO }&ל6ѣ^Is0`5b)^$VC5g pFaLA-|M-yK* 30;;}c|Bh/H%1FЀ[Աɂb $Ԯ©@90T-C\D键ԍPxZMw ͫjq814ZG fӐZPm (!VdnrpER9MUN@4HmV;E ^gVkM$0OX-D}I7Gdg9DN5Ð}M'hc2l9:_eJiEc #eBq Puh(CdC,Wʠ&[wZG[E.T/`|cv"E#vDӵCbsLKUTe<1Ker0D 'j{qpueꈫYXլW8puMQ+H7X+-eD4_u)Ce97Ј: IX϶[]p=rl\x$Z -`T2Xţ6LK=R6.欭UR[֒dNd)=lBqBPA]:*642sV|]!rbԣ`}eZe4#87Fi6 tZhq}}Z#51[6sjr#^9+*ލ1(eqlQAQzg@O2w9ccBusQoVW TMÖxQ1bӌݔv3A|9IkT^1=\%*ixG~XX b}5RN=gɜHREH3mu‘eGo0X^uX0aUM+d.RWހSN{?BQa=w73vy[Fe\ćþG_;ukmh`tPIScDqB.!HH۰8٭ؔXQts:(yl8kӌl**~kt|ϾJ+ZI1Jޠv}dy`ᗪH(&;AkC*'yx-ebfL3x`R 1)6UJx썯畯z%/qgFjl(R!e"FQ6sC85SZr@8rÿqʤyu)TEbTi ]q0)_Wo|M<~hDjhմz**M[):cj!G娎4A~D7 96൚Ԥ΍ 80(bzZvݬ+ LcM9$i5 TY h~$8L &:4^[zUn003"X#EG:H6 ,}_4^#DOCql"3N"J]Xn@Y.0|\Gs(0O VL'B8G *PiQ%-]&Lb"oSxE5\jbgn<ԇ}}z~Y"e)j|ȡ5ϮVLȰlnQ7{I O4 1Fgl|M3k&Ij~ \&Z (ԘTAJ#4}&Q[5F} xtU &Dkh2"t!lKX@QH+H4R # ĩ2e˔iboƒqB#M m<Ӟ!?S™!aK-rh&`U ʒ62"Cq{O4*7MiX)gI\el,%I,Yoi#E<5U F%nKkϐsh#ucɧtW?d |J1J('"Z֐6dmٶb]5JC Q%$ab/1L6G/>8|]ܕx IDATىۆ4͝@wG󄓸5_\[FpwpF8J1*쓟L]\~Woy/• ZWmcgfB݈~]sDǀN, `b%tЈ1(d}.wOo}XXX̝g+șg=!BV$W6mAw{%[6&'XÙ \%a-&nIXWbT% QRQ'Q s{8۷={vCtsnjk"ZJA< ,":-P+`OY1tVg#2?^F)yjQ b&51mIg'?[?M]׌>mu,tm9?']!b@9E)f,E&#G6eMDO+@ cFڡn9k% .* /KRLZiY/#/ uf%F<x/GFM`U'vx¶ǹz]սoι[v]l`[ 0$r`zKLƔH'NH$4$l q&˒յ~*cÓ{opyɒ]޽5?evQk#@CjmEQO];g="X):DW4c&voAt`7XYr[1nĴin55 Ӧ:&ZY+ l$](Uk^:Z6[l-oy+D/x>Ļg2nw7gQDDf4Yǯo@\ R\0~‰'?,Unlby/z/>Je/ρR|  }- D)S{hbbqfV}%{_ R A:M+:bhh4PC(qM'YX&"mfB9mE5[!Ƚ'N)_F˄bt} >v}iF¯Msm3Yxf4ѬiŎAok>;yl1G:~!!&"艝k#-LDLN:~+S ;wcChD\dCF/ 7AX`xW *1WXN+QcU>{rbhU#?}zuӊs4tJy_EyO4bI-m y32p#JH҈cc:b3-$,v,߯(i7ƹs"gD[̨9ötpS4nk ێ9x/kC&M40l_a11?ډsU'S~U(q-扢$2}GF;wW\?%PGd4F%WR.6I{߶g=m 4ƘdldsˊIx#M4urvR>pq3[naߣ{ɥя] 羁/6S b$L JH1-#Іu۞ǡ' WO]a]#n>|߇ Y)(CW={qF.g߭P:͛Gv19}S|MLqA䮲3eT5X- Y\WT>"RoBP&`sUW^͖-[xyミSTmV55i ila]O?6_u; ̈́FRdX4V/uLinyDصVLUfN<ȇ5=ǃx}PSB7{ϯigEҚ't*FNsd0jYW@ .1)%"^=FGq(fBGYhc2F% Hx/^)s3Qt-/hrLpp!peMZc°uXEV*k8eE1}R`%uf$ZpWیR\W␦d͸ZH,ӎ}B޳qiMZaP!EXՔ#mW83=gʹ޽Jq<+~9sZ?8<Zk:m0ͣw]?̷E~L<9gX 0jMrp+HxJ%4?4ӻ`̧q7ȔTIQ׾7@PҲ6[.4 B"(GGb H2RM )Mv'?I>bY:G8q&$%M$2P)Xljh1llÚ1P11H~H]2i͹OL9##<*Ut*I.k"fk"zHqV@v# u)iRR*8Q|x%OiljkzQSf L{V]Ӧꆲge -hid&Dg(`|&3Z/Q^r*б0HG2gE1fdB#4Zٯ@- ` ,eHc^(=XBqt(pBQE?EhX38fRqQˮ_v~u hP5e䞢n>&ցkΠ F@.(L^S/1 TI>:7Ŋx>timү-zcSRVNbc%Pi r[XEI17웭EjNQ-k"RRZ>Tj W*;IǮ0;+wfRD"]vsWs}ؐPb̬C+Q,v<D4=E0Z3قܳbj {I AW(z(** RrD'R[XbeG聜ㆃq `%E9딄. @9Z`|":ZrUңV;F{=Ȍ>O{'qLFt3*JcV6TʡI5i{ t\?xHSVG:/T  eOx"s73z9,zA^OW_2'x9e1Ld?ffxg7\qC8D$!a(XbG|5ײg^BWyQ= %Wica~(wGdqS|FW(}]ߎс蒚E]cȝ#_J" S[y*cdl%}kC(o䨮w</Ig:ǟr*kmH# vKiE2+M *B '9cj ByMαaw"hŌ}9A"W7yF M *hwfaN%b]La$b+1FeW©ď/Ngc6%#2ݪ B))*E:O$8gyC.dD^.ُqw.D+H"ZXՊ;^㯙N7׹p^Er ek5݅C C^сI`izSvʒRJLyqѷ{߻(jkl#)C7 Uup7傿a$ Cު0$i]-$LRdӨDoЩ$O\r*i+PxV+<ydqLn]jG;X;QTղsݚd[pQ)%5?;MH&):H\8AW%R(W |)޳Gq1eWS#EP528x/ʊQ/=H/4?xטX3Wu|Y%5I{y(PZ* G {ݲ 8Z|lw߳!oF^a_)~[̔]:EG-\5l. Թr$3Lix'>U[s㿑@IoFqӭwp8r0I066<mش|o{"g}"R`+d?{w}{MgihTF}1S2:Ij[Z )h= zA32HM !hnG<_5RzN4A^  W2G<)<6q2׭͈ʉI x=L[6ȘZ9Q;3ގqP:ͺ8FN>k^lehPkyqȆ7NyvQ~QLQ-`L*M roь وpA/4s:H'p,@J9ʳڔhO ɰ3PF"%zbj2l޼\3?HPA8N~07s8ڨ=ƒ'>W;;W*~2SEU#C E3Հj^I֏%T^@õCR]\Xzn ʓB:y_ebb={aظq#n=nTgs^J藁 gXFRԒkesM7p2(](b/[~e ߵi3yiq-Q}bDc_jFauYTM^g?}''ҌDzhgn&0)֊ 0֮JD@{UУ4#xhIija/AV$J\.JJ9%FN5t Y,TkFLǜԔ!LY/9Y-b^,5i9+B8Ѥe/Q&Jh>x".ϓ^c~;ny :tI.w댙;%pͼ5W]̜rß񒗜#Z!!>s;_W2D`y@+!)4HmAh} E|"IT%1KzuJ@O4^ԍU0?hhhˍW^_#IQf݆_Y[{w*5Bp4fuge h ~W:URd IDAT+xI]}ra-4R,tP[ӌyhg0"# dΣCjӚ~@}+aqWڇrKvwB͋VpQp=_ɭ$+k/qeX))hFlIMXYwe+cC-F\{ v\c:^N}27R-nsQ(_. bl%|cݠzXEoRTJfX3r&Q$LF5kr a˱lxQq՗_vk):D@N^2n"&C xG+>ZGL=y$lw'J,lmJ~IoHY8+*O<19pŲ&hT Jq_[o沟"n>ɓR{.GS8UZA,,L@ EF 244]>H EҒrx C~%w'22 $#0+亏#E咁L >z:I5xB࡫.d ?! U"xֺQ rydMZ[ϡTr_Ab @dx`HXakw0wb#?J*e Xɬj{s4 E>J*Yv AKAN4tn. !2#_rB^(ؚ0n0m3* ƆbD L֜rB>(KSG" Fˇ:HCs,\F VX[Jw QMȒ&nkAbm<^DA)x/'Ϩ '`PDhȂ}6E?pP@La5ԯCtctCžgi$b;XXk h(Gr(aN5|F(tqI"7 {`kHb(gr4"MrS;_j) #ccC o 7QA}Kkx 5CՎbkbE'"$`+ڰ_ owꔗFLU4dH5n#—rIc QTb7*8٠lv *nC֍E.!MS;W. C-#Rdq6Қ 7;vfggO qU'q7рA_>+~ʓWh6dkЈl&#JHjP"F5US/Z6R8دt='9V85N],,K@>s!<"B A)Rj{v-+5A ,x.Suf=w1<:'Ț똙+gu/cU,fgGg84(\[ "!O%DC<ϓ$-֍k1X&"Kcb5Qs=?Bkw Y5EЂ=['4EY8ç!RދZ2Z1&I"JFkYuC੓㍛1ưhɡS p%`nCXn\bv0-)[39.$" CtA2J6hxDZ/gڴl||LscV`M*JctX%'ǽ_x}aq Hj# Eb}Tjd[Z"5z,^GWS;<YT%Bc#nFk t _`?$[CPvm| P:"(PIӞ,fffpT)En\pG;8H,T/xPu 3ëۥ[i[>sIH$xxxnb%6W^u?r5rх񜳟Gf?-E(*qJND f q^spA`P_b[m1::J羝Tx\Aބ'<G.k_ßq&Q4RFE%WrgpPATOY < 'yBm3+Y }Ŏ Q2O'Þ"("M, ,M}%Y,/@w@`Q Q l^B4IlJSbpXk0De1L%H iC(,eǡL%ԏT)j.{`* ]X.j]tݍ<n>bXV7 k5}ټ"ugҤ"M3o0r(9PZx.߽[e%ả=gv W_@Q qrr? V)^Sy~xHu}J!&/%"Siy^b%@dC1:G XbgJ\E-DFmԓV}3y_{VNƿ_ J`anݻIΈdU {F)Rz vDyVF| (%:QO`vn>BׅYiRK)h3UO)cH\z)l qk3iF6,/Agb5Ӆú1Lm pwy.0KrJK$ZCSSݲ~:_jU\B e͒_ړ= KSVnHRz+Ҋ XR^wsyi ,N56˹@Uy)'[z=J'kִ8eObH̥7-HptfÚN@Qxd+{G߷DFV/TtzQn霸e7ᜲ4hOldQySg94WW`ц4NȲqJ݅.RPo&{#(~t ){3Kbl9)}}ѪbayITAp?J$I7U-[>~tIWЁanF:82$I pu LѝYLҢ4M{ ^Ȉl:[Kkՙ 0i)+OiZfp!D$F@?@4h~,Wq^nEXС_u:92FK&DG7g0/4 Z .o㮯(Oǟ( ^+v?ͯ3G7(!tM uQX%#NL1bx#,斋~JEu(S (*no)z_["10ࢋرE|D%<)dxdYwhڑxȓO+~d7s, K^.01S̔R4sw܎*(tܦ٘I^ڜjqq&GwavVhX"xP%NXcPO}pS?cYzeRJPTUhȊ}m͊ fm;SИZQ`Q$4t:t3W8@_Iā+V!@W(Zʭ"ePt*8St%Z2N}'4cr8B<1X'\}/A[ii*tj=VrnƧO͛O~sע)JsN,;A5}N{~e㘢(_uX-{|@w~Ǜ8oVΆfmKeJhJQHҌ*޽}|+96|93|r1",ϟ Jz4Rh$!ҊTmzb*O:_c\{ViXY(pp$Ⴀ#k᧗\ws!^#z> ,4!(:M<ÃP,HzњVq#@, o(t& T5D5J5f HƻkCXY^j`IGQ J",9-!-!CS+J)I{Kc#F2ҚD 0 ֱbb<0<}*VLr&5"~oȥQ:y٭iq4,޽?oG D<%c"Zc;(Jǣzo BD g.y։k.8jҠf~UɵvX*FbG T,!)NxK E㩪A0\.N&M]F ੐$fq&6x|sJP/V]e4&[DB4N޳rYdgqZg#B` ? W=8gPt_iȒzSSΫb)K<%1- ubi#en 76oב:gY5EQ9icX+"V6|P*ƚP9Ki-J92t-J:C1n!9 Rdq7xϻ\ ^W^4pÁ }pn|VĜu]eo4sRE>FG [#"p6bH H0 $T~5Xzϣߘ ޵מs12a5>R!q@ck~ɦ+d+-b~:6Q5ɬ+$( rAr .;\vc٤KkΝV8 wT'JfB3kI?P G#C`M9\*F,NTg>7yOpL+VMBuQacR12w%8* 䌩 xtM.F82=VELȶ\ Gؤ1ǨZQ+9y`Eql᜜wk#ZQd ZFqO=Sdc9XhZD5/Kf=>JVEuegOݶ"M<:$AZF\Mѩoܳ\~xG~$} BI>Gdɛc`5#ڃ< ]ʠPQ(hg-sbLN cZXSݒBޢP|4AR3 ҳgqH蝋W)\pEH15W8h*ΜС -rŊI[6Fe$& *4r\o&}%\.BBCO ƟL5*ODZv=: M)r+ݩ5CO{CdmyHYK$iV$=QFjeIn ]lfe'2ll_x РU@-ʐ\ 3"jX]?FNLe$܀UFs1(dYCZh@@ Saiv5_Y"o>Aж+ 뇅2-2~pI }EdeRa9^\CQ|EOd݂NḲ:Vf *gR Y^t Efh2CkTiCHFѶ _oO[ IDAT1 ѱB1,iݖmh,6O(=퇼sLxjHB` ,ҰEgLu }C&GOOq s8Y#a]QAKK :bWhfJE/y׻~ι C/=}aDC+O߼S76˜:J" *!GKru]2#2Τ|@;E%)Z}jAk.-Q>ͷ|=gcOz[?2+cYai6fPSs/ oNs)u|+ fsY(EPͺ*(L~9drTtMjx i"DI{Lt ̏X VöcEuE-9,yU& ^L.@K6b!05FK,J/TGc!5!hNJ^ )ܶeGVBvfCG LiŦ6=sdڐ~梨zoHKQBcݟL҄XtLB"*TA@Bqq.;s%sz,H$)}Ĺ M [Mn*YZifDedձ%.mR!Q趫Qa klM\ IfFsIye{dڈnu*9'9}cmFwU4jT\o& .53*Dn Hp"Sm͡Gu:"_\fy<)*T4AqpN&^1J)!F8xPŸ KDŽnk`c&c۴U Hg,#,5 yf27O~,җnફM_A.khe'W=|mFUU:ő5OT"x3*}gPfܴP*ckh*:V /과|Գ(4]-UpKY m2֨0bf0g7r7n?UnG5BN3hIKmEKP{{w^oy{96Wdh(w]{XZZr86OmޟYU#zk؛BHt(qԧ{;P*;1SoB1"*QwM(-踱U BpB! udT(;[ S@`\; 8cV*Zl.P1mJh 'c#(^Jl#qA]Zcn,Zb͂l2GWn:A˾ 䙕0u ).Lsd wrM_s k^O|+7ciD3)OO/>{~m\prx͏>'(SGhFkGqmӟ"xūz>Orws="L)WY"SLcHS6uo%n3?QKCMur:夈$TQLkM=qc2`R! 02ж c)ҵ&]IVP@9YҭG'~L 6-yD&J sRyyiV`Wj$f TҞ ɕ<)=4ISLq~h5 jmXN5O7nk+8~bnڲ6 뫕WB t )N'c} {~xhd6|umWXB$+.s۝+(Q:c˹r辯3e=xȘՊN27Xmxn=ؘZ-Sq`PzE9yr4o`D4> &]HN()/ѯ]/R*]3iZ!:!ALĶ q" ”fn#ud GvKzmh4zBnx_rR=6Q ۜ7Ҝ?_8ATv'cTittL?!j4kk_~_왎ۆB^(N;|soE9Q1۱cXjmj<>hSms6ǧ ՆorH enó.=^bX0280kk#;g3ZVMQN} X(Xb\8Q"bڠV9opI6w(YYN \px52=Sb˖Ug w?z盱k%T2]&%0xk"SXSa!3Ӟ c^v8VHTpyOi[7Ln^ԣhOg,УmgX*VhH_5b?4&k1񐦉8=ՎaT5gzj~\~~? iqAѹ.ҟꉄxk^ŧ>q +R-Ǫ%RGq+@5ABFM@jߠLrOC)џUVcU o1&S)M ]Q#ņQKg,J4X_؅I"\w"\:295Jhu0ll qd7n$ԈAFj6Z"Zt`P3Vq~i.;6syO|c'GG׾v#/POJCeӖ-^ǻ<9144NV$o?9>[sg0?% p} d+eOi04䴭3??Tn;|/?%{@&/k/-]ikXM#ѡ89/=K5n([` ioa=]-2 qCsL"OҊvn\K;1FIuk҆ ֟RWC=ñԛTezVb׬C`&5e74!7~Llrn mZKZ7gP !~ROٍmPqR[4!a&FiDM}O 's\:K/ٟҔMIP)VBn(4\cvhm0LϧQ Ud`Q>}Oʲdqq;3=ym<#AnoL|ٛti/FͰt[ =#-T=cY%E,I@mߌȴ!3=GO9I'X'tF. `՘\&U ZY;S݌C+9nm)>\2*=g6Cm6_gbAnoabEYBcq=|5v?/[VKOYzP G~0;|P޹'Opy ]j U-bg^֦mFvτva4Y lT#<ӬƉ;McrJfF֓Q csfOrA{ɹ]-U55ϧ>Y.BVV}-/`liGᑓ-Gǎ=.(\cՅ1R [/&V,-HEub*(H>cZr$d'zA9):1 ,"d2JĚCF@$ĆE48iXvI8%3##^(UN )A;FQgueӐ)2[2vGbSa8P 8S;jlFxWЊU?#\(~VXևp(rPx7KG?k_{rY/>4igF1m"^Z)WPS$zA $ȗ)lau5b [6L˾+pF3UFی9>1ID.tNf*&@xsJL O6]3yàk$qŔ.C/{(VF /k۲Wd AR:DzzĘ&~!OhzD މ8_) MdÉRUCA o?ւ^Y*v89t҄ɅJ`t(03X PLzJ l%F+M!NMN$13|Lm3-9*44!30 ߣ@dߞiè A,S$ZU{*Knc_bC<\r ZW-owwk믗xl( myҞ#BR qn.DyUƄ㒥:ZOQb9D3IKoRr B!ZRqhش7D&6|g9|dҪ~'JnجS.:6Kr 14‹9u0T2dW geM"u%Atӽ4,1x|Lz9^8֣R8t4<̜}Gl]]O{< '|r u(kA#jvY[= bw[_"=Zy\AWe}Z0J.Y Ҥrvu#^vdZ&Md s'AJNOJK0 {Ӣb,:KnNށ'ъ-{"5^ܡ|zf_In‘&"ӑb-\i"Ӭ:;gN)L٩ѓH@Rl"TCXNYV+uġ[Y=ŁRѶEFT ZybVCD֪SBT5h»LchƵP/s `%1GzOGߊKKo) kλ_u]Gꫯwu5 //o>>•"qYRR4LŹheEMl߼]j!Q#uE4P%CgtH8Mɭjei~ocZ\;GP89mG<ܵHG2SiP2^1;)ɆqhVǑ55\Ǣ Nu]c,J)9⪣Rt[b%< ɍDWr6΁Ç-W$beʱpWxֿGkwvKM.v:Dq^HtU|7ZM jk溊]ޣ3ko8}^1XCU/he[[M̽{/\zts)z(سfy䡇8CBvZmb/+N42Xtb O7SB)]/J|{h}`vvi8q0?;[k՛ٽ{=5's IDAT<%"4閥Gy8^Iom#j9Cs oFu8E U P 4A eR,u|4!N)Ś2ql^UyiQذ#(  QɤI"V9k81n9khW&I]rщMh I©e"E{3O4U3 *r $U(Nu3زPF\ !Ro!SGNG-V\y.|O#bs\/LP;q"24<}7]->9Q:Z1rƔb*7~~>?h&ZdM5D!e_f(pc,ٹsmY/19mβu>k4V֭m~x?ӯr6x[{=[3M4.ʟd[{zj)[gq{hhGtUJ}58&NNJ xF:*Ew3xAAw(eٶeE*P8}:糺𯄤ȵ !?c}L٘ꈝ- r(1V3 n5r-Ɋ,U-_ )nVljpX, )2pl3lY,Ƞo\s0Tc2.l͸Kn/MPUB Q1;f.w=c pςGCp3Je-^bˌJC%FZ(;:h]G$PHcXTX[meʡ.`[sj=w!C Lw-sS+:mLpQѳk&Ƿy +b{œI֩\FŨJZD; h(]*QjR<(Y{;yc*!y36 #AVoY]ɲ.Eg*è="h~`섮vfxxɳ4_}]|~h/O(#Zhgʥo+9t&,fWOѲՀ5"WZh х?y89$QāT$FBBT)8B{SMRJ8j`)L0Ҷ R@n2Z* .pr*gm% L r˨W\$E)C^H>azc(r;i.*8X\/̀SV&%D, q-/VU'>"6ˆh*Zrrਜ 6BiiG+Sdj/yt 5(ZJa*HUጝu6ʆX"W^<2m6hEiCY:jCW0/N'cvV27c1Zz-[ei DݶeӦ+waB P4!hf,)Kh%:.ypdT:UJ6X#Ӳ80kw(ZUY$TuITKĵ+k>s55e֊}OTD4e=dE+:w8/"C+ʪ 9E.G|;묏9w<; Q(hViM+/Q#s:~.1b1,yjHfēswy3б@f\ȥ3Դ^X^l1ŦM]frvs՗ϒe,erVVkPl~=/7P*zXȎ?v1,9N.Uø ØKvXgUE)Bxg9oV1W BicduTobk&3Y^D7 5Zj0 fDn2a+ /sS$ t[v9<&j<-r1{Vْ#{JF+áce,<SOr;ȰQD3*+,EVǑr8;kIu5p&E2hX $91pѼf{7ÏlG= ңFc '&NB+p>~#30Npa=6M:7WU;Twui&4I&(eqWpFGŀaH*&FE 44sUWz|8mXg?裪“p+[ |0]$U 7<|\((8/C'c {B2:ͳt~~ w[ |bl$1r\HU5 ኢ}Y{ie j%3fc4}ȔpcR%05'6!ح=0 lj}#W, 6]pjRO+,<suW.z}y9C]RW 2Kuj")ꪢW -\K풭Q+EV$%˚X|RBu:qScJ߾k$s[n )Y9CghhN5 i5KK]E+GiJM\p:1yWF lIإgcaO^`}PSp8~[~c4LlLj>ŵA8]/?:>7cxDqc_7ypCd! sGB?&i{;Ȍ˜eц,eXq^D֚H3 8Q".EI yX(eRgn"5WhN|V w=Zs׃$"}k| wE8XzGJs+1Tu}:ENa5{J=X5]2Qu-CĻMrCaM+hǤPfS%bȉ{<nU̙}iPcU0i4N8|HtJ RZ,jN<7 l/ ĉDr4ϪĤJsDqӓw?(;|m$ p"^=:XuH!4L- 9X 51j$psL[ϖ(v^V+)9w8ퟃu;)lz2RQR aPmQmc/1e ֔F+<\ 0qjpםev6\NH%1K|xb?{3KEj&pj"2frA.E" /g20\.bmN餦j<#p{ȘMkK/Lg\72??ÂGNMP*ce-#:1v?&1&K<ҦEuq:E),gpf_yt.|xk2uL_'E=W1sS-^6|G+q,:3(ʃg:v`z{N@\Ω cH5\4de#na~иx:79eM@2[v >ٰٰ9 8V(?uΟie):գN c5Of^iIaJUSƒ,ˌ)Lw?ŴjX(? !ChGz3hIʴbT V*z9ZM#D#g"RrI(''DtsMI)`_/cS4qǶE>@ʹ˙[JÄs|phbaﱆ3Nsr^/7nm&V| K%3SR8Cd2Pz9,5d7((2C&krt( bo mRgO]HIRgGO '$4~yM{:n89Jl«0Yy6*q0;: {V|lM%}NY?a>җ5~;_Ez;3quYf Mʔ0Zq jm[YRZGӮa*(&ՑO;{^ǡEIY ^LQN'CF*y3TYT'Rpe]6T<ڀ)8Z vг"lUO88EX[V1K%O"ւ|xZbkD=[@H)J@U 6e3*)JFUZ j{#}}!G#QgIbk^yGY*Გngh|۱ '{9ƥR2{wIXlH>"v WRԔZ*X:i)դCgur\+ R 8%c KRjQ7{@NnhR3XYX1떆^א.Јts[rOKߘ6h#hܽ| 7]mX4,oF>m(̰wj*cSkF&ǰo6WZxbyd4cMK3ƢÈ[XB4H v$}(2igtR6G801EeWr~BJ\PxxS P5A-+ Yer:6qahZ˴E99(.tɘn{>G\G{}ߟR3Et3urIOcJ m 0EOK[lHsEkVo%*aBL__߾e/co5~ _z3L]٬~)Ah-U$^([[ZE'| MQK͊V#9`i+0Z>S5"{^ǽ+>cI秚ddnу5>I^ m40 L'bm۱%w뭈L+E "4Y/#:P*r^ͩK B $gnŝUtF<-f !D[%"\8-F,8x%|DZ>H)i-4u/}8{w~oz'߼zGg~mVnRKUY*Eh&b۲ @AmjM;PҖ{;0?rߍRML\3#&U;4V0enV0 PNF|H"g<'&5g(jM`_^'2ɵCibJDFmԖ F&:AUrQ6DS:&(wܚ5Զ^5o4uQFOk1iDAJZgN+iMo( ζ= sMгILr96]\%fj'ֲ(32pWIU y_˥]YVˠAm'W[Hk,<_ҰLFťL2_H!qR&qp_o|#V3i&cm j|L(YD:()Qf11DʼnIqSJ388H(ES2+2=SLYc(EJ-eqck!SA{ M*[jT$2/B$ ̒}yEL3L\L\~FzG^OX)/</-dʆcXiƵ"#O6-o" LȵÆ3C)UJ xh%0W(nX|TKr^ypb~n܋scqb䄪XX {?I'?A'ӂY6 +|R$rk Iy/|>;TDϢbn4:'FOf;=75zqh|nZSmQ~kˌM,0FRȽ_\)kV~~;ll̬JP21c)mCd mIF& a'<"JنDaEcx·f,~:nzO#j)P ad-2Z4 hP| -TNf$a:Hˮܷ'>s1!$f,TA^.|AZB2VK!| 'bg Iap 1RE&IzY1ʾN(nS)`Ū0` LVԞ"+ژP!-krk^GZR|kkR$%WQфF ֧m@C@;t^+čQ)hE$mWgX"j7<1W 7PYdMkEK{J(FMK!PoaQI~n+1pȴ(xm:=<8iS%؞!B]Fmusr-39Åq r_Z۩j@I\cf[ְmky$N+TYeY]jPU n˟}|T^Niyge )I#34_EzZ%.ۓqa31iJF.ݎeq>J= jK[h9wr͑=?1eaxo\4(M0 zN]yS4M 3xFN =h9cg8Xڦab$\o74٨"hQj/wpќY|Q>x׈n m-W0I/Q~_=]hd5וjtSŵE8mbaMbc(}'BV_j+WbYQ5AhmإX_s!#' YZɿE:61ӜZ bӼ6:mW|cm"L4c8J-eKzQrg S,xh*TB.`f$rcEܻVEF#~3D1RdSdRZ,38'ʒssg/|kӘx/W{g⵷9Qi .Fr-RIv]>{-nrd-EǤx8`Z'diԾu+Z[X$ L[rVݐf^Z%.V210J5r6vC8#gYn@Wp( %H ,pk3Fy&mCtb6G]ȕS]+ pÁIhU=$D(´g@_A ^B뒒$#Ơsg4o91I#F_YsRGt秉iDff˝T;f>OBR'vw$054LG 6i#_쭱=4;J) ŖdJ.k5ȮB6|2Ŗ߶%?]o)2?ΠJkY+&/TwyϷay콤 SdcnvS*&],,esn3 y v߾,j >8 r< r-[ǻoq֏s~ehgxw\6x>Sul^:ˤlį"S\z;|M]VL!\z0Ȱ𜣃(3LOR&e{aX'L<=ť[l㯫iE9){Aøļ\g._s$a][#g]/ &jMKm5#gNWޡ癙RcݖY%FAeF2rw7ds{,QYx`8DdĔՁa[VIƴёiP^ ٨@\2_7A8UpZ_u1Ad,a\Ei4n$$u]OƒZIf`T*EY.2"%F{9]Z)rI-nӁO]J#n.ʤi)dBo \>Ӻ 0*FNo%zeD4ѢgafW (Ms.8r)\PQ6/k 4.r,g0l]ZIc Q.+.lxYW.qMKfa\OsNUdhЃ[|k R۞(qwƴec|3&WЩSf,-Lf'>?b:H=2ݰ>Ʀgs,4E"$KdPd@g(G=jx=F[Oߛ3h>ŊAMrB#g*4\=ĴP"NW|5V* 67Sw,H1q̘3<9ubasPQ7j:L\qEV6TϋOl9&Hk:t[آ\Urv#553۷wo ]Kg!1b bpuK" 23zK|ݿv-w+|!xfq=1L918r3+KJ4^$b8Y6 Rؚg)Vi]V8dgQ$Z.O:k,f^ }Wk?j9 )>f>J+V HpҐ)OٛЦz/ut\)17;/Oc:3KNn&5T: (9^$RjͶ kر?$KN"Wq˭Cmo#}c| Zq6V.3&(E>sbr,Nimϵ?4bPRhn``#A}.JAHk%HRsBV l#ƴNBkK061ѽ6U"'jqvwv yJq֩CbV% )bVαYyWR$i7. /'x0>w[y$8X}@˫)"(S+τӛ'#߬vsC䲘XAQ iD}r-2J&iZ* 5)ꬕۄI &1yCH '"k6)n'(i^Gze IDATD1٢DŽVNaL":)q16B$BR4 'A;0S"HialX)L )捖f(9Wi 9ND$*K 5U3tiG&˧ҿgv>r옑[77~*ᑺb|+_fv31ϱ4i8szVb?'ɻ2 N%dnĝV\Meڵ{$gS|s !i3 ǁcW̰5ɹd.pv3R y&8u#24[ >lfd"a8j![dEMo8?HAbẁfEcЖք 35iAdl&Ȕ[)Q9.2ѭ8 υ~a=6 xi@xqQ֕ɨbq?;`Li;o[G22fvs S`] DV&89&RzX S]dd4x op&Oq.r>U-vC *Lb 7lOfFiհYSMFCUpA$ǵpac]bV{0 ]7:JkrUDf6^EzA&+=y ڷ:Ʉx)5lN%y3Ls򬈳CP#7Yp`w[rhmӜY4bAx%i>a L'<.fۇkbD~%Ov89Xc]`esL,Ĥxl3Qe{>O+o{-k8} Qc)4YVĆ0 L/lJ} ~W\4=h( R\E),|$H:a/-^7 /}x?ȓF#^5)a! Koxj褚*J%Å*rU7tLɁ Fcr2PĨuRL|T(#Ma 04I[. g1˜Q=Nms*$҇]Qpax >>1 [dEOn 瘱R˪RkJͦ -t_6#YggGNc,6:);"x‚bWXmDLG)B S+6iD[% (fg[?Ш)N ۅv )G/劳COCkckcDZmQo:Hc; 0 sdiR,t)fns]ȰdZ^[Na:Vt>۵! :$__cgm⚞b|7u@SµM5V$ݺJV@ aUWf[4Gj2hp{J!1ˊ7pV#ANo%cc[ڌC{KƄLN[_)p.b抽?+9p+ʔ-ڞt_b/IM #O㡊&AHV.pfg3ʱZkW&*Ch6Y.c3ƢCNY+soHX9M Cց)E8n!Y&rf5)!#<XM<}s W.jB5ڢMpΓ'tkK \]Ci{qž=去_=Aq@xPOΟ]۔*r9j9x Kf+|T|ʣ+-Ev8{D_J85rL*OñG|ͳu w;׫_}^! $AJ « #6.uKK*((RJBHH8J}_Zk8^/+}֯<ϳ6~c~5+z#do߂՞nseUlCI1J+I ǚި\ sfm.X .N5brN!Z~IW ^?<4f;?E!Ѹy+^oTrc;I0DQR~}u BQUQ.g}0;Q`Ʉ}O}ڶNAp%yqHLPVʀSpj3|R sL z ^;naw`ݗXez"ṗX'h>9s;8^uPDčJjZ ((u{G&L &V2==qa+СKY.rVmk6(n!M~o_=G-\D脺Mm5Eu%W^:E+\wN (4Y)I!wJ}M}S9s:4wݙ&3-f8p㪧n!AVyd8rǡEh%k&(E4!Lwt w6G?y>r#&YOW\aկ@ 7ڂ}iXssc#b^J;J3)qy\w1b1=%4<W ƎǤ.nX{B(D*xt&4]<EB]:pьO'u g4r /);O3”6"đ _W[y/enʢlojDOEDHRqjIQ]V+fRxⵎqx<&U9P iDc)PpdnL +!1& @kSwx+kN pY+0@3LdNrđBE4h-P~lCmc11KYL0[XHpqcE )V z>lh4"Aɥ!DZ S4WFXCϙ\{Z:pizXv0͝hxh(e1f4\;l"#gAQ<}fVEh! *et.hJ(1mT(!3&0KX-EH1'.(,- Tܸϰ%sa3%_jFABxvBE |VMd eP%Xe$*|ŢD pwuEB`yTXM0q"?v??򗿂Ϻ9Ot"KGy~ÊW IS :[DqJG)[RU+Kq"e71,6jFWq&%k҆g{:>_ kw6Ba)҉˛lQ5&gC+tT M-ya'8lhfRǞYO]ex҂+bUW250l"I (-vVT6hmo 悆ܧF.EEç{c“g%I"&beTqTc_yR uhĞaVqИO~nIB4:SH["2uh 1třpeW %TjG۔Uh +#j1U)C$!Oj0ДU`8q]WL?A1˫9ßShΜ졀p#8uv 1Gp-NGȂ'&qO><@) `k4M9s`|_x't*w=Xp1G<=AiYA<ñcui%F2.`Pش9Eb-*;:QŎYMj$* ^.XA5Z:MCk5[@vnI7]/ں41q1% 6 JiکbǜW5aL;(MH"͓/HHqzZ Go\Qx<|$ {H"ee`#89$[͟Zۿd8Ⱥ\ c3MèbjOl &0kZVtHZ)V5HGelߓF4MxL>V)~5|>@*{pDfH؀ſlSQKD4#S\#mvqx)mta6Ѭr^q)[+{"~ YJ+'9~q2V<yeZssq~'c'CjH>5CqSG=kb5c͈DIq! yrF-LP"5[ln ~\4: YHbGSW5Sb*Qju6*p'L4DB* d[,~ ?;8}Ow_e7,vן 8t_yM mF!ivY ا#-, m0.g{1- *aN.{6%^#klK_[ ܲ7y=6.pxXjm6,.H\_ i%2i'R"5MX-joupbR嶹L"k) %{qAzS&)ڴYNYYEV(y]jmke1C4nW]m?kivPZ(J?cu6a KCY[F6$rBK_TG*&c^jH0ؕovtZAέ)F+VK2xYA3є!ԁnF#fWB(^& WaĊ2s^8"#V(6A1uC;I#L,:q}KX:3L*BY褁mKG?:!{ͫ?I^tÍ t:|?v 2qiy oFVECq\ƥ/3cy5x6$ Z8*k,$a$ ɋގ)(B`{Cqt,y'wJA3Rd.pՒ8EzE`kXyP\3aiP2(Rx`3*%Z>{bT0qlBCЭ#O7{RdF|Ex*/C=Lx RBgJjF(UAC$f~fK=8pObJ)(@OAŘOHg⨃&2e%v3 #zq^M{ةTQV IDAT dU`}"zXqh75Qu=yV?VϿN61,AE4D/tע3|M0*2zTj ef@ZJ#DK135s4ZU%EmPQ=t4Iq:Oj η5Wo7sE lziffD\ ōH@TY0lG "2C+8Md$_]Wg>{*g:zVO3(к>yMQXУGxϻݻPDđ˦$AkE )0$j0(52MU*`<)FG 5:V:OV aTU 4f&ϸiBsď.VVy{wr\{ͳtwӉ:M-W `myYALfОݶ[EBʉid`s>V`6ʣ8a8(\Ei>CIijpE[Xؽ*,L#V܄VRB[ڶ jjY$,K<3SM7yK}_C\1ќ\>{Kh^|mi $s[5R rϖ-MΜ0yf9n2V䥄>!I*g0.1SU`Kh[R\R9Gi(%{I:;h16B"._ùP u!Z20$zS)v)z&z^ɏ{W_ƐA (%;J^{]q5aS3 ^kYWQ\Ty*}ƱopxB}0{^lc a|>6e>&qU&ťwB+LŸ4"K^Vb| xLc+guOTۿ *"V%s ov_CW7j*fb1<\qaR#"F̉CScCv`ʓL3M}P\STɾWIFG9qIU)Sh-崳(ĉ˔1ٰJ54EBT]sqXR1m!Kf(>WPO#Zej)Z B`zq+õUPo"C+IB:/@Ŕ,رm wcZzy˾Us3RvTɳBkAI 'aZ(XEkn3wI3 CYWAq%,9*`n,HJ{+U 3)k\"^WO}(콐}m,??Ë_k. 51KU@G1;wM=o_`mm{yo0,M#FAS*0"E3RsqCF6Z h X-QTW4N[9g3ɜc!U57qmXƱxǑ@o<:gc&cT^iG#ٮeRIYZ$)I.⌥7tut!nƑr Y)Md1qўe/Ⴙדqj{N2d[* p7>*镕єAR#m˸-2U EbnP4cM^MP"|Ҿu᱃p7So~(@ L$DglywB#.*>(˼W~pTZ'>(0\9AYU/xFݛf24ۋ\9rL6W۟_=%(k9k9sQA|̅ZTAj(vopj)c}y!#e'#+DiE;R,4gFORMq+hF 2exNs91q$pΈ2RUQ*hR- @cʆ wNsY/2𼝆htQ)Uןu=TiX+yX`Zx:IPҨzD*'2nU;  L8(&Tpp1ʪ$(QrNZ2>߾UEm;v. 4qA1nk2U}萂nC#峬Ɯc/$m}`%뭳=};Ȅ }StRgj3e5"$E-].IaIuS¿"jKc%(Uˎ"ʘdw8JswT!0+2aO4XD^MjFKs15ðɼ(ԩd0tC9EڭVA73yZ%RZu{鶍V(zmqAD̦.N=ЪJ0.L*IBo7lC+"0 kW3K?.z4yjC%v/7q|P>n3ŻV'r-n ZHƍdh\4UI, AADH J Ho(tkեnpT.TGPLɬUAL35yˋ҈b6% 儊T="@P!CkؿkF$v_gD,!F#1wdex[)1VP/VC(V6I8x,u>HsF e}*&\yqpTc{mI%3ՆL`v&*$k803 /F-q5F{=׼yV>U8$ьI ZjZȀ/)* ⺧t#sV-BgF%P&Jە5Kݫ,N[b[U즇vR%E(cʲؕ]8|*2P8A"z|קhlfc:b+yք}Łq*FMLC:a}P1Z)]4b(g/q"\.S$&9N#?31Dx_/_|5^J-d?3W?ӑ^033֭RDuӸN- a-ׄ; ES Ϥ(U0g B:g&iAw#IR $(oo1Рb5Dτ Vw/hV HZ>tz(T,c\=T |m50q-inzIWDqD[QH.dDzCGVUDPV٦on]\\ײYkcqgAJzza-pQiqFqtFd^GseIiY^hUxÏ^̇?t%b0|=˩tԇD,di=R3 L$D\q٢ fk~5t^#I1)&4eA ] Z{qtijSGneGgGOg+T2+vm䐉!+; AĨN8pI`% t"X WY~k%jMĩ_t$Qp6vHqX<[_ߡRtIHi$4*A.Zm$ 4t Z5\7$iͨ3|MoWc@`OCJM$U]MFܛ6M(tI4m%RL5ՍĆ,CP4/%g}fCSx5)\vO)Wk{"*wr2&癯{ o'9u!-A=张mˤ@X2/ýuOk8W#")[uhA-6Z'U0H3aJFp! *d{ĩG/5N3$ȵYNӔYkh{*-hB[ƫஒ~hV4F$ EYL02 W- "PJG 2 C@lfpVY*',vنCOWVDڦnp FPY[k;\v)AԸV~~ZZmph\@<♊8LzׄǂaΔ⚧]O[kf⛸>׼~u~_u~_MYx_Of⛸g?޽{i4~ٳp |?Ҿ>{?|lٲa>{>}o_ݾgXXX8wޓɄ#G/uC=.9rue{G}?~~}Ͻ=j#G >>miiiwߍ/!+r9nnnc&54,-T^^Qggg3ٴiӐ03^d[t["!!aBgS-T^^~ m7 jkkO wyS#== Xz5>shd-/t0vanY6.s"2 ++ gφBSR^RTooF[UUT7{a?` 22uuu8|0444ܞIF9񁃃~\rĻQnVEDDm-uPsrqfOOO;(((_ /FKK f͚Ʊc744$̙3GT:˜t7zyy&ϒ&;C9R;v >>>8}4J% c( ''aenrPsr 2 ** PRRb4AAAPhiiD"ڮ%i۶m7oZtXd}n3HKKCee%|}}@(b #zt=a, 1,9ݤ;wbٲec裏ޒʙ .{쁻;|gf%YGIIIpuu? Y2c%s, g&nB]]Μ9%KYk Ehh~1Zw}/ndd(g.^V3g~ٳg`̘1B2 [lADD[$2ܲl ;wSO=5֢V%33vvv 6fBLL̘K򈀱Gs΅J %Y"c%s,g&L444dgg[QQ&gbZ-r9Ν;qGXlݺJc"c\%JnD1[;|h/ www@P@&ʰtRA.7^G~WV 鏬X9tRT*|hnnFHHكGyČ&K`,H$ć~&899kd!Rs,wXZZ`dIRLL/R.鏬X9+W...xXH(roP(p}2ukAL """""l"""""2 """""2 """""2 """""2 """""2 """""2 """""2 """""2 """""2 """""2 ""z-(11100̎).. jaK/Lݻw꿽7o%l3g憨(455FgggT*DGGC/֮]r̞=666Î;SRRV+ ""'flڴ ~)~Qq(,,Drr2rssEzwu h4TWW W^EXXo!&)) ݻQQQ6,^XhDdd$qqcǎذasyDFFGũSfСCBL@@O]v:?""k%6 hrCww7/싎?#;;Bcc#|||իWC=:;;憊 Cxg{QUU… www@vv6֭[N(J[Ũn 6n܈2TVV/YLѸP*ڶoߎX899!""b]| x5iӦN|XԄVpi\tI)++#kЩP  "",Y2 FnD`` ׳>S/a?RO`׮](((.3NNNXr%^}U=z'OĊ+^x :h4܌d466O>_$TVV",,DDD.#11hiiAqq{(baѢEzKB ˅,hZSx}WB̦MpBDGG#88ػw.PTTL bٲeظqVQ\\2"##999b~Zj8""+L c޼yHJJ?`!y~~~غuG7ZVVۇC!"2+LI$l۶ BQQG=aP(زeADdv "IeѢEˑ Db!,&$\DDDDDD&a1ADDDDD&a1ADDDDD&a1ADDDDD&a1ADDDDD&a1ADDDDD&a1ADDDDD&a1ADDDDD&a1ADDDDD&.n@AZIENDB`APLpy-2.0.3/docs/fitsfigure/quick_reference.rst0000644000077000000240000003203113432763221021404 0ustar tomstaff00000000000000Quick reference Guide --------------------- .. toctree:: :maxdepth: 1 .. note:: Rather than showing the generic call signature for the methods on this page, these are given in the form of example values. In addition, not all of the optional keywords are mentioned here. For more information on a specific command and all the options available, use the ``help()`` function, e.g. ``help(fig.show_grayscale)``. When multiple optional arguments are given, this does not mean that all of them have to be specified, but just shows all the options available. Introduction ^^^^^^^^^^^^ To import APLpy:: import aplpy To create a figure of a FITS file:: fig = aplpy.FITSFigure('myimage.fits') Here and in the remainder of this reference guide, we use the variable name ``fig`` for the figure object, but any name can be used. A grayscale or colorscale representation of the FITS image can be shown and hidden using the following methods:: fig.show_grayscale() fig.hide_grayscale() fig.show_colorscale() fig.hide_colorscale() To show a three-color image, use the following method, specifying the filename of the color image:: fig.show_rgb('m17.jpeg') The figure can be interactively explored by zooming and panning. To recenter on a specific region programmatically, use the following method, specifying either a radius:: fig.recenter(33.23, 55.33, radius=0.3) # degrees or a separate width and height:: fig.recenter(33.23, 55.33, width=0.3, height=0.2) # degrees To overlay contours, use:: fig.show_contour('co_data.fits') To save the current figure, use:: fig.save('myplot.eps') Other formats such as PDF, PNG, etc. can be used. Labels ^^^^^^ Labels can be added either in world coordinates:: fig.add_label(34.455, 54.112, 'My favorite star') or relative to the axes:: fig.add_label(0.1, 0.9, '(a)', relative=True) Shapes ^^^^^^ To overlay different shapes, the following methods are available:: fig.show_markers(x_world, y_world) fig.show_circles(x_world, y_world, radius) fig.show_ellipses(x_world, y_world, width, height) fig.show_rectangles(x_world, y_world, width, height) fig.show_arrows(x_world, y_world, dx, dy) where ``x_world``, ``y_world``, ``radius``, ``width``, ``height``, ``dx``, and ``dy`` should be 1D arrays specified in degrees. It is also possible to plot lines and polygons using:: fig.show_lines(line_list) fig.show_polygons(polygon_list) For these methods, ``line_list`` and ``polygon_list`` should be lists of 2xN Numpy arrays describing the coordinates of the vertices in degrees. DS9 Regions ^^^^^^^^^^^ DS9 region files can be overlaid with:: fig.show_regions('myregions.reg') Layers ^^^^^^ Markers, shapes, regions and text labels are stored in layers. These layers can be listed using:: fig.list_layers() Layers can be hidden and shown with the following methods:: fig.hide_layer('regions') fig.show_layer('regions') Any layer can be retrieved using:: layer = fig.get_layer('circles') Finally, layers can be removed using:: fig.remove_layer('rectangles') Coordinates ^^^^^^^^^^^ Two methods are provided to help transform coordinates between world and pixel coordinates. These accept either scalars or arrays in degrees:: x_pix, y_pix = fig.world2pixel(45.3332, 22.1932) x_world, y_world = fig.pixel2world(np.array([1., 2., 3]), np.array([1., 3., 5.])) Frame ^^^^^ To set the look of the frame around the figure, use:: fig.frame.set_linewidth(1) # points fig.frame.set_color('black') Colorbar ^^^^^^^^ A grid can be added and removed using the following commands:: fig.add_colorbar() fig.remove_colorbar() Once :meth:`~aplpy.FITSFigure.add_colorbar` has been called, the ``fig.colorbar`` object is created and the following methods are then available: * Show and hide the colorbar:: fig.colorbar.show() fig.colorbar.hide() * Set where to place the colorbar:: fig.colorbar.set_location('right') This can be one of ``left``, ``right``, ``bottom`` or ``top``. * Set the width of the colorbar:: fig.colorbar.set_width(0.1) # arbitrary units, default is 0.2 * Set the amount of padding between the colorbar and the parent axes:: fig.colorbar.set_pad(0.03) # arbitrary units, default is 0.05 * Set the font properties of the labels:: fig.colorbar.set_font(size='medium', weight='medium', \ stretch='normal', family='sans-serif', \ style='normal', variant='normal') * Add a colorbar label:: f.colorbar.set_axis_label_text('Surface Brightness (Jy/beam)') * Set some of the colorbar label properties:: f.colorbar.set_axis_label_font(size=12, weight='bold') * Set the padding between the colorbar and the label in points:: f.colorbar.set_axis_label_pad(10) * Change the rotation of the colorbar label, in degrees:: f.colorbar.set_axis_label_rotation(270) Coordinate Grid ^^^^^^^^^^^^^^^ A coordinate grid can be added and removed using the following commands:: fig.add_grid() fig.remove_grid() Once :meth:`~aplpy.FITSFigure.add_grid` has been called, the ``fig.grid`` object is created and the following methods are then available: * Show and hide the grid:: fig.grid.show() fig.grid.hide() * Set the x and y spacing for the grid:: fig.grid.set_xspacing(0.2) # degrees fig.grid.set_yspacing(0.2) # degrees * Set the color of the grid lines:: fig.grid.set_color('white') * Set the transparency level of the grid lines:: fig.grid.set_alpha(0.8) * Set the line style and width for the grid lines:: fig.grid.set_linestyle('solid') fig.grid.set_linewidth(1) # points Scalebar ^^^^^^^^ A scalebar can be added and removed using the following commands:: fig.add_scalebar() fig.remove_scalebar() Once :meth:`~aplpy.FITSFigure.add_scalebar` has been called, the ``fig.scalebar`` object is created and the following methods are then available: * Show and hide the scalebar:: fig.scalebar.show(0.2) # length in degrees fig.scalebar.hide() * Change the length of the scalebar:: fig.scalebar.set_length(0.02) # degrees * Specify the length of the scalebar in different units:: from astropy import units as u fig.scalebar.set_length(72 * u.arcsecond) * Change the label of the scalebar:: fig.scalebar.set_label('5 pc') * Change the corner that the beam is shown in:: fig.scalebar.set_corner('top right') This can be one of ``top right``, ``top left``, ``bottom right``, ``bottom left``, ``left``, ``right``, ``bottom`` or ``top``. * Set whether or not to show a frame around the beam:: fig.scalebar.set_frame(False) * Set the transparency level of the scalebar and label:: fig.scalebar.set_alpha(0.7) * Set the color of the scalebar and label:: fig.scalebar.set_color('white') * Set the font properties of the label:: fig.scalebar.set_font(size='medium', weight='medium', \ stretch='normal', family='sans-serif', \ style='normal', variant='normal') * Set the line style and width for the scalebar:: fig.scalebar.set_linestyle('solid') fig.scalebar.set_linewidth(3) # points * Set multiple properties at once:: fig.scalebar.set(linestyle='solid', color='red', ...) Beam ^^^^ A beam can be added and removed using the following commands:: fig.add_beam() fig.remove_beam() Once :meth:`~aplpy.FITSFigure.add_beam` has been called, the ``fig.beam`` object is created and the following methods are then available: * Show and hide the beam:: fig.beam.show() fig.beam.hide() * Change the major and minor axes, and the position angle:: fig.beam.set_major(0.03) # degrees fig.beam.set_minor(0.02) # degrees fig.beam.set_angle(45.) # degrees * Specify the major and minor axes, and the position angle, in explicit units:: from astropy import units as u fig.beam.set_major(108 * u.arcsecond) fig.beam.set_minor(349 * u.microradian) fig.beam.set_angle(45 * u.degree) * Change the corner that the beam is shown in:: fig.beam.set_corner('top left') This can be one of ``top right``, ``top left``, ``bottom right``, ``bottom left``, ``left``, ``right``, ``bottom`` or ``top``. * Set whether or not to show a frame around the beam:: fig.beam.set_frame(False) * Set the transparency level of the beam:: fig.beam.set_alpha(0.5) * Set the color of the whole beam, or the edge and face color individually:: fig.beam.set_color('white') fig.beam.set_edgecolor('white') fig.beam.set_facecolor('green') * Set the line style and width for the edge of the beam:: fig.beam.set_linestyle('dashed') fig.beam.set_linewidth(2) # points * Set the hatch style of the beam:: fig.beam.set_hatch('/') * Set multiple properties at once:: fig.beam.set(facecolor='red', linestyle='dashed', ...) Coordinate types ^^^^^^^^^^^^^^^^ APLpy supports three types of coordinates: longitudes (in the range 0 to 360 with wrap-around), latitudes (in the range -90 to 90), and scalars (any arbitrary value). APLpy tries to guess the correct type of coordinate for each axis, but it is possible to override this:: fig.set_xaxis_coord_type('scalar') fig.set_yaxis_coord_type('longitude') Valid options are ``longitude``, ``latitude``, and ``scalar``. Axis labels ^^^^^^^^^^^ The methods to control the x- and y- axis labels are the following * Show/hide both axis labels:: fig.axis_labels.show() fig.axis_labels.hide() * Show/hide the x-axis label:: fig.axis_labels.show_x() fig.axis_labels.hide_x() * Show/hide the y-axis label:: fig.axis_labels.show_y() fig.axis_labels.hide_y() * Set the text for the x- and y-axis labels:: fig.axis_labels.set_xtext('Right Ascension (J2000)') fig.axis_labels.set_ytext('Declination (J2000)') * Set the displacement of the x- and y-axis labels from the x- and y-axis respectively:: fig.axis_labels.set_xpad(...) fig.axis_labels.set_ypad(...) * Set where to place the x-axis label:: fig.axis_labels.set_xposition('bottom') * Set where to place the y-axis label:: fig.axis_labels.set_yposition('right') * Set the font properties of the labels:: fig.axis_labels.set_font(size='medium', weight='medium', \ stretch='normal', family='sans-serif', \ style='normal', variant='normal') Tick labels ^^^^^^^^^^^ The methods to control the numerical labels below each tick are the following * Show/hide all tick labels:: fig.tick_labels.show() fig.tick_labels.hide() * Show/hide the x-axis labels:: fig.tick_labels.show_x() fig.tick_labels.hide_x() * Show/hide the y-axis labels:: fig.tick_labels.show_y() fig.tick_labels.hide_y() * Set the format for the x-axis labels (e.g hh:mm, hh:mm:ss.s, etc.):: fig.tick_labels.set_xformat('hh:mm:ss.ss') * Set the format for the y-axis labels (e.g dd:mm, dd:mm:ss.s, etc.):: fig.tick_labels.set_yformat('dd:mm:ss.s') * Set where to place the x-axis tick labels:: fig.tick_labels.set_xposition('top') * Set where to place the y-axis tick labels:: fig.tick_labels.set_yposition('left') * Set the style of the labels ('colons' or 'plain'):: fig.tick_labels.set_style('colons') * Set the font properties of the labels:: fig.tick_labels.set_font(size='medium', weight='medium', \ stretch='normal', family='sans-serif', \ style='normal', variant='normal') Ticks ^^^^^ The methods to control properties relating to the tick marks are the following: * Show/hide all ticks:: fig.ticks.show() fig.ticks.hide() * Show/hide the x-axis ticks:: fig.ticks.show_x() fig.ticks.hide_x() * Show/hide the y-axis ticks:: fig.ticks.show_y() fig.ticks.hide_y() * Change the tick spacing for the x- and y-axis:: fig.ticks.set_xspacing(0.04) # degrees fig.ticks.set_yspacing(0.03) # degrees * Change the length of the ticks:: fig.ticks.set_length(10) # points * Change the color of the ticks:: fig.ticks.set_color('black') * Set the line width for the ticks:: fig.ticks.set_linewidth(2) # points * Set the number of minor ticks per major tick:: fig.ticks.set_minor_frequency(5) Set this to ``1`` to get rid of minor ticks Advanced ^^^^^^^^ To control whether to refresh the display after each command, use the following method:: fig.set_auto_refresh(False) To force a refresh, use:: fig.refresh() To use the system LaTeX instead of the matplotlib LaTeX, use:: fig.set_system_latex(True) The color for NaN values can be controlled using the following method:: fig.set_nan_color('black') The order of figure elements (eg lines, shapes, imagemap) can be controlled using the zorder parameter using for example:: fig.show_ellipses(x_world, y_world, width, height, zorder=1) Increasing integers from 0 will place elements towards the front. Setting zorder=0 places layer at the bottom. Finally, to change the look of the plot using pre-set themes, use:: fig.set_theme('publication') APLpy-2.0.3/docs/fitsfigure/quickstart.rst0000644000077000000240000001317013432763221020447 0ustar tomstaff00000000000000Beginner Tutorial ----------------- .. toctree:: :maxdepth: 1 The following tutorial will take you, step by step, through the main features of APLpy. You will need to download the following `file `_. First, unpack the example files and go to the ``tutorial`` directory:: tar -xvzf tutorial.tar.gz cd tutorial Now, start up ``ipython``:: ipython --pylab and import the ``aplpy`` module as follows:: import aplpy To start off, use the :class:`~aplpy.FITSFigure` class to create a canvas to where your data will be plotted:: gc = aplpy.FITSFigure('fits/2MASS_k.fits') and display the image using a grayscale stretch:: gc.show_grayscale() Check out the buttons at the top or bottom of the canvas (depending on the version of matplotlib). You will see seven buttons: .. image:: buttons.png The first five are of interest to us here. The button with the magnifying glass will allow you to select an area on the plot and zoom in. To zoom out you can click on the home button (first one on the left). When you're zoomed in you can pan around by clicking on the button with the arrows (fourth button from the left). Use the following command to show a colorscale image instead:: gc.show_colorscale() The colormap used for the colorscale image can be changed. Try the following:: gc.show_colorscale(cmap='gist_heat') to show the image showing a 'heat' map. You can find more information in the :meth:`~aplpy.FITSFigure.show_grayscale` and :meth:`~aplpy.FITSFigure.show_colorscale` documentation. For example, you can control the minimum and maximum pixel values to show and the stretch function to use. It is possible to use APLpy to show 3-color images. To do this, you need a FITS file with the image - this is used for the information relating to the coordinates - and a PNG file containing the 3-color image. Both files need to have exactly the same dimensions and the pixels from the PNG file have to match those from the FITS file. An example is provided in the tutorial files. Try the following:: gc.show_rgb('graphics/2MASS_arcsinh_color.png') It is very easy to modify the font properties of the various labels. For example, in this case, we can change the font size of the tick labels to be smaller than the default:: gc.tick_labels.set_font(size='small') APLpy can be used to overlay contours onto a grayscale/colorscale/3-color image. Try typing the following command:: gc.show_contour('fits/mips_24micron.fits', colors='white') There are a number of arguments that can be passed to :meth:`~aplpy.FITSFigure.show_contour` to control the appearance of the contours as well as the number of levels to show. For more information, see the see the :meth:`~aplpy.FITSFigure.show_contour` documentation. Display a coordinate grid using:: gc.add_grid() and hide it again using:: gc.remove_grid() Let's overplot positions from a source list. Here we will use loadtxt to read in the coordinates from a file, but in general you can pass any pair of lists or numpy arrays that are already defined:: import numpy ra, dec = numpy.loadtxt('data/yso_wcs_only.txt', unpack=True) gc.show_markers(ra, dec, edgecolor='green', facecolor='none', marker='o', s=10, alpha=0.5) For more information, see the :meth:`~aplpy.FITSFigure.show_markers` documentation. It's often the case that you might want to change the look of a contour or markers, but if you run :meth:`~aplpy.FITSFigure.show_contour` or :meth:`~aplpy.FITSFigure.show_markers` a second time, it will overplot rather than replacing. To solve this problem APLpy has 'layers' which can be manipulated in a basic way. Type:: gc.list_layers() which will print out something like this:: There are 2 layers in this figure: -> contour_set_1 -> marker_set_1 You can use :meth:`~aplpy.FITSFigure.remove_layer`, :meth:`~aplpy.FITSFigure.hide_layer`, and :meth:`~aplpy.FITSFigure.show_layer` to manipulate the layers, and you can also specify the ``layer=name`` argument to :meth:`~aplpy.FITSFigure.show_contour` or :meth:`~aplpy.FITSFigure.show_markers`. Using the latter forces APLpy to name the layer you are creating with the name provided, and can also be used to replace an existing layer. For example, let's change the color of the markers from green to red:: gc.show_markers(ra, dec, layer='marker_set_1', edgecolor='red', facecolor='none', marker='o', s=10, alpha=0.5) Note the presence of the ``layer='marker_set_1'`` which means that the current markers plot will be replaced. To view active layers, you can use the :meth:`~aplpy.FITSFigure.list_layers` documentation. To wrap up this tutorial, we will save the plot to a file. Type the following:: gc.save('myfirstplot.png') This will produce the following plot: .. image:: myfirstplot.png You can of course save it as a PS/EPS, PDF, or SVG file instead. The EPS output is suitable for publication. To summarize, the above plot was made using the following commands:: import aplpy import numpy gc = aplpy.FITSFigure('fits/2MASS_k.fits') gc.show_rgb('graphics/2MASS_arcsinh_color.png') gc.tick_labels.set_font(size='small') gc.show_contour('fits/mips_24micron.fits', colors='white') ra, dec = numpy.loadtxt('data/yso_wcs_only.txt', unpack=True) gc.show_markers(ra, dec, layer='marker_set_1', edgecolor='red', facecolor='none', marker='o', s=10, alpha=0.5) gc.save('myfirstplot.png') There are many more methods and options, from setting the tick spacing and format to controlling the label fonts. For more information, see the :doc:`quick_reference` or the :ref:`api`. APLpy-2.0.3/docs/fitsfigure/slicing.rst0000644000077000000240000000712013432763221017703 0ustar tomstaff00000000000000Slicing multi-dimensional data cubes ==================================== How to slice data cubes ----------------------- APLpy supports extracting a slice from n-dimensional FITS cubes, and re-ordering dimensions. The two key arguments to :class:`~aplpy.FITSFigure` to control this are ``dimensions`` and ``slices``. These arguments can also be passed to :meth:`~aplpy.FITSFigure.show_contour`. The ``dimensions`` argument is used to specify which dimensions should be used for the x- and y-axis respectively (zero based). The default values are ``[0, 1]`` which means that the x-axis should use the first dimension in the FITS cube, and the y-axis should use the second dimension. For a 2-dimensional FITS file, this means that one can use ``[1, 0]`` to flip the axes. For a FITS cube with R.A., Declination, and Velocity, ``[0, 2]`` would make a R.A.-Velocity plot. The ``slices`` argument gives the pixels slice to extract from the remaining dimensions, skipping the dimensions used, so ``slices`` should be a list with length n-2 where n is the number of dimensions in the FITS file. For example, if one has a FITS file with R.A., Declination, Velocity, and Time (in that order), then: * ``dimensions=[0, 1]`` means the plot will be an R.A-Declination plot, and ``slices=[33, 56]`` means that pixel slices 33 and 56 will be used in Velocity and Time respectively (in this case, ``dimensions`` does not need to be specified since it defaults to ``[0, 1]``) * ``dimensions=[0, 2]`` means the plot will be an R.A-Velocity plot, and ``slices=[22, 56]`` means that pixel slices 22 and 56 will be used in Declination and Time respectively. * ``dimensions=[3, 2]`` means the plot will be a Time-Velocity plot, and ``slices=[10, 22]`` means that pixel slices 10 and 22 will be used in R.A and Declination respectively. See :ref:`arbitrary` for information on formatting the labels when non-longitude/latitude coordinates are used. Aspect ratio ------------ When plotting images in sky coordinates, APLpy makes pixel square by default, but it is possible to change this. When calling :meth:`~aplpy.FITSFigure.show_grayscale` or :meth:`~aplpy.FITSFigure.show_colorscale`, simply add ``aspect='auto'`` which will override the ``aspect='equal'`` default. The ``aspect='auto'`` is demonstrated below. Example ------- The following examples demonstrates this functionality in use .. plot:: :context: reset :include-source: from astropy.utils.data import get_pkg_data_filename co_cube = get_pkg_data_filename('l1448/l1448_13co.fits') import aplpy f = aplpy.FITSFigure(co_cube, slices=[30], figsize=(8, 6)) f.show_colorscale() f.add_grid() f.tick_labels.set_font(size='x-small') f.axis_labels.set_font(size='small') .. plot:: :context: reset :include-source: from astropy.utils.data import get_pkg_data_filename co_cube = get_pkg_data_filename('l1448/l1448_13co.fits') import aplpy f = aplpy.FITSFigure(co_cube, slices=[30], dimensions=[1, 0], figsize=(8, 6)) f.show_colorscale() f.add_grid() f.tick_labels.set_font(size='x-small') f.axis_labels.set_font(size='small') .. plot:: :context: reset :include-source: from astropy.utils.data import get_pkg_data_filename co_cube = get_pkg_data_filename('l1448/l1448_13co.fits') import aplpy f = aplpy.FITSFigure(co_cube, dimensions=[2, 1], slices=[50], figsize=(8, 6)) f.show_colorscale(aspect='auto') f.add_grid() f.tick_labels.set_font(size='x-small') f.axis_labels.set_font(size='small') f.tick_labels.set_xformat('%.1f') APLpy-2.0.3/docs/index.rst0000644000077000000240000000714513432763221015222 0ustar tomstaff00000000000000******************* APLpy documentation ******************* `APLpy `_ (the Astronomical Plotting Library in Python - pronounced *apple pie*) is a Python package module aimed at producing publication-quality plots of astronomical imaging data, and has been around since 2009. Since APLpy 2.0, APLpy relies on Astropy's `WCSAxes `_ package to draw the coordinate axes and grids, which in turn uses `Matplotlib `_ to do the rendering. This is a big change compared to previous versions of APLpy, which handled the drawing of the coordinate axes and grids directly. For information about backward-compatibility, see the `Backward-compatibility notes`_. Note that APLpy 2.x is only compatible with Python 3.5 and later. If you use APLpy for a publication, please consider citing it as described in the `CITATION `__ file. Should you use APLpy? ===================== The `WCSAxes`_ package in Astropy can be used without APLpy to produce plots of astronomical images. It provides a programmatic interface that is conceptually very close to Matplotlib, and can be used to make plots that are more complex than what APLpy has historically been able to do. If you want to be able to control the appearance of your plots in detail, including for example adding overlay coordinate systems, or if you simply want a programmatic interface that is consistent with Matplotlib, then we recommend you use `WCSAxes`_ directly. If you have a FITS file and just want to make it into a plot in a couple of lines, then APLpy is the package for you. Installing APLpy ================ You can install APLpy with pip using:: pip install aplpy If you prefer to use conda, you can install APLpy with:: conda install -c astropy aplpy Using APLpy =========== APLpy includes a :class:`~aplpy.FITSFigure` class that provides a simple interface to make plots and provides easy methods for overlaying shapes, beams, adding colorbars, and overplotting regions. .. toctree:: :maxdepth: 1 fitsfigure/quickstart.rst fitsfigure/quick_reference.rst fitsfigure/arbitrary_coordinate_systems.rst fitsfigure/slicing.rst fitsfigure/howto_noninteractive.rst fitsfigure/howto_avm.rst fitsfigure/howto_subplot.rst rgb .. _backcompat: Backward-compatibility notes ============================ APLpy continues to include a :class:`~aplpy.FITSFigure` class that provides a simpler interface and deals with the reading of FITS files and constructing WCS objects. This class uses `WCSAxes`_ behind the scenes, but provides easy methods for overlaying shapes, beams, adding colorbars, and overplotting regions. The interface of this class is intended to be backward-compatible with existing scripts that used APLpy 1.0 and earlier. If you run into issues with old scripts, please report the issues in the `issue tracker `_. Note however that if you have made adjustments to figures in the past using private attributes (e.g. ``fig._ax1``), these will no longer work and this cannot be fixed in APLpy 2.x. In any case, if you have issues with APLpy 2.x and want to continue using APLpy 1.x, you can always restrict the version of APLpy when installing it using e.g.:: pip install "aplpy<2" or:: conda install "aplpy<2" If critical bugs are found in the 1.x releases and can easily be fixed, we may release new 1.x versions. .. _api: Reference/API ============= .. automodapi:: aplpy :no-main-docstr: :no-heading: :no-inheritance-diagram: :inherited-members: APLpy-2.0.3/docs/index.txt0000644000077000000240000000042413432763221015222 0ustar tomstaff00000000000000APLpy documentation =================== This is the documentation for APLpy. The APLpy homepage is located at http://aplpy.github.io .. toctree:: :maxdepth: 1 quickstart.rst quick_reference.rst arbitrary_coordinate_systems.rst slicing.rst howtos.rst api.rst APLpy-2.0.3/docs/make.bat0000644000077000000240000001064112536551502014762 0ustar tomstaff00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Astropy.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Astropy.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end APLpy-2.0.3/docs/rgb.rst0000644000077000000240000000667113432763221014670 0ustar tomstaff00000000000000Making RGB images ----------------- APLpy includes helper functions to generate RGB images from scratch, even for files with initially different projections/resolutions. Reprojecting three images to the same projection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you are starting from three images with different projections/resolutions, the first step is to reproject these to a common projection/resolution. The following code shows how this can be done using the :func:`~aplpy.make_rgb_cube` function:: aplpy.make_rgb_cube(['2mass_k.fits', '2mass_h.fits', '2mass_j.fits'], '2mass_cube.fits') This method makes use of the `reproject `_ package to reproject the images to a common projection. The above example produces a FITS cube named ``2mass_cube.fits`` which contains the three channels in the same projection. This can be used to then produce an RGB image (see next section) Producing an RGB image from images in a common projection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The :func:`~aplpy.make_rgb_image` function can be used to produce an RGB image from either three FITS files in the exact same projection, or a FITS cube containing the three channels (such as that output by :func:`~aplpy.make_rgb_cube`). The following example illustrates how to do this:: aplpy.make_rgb_image('2mass_cube.fits','2mass_rgb.png') In the above example, APLpy will automatically adjust the stretch of the different channels to try and produce a reasonable image, but it is of course possible to specify one or more of the lower/upper limits of the scale to use for each channel. For each lower/upper scale limit, this can be done in two ways. The first is to use the vmin_r/g/b or vmax_r/g/b argument which specifies the pixel value to use for the lower or upper end of the scale respectively. The alternative is to use the pmin_r/g/b or pmax_r/g/b arguments, which specify the percentile value to use instead of an absolute value. The two can of course be mixed, such as in the following example:: aplpy.make_rgb_image('2mass_cube.fits', '2mass_rgb.png', vmin_r=0., pmax_g=90.) Plotting the resulting RGB image ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If `PyAVM `_ is installed (which is recommended but not required), then if you produce a JPEG or PNG image, you can plot it directly using the :class:`~aplpy.FITSFigure` class with:: f = aplpy.FITSFigure('2mass_rgb.png') f.show_rgb() For more information, see :ref:`howto-avm`. On the other hand, if you are not able to use PyAVM, or need to use a format other than JPEG or PNG, then you need to instantiate the :class:`~aplpy.FITSFigure` class with a FITS file with exactly the same dimensions and WCS as the RGB image. The :func:`~aplpy.make_rgb_cube` function will in fact produce a file with the same name as the main output, but including a ``_2d`` suffix, and this can be used to instantiate :class:`~aplpy.FITSFigure`:: # Reproject the images to a common projection - this will also # produce 2mass_cube_2d.fits aplpy.make_rgb_cube(['2mass_k.fits', '2mass_h.fits', '2mass_j.fits'], '2mass_cube.fits') # Make an RGB image aplpy.make_rgb_image('2mass_cube.fits', '2mass_rgb.png') # Plot the RGB image using the 2d image to indicate the projection f = aplpy.FITSFigure('2mass_cube_2d.fits') f.show_rgb('2mass_rgb.png') APLpy-2.0.3/setup.cfg0000644000077000000240000000165613432765673014270 0ustar tomstaff00000000000000[build_sphinx] source-dir = docs build-dir = docs/_build all_files = 1 [build_docs] source-dir = docs build-dir = docs/_build all_files = 1 [upload_docs] upload-dir = docs/_build/html show-response = 1 [tool:pytest] minversion = 3.0 norecursedirs = build docs/_build [ah_bootstrap] auto_use = True [metadata] package_name = aplpy description = The Astronomical Plotting Library in Python author = Thomas Robitaille and Eli Bressert author_email = thomas.robitaille@gmail.com, elibre@users.sourceforge.net license = MIT url = http://aplpy.github.io edit_on_github = False github_project = aplpy/aplpy install_requires = numpy, astropy>=3.1, matplotlib>=2.0, reproject>=0.4, pyregion>=2.0, pillow>=4.0, pyavm>=0.9.4, scikit-image>=0.14, shapely>=1.6 # version should be PEP440 compatible (https://www.python.org/dev/peps/pep-0440/) version = 2.0.3 [options.extras_require] docs = sphinx-astropy test = pytest-astropy; codecov; pytest-mpl APLpy-2.0.3/setup.py0000755000077000000240000001121113432763221014133 0ustar tomstaff00000000000000#!/usr/bin/env python # Licensed under a 3-clause BSD style license - see LICENSE.rst import glob import os import sys import ah_bootstrap from setuptools import setup # A dirty hack to get around some early import/configurations ambiguities if sys.version_info[0] >= 3: import builtins else: import __builtin__ as builtins builtins._ASTROPY_SETUP_ = True from astropy_helpers.setup_helpers import (register_commands, get_debug_option, get_package_info) from astropy_helpers.git_helpers import get_git_devstr from astropy_helpers.version_helpers import generate_version_py # Get some values from the setup.cfg try: from ConfigParser import ConfigParser except ImportError: from configparser import ConfigParser conf = ConfigParser() conf.read(['setup.cfg']) metadata = dict(conf.items('metadata')) PACKAGENAME = metadata.get('package_name', 'packagename') DESCRIPTION = metadata.get('description', 'packagename') AUTHOR = metadata.get('author', 'Astropy Developers') AUTHOR_EMAIL = metadata.get('author_email', '') LICENSE = metadata.get('license', 'unknown') URL = metadata.get('url', 'http://astropy.org') # order of priority for long_description: # (1) set in setup.cfg, # (2) load LONG_DESCRIPTION.rst, # (3) load README.rst, # (4) package docstring readme_glob = 'README*' _cfg_long_description = metadata.get('long_description', '') if _cfg_long_description: LONG_DESCRIPTION = _cfg_long_description elif os.path.exists('LONG_DESCRIPTION.rst'): with open('LONG_DESCRIPTION.rst') as f: LONG_DESCRIPTION = f.read() elif len(glob.glob(readme_glob)) > 0: with open(glob.glob(readme_glob)[0]) as f: LONG_DESCRIPTION = f.read() else: # Get the long description from the package's docstring __import__(PACKAGENAME) package = sys.modules[PACKAGENAME] LONG_DESCRIPTION = package.__doc__ # Store the package name in a built-in variable so it's easy # to get from other parts of the setup infrastructure builtins._ASTROPY_PACKAGE_NAME_ = PACKAGENAME # VERSION should be PEP440 compatible (http://www.python.org/dev/peps/pep-0440) VERSION = metadata.get('version', '0.0.dev0') # Indicates if this version is a release version RELEASE = 'dev' not in VERSION if not RELEASE: VERSION += get_git_devstr(False) # Populate the dict of setup command overrides; this should be done before # invoking any other functionality from distutils since it can potentially # modify distutils' behavior. cmdclassd = register_commands(PACKAGENAME, VERSION, RELEASE) # Freeze build information in version.py generate_version_py(PACKAGENAME, VERSION, RELEASE, get_debug_option(PACKAGENAME)) # Treat everything in scripts except README* as a script to be installed scripts = [fname for fname in glob.glob(os.path.join('scripts', '*')) if not os.path.basename(fname).startswith('README')] # Get configuration information from all of the various subpackages. # See the docstring for setup_helpers.update_package_files for more # details. package_info = get_package_info() # Add the project-global data package_info['package_data'].setdefault(PACKAGENAME, []) package_info['package_data'][PACKAGENAME].append('data/*') # Define entry points for command-line scripts entry_points = {'console_scripts': []} if conf.has_section('entry_points'): entry_point_list = conf.items('entry_points') for entry_point in entry_point_list: entry_points['console_scripts'].append('{0} = {1}'.format( entry_point[0], entry_point[1])) # Include all .c files, recursively, including those generated by # Cython, since we can not do this in MANIFEST.in with a "dynamic" # directory name. c_files = [] for root, dirs, files in os.walk(PACKAGENAME): for filename in files: if filename.endswith('.c'): c_files.append( os.path.join( os.path.relpath(root, PACKAGENAME), filename)) package_info['package_data'][PACKAGENAME].extend(c_files) # Note that requires and provides should not be included in the call to # ``setup``, since these are now deprecated. See this link for more details: # https://groups.google.com/forum/#!topic/astropy-dev/urYO8ckB2uM setup(name='APLpy', version=VERSION, description=DESCRIPTION, scripts=scripts, install_requires=[s.strip() for s in metadata.get('install_requires', 'astropy').split(',')], author=AUTHOR, author_email=AUTHOR_EMAIL, license=LICENSE, url=URL, long_description=LONG_DESCRIPTION, cmdclass=cmdclassd, zip_safe=False, use_2to3=False, entry_points=entry_points, python_requires='>=3.5', **package_info )