pax_global_header00006660000000000000000000000064131547231610014515gustar00rootroot0000000000000052 comment=8b57d9508ba22d11f6b718762a2038fdab0cedfa glances-2.11.1/000077500000000000000000000000001315472316100132135ustar00rootroot00000000000000glances-2.11.1/.ci/000077500000000000000000000000001315472316100136645ustar00rootroot00000000000000glances-2.11.1/.ci/appveyor/000077500000000000000000000000001315472316100155315ustar00rootroot00000000000000glances-2.11.1/.ci/appveyor/README.rst000066400000000000000000000002001315472316100172100ustar00rootroot00000000000000This directory contains support files for appveyor, a continuous integration service which runs tests on Windows on every push. glances-2.11.1/.ci/appveyor/download_exes.py000066400000000000000000000100541315472316100207360ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009 Giampaolo Rodola'. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """ Script which downloads exe and wheel files hosted on AppVeyor: https://ci.appveyor.com/project/giampaolo/psutil Copied and readapted from the original recipe of Ibarra Corretge' : http://code.saghul.net/index.php/2015/09/09/ """ from __future__ import print_function import argparse import errno import multiprocessing import os import requests import shutil import sys from concurrent.futures import ThreadPoolExecutor BASE_URL = 'https://ci.appveyor.com/api' PY_VERSIONS = ['2.7', '3.3', '3.4', '3.5'] def term_supports_colors(file=sys.stdout): try: import curses assert file.isatty() curses.setupterm() assert curses.tigetnum("colors") > 0 except Exception: return False else: return True if term_supports_colors(): def hilite(s, ok=True, bold=False): """Return an highlighted version of 'string'.""" attr = [] if ok is None: # no color pass elif ok: # green attr.append('32') else: # red attr.append('31') if bold: attr.append('1') return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), s) else: def hilite(s, *a, **k): return s def safe_makedirs(path): try: os.makedirs(path) except OSError as err: if err.errno == errno.EEXIST: if not os.path.isdir(path): raise else: raise def safe_rmtree(path): def onerror(fun, path, excinfo): exc = excinfo[1] if exc.errno != errno.ENOENT: raise shutil.rmtree(path, onerror=onerror) def download_file(url): local_fname = url.split('/')[-1] local_fname = os.path.join('dist', local_fname) print(local_fname) safe_makedirs('dist') r = requests.get(url, stream=True) with open(local_fname, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) return local_fname def get_file_urls(options): session = requests.Session() data = session.get( BASE_URL + '/projects/' + options.user + '/' + options.project) data = data.json() urls = [] for job in (job['jobId'] for job in data['build']['jobs']): job_url = BASE_URL + '/buildjobs/' + job + '/artifacts' data = session.get(job_url) data = data.json() for item in data: file_url = job_url + '/' + item['fileName'] urls.append(file_url) if not urls: sys.exit("no artifacts found") for url in sorted(urls, key=lambda x: os.path.basename(x)): yield url def rename_27_wheels(): # See: https://github.com/giampaolo/psutil/issues/810 src = 'dist/psutil-4.3.0-cp27-cp27m-win32.whl' dst = 'dist/psutil-4.3.0-cp27-none-win32.whl' print("rename: %s\n %s" % (src, dst)) os.rename(src, dst) src = 'dist/psutil-4.3.0-cp27-cp27m-win_amd64.whl' dst = 'dist/psutil-4.3.0-cp27-none-win_amd64.whl' print("rename: %s\n %s" % (src, dst)) os.rename(src, dst) def main(options): files = [] safe_rmtree('dist') with ThreadPoolExecutor(max_workers=multiprocessing.cpu_count()) as e: for url in get_file_urls(options): fut = e.submit(download_file, url) files.append(fut.result()) # 2 exes (32 and 64 bit) and 2 wheels (32 and 64 bit) for each ver. expected = len(PY_VERSIONS) * 4 got = len(files) if expected != got: print(hilite("expected %s files, got %s" % (expected, got), ok=False), file=sys.stderr) rename_27_wheels() if __name__ == '__main__': parser = argparse.ArgumentParser( description='AppVeyor artifact downloader') parser.add_argument('--user', required=True) parser.add_argument('--project', required=True) args = parser.parse_args() main(args) glances-2.11.1/.ci/appveyor/install.ps1000066400000000000000000000053421315472316100176300ustar00rootroot00000000000000# Sample script to install Python and pip under Windows # Authors: Olivier Grisel and Kyle Kastner # License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ $BASE_URL = "https://www.python.org/ftp/python/" $GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" $GET_PIP_PATH = "C:\get-pip.py" function DownloadPython ($python_version, $platform_suffix) { $webclient = New-Object System.Net.WebClient $filename = "python-" + $python_version + $platform_suffix + ".msi" $url = $BASE_URL + $python_version + "/" + $filename $basedir = $pwd.Path + "\" $filepath = $basedir + $filename if (Test-Path $filename) { Write-Host "Reusing" $filepath return $filepath } # Download and retry up to 5 times in case of network transient errors. Write-Host "Downloading" $filename "from" $url $retry_attempts = 3 for($i=0; $i -lt $retry_attempts; $i++){ try { $webclient.DownloadFile($url, $filepath) break } Catch [Exception]{ Start-Sleep 1 } } Write-Host "File saved at" $filepath return $filepath } function InstallPython ($python_version, $architecture, $python_home) { Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home if (Test-Path $python_home) { Write-Host $python_home "already exists, skipping." return $false } if ($architecture -eq "32") { $platform_suffix = "" } else { $platform_suffix = ".amd64" } $filepath = DownloadPython $python_version $platform_suffix Write-Host "Installing" $filepath "to" $python_home $args = "/qn /i $filepath TARGETDIR=$python_home" Write-Host "msiexec.exe" $args Start-Process -FilePath "msiexec.exe" -ArgumentList $args -Wait -Passthru Write-Host "Python $python_version ($architecture) installation complete" return $true } function InstallPip ($python_home) { $pip_path = $python_home + "/Scripts/pip.exe" $python_path = $python_home + "/python.exe" if (-not(Test-Path $pip_path)) { Write-Host "Installing pip..." $webclient = New-Object System.Net.WebClient $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH) Write-Host "Executing:" $python_path $GET_PIP_PATH Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru } else { Write-Host "pip already installed." } } function InstallPackage ($python_home, $pkg) { $pip_path = $python_home + "/Scripts/pip.exe" & $pip_path install $pkg } function main () { InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON InstallPip $env:PYTHON InstallPackage $env:PYTHON wheel } main glances-2.11.1/.ci/appveyor/run_with_compiler.cmd000066400000000000000000000064461315472316100217610ustar00rootroot00000000000000:: To build extensions for 64 bit Python 3, we need to configure environment :: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) :: :: To build extensions for 64 bit Python 2, we need to configure environment :: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) :: :: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific :: environment configurations. :: :: Note: this script needs to be run with the /E:ON and /V:ON flags for the :: cmd interpreter, at least for (SDK v7.0) :: :: More details at: :: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows :: http://stackoverflow.com/a/13751649/163740 :: :: Author: Olivier Grisel :: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ :: :: Notes about batch files for Python people: :: :: Quotes in values are literally part of the values: :: SET FOO="bar" :: FOO is now five characters long: " b a r " :: If you don't want quotes, don't include them on the right-hand side. :: :: The CALL lines at the end of this file look redundant, but if you move them :: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y :: case, I don't know why. @ECHO OFF SET COMMAND_TO_RUN=%* SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf :: Extract the major and minor versions, and allow for the minor version to be :: more than 9. This requires the version number to have two dots in it. SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1% IF "%PYTHON_VERSION:~3,1%" == "." ( SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1% ) ELSE ( SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,2% ) :: Based on the Python version, determine what SDK version to use, and whether :: to set the SDK for 64-bit. IF %MAJOR_PYTHON_VERSION% == 2 ( SET WINDOWS_SDK_VERSION="v7.0" SET SET_SDK_64=Y ) ELSE ( IF %MAJOR_PYTHON_VERSION% == 3 ( SET WINDOWS_SDK_VERSION="v7.1" IF %MINOR_PYTHON_VERSION% LEQ 4 ( SET SET_SDK_64=Y ) ELSE ( SET SET_SDK_64=N IF EXIST "%WIN_WDK%" ( :: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ REN "%WIN_WDK%" 0wdf ) ) ) ELSE ( ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" EXIT 1 ) ) IF %PYTHON_ARCH% == 64 ( IF %SET_SDK_64% == Y ( ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture SET DISTUTILS_USE_SDK=1 SET MSSdk=1 "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release ECHO Executing: %COMMAND_TO_RUN% call %COMMAND_TO_RUN% || EXIT 1 ) ELSE ( ECHO Using default MSVC build environment for 64 bit architecture ECHO Executing: %COMMAND_TO_RUN% call %COMMAND_TO_RUN% || EXIT 1 ) ) ELSE ( ECHO Using default MSVC build environment for 32 bit architecture ECHO Executing: %COMMAND_TO_RUN% call %COMMAND_TO_RUN% || EXIT 1 ) glances-2.11.1/.coveragerc000066400000000000000000000010531315472316100153330ustar00rootroot00000000000000[report] include = *glances* omit = setup.py glances/outputs/* glances/exports/* glances/compat.py glances/autodiscover.py glances/client_browser.py glances/config.py glances/history.py glances/monitored_list.py glances/outdated.py glances/password*.py glances/snmp.py glances/static_list.py exclude_lines = pragma: no cover if PY3: if __name__ == .__main__.: if sys.platform.startswith except ImportError: raise NotImplementedError if WINDOWS if MACOS if BSD glances-2.11.1/.gitattributes000066400000000000000000000000701315472316100161030ustar00rootroot00000000000000glances/outputs/static/public/* -diff linguist-vendored glances-2.11.1/.github/000077500000000000000000000000001315472316100145535ustar00rootroot00000000000000glances-2.11.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000011011315472316100172510ustar00rootroot00000000000000Before filling this issue, please read the manual (https://glances.readthedocs.io/en/latest/) and search if the bug do not already exists in the database (https://github.com/nicolargo/glances/issues). #### Description For a bug: Describe the bug and list the steps you used when the issue occurred. For an enhancement or new feature: Describe your needs. #### Versions * Glances (glances -V): * PSutil (glances -V): * Operating System (lsb_release -a): #### Logs You can also pastebin the Glances logs file (https://glances.readthedocs.io/en/latest/config.html#logging) glances-2.11.1/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000003001315472316100203450ustar00rootroot00000000000000#### Description Please describe the goal of this pull request. #### Resume * Bug fix: yes/no * New feature: yes/no * Fixed tickets: comma-separated list of tickets fixed by the PR, if any glances-2.11.1/.gitignore000066400000000000000000000006731315472316100152110ustar00rootroot00000000000000*~ *.py[co] # Packages *.egg *.egg-info dist build # Eclipse *.pydevproject .project .metadata bin/** tmp/** tmp/**/* *.tmp *.bak *.swp *~.nib local.properties .classpath .settings/ .loadpath # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # PDT-specific .buildpath # ctags .tags* # Sphinx _build # Tox .tox/ # web ui node_modules/ bower_components/ glances-2.11.1/.travis.yml000066400000000000000000000011541315472316100153250ustar00rootroot00000000000000language: python python: - '2.7' - '3.3' - '3.4' - '3.5' - '3.6' - pypy install: - pip install -U pip setuptools - pip install -r requirements.txt - pip install coveralls script: - python setup.py install - coverage run --source=glances unitest.py after_success: - coveralls deploy: provider: pypi user: nicolargo password: secure: Fms23jiiKKq6qJMsZYrmBz5mC753VGrjCxzVrsioENfH3KaFf6kUc9fTYntaLvjLPTNBkU3R2IORfVOikJKmNWqWVZOdJ/nq8zPl6o9MgdNcX7qWTvY8Fi9MW7tIZHrehhm0LvWFVq8ZSc8iYzw3/741lvBh8vpJZSQs3sq/1QI= on: tags: true branch: master distributions: sdist bdist_wheel repo: nicolargo/glances glances-2.11.1/AUTHORS000066400000000000000000000026011315472316100142620ustar00rootroot00000000000000========== Developers ========== Nicolas Hennion (aka) Nicolargo http://blog.nicolargo.com https://twitter.com/nicolargo https://github.com/nicolargo nicolashennion@gmail.com PGP Fingerprint: 835F C447 3BCD 60E9 9200 2778 ABA4 D1AB 9731 6A3C PGP Public key: gpg --keyserver pgp.mit.edu --recv-keys 0xaba4d1ab97316a3c Alessio Sergi (aka) Al3hex https://twitter.com/al3hex https://github.com/asergi Brandon Philips (aka) Philips http://ifup.org/ https://github.com/philips Jon Renner (aka) Jrenner https://github.com/jrenner Maxime Desbrus (aka) Desbma https://github.com/desbma Nicolas Hart (aka) NclsHart (for the Web user interface) https://github.com/nclsHart Sylvain Mouquet (aka) SylvainMouquet (for the Web user interface) http://github.com/sylvainmouquet Floran Brutel (aka) notFloran (for the Web user interface) https://github.com/notFloran ========= Packagers ========= Daniel Echeverry and Sebastien Badia for the Debian package https://tracker.debian.org/pkg/glances Philip Lacroix and Nicolas Kovacs for the Slackware (SlackBuild) package gasol.wu@gmail.com for the FreeBSD port Frederic Aoustin (https://github.com/fraoustin) and Nicolas Bourges (installer) for the Windows port Aljaž Srebrnič for the MacPorts package http://www.macports.org/ports.php?by=name&substr=glances John Kirkham for the conda package (at conda-forge) https://github.com/conda-forge/glances-feedstock glances-2.11.1/CONTRIBUTING.md000066400000000000000000000127331315472316100154520ustar00rootroot00000000000000# Contributing to Glances Looking to contribute something to Glances ? **Here's how you can help.** Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features. ## Using the issue tracker The [issue tracker](https://github.com/nicolargo/glances/issues) is the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) and [submitting pull requests](#pull-requests), but please respect the following restrictions: * Please **do not** use the issue tracker for personal support requests. A official Q&A exist. [Use it](https://groups.google.com/forum/?hl=en#!forum/glances-users)! * Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others. ## Bug reports A bug is a _demonstrable problem_ that is caused by the code in the repository. Good bug reports are extremely helpful, so thanks! Guidelines for bug reports: 0. **Use the GitHub issue search** — check if the issue has already been reported. 1. **Check if the issue has been fixed** — try to reproduce it using the latest `master` or `develop` branch in the repository. 2. **Isolate the problem** — ideally create a simple test bed. 3. **Give us your test environment** — Operating system name and version Glances version... Example: > Short and descriptive example bug report title > > Glances and PsUtil version used (glances -V) > > Operating system description (name and version). > > A summary of the issue and the OS environment in which it occurs. If > suitable, include the steps required to reproduce the bug. > > 1. This is the first step > 2. This is the second step > 3. Further steps, etc. > > Screenshot (if usefull) > > Any other information you want to share that is relevant to the issue being > reported. This might include the lines of code that you have identified as > causing the bug, and potential solutions (and your opinions on their > merits). ## Feature requests Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible. ## Pull requests Good pull requests—patches, improvements, new features—are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. **Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. First of all, all pull request should be done on the `develop` branch. Glances uses PEP8 compatible code, so use a PEP validator before submitting your pull request. Also uses the unitaries tests scripts (unitest-all.py). Similarly, when contributing to Glances's documentation, you should edit the documentation source files in [the `/doc/` and `/man/` directories of the `develop` branch](https://github.com/nicolargo/glances/tree/develop/docs) and generate the documentation outputs files by reading the [README](https://github.com/nicolargo/glances/tree/develop/docs/README.txt) file. Adhering to the following process is the best way to get your work included in the project: 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: ```bash # Clone your fork of the repo into the current directory git clone https://github.com//glances.git # Navigate to the newly cloned directory cd glances # Assign the original repo to a remote called "upstream" git remote add upstream https://github.com/nicolargo/glances.git ``` 2. Get the latest changes from upstream: ```bash git checkout develop git pull upstream develop ``` 3. Create a new topic branch (off the main project development branch) to contain your feature, change, or fix (best way is to call it issue#xxx): ```bash git checkout -b ``` 4. It's coding time ! Please respect the following coding convention: [Elements of Python Style](https://github.com/amontalenti/elements-of-python-style) Commit your changes in logical chunks. Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your code is unlikely be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. 5. Locally merge (or rebase) the upstream development branch into your topic branch: ```bash git pull [--rebase] upstream develop ``` 6. Push your topic branch up to your fork: ```bash git push origin ``` 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `develop` branch. **IMPORTANT**: By submitting a patch, you agree to allow the project owners to license your work under the terms of the [LGPLv3](COPYING) (if it includes code changes). glances-2.11.1/COPYING000066400000000000000000000167441315472316100142620ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. glances-2.11.1/MANIFEST.in000066400000000000000000000003251315472316100147510ustar00rootroot00000000000000include AUTHORS include CONTRIBUTING.md include COPYING include NEWS include README.rst include conf/glances.conf recursive-include docs * recursive-include glances *.py recursive-include glances/outputs/static * glances-2.11.1/NEWS000066400000000000000000001042761315472316100137240ustar00rootroot00000000000000============================================================================== Glances Version 2 ============================================================================== Version 2.11.1 ============== * [WebUI] Sensors not showing on Web (issue #1142) * Client and Quiet mode don't work together (issue #1139) Version 2.11 ============ Enhancements and new features: * New export plugin: standard and configurable Restfull exporter (issue #1129) * Add a JSON export module (issue #1130) * [WIP] Refactoring of the WebUI Bugs corrected: * Installing GPU plugin crashes entire Glances (issue #1102) * Potential memory leak in Windows WebUI (issue #1056) * glances_network `OSError: [Errno 19] No such device` (issue #1106) * GPU plugin. : ... not JSON serializable"> (issue #1112) * PermissionError on macOS (issue #1120) * Cant move up or down in glances --browser (issue #1113) * Unable to give aliases to or hide network interfaces and disks (issue #1126) * `UnicodeDecodeError` on mountpoints with non-breaking spaces (issue #1128) Installation: * Create a Snap of Glances (issue #1101) Version 2.10 ============ Enhancements and new features: * New plugin to scan remote Web sites (URL) (issue #981) * Add trends in the Curses interface (issue #1077) * Add new repeat function to the action (issue #952) * Use -> and <- arrows keys to switch between processing sort (issue #1075) * Refactor __init__ and main scripts (issue #1050) * [WebUI] Improve WebUI for Windows 10 (issue #1052) Bugs corrected: * StatsD export prefix option is ignored (issue #1074) * Some FS and LAN metrics fail to export correctly to StatsD (issue #1068) * Problem with non breaking space in file system name (issue #1065) * TypeError: string indices must be integers (Network plugin) (issue #1054) * No Offline status for timeouted ports? (issue #1084) * When exporting, uptime values loop after 1 day (issue #1092) Installation: * Create a package.sh script to generate .DEB, .RPM and others... (issue #722) ==> https://github.com/nicolargo/glancesautopkg * OSX: can't python setup.py install due to python 3.5 constraint (issue #1064) Version 2.9.1 ============= Bugs corrected: * Glances PerCPU issues with Curses UI on Android (issue #1071) * Remove extra } in format string (issue #1073) Version 2.9.0 ============= Enhancements and new features: * Add a Prometheus export module (issue #930) * Add a Kafka export module (issue #858) * Port in the -c URI (-c hostname:port) (issue #996) Bugs corrected: * On Windows --export-statsd terminates immediately and does not export (issue #1067) * Glances v2.8.7 issues with Curses UI on Android (issue #1053) * Fails to start, OSError in sensors_temperatures (issue #1057) * Crashs after long time running the glances --browser (issue #1059) * Sensor values don't refresh since psutil backend (issue #1061) * glances-version.db Permission denied (issue #1066) Version 2.8.8 ============= Bugs corrected: * Drop requests to check for outdated Glances version * Glances cannot load "Powersupply" (issue #1051) Version 2.8.7 ============= Bugs corrected: * Windows OS - Global name standalone not defined again (issue #1030) Version 2.8.6 ============= Bugs corrected: * Windows OS - Global name standalone not defined (issue #1030) Version 2.8.5 ============= Bugs corrected: * Cloud plugin error: Name 'requests' is not defined (issue #1047) Version 2.8.4 ============= Bugs corrected: * Correct issue on Travis CI test Version 2.8.3 ============= Enhancements and new features: * Use new sensors-related APIs of Psutil 5.1.0 (issue #1018) * Add a "Cloud" plugin to grab stats inside the AWS EC2 API (issue #1029) Bugs corrected: * Unable to launch Glances on Windows (issue #1021) * Glances --export-influxdb starts Webserver (issue #1038) * Cut mount point name if it is too long (issue #1045) * TypeError: string indices must be integers in per cpu (issue #1027) * Glances crash on RPi 1 running ArchLinuxARM (issue #1046) Version 2.8.2 ============= Bugs corrected: * InfluxDB export in 2.8.1 is broken (issue #1026) Version 2.8.1 ============= Enhancements and new features: * Enable docker plugin on Windows (issue #1009) - Thanks to @fraoustin Bugs corrected: * Glances export issue with CPU and SENSORS (issue #1024) * Can't export data to a CSV file in Client/Server mode (issue #1023) * Autodiscover error while binding on IPv6 addresses (issue #1002) * GPU plugin is display when hitting '4' or '5' shortkeys (issue #1012) * Interrupts and usb_fiq (issue #1007) * Docker image does not work in web server mode! (issue #1017) * IRQ plugin is not display anymore (issue #1013) * Autodiscover error while binding on IPv6 addresses (issue #1002) Version 2.8 =========== Changes: * The curses interface on Windows is no more. The web-based interface is now the default. (issue #946) * The name of the log file now contains the name of the current user logged in, i.e., 'glances-USERNAME.log'. * IRQ plugin off by default. '--disable-irq' option replaced by '--enable-irq'. Enhancements and new features: * GPU monitoring (limited to NVidia) (issue #170) * WebUI CPU consumption optimization (issue #836) * Not compatible with the new Docker API 2.0 (Docker 1.13) (issue #1000) * Add ZeroMQ exporter (issue #939) * Add CouchDB exporter (issue #928) * Add hotspot Wifi informations (issue #937) * Add default interface speed and automatic rate thresolds (issue #718) * Highlight max stats in the processes list (issue #878) * Docker alerts and actions (issue #875) * Glances API returns the processes PPID (issue #926) * Configure server cached time from the command line --cached-time (issue #901) * Make the log logger configurable (issue #900) * System uptime in export (issue #890) * Refactor the --disable-* options (issue #948) * PID column too small if kernel.pid_max is > 99999 (issue #959) Bugs corrected: * Glances RAID plugin Traceback (issue #927) * Default AMP crashes when 'command' given (issue #933) * Default AMP ignores `enable` setting (issue #932) * /proc/interrupts not found in an OpenVZ container (issue #947) Version 2.7.1 ============= Bugs corrected: * AMP plugin crashs on start with Python 3 (issue #917) * Ports plugin crashs on start with Python 3 (issue #918) Version 2.7 =========== Backward-incompatible changes: * Drop support for Python 2.6 (issue #300) Deprecated: * Monitoring process list module is replaced by AMP (see issue #780) * Use --export-graph instead of --enable-history (issue #696) * Use --path-graph instead of --path-history (issue #696) Enhancements and new features: * Add Application Monitoring Process plugin (issue #780) * Add a new "Ports scanner" plugin (issue #734) * Add a new IRQ monitoring plugin (issue #911) * Improve IP plugin to display public IP address (issue #646) * CPU additionnal stats monitoring: Context switch, Interrupts... (issue #810) * Filter processes by others stats (username) (issue #748) * [Folders] Differentiate permission issue and non-existence of a directory (issue #828) * [Web UI] Add cpu name in quicklook plugin (issue #825) * Allow theme to be set in configuration file (issue #862) * Display a warning message when Glances is outdated (issue #865) * Refactor stats history and export to graph. History available through API (issue #696) * Add Cassandra/Scylla export plugin (issue #857) * Huge pull request by Nicolas Hart to optimize the WebUI (issue #906) * Improve documentation: http://glances.readthedocs.io (issue #872) Bugs corrected: * Crash on launch when viewing temperature of laptop HDD in sleep mode (issue #824) * [Web UI] Fix folders plugin never displayed (issue #829) * Correct issue IP plugin: VPN with no internet access (issue #842) * Idle process is back on FreeBSD and Windows (issue #844) * On Windows, Glances try to display unexisting Load stats (issue #871) * Check CPU info (issue #881) * Unicode error on processlist on Windows server 2008 (french) (issue #886) * PermissionError/OSError when starting glances (issue #885) * Zeroconf problem with zeroconf_type = "_%s._tcp." % __appname__ (issue #888) * Zeroconf problem with zeroconf service name (issue #889) * [WebUI] Glances will not get past loading screen - Windows OS (issue #815) * Improper bytes/unicode in glances_hddtemp.py (issue #887) * Top 3 processes are back in the alert summary Code quality follow up: from 5.93 to 6.24 (source: https://scrutinizer-ci.com/g/nicolargo/glances) Version 2.6.2 ============= Bugs corrected: * Crash with Docker 1.11 (issue #848) Version 2.6.1 ============= Enhancements and new features: * Add a connector to Riemann (issue #822 by Greogo Nagy) Bugs corrected: * Browsing for servers which are in the [serverlist] is broken (issue #819) * [WebUI] Glances will not get past loading screen (issue #815) opened 9 days ago * Python error after upgrading from 2.5.1 to 2.6 bug (issue #813) Version 2.6 =========== Deprecations: * Add deprecation warning for Python 2.6. Python 2.6 support will be dropped in future releases. Please switch to at least Python 2.7 or 3.3+ as soon as possible. See http://www.snarky.ca/stop-using-python-2-6 for more information. Enhancements and new features: * Add a connector to ElasticSearch (welcome to Kibana dashboard) (issue #311) * New folders' monitoring plugins (issue #721) * Use wildcard (regexp) to the hide configuration option for network, diskio and fs sections (issue #799 ) * Command line arguments are now take into account in the WebUI (#789 by @notFloran) * Change username for server and web server authentication (issue #693) * Add an option to disable top menu (issue #766) * Add IOps in the DiskIO plugin (issue #763) * Add hide configuration key for FS Plugin (issue #736) * Add process summary min/max stats (issue #703) * Add timestamp to the CSV export module (issue #708) * Add a shortcut 'E' to delete process filter (issue #699) * By default, hide disk I/O ram1-** (issue #714) * When Glances is starting the notifications should be delayed (issue #732) * Add option (--disable-bg) to disable ANSI background colours (issue #738 by okdana) * [WebUI] add "pointer" cursor for sortable columns (issue #704 by @notFloran) * [WebUI] Make web page title configurable (issue #724) * Do not show interface in down state (issue #765) * InfluxDB > 0.9.3 needs float and not int for numerical value (issue#749 and issue#750 by nicolargo) Bugs corrected: * Can't read sensors on a Thinkpad (issue #711) * InfluxDB/OpenTSDB: tag parsing broken (issue #713) * Grafana Dashboard outdated for InfluxDB 0.9.x (issue #648) * '--tree' breaks process filter on Debian 8 (issue #768) * Fix highlighting of process when it contains whitespaces (issue #546 by Alessio Sergi) * Fix RAID support in Python 3 (issue #793 by Alessio Sergi) * Use dict view objects to avoid issue (issue #758 by Alessio Sergi) * System exit if Cpu not supported by the Cpuinfo lib (issue #754 by nicolargo) * KeyError: 'cpucore' when exporting data to InfluxDB (issue #729) by nicolargo) Others: * A new Glances docker container to monitor your Docker infrastructure is available here (issue #728): https://hub.docker.com/r/nicolargo/glances/ * Documentation is now generated automatically thanks to Sphinx and the Alessio Sergi patch (https://glances.readthedocs.io/en/latest/) Contributors summary: * Nicolas Hennion: 112 commits * Alessio Sergi: 55 commits * Floran Brutel: 19 commits * Nicolas Hart: 8 commits * @desbma: 4 commits * @dana: 2 commits * Damien Martin, Raju Kadam, @georgewhewell: 1 commit Version 2.5.1 ============= Bugs corrected: * Unable to unlock password protected servers in browser mode bug (issue #694) * Correct issue when Glances is started in console on Windows OS * [WebUI] when alert is ongoing hide level enhancement (issue #692) Version 2.5 =========== Enhancements and new features: * Allow export of Docker and sensors plugins stats to InfluxDB, StatsD... (issue #600) * Docker plugin shows IO and network bitrate (issue #520) * Server password configuration for the browser mode (issue #500) * Add support for OpenTSDB export (issue #638) * Add additional stats (iowait, steal) to the perCPU plugin (issue #672) * Support Fahrenheit unit in the sensor plugin using the --fahrenheit command line option (issue #620) * When a process filter is set, display sum of CPU, MEM... (issue #681) * Improve the QuickLookplugin by adding hardware CPU info (issue #673) * WebUI display a message if server is not available (issue #564) * Display an error if export is not used in the standalone/client mode (issue #614) * New --disable-quicklook, --disable-cpu, --disable-mem, --disable-swap, --disable-load tags (issue #631) * Complete refactoring of the WebUI thanks to the (awesome) Floran pull (issue #656) * Network cumulative /combination feature available in the WebUI (issue #552) * IRIX mode off implementation (issue#628) * Short process name displays arguments (issue #609) * Server password configuration for the browser mode (issue #500) * Display an error if export is not used in the standalone/client mode (issue #614) Bugs corrected: * The WebUI displays bad sensors stats (issue #632) * Filter processes crashs with a bad regular expression pattern (issue #665) * Error with IP plugin (issue #651) * Crach with Docker plugin (issue #649) * Docker plugin crashs with webserver mode (issue #654) * Infrequently crashing due to assert (issue #623) * Value for free disk space is counterintuative on ext file systems (issue #644) * Try/catch for unexpected psutil.NoSuchProcess: process no longer exists (issue #432) * Fatal error using Python 3.4 and Docker plugin bug (issue #602) * Add missing new line before g man option (issue #595) * Remove unnecessary type="text/css" for link (HTML5) (issue #595) * Correct server mode issue when no network interface is available (issue #528) * Avoid crach on olds kernels (issue #554) * Avoid crashing if LC_ALL is not defined by user (issue #517) * Add a disable HDD temperature option on the command line (issue #515) Version 2.4.2 ============= Bugs corrected: * Process no longer exists (again) (issue #613) * Crash when "top extended stats" is enabled on OS X (issue #612) * Graphical percentage bar displays "?" (issue #608) * Quick look doesn't work (issue #605) * [Web UI] Display empty Battery sensors enhancement (issue #601) * [Web UI] Per CPU plugin has to be improved (issue #566) Version 2.4.1 ============= Bugs corrected: * Fatal error using Python 3.4 and Docker plugin bug (issue #602) Version 2.4 =========== Changes: * Glances doesn't provide a system-wide configuration file by default anymore. Just copy it in any of the supported locations. See glances-doc.html for more information. (issue #541) * The default key bindings have been changed to: - 'u': sort processes by USER - 'U': show cumulative network I/O * No more translations Enhancements and new features: * The Web user interface is now based on AngularJS (issue #473, #508, #468) * Implement a 'quick look' plugin (issue #505) * Add sort processes by USER (issue #531) * Add a new IP information plugin (issue #509) * Add RabbitMQ export module (issue #540 Thk to @Katyucha) * Add a quiet mode (-q), can be useful using with export module * Grab FAN speed in the Glances sensors plugin (issue #501) * Allow logical mounts points in the FS plugin (issue #448) * Add a --disable-hddtemp to disable HDD temperature module at startup (issue #515) * Increase alert minimal delay to 6 seconds (issue #522) * If the Curses application raises an exception, restore the terminal correctly (issue #537) Bugs corrected: * Monitor list, all processes are take into account (issue #507) * Duplicated --enable-history in the doc (issue #511) * Sensors title is displayed if no sensors are detected (issue #510) * Server mode issue when no network interface is available (issue #528) * DEBUG mode activated by default with Python 2.6 (issue #512) * Glances display of time trims the hours showing only minutes and seconds (issue #543) * Process list header not decorating when sorting by command (issue #551) Version 2.3 =========== Enhancements and new features: * Add the Docker plugin (issue #440) with per container CPU and memory monitoring (issue #490) * Add the RAID plugin (issue #447) * Add actions on alerts (issue #132). It is now possible to run action (command line) by triggers. Action could contain {{tag}} (Mustache) with stat value. * Add InfluxDB export module (--export-influxdb) (issue #455) * Add StatsD export module (--export-statsd) (issue #465) * Refactor export module (CSV export option is now --export-csv). It is now possible to export stats from the Glances client mode (issue #463) * The Web inteface is now based on Bootstrap / RWD grid (issue #417, #366 and #461) Thanks to Nicolas Hart @nclsHart * It is now possible, through the configuration file, to define if an alarm should be logged or not (using the _log option) (issue #437) * You can now set alarm for Disk IO * API: add getAllLimits and getAllViews methods (issue #481) and allow CORS request (issue #479) * SNMP client support NetApp appliance (issue #394) Bugs corrected: * R/W error with the glances.log file (issue #474) Other enhancement: * Alert < 3 seconds are no longer displayed Version 2.2.1 ============= * Fix incorrect kernel thread detection with --hide-kernel-threads (issue #457) * Handle IOError exception if no /etc/os-release to use Glances on Synology DSM (issue #458) * Check issue error in client/server mode (issue #459) Version 2.2 =========== Enhancements and new features: * Add centralized curse interface with a Glances servers list to monitor (issue #418) * Add processes tree view (--tree) (issue #444) * Improve graph history feature (issue #69) * Extended stats is disable by default (use --enable-process-extended to enable it - issue #430) * Add a short key ('F') and a command line option (--fs-free-space) to display FS free space instead of used space (issue #411) * Add a short key ('2') and a command line option (--disable-left-sidebar) to disable/enable the side bar (issue #429) * Add CPU times sort short key ('t') in the curse interface (issue #449) * Refactor operating system detection for GNU/Linux operating system * Code optimization Bugs corrected: * Correct a bug with Glances pip install --user (issue #383) * Correct issue on battery stat update (issue #433) * Correct issue on process no longer exist (issues #414 and #432) Version 2.1.2 ============= Maintenance version (only needed for Mac OS X). Bugs corrected: * Mac OS X: Error if Glances is not ran with sudo (issue #426) Version 2.1.1 ============= Enhancement: * Automaticaly compute top processes number for the current screen (issue #408) * CPU and Memory footprint optimization (issue #401) Bugs corrected: * Mac OS X 10.9: Exception at start (issue #423) * Process no longer exists (issue #421) * Error with Glances Client with Python 3.4.1 (issue #419) * TypeError: memory_maps() takes exactly 2 arguments (issue #413) * No filesystem informations since Glances 2.0 bug enhancement (issue #381) Version 2.1 =========== * Add user process filter feature User can define a process filter pattern (as a regular expression). The pattern could be defined from the command line (-f ) or by pressing the ENTER key in the curse interface. For the moment, process filter feature is only available in standalone mode. * Add extended processes informations for top process Top process stats availables: CPU affinity, extended memory information (shared, text, lib, datat, dirty, swap), open threads/files and TCP/UDP network sessions, IO nice level For the moment, extended processes stats are only available in standalone mode. * Add --process-short-name tag and '/' key to switch between short/command line * Create a max_processes key in the configuration file The goal is to reduce the number of displayed processes in the curses UI and so limit the CPU footprint of the Glances standalone mode. The API always return all the processes, the key is only active in the curses UI. If the key is not define, all the processes will be displayed. The default value is 20 (processes displayed). For the moment, this feature is only available in standalone mode. * Alias for network interfaces, disks and sensors Users can configure alias from the Glances configuration file. * Add Glances log message (in the /tmp/glances.log file) The default log level is INFO, you can switch to the DEBUG mode using the -d option on the command line. * Add RESTFul API to the Web server mode RestFul API doc: https://github.com/nicolargo/glances/wiki/The-Glances-RESTFULL-JSON-API * Improve SNMP fallback mode for Cisco IOS, VMware ESXi * Add --theme-white feature to optimize display for white background * Experimental history feature (--enable-history option on the command line) This feature allows users to generate graphs within the curse interface. Graphs are available for CPU, LOAD and MEM. To generate graph, click on the 'g' key. To reset the history, press the 'r' key. Note: This feature uses the matplotlib library. * CI: Improve Travis coverage Bugs corrected: * Quitting glances leaves a column layout to the current terminal (issue #392) * Glances crashes with malformed UTF-8 sequences in process command lines (issue #391) * SNMP fallback mode is not Python 3 compliant (issue #386) * Trouble using batinfo, hddtemp, pysensors w/ Python (issue #324) Version 2.0.1 ============= Maintenance version. Bugs corrected: * Error when displaying numeric process user names (#380) * Display users without username correctly (#379) * Bug when parsing configuration file (#378) * The sda2 partition is not seen by glances (#376) * Client crash if server is ended during XML request (#375) * Error with the Sensors module on Debian/Ubuntu (#373) * Windows don't view all processes (#319) Version 2.0 =========== Glances v2.0 is not a simple upgrade of the version 1.x but a complete code refactoring. Based on a plugins system, it aims at providing an easy way to add new features. - Core defines the basics and commons functions. - all stats are grabbed through plugins (see the glances/plugins source folder). - also outputs methods (Curse, Web mode, CSV) are managed as plugins. The Curse interface is almost the same than the version 1.7. Some improvements have been made: - space optimisation for the CPU, LOAD and MEM stats (justified alignment) - CPU: . CPU stats are displayed as soon as Glances is started . steal CPU alerts are no more logged - LOAD: . 5 min LOAD alerts are no more logged - File System: . Display the device name (if space is available) - Sensors: . Sensors and HDD temperature are displayed in the same block - Process list: . Refactor columns: CPU%, MEM%, VIRT, RES, PID, USER, NICE, STATUS, TIME, IO, Command/name . The running processes status is highlighted . The process name is highlighted in the command line Glances 2.0 brings a brand new Web Interface. You can run Glances in Web server mode and consult the stats directly from a standard Web Browser. The client mode can now fallback to a simple SNMP mode if Glances server is not found on the remote machine. Complete release notes: * Cut ifName and DiskName if they are too long in the curses interface (by Nicolargo) * Windows CLI is OK but early experimental (by Nicolargo) * Add bitrate limits to the networks interfaces (by Nicolargo) * Batteries % stats are now in the sensors list (by Nicolargo) * Refactor the client/server password security: using SHA256 (by Nicolargo, based on Alessio Sergi's example script) * Refactor the CSV output (by Nicolargo) * Glances client fallback to SNMP server if Glances one not found (by Nicolargo) * Process list: Highlight running/basename processes (by Alessio Sergi) * New Web server mode thk to the Bottle library (by Nicolargo) * Responsive design for Bottle interface (by Nicolargo) * Remove HTML output (by Nicolargo) * Enable/disable for optional plugins through the command line (by Nicolargo) * Refactor the API (by Nicolargo) * Load-5 alert are no longer logged (by Nicolargo) * Rename In/Out by Read/Write for DiskIO according to #339 (by Nicolargo) * Migrate from pysensors to py3sensors (by Alessio Sergi) * Migration to PsUtil 2.x (by Nicolargo) * New plugins system (by Nicolargo) * Python 2.x and 3.x compatibility (by Alessio Sergi) * Code quality improvements (by Alessio Sergi) * Refactor unitaries tests (by Nicolargo) * Development now follow the git flow workflow (by Nicolargo) ============================================================================== Glances Version 1 ============================================================================== Version 1.7.7 ============= * Fix CVS export [issue #348] * Adapt to PSUtil 2.1.1 * Compatibility with Python 3.4 * Improve German update Version 1.7.6 ============= * Adapt to psutil 2.0.0 API * Fixed psutil 0.5.x support on Windows * Fix help screen in 80x24 terminal size * Implement toggle of process list display ('z' key) Version 1.7.5 ============= * Force the Pypi installer to use the PsUtil branch 1.x (#333) Version 1.7.4 ============= * Add threads number in the task summary line (#308) * Add system uptime (#276) * Add CPU steal % to cpu extended stats (#309) * You can hide disk from the IOdisk view using the conf file (#304) * You can hide network interface from the Network view using the conf file * Optimisation of CPU consumption (around ~10%) * Correct issue #314: Client/server mode always asks for password * Correct issue #315: Defining password in client/server mode doesn't work as intended * Correct issue #316: Crash in client server mode * Correct issue #318: Argument parser, try-except blocks never get triggered Version 1.7.3 ============= * Add --password argument to enter the client/server password from the prompt * Fix an issue with the configuration file path (#296) * Fix an issue with the HTML template (#301) Version 1.7.2 ============= * Console interface is now Microsoft Windows compatible (thk to @fraoustin) * Update documentation and Wiki regarding the API * Added package name for python sources/headers in openSUSE/SLES/SLED * Add FreeBSD packager * Bugs corrected Version 1.7.1 ============= * Fix IoWait error on FreeBSD / Mac OS * HDDTemp module is now Python v3 compatible * Don't warn a process is not running if countmin=0 * Add Pypi badge on the README.rst * Update documentation * Add document structure for http://readthedocs.org Version 1.7 =========== * Add monitored processes list * Add hard disk temperature monitoring (thanks to the HDDtemp daemon) * Add batteries capacities information (thanks to the Batinfo lib) * Add command line argument -r toggles processes (reduce CPU usage) * Add command line argument -1 to run Glances in per CPU mode * Platform/architecture is more specific now * XML-RPC server: Add IPv6 support for the client/server mode * Add support for local conf file * Add a uninstall script * Add getNetTimeSinceLastUpdate() getDiskTimeSinceLastUpdate() and getProcessDiskTimeSinceLastUpdate() in the API * Add more translation: Italien, Chinese * and last but not least... up to 100 hundred bugs corrected / software and * docs improvements Version 1.6.1 ============= * Add per-user settings (configuration file) support * Add -z/--nobold option for better appearance under Solarized terminal * Key 'u' shows cumulative net traffic * Work in improving autoUnit * Take into account the number of core in the CPU process limit * API improvment add time_since_update for disk, process_disk and network * Improve help display * Add more dummy FS to the ignore list * Code refactory: PsUtil < 0.4.1 is depredicated (Thk to Alessio) * Correct a bug on the CPU process limit * Fix crash bug when specifying custom server port * Add Debian style init script for the Glances server Version 1.6 =========== * Configuration file: user can defines limits * In client/server mode, limits are set by the server side * Display limits in the help screen * Add per process IO (read and write) rate in B per second IO rate only available on Linux from a root account * If CPU iowait alert then sort by processes by IO rate * Per CPU display IOwait (if data is available) * Add password for the client/server mode (-P password) * Process column style auto (underline) or manual (bold) * Display a sort indicator (is space is available) * Change the table key in the help screen Version 1.5.2 ============= * Add sensors module (enable it with -e option) * Improve CPU stats (IO wait, Nice, IRQ) * More stats in lower space (yes it's possible) * Refactor processes list and count (lower CPU/MEM footprint) * Add functions to the RCP method * Completed unit test * and fixes... Version 1.5.1 ============= * Patch for PsUtil 0.4 compatibility * Test PsUtil version before running Glances Version 1.5 =========== * Add a client/server mode (XMLRPC) for remote monitoring * Correct a bug on process IO with non root users * Add 'w' shortkey to delete finished warning message * Add 'x' shortkey to delete finished warning/critical message * Bugs correction * Code optimization Version 1.4.2.2 =============== * Add switch between bit/sec and byte/sec for network IO * Add Changelog (generated with gitchangelog) Version 1.4.2.1 =============== * Minor patch to solve memomy issue (#94) on Mac OS X Version 1.4.2 ============= * Use the new virtual_memory() and virtual_swap() fct (PsUtil) * Display "Top process" in logs * Minor patch on man page for Debian packaging * Code optimization (less try and except) Version 1.4.1.1 =============== * Minor patch to disable Process IO for OS X (not available in PsUtil) Version 1.4.1 ============= * Per core CPU stats (if space is available) * Add Process IO Read/Write information (if space is available) * Uniformize units Version 1.4 =========== * Goodby StatGrab... Welcome to the PsUtil library ! * No more autotools, use setup.py to install (or package) * Only major stats (CPU, Load and memory) use background colors * Improve operating system name detection * New system info: one-line layout and add Arch Linux support * No decimal places for values < GB * New memory and swap layout * Add percentage of usage for both memory and swap * Add MEM% usage, NICE, STATUS, UID, PID and running TIME per process * Add sort by MEM% ('m' key) * Add sort by Process name ('p' key) * Multiple minor fixes, changes and improvements * Disable Disk IO module from the command line (-d) * Disable Mount module from the command line (-m) * Disable Net rate module from the command line (-n) * Improved FreeBSD support * Cleaning code and style * Code is now checked with pep8 * CSV and HTML output (experimental functions, no yet documentation) Version 1.3.7 ============= * Display (if terminal space is available) an alerts history (logs) * Add a limits classe to manage stats limits * Manage black and white console (issue #31) Version 1.3.6 ============= * Add control before libs import * Change static Python path (issue #20) * Correct a bug with a network interface disaippear (issue #27) * Add French and Spanish translation (thx to Jean Bob) Version 1.3.5 ============= * Add an help panel when Glances is running (key: 'h') * Add keys descriptions in the syntax (--help | -h) Version 1.3.4 ============= * New key: 'n' to enable/disable network stats * New key: 'd' to enable/disable disk IO stats * New key: 'f' to enable/disable FS stats * Reorganised the screen when stat are not available|disable * Force Glances to use the enmbeded fs stats (issue #16) Version 1.3.3 ============= * Automatically swith between process short and long name * Center the host / system information * Always put the hour/date in the bottom/right * Correct a bug if there is a lot of Disk/IO * Add control about available libstatgrab functions Version 1.3.2 ============= * Add alert for network bit rate° * Change the caption * Optimised net, disk IO and fs display (share the space) Disable on Ubuntu because the libstatgrab return a zero value for the network interface speed. Version 1.3.1 ============= * Add alert on load (depend on number of CPU core) * Fix bug when the FS list is very long Version 1.3 =========== * Add file system stats (total and used space) * Adapt unit dynamically (K, M, G) * Add man page (Thanks to Edouard Bourguignon) Version 1.2 =========== * Resize the terminal and the windows are adapted dynamically * Refresh screen instantanetly when a key is pressed Version 1.1.3 ============= * Add disk IO monitoring * Add caption * Correct a bug when computing the bitrate with the option -t * Catch CTRL-C before init the screen (Bug #2) * Check if mem.total = 0 before division (Bug #1) glances-2.11.1/README.rst000066400000000000000000000247641315472316100147170ustar00rootroot00000000000000=============================== Glances - An eye on your system =============================== .. image:: https://img.shields.io/pypi/v/glances.svg :target: https://pypi.python.org/pypi/Glances .. image:: https://img.shields.io/github/stars/nicolargo/glances.svg :target: https://github.com/nicolargo/glances/ :alt: Github stars .. image:: https://img.shields.io/travis/nicolargo/glances/master.svg?maxAge=3600&label=Linux%20/%20BSD%20/%20macOS :target: https://travis-ci.org/nicolargo/glances :alt: Linux tests (Travis) .. image:: https://img.shields.io/appveyor/ci/nicolargo/glances/master.svg?maxAge=3600&label=Windows :target: https://ci.appveyor.com/project/nicolargo/glances :alt: Windows tests (Appveyor) .. image:: https://img.shields.io/scrutinizer/g/nicolargo/glances.svg :target: https://scrutinizer-ci.com/g/nicolargo/glances/ .. image:: https://img.shields.io/badge/Donate-PayPal-green.svg :target: https://www.paypal.me/nicolargo Follow Glances on Twitter: `@nicolargo`_ Summary ======= **Glances** is a cross-platform monitoring tool which aims to present a maximum of information in a minimum of space through a curses or Web based interface. It can adapt dynamically the displayed information depending on the user interface size. .. image:: https://raw.githubusercontent.com/nicolargo/glances/develop/docs/_static/glances-summary.png It can also work in client/server mode. Remote monitoring could be done via terminal, Web interface or API (XML-RPC and RESTful). Stats can also be exported to files or external time/value databases. .. image:: https://raw.githubusercontent.com/nicolargo/glances/develop/docs/_static/glances-responsive-webdesign.png Glances is written in Python and uses libraries to grab information from your system. It is based on an open architecture where developers can add new plugins or exports modules. Requirements ============ - ``python 2.7,>=3.3`` - ``psutil>=2.0.0`` (better with latest version) Optional dependencies: - ``bernhard`` (for the Riemann export module) - ``bottle`` (for Web server mode) - ``cassandra-driver`` (for the Cassandra export module) - ``couchdb`` (for the CouchDB export module) - ``docker`` (for the Docker monitoring support) [Linux-only] - ``elasticsearch`` (for the Elastic Search export module) - ``hddtemp`` (for HDD temperature monitoring support) [Linux-only] - ``influxdb`` (for the InfluxDB export module) - ``kafka-python`` (for the Kafka export module) - ``matplotlib`` (for graphical/chart support) - ``netifaces`` (for the IP plugin) - ``nvidia-ml-py3`` (for the GPU plugin) - ``pika`` (for the RabbitMQ/ActiveMQ export module) - ``potsdb`` (for the OpenTSDB export module) - ``prometheus_client`` (for the Prometheus export module) - ``py-cpuinfo`` (for the Quicklook CPU info module) - ``pymdstat`` (for RAID support) [Linux-only] - ``pysnmp`` (for SNMP support) - ``pystache`` (for the action script feature) - ``pyzmq`` (for the ZeroMQ export module) - ``requests`` (for the Ports, Cloud plugins and Restful export module) - ``scandir`` (for the Folders plugin) [Only for Python < 3.5] - ``statsd`` (for the StatsD export module) - ``wifi`` (for the wifi plugin) [Linux-only] - ``zeroconf`` (for the autodiscover mode) *Note for Python 2.6 users* Since version 2.7, Glances no longer support Python 2.6. Please upgrade to at least Python 2.7/3.3+ or downgrade to Glances 2.6.2 (latest version with Python 2.6 support). *Note for CentOS Linux 6 and 7 users* Python 2.7, 3.3 and 3.4 are now available via SCLs. See: https://lists.centos.org/pipermail/centos-announce/2015-December/021555.html. Installation ============ Several method to test/install Glances on your system. Choose your weapon ! Glances Auto Install script: the total way ------------------------------------------ To install both dependencies and latest Glances production ready version (aka *master* branch), just enter the following command line: .. code-block:: console curl -L https://bit.ly/glances | /bin/bash or .. code-block:: console wget -O- https://bit.ly/glances | /bin/bash *Note*: Only supported on some GNU/Linux distributions. If you want to support other distributions, please contribute to `glancesautoinstall`_. PyPI: The simple way -------------------- Glances is on ``PyPI``. By using PyPI, you are sure to have the latest stable version. To install, simply use ``pip``: .. code-block:: console pip install glances *Note*: Python headers are required to install `psutil`_. For example, on Debian/Ubuntu you need to install first the *python-dev* package. For Fedora/CentOS/RHEL install first *python-devel* package. For Windows, just install psutil from the binary installation file. *Note 2 (for the Wifi plugin)*: If you want to use the Wifi plugin, you need to install the *wireless-tools* package on your system. You can also install the following libraries in order to use optional features (like the Web interface, exports modules...): .. code-block:: console pip install glances[action,browser,cloud,cpuinfo,chart,docker,export,folders,gpu,ip,raid,snmp,web,wifi] To upgrade Glances to the latest version: .. code-block:: console pip install --upgrade glances pip install --upgrade glances[...] If you need to install Glances in a specific user location, use: .. code-block:: console export PYTHONUSERBASE=~/mylocalpath pip install --user glances Docker: the funny way --------------------- A Glances container is available. It will include the latest development HEAD version. You can use it to monitor your server and all your others containers ! Get the Glances container: .. code-block:: console docker pull nicolargo/glances Run the container in *console mode*: .. code-block:: console docker run -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host -it docker.io/nicolargo/glances Additionally, if you want to use your own glances.conf file, you can create your own Dockerfile: .. code-block:: console FROM nicolargo/glances COPY glances.conf /glances/conf/glances.conf CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT Alternatively, you can specify something along the same lines with docker run options: .. code-block:: console docker run -v ./glances.conf:/glances/conf/glances.conf -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host -it docker.io/nicolargo/glances Where ./glances.conf is a local directory containing your glances.conf file. Run the container in *Web server mode* (notice the `GLANCES_OPT` environment variable setting parameters for the glances startup command): .. code-block:: console docker run -d --restart="always" -p 61208-61209:61208-61209 -e GLANCES_OPT="-w" -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host docker.io/nicolargo/glances GNU/Linux --------- `Glances` is available on many Linux distributions, so you should be able to install it using your favorite package manager. Be aware that Glances may not be the latest one using this method. FreeBSD ------- To install the binary package: .. code-block:: console # pkg install py27-glances To install Glances from ports: .. code-block:: console # cd /usr/ports/sysutils/py-glances/ # make install clean macOS ----- macOS users can install Glances using ``Homebrew`` or ``MacPorts``. Homebrew ```````` .. code-block:: console $ brew install python $ pip install glances MacPorts ```````` .. code-block:: console $ sudo port install glances Windows ------- Install `Python`_ for Windows (Python 2.7.9+ and 3.4+ ship with pip) and then just: .. code-block:: console $ pip install glances Android ------- You need a rooted device and the `Termux`_ application (available on the Google Store). Start Termux on your device and enter: .. code-block:: console $ apt update $ apt upgrade $ apt install clang python python-dev $ pip install bottle $ pip install glances And start Glances: .. code-block:: console $ glances You can also run Glances in server mode (-s or -w) in order to remotely monitor your Android device. Source ------ To install Glances from source: .. code-block:: console $ wget https://github.com/nicolargo/glances/archive/vX.Y.tar.gz -O - | tar xz $ cd glances-* # python setup.py install *Note*: Python headers are required to install psutil. Chef ---- An awesome ``Chef`` cookbook is available to monitor your infrastructure: https://supermarket.chef.io/cookbooks/glances (thanks to Antoine Rouyer) Puppet ------ You can install Glances using ``Puppet``: https://github.com/rverchere/puppet-glances Usage ===== For the standalone mode, just run: .. code-block:: console $ glances For the Web server mode, run: .. code-block:: console $ glances -w and enter the URL ``http://:61208`` in your favorite web browser. For the client/server mode, run: .. code-block:: console $ glances -s on the server side and run: .. code-block:: console $ glances -c on the client one. You can also detect and display all Glances servers available on your network or defined in the configuration file: .. code-block:: console $ glances --browser and RTFM, always. Documentation ============= For complete documentation have a look at the readthedocs_ website. If you have any question (after RTFM!), please post it on the official Q&A `forum`_. Gateway to other services ========================= Glances can export stats to: ``CSV`` file, ``JSON`` file, ``InfluxDB``, ``Cassandra``, ``CouchDB``, ``OpenTSDB``, ``Prometheus``, ``StatsD``, ``ElasticSearch``, ``RabbitMQ/ActiveMQ``, ``ZeroMQ``, ``Kafka``, ``Riemann`` and ``Restful`` server. How to contribute ? =================== If you want to contribute to the Glances project, read this `wiki`_ page. There is also a chat dedicated to the Glances developers: .. image:: https://badges.gitter.im/Join%20Chat.svg :target: https://gitter.im/nicolargo/glances?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge Author ====== Nicolas Hennion (@nicolargo) License ======= LGPLv3. See ``COPYING`` for more details. .. _psutil: https://github.com/giampaolo/psutil .. _glancesautoinstall: https://github.com/nicolargo/glancesautoinstall .. _@nicolargo: https://twitter.com/nicolargo .. _Python: https://www.python.org/getit/ .. _Termux: https://play.google.com/store/apps/details?id=com.termux .. _readthedocs: https://glances.readthedocs.io/ .. _forum: https://groups.google.com/forum/?hl=en#!forum/glances-users .. _wiki: https://github.com/nicolargo/glances/wiki/How-to-contribute-to-Glances-%3F glances-2.11.1/appveyor.yml000066400000000000000000000031471315472316100156100ustar00rootroot00000000000000os: Visual Studio 2015 environment: matrix: # Pre-installed Python versions, which Appveyor may upgrade to # a later point release. # 32 bits - PYTHON: "C:\\Python27" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "32" - PYTHON: "C:\\Python35" PYTHON_VERSION: "3.5.x" PYTHON_ARCH: "32" # 64 bits - PYTHON: "C:\\Python27-x64" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" - PYTHON: "C:\\Python35-x64" PYTHON_VERSION: "3.5.x" PYTHON_ARCH: "64" ARCH: x86_64 VS_VER: "2015" INSTANCENAME: "SQL2012SP1" # Also build on a Python version not pre-installed by Appveyor. # See: https://github.com/ogrisel/python-appveyor-demo/issues/10 # - PYTHON: "C:\\Python266" # PYTHON_VERSION: "2.6.6" # PYTHON_ARCH: "32" init: - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" install: - "powershell .ci\\appveyor\\install.ps1" # - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:/get-pip.py') - "%WITH_COMPILER% %PYTHON%/python.exe -m pip --version" - "%WITH_COMPILER% %PYTHON%/python.exe -m pip install --upgrade --user psutil bottle requests netifaces pystache py-cpuinfo scandir" - "%WITH_COMPILER% %PYTHON%/python.exe -m pip freeze" - "%WITH_COMPILER% %PYTHON%/python.exe setup.py install" build: off test_script: - "%WITH_COMPILER% %PYTHON%/python -V" - "%WITH_COMPILER% %PYTHON%/python unitest.py" artifacts: - path: dist\* # on_success: # - might want to upload the content of dist/*.whl to a public wheelhouse skip_commits: message: skip-ci glances-2.11.1/circle.yml000066400000000000000000000002731315472316100152010ustar00rootroot00000000000000machine: post: - pyenv local 2.7.10 3.3.3 3.4.3 3.5.0 dependencies: override: - pip install tox tox-pyenv pre: - pip install -U pip setuptools - pip install psutil glances-2.11.1/conf/000077500000000000000000000000001315472316100141405ustar00rootroot00000000000000glances-2.11.1/conf/glances-grafana.json000066400000000000000000001715761315472316100200650ustar00rootroot00000000000000{ "annotations": { "list": [] }, "editable": true, "gnetId": null, "graphTooltip": 0, "hideControls": false, "id": 2, "links": [], "refresh": false, "rows": [ { "collapse": false, "height": 229, "panels": [ { "cacheTimeout": null, "colorBackground": false, "colorValue": false, "colors": [ "rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)" ], "datasource": "glances", "editable": true, "error": false, "format": "none", "gauge": { "maxValue": 100, "minValue": 0, "show": false, "thresholdLabels": false, "thresholdMarkers": true }, "id": 5, "interval": null, "links": [], "mappingType": 1, "mappingTypes": [ { "name": "value to text", "value": 1 }, { "name": "range to text", "value": 2 } ], "maxDataPoints": 100, "nullPointMode": "connected", "nullText": null, "postfix": "", "postfixFontSize": "50%", "prefix": "", "prefixFontSize": "50%", "rangeMaps": [ { "from": "null", "text": "N/A", "to": "null" } ], "span": 1, "sparkline": { "fillColor": "rgba(31, 118, 189, 0.18)", "full": false, "lineColor": "rgb(31, 120, 193)", "show": false }, "tableColumn": "", "targets": [ { "column": "cpucore", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "measurement": "localhost.load", "query": "SELECT mean(\"cpucore\") FROM \"localhost.load\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "cpucore" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "load", "tags": [] } ], "thresholds": "", "title": "Core", "type": "singlestat", "valueFontSize": "80%", "valueMaps": [ { "op": "=", "text": "N/A", "value": "null" } ], "valueName": "avg" }, { "aliasColors": {}, "annotate": { "enable": false }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "fill": 1, "grid": { "max": null, "min": null }, "id": 4, "interactive": true, "legend": { "alignAsTable": true, "avg": true, "current": false, "max": true, "min": true, "rightSide": true, "show": true, "total": false, "values": true }, "legend_counts": true, "lines": true, "linewidth": 2, "links": [], "nullPointMode": "null", "options": false, "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "resolution": 100, "scale": 1, "seriesOverrides": [], "spaceLength": 10, "span": 10, "spyable": true, "stack": true, "steppedLine": false, "targets": [ { "alias": "1min", "column": "min1", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.load", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"min1\") FROM \"localhost.load\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "min1" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "load", "tags": [], "target": "randomWalk('random walk')" }, { "alias": "5mins", "column": "min5", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.load", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"min5\") FROM \"localhost.load\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "min5" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "load", "tags": [], "target": "" }, { "alias": "15mins", "column": "min15", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.load", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"min15\") FROM \"localhost.load\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "C", "resultFormat": "time_series", "select": [ [ { "params": [ "min15" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "load", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "timezone": "browser", "title": "Load", "tooltip": { "query_as_alias": true, "shared": false, "sort": 0, "value_type": "cumulative" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "cacheTimeout": null, "colorBackground": false, "colorValue": false, "colors": [ "rgba(50, 172, 45, 0.97)", "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)" ], "datasource": "glances", "editable": true, "error": false, "format": "none", "gauge": { "maxValue": 100, "minValue": 0, "show": false, "thresholdLabels": false, "thresholdMarkers": true }, "id": 18, "interval": null, "links": [], "mappingType": 1, "mappingTypes": [ { "name": "value to text", "value": 1 }, { "name": "range to text", "value": 2 } ], "maxDataPoints": 100, "nullPointMode": "connected", "nullText": null, "postfix": "", "postfixFontSize": "50%", "prefix": "", "prefixFontSize": "50%", "rangeMaps": [ { "from": "null", "text": "N/A", "to": "null" } ], "span": 1, "sparkline": { "fillColor": "rgba(31, 118, 189, 0.18)", "full": false, "lineColor": "rgb(31, 120, 193)", "show": true }, "tableColumn": "", "targets": [ { "column": "total", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "$__interval" ], "type": "time" } ], "measurement": "localhost.processcount", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"total\") FROM \"localhost.processcount\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "total" ], "type": "field" }, { "params": [], "type": "last" } ] ], "series": "processcount", "tags": [] } ], "thresholds": "", "title": "Processes", "type": "singlestat", "valueFontSize": "80%", "valueMaps": [ { "op": "=", "text": "N/A", "value": "null" } ], "valueName": "avg" } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "test", "titleSize": "h6" }, { "collapse": false, "height": "250px", "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 6, "legend": { "avg": true, "current": false, "max": true, "min": true, "rightSide": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "alias": "User", "column": "user", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.cpu", "query": "SELECT mean(\"user\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "user" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [] }, { "alias": "System", "column": "system", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.cpu", "query": "SELECT mean(\"system\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "system" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [], "target": "" }, { "alias": "IoWait", "column": "iowait", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.cpu", "query": "SELECT mean(\"iowait\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "C", "resultFormat": "time_series", "select": [ [ { "params": [ "iowait" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "CPU (%)", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "percent", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": { "Max": "#BF1B00" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 7, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "alias": "Used", "column": "used", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "$__interval" ], "type": "time" } ], "measurement": "localhost.mem", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"used\") FROM \"localhost.mem\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "used" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "mem", "tags": [] }, { "alias": "Max", "column": "total", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "$__interval" ], "type": "time" } ], "measurement": "localhost.mem", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"total\") FROM \"localhost.mem\" WHERE $timeFilter GROUP BY time($interval)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "total" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "mem", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "MEM", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "New row", "titleSize": "h6" }, { "collapse": false, "height": "250px", "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 3, "grid": {}, "id": 9, "legend": { "avg": true, "current": false, "max": true, "min": true, "show": true, "total": false, "values": true }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [ { "alias": "Tx", "yaxis": 2 } ], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "alias": "Rx", "column": "enp0s25.rx", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "interval": "", "measurement": "localhost.network", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"wlp2s0.rx\")/mean(\"wlp2s0.time_since_update\")*8 FROM \"localhost.network\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "rawQuery": true, "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "eth0.rx" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "network", "tags": [] }, { "alias": "Tx", "column": "eth0.tx*-1", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.network", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"wlp2s0.tx\")/mean(\"wlp2s0.time_since_update\")*8 FROM \"localhost.network\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "rawQuery": true, "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "eth0.tx" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "network", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Net", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "transparent": false, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bps", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": { "Max": "#BF1B00" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 8, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "alias": "Used", "column": "used", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "$__interval" ], "type": "time" } ], "measurement": "localhost.memswap", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"used\") FROM \"localhost.memswap\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "used" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "memswap", "tags": [] }, { "alias": "Max", "column": "total", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "$__interval" ], "type": "time" } ], "measurement": "localhost.memswap", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"total\") FROM \"localhost.memswap\" WHERE $timeFilter GROUP BY time($interval)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "total" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "memswap", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "SWAP", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "New row", "titleSize": "h6" }, { "collapse": false, "height": "250px", "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 10, "legend": { "avg": true, "current": false, "max": true, "min": true, "show": true, "total": false, "values": true }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "alias": "Read", "column": "sda2.read_bytes", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.diskio", "query": "SELECT mean(\"sda2.read_bytes\")/mean(\"sda2.time_since_update\")*8 FROM \"localhost.diskio\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "sda2.read_bytes" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "diskio", "tags": [] }, { "alias": "Write", "column": "sda2.write_bytes", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.diskio", "query": "SELECT mean(\"sda2.write_bytes\")/mean(\"sda2.time_since_update\")*8 FROM \"localhost.diskio\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "sda2.write_bytes" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "diskio", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "sda2 disk IO", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": { "Max": "#BF1B00" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 11, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 4, "stack": false, "steppedLine": false, "targets": [ { "alias": "Used", "column": "\"/.used\"", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "$__interval" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.fs", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"/.used\") FROM \"localhost.fs\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "/.used" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "fs", "tags": [] }, { "alias": "Max", "column": "\"/.size\"", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "$__interval" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.fs", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"/.size\") FROM \"localhost.fs\" WHERE $timeFilter GROUP BY time($interval) fill(null)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "/.size" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "fs", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "/ Size", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", "logBase": 1, "max": null, "min": 0, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "cacheTimeout": null, "colorBackground": true, "colorValue": false, "colors": [ "rgba(71, 212, 59, 0.4)", "rgba(245, 150, 40, 0.73)", "rgba(225, 40, 40, 0.59)" ], "datasource": "glances", "editable": true, "error": false, "format": "percent", "gauge": { "maxValue": 100, "minValue": 0, "show": false, "thresholdLabels": false, "thresholdMarkers": true }, "id": 16, "interval": null, "links": [], "mappingType": 1, "mappingTypes": [ { "name": "value to text", "value": 1 }, { "name": "range to text", "value": 2 } ], "maxDataPoints": 100, "nullPointMode": "connected", "nullText": null, "postfix": "", "postfixFontSize": "50%", "prefix": "", "prefixFontSize": "50%", "rangeMaps": [ { "from": "null", "text": "N/A", "to": "null" } ], "span": 1, "sparkline": { "fillColor": "rgba(31, 118, 189, 0.18)", "full": false, "lineColor": "rgb(193, 71, 31)", "show": true }, "tableColumn": "", "targets": [ { "column": "\"/.percent\"", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "measurement": "localhost.fs", "query": "SELECT mean(\"/.percent\") FROM \"localhost.fs\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "/.percent" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "fs", "tags": [] } ], "thresholds": "70,90", "title": "/ used", "type": "singlestat", "valueFontSize": "80%", "valueMaps": [ { "op": "=", "text": "N/A", "value": "null" } ], "valueName": "avg" }, { "cacheTimeout": null, "colorBackground": true, "colorValue": false, "colors": [ "rgba(71, 212, 59, 0.4)", "rgba(245, 150, 40, 0.73)", "rgba(225, 40, 40, 0.59)" ], "datasource": "glances", "editable": true, "error": false, "format": "percent", "gauge": { "maxValue": 100, "minValue": 0, "show": false, "thresholdLabels": false, "thresholdMarkers": true }, "id": 17, "interval": null, "links": [], "mappingType": 1, "mappingTypes": [ { "name": "value to text", "value": 1 }, { "name": "range to text", "value": 2 } ], "maxDataPoints": 100, "nullPointMode": "connected", "nullText": null, "postfix": "", "postfixFontSize": "50%", "prefix": "", "prefixFontSize": "50%", "rangeMaps": [ { "from": "null", "text": "N/A", "to": "null" } ], "span": 1, "sparkline": { "fillColor": "rgba(31, 118, 189, 0.18)", "full": false, "lineColor": "rgb(193, 71, 31)", "show": true }, "tableColumn": "", "targets": [ { "column": "\"/home.percent\"", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "measurement": "localhost.fs", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"/boot/efi.percent\") FROM \"localhost.fs\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "/boot.percent" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "fs", "tags": [] } ], "thresholds": "70,90", "title": "/boot used", "type": "singlestat", "valueFontSize": "80%", "valueMaps": [ { "op": "=", "text": "N/A", "value": "null" } ], "valueName": "avg" } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "New row", "titleSize": "h6" }, { "collapse": false, "height": "25px", "panels": [ { "content": "", "editable": true, "error": false, "id": 13, "links": [], "mode": "markdown", "span": 12, "style": {}, "title": "CPU details", "type": "text" } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "New row", "titleSize": "h6" }, { "collapse": false, "height": "150px", "panels": [ { "aliasColors": { "max": "#890F02" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 12, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": false, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [ { "alias": "max", "fillBelowTo": "min", "lines": false }, { "alias": "min", "lines": false }, { "alias": "mean", "linewidth": 2, "zindex": 3 } ], "spaceLength": 10, "span": 12, "stack": false, "steppedLine": false, "targets": [ { "alias": "mean", "column": "user", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT mean(\"user\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "user" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [] }, { "alias": "min", "column": "user", "dsType": "influxdb", "function": "min", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT min(\"user\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "user" ], "type": "field" }, { "params": [], "type": "min" } ] ], "series": "cpu", "tags": [], "target": "" }, { "alias": "max", "column": "user", "dsType": "influxdb", "function": "max", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT max(\"user\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "C", "resultFormat": "time_series", "select": [ [ { "params": [ "user" ], "type": "field" }, { "params": [], "type": "max" } ] ], "series": "cpu", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "CPU user", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "transparent": true, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "percent", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": { "max": "#890F02" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 14, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": false, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [ { "alias": "max", "fillBelowTo": "min", "lines": false }, { "alias": "min", "lines": false }, { "alias": "mean", "linewidth": 2, "zindex": 3 } ], "spaceLength": 10, "span": 12, "stack": false, "steppedLine": false, "targets": [ { "alias": "mean", "column": "system", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT mean(\"system\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "system" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [] }, { "alias": "min", "column": "system", "dsType": "influxdb", "function": "min", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT min(\"system\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "system" ], "type": "field" }, { "params": [], "type": "min" } ] ], "series": "cpu", "tags": [], "target": "" }, { "alias": "max", "column": "system", "dsType": "influxdb", "function": "max", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT max(\"system\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "C", "resultFormat": "time_series", "select": [ [ { "params": [ "system" ], "type": "field" }, { "params": [], "type": "max" } ] ], "series": "cpu", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "CPU system", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "transparent": true, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "percent", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": { "max": "#890F02" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 0, "grid": {}, "id": 15, "legend": { "alignAsTable": false, "avg": false, "current": false, "hideEmpty": false, "max": false, "min": false, "show": false, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [ { "alias": "max", "fillBelowTo": "min", "lines": false }, { "alias": "min", "lines": false }, { "alias": "mean", "linewidth": 2, "zindex": 3 } ], "spaceLength": 10, "span": 12, "stack": false, "steppedLine": false, "targets": [ { "alias": "mean", "column": "iowait", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT mean(\"iowait\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "iowait" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [] }, { "alias": "min", "column": "iowait", "dsType": "influxdb", "function": "min", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT min(\"iowait\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": [ "iowait" ], "type": "field" }, { "params": [], "type": "min" } ] ], "series": "cpu", "tags": [], "target": "" }, { "alias": "max", "column": "iowait", "dsType": "influxdb", "function": "max", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT max(\"iowait\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "refId": "C", "resultFormat": "time_series", "select": [ [ { "params": [ "iowait" ], "type": "field" }, { "params": [], "type": "max" } ] ], "series": "cpu", "tags": [], "target": "" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "CPU iowait", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "transparent": true, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "percent", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": { "max": "#890F02" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 2, "grid": {}, "id": 19, "legend": { "alignAsTable": false, "avg": false, "current": false, "hideEmpty": false, "max": false, "min": false, "show": false, "total": false, "values": false }, "lines": true, "linewidth": 2, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 12, "stack": false, "steppedLine": false, "targets": [ { "alias": "mean", "column": "iowait", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT mean(\"ctx_switches\") / mean(\"time_since_update\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "rawQuery": true, "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "time_since_update" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [] } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Context switches", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "transparent": true, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "none", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": { "max": "#890F02" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "glances", "editable": true, "error": false, "fill": 2, "grid": {}, "id": 20, "legend": { "alignAsTable": false, "avg": false, "current": false, "hideEmpty": false, "max": false, "min": false, "show": false, "total": false, "values": false }, "lines": true, "linewidth": 2, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 12, "stack": false, "steppedLine": false, "targets": [ { "alias": "mean", "column": "iowait", "dsType": "influxdb", "function": "mean", "groupBy": [ { "params": [ "auto" ], "type": "time" } ], "interval": "60s", "measurement": "localhost.cpu", "query": "SELECT mean(\"interrupts\") / mean(\"time_since_update\") FROM \"localhost.cpu\" WHERE $timeFilter GROUP BY time($interval)", "rawQuery": true, "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "time_since_update" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "series": "cpu", "tags": [] } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Interrupts", "tooltip": { "shared": false, "sort": 0, "value_type": "cumulative" }, "transparent": true, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "none", "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "logBase": 1, "max": null, "min": null, "show": true } ] } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "New row", "titleSize": "h6" }, { "collapse": false, "height": 4, "panels": [ { "content": "", "id": 22, "links": [], "mode": "markdown", "span": 12, "title": "Sensors", "type": "text" } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "Dashboard Row", "titleSize": "h6" }, { "collapse": false, "height": 250, "panels": [ { "cards": { "cardPadding": null, "cardRound": null }, "color": { "cardColor": "rgb(255, 0, 0)", "colorScale": "sqrt", "colorScheme": "interpolateReds", "exponent": 1, "mode": "opacity" }, "dataFormat": "timeseries", "datasource": "glances", "heatmap": {}, "highlightCards": true, "id": 21, "links": [], "span": 12, "targets": [ { "alias": "AmbientTemperature", "dsType": "influxdb", "groupBy": [ { "params": [ "$__interval" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.sensors", "orderByTime": "ASC", "policy": "default", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "Ambient.value" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] } ], "title": "Ambiant temperature", "tooltip": { "show": true, "showHistogram": false }, "type": "heatmap", "xAxis": { "show": true }, "xBucketNumber": null, "xBucketSize": null, "yAxis": { "decimals": null, "format": "celsius", "logBase": 1, "max": null, "min": "0", "show": true, "splitFactor": null }, "yBucketNumber": null, "yBucketSize": null } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "Dashboard Row", "titleSize": "h6" }, { "collapse": false, "height": 250, "panels": [ { "cards": { "cardPadding": null, "cardRound": null }, "color": { "cardColor": "rgb(255, 0, 0)", "colorScale": "sqrt", "colorScheme": "interpolateOranges", "exponent": 1, "mode": "opacity" }, "dataFormat": "timeseries", "datasource": "glances", "heatmap": {}, "highlightCards": true, "id": 23, "links": [], "span": 12, "targets": [ { "alias": "CpuTemperature", "dsType": "influxdb", "groupBy": [ { "params": [ "$__interval" ], "type": "time" }, { "params": [ "null" ], "type": "fill" } ], "measurement": "localhost.sensors", "orderByTime": "ASC", "policy": "default", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": [ "CPU.value" ], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] } ], "title": "Cpu Temperature", "tooltip": { "show": true, "showHistogram": false }, "type": "heatmap", "xAxis": { "show": true }, "xBucketNumber": null, "xBucketSize": null, "yAxis": { "decimals": null, "format": "celsius", "logBase": 1, "max": null, "min": "0", "show": true, "splitFactor": null }, "yBucketNumber": null, "yBucketSize": null } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "Dashboard Row", "titleSize": "h6" } ], "schemaVersion": 14, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { "from": "2017-06-03T10:48:04.174Z", "to": "2017-06-03T16:49:42.693Z" }, "timepicker": { "collapse": false, "enable": true, "notice": false, "now": true, "refresh_intervals": [ "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d" ], "status": "Stable", "time_options": [ "5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d" ], "type": "timepicker" }, "timezone": "browser", "title": "Glances", "version": 9 } glances-2.11.1/conf/glances.conf000066400000000000000000000307161315472316100164320ustar00rootroot00000000000000############################################################################## # Globals Glances parameters ############################################################################## [global] # Does Glances should check if a newer version is available on PyPI ? check_update=true # History size (maximum number of values) # Default is 28800: 1 day with 1 point every 3 seconds (default refresh time) history_size=28800 ############################################################################## # User interface ############################################################################## [outputs] # Theme name for the Curses interface: black or white curse_theme=black # Limit the number of processes to display in the WebUI max_processes_display=30 ############################################################################## # plugins ############################################################################## [quicklook] # Define CPU, MEM and SWAP thresholds in % cpu_careful=50 cpu_warning=70 cpu_critical=90 mem_careful=50 mem_warning=70 mem_critical=90 swap_careful=50 swap_warning=70 swap_critical=90 [cpu] # Default values if not defined: 50/70/90 (except for iowait) user_careful=50 user_warning=70 user_critical=90 #user_log=False #user_critical_action=echo {{user}} {{value}} {{max}} > /tmp/cpu.alert system_careful=50 system_warning=70 system_critical=90 steal_careful=50 steal_warning=70 steal_critical=90 #steal_log=True # I/O wait percentage should be lower than 1/# (of CPU cores) # Leave commented to just use the default config (1/#-20% / 1/#-10% / 1/#) #iowait_careful=30 #iowait_warning=40 #iowait_critical=50 # Context switch limit (core / second) # Leave commented to just use the default config (critical is 56000/# (of CPU core)) #ctx_switches_careful=10000 #ctx_switches_warning=12000 #ctx_switches_critical=14000 [percpu] # Define CPU thresholds in % # Default values if not defined: 50/70/90 user_careful=50 user_warning=70 user_critical=90 iowait_careful=50 iowait_warning=70 iowait_critical=90 system_careful=50 system_warning=70 system_critical=90 [gpu] # Default processor values if not defined: 50/70/90 proc_careful=50 proc_warning=70 proc_critical=90 # Default memory values if not defined: 50/70/90 mem_careful=50 mem_warning=70 mem_critical=90 [mem] # Define RAM thresholds in % # Default values if not defined: 50/70/90 careful=50 #careful_action_repeat=echo {{percent}} >> /tmp/memory.alert warning=70 critical=90 [memswap] # Define SWAP thresholds in % # Default values if not defined: 50/70/90 careful=50 warning=70 critical=90 [load] # Define LOAD thresholds # Value * number of cores # Default values if not defined: 0.7/1.0/5.0 per number of cores # Source: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages # http://www.linuxjournal.com/article/9001 careful=0.7 warning=1.0 critical=5.0 #log=False [network] # Default bitrate thresholds in % of the network interface speed # Default values if not defined: 70/80/90 rx_careful=70 rx_warning=80 rx_critical=90 tx_careful=70 tx_warning=80 tx_critical=90 # Define the list of hidden network interfaces (comma-separated regexp) #hide=docker.*,lo # WLAN 0 alias #wlan0_alias=Wireless IF # It is possible to overwrite the bitrate thresholds per interface # WLAN 0 Default limits (in bits per second aka bps) for interface bitrate #wlan0_rx_careful=4000000 #wlan0_rx_warning=5000000 #wlan0_rx_critical=6000000 #wlan0_rx_log=True #wlan0_tx_careful=700000 #wlan0_tx_warning=900000 #wlan0_tx_critical=1000000 #wlan0_tx_log=True [wifi] # Define the list of hidden wireless network interfaces (comma-separated regexp) hide=lo,docker.* # Define SIGNAL thresholds in db (lower is better...) # Based on: http://serverfault.com/questions/501025/industry-standard-for-minimum-wifi-signal-strength careful=-65 warning=-75 critical=-85 [diskio] # Define the list of hidden disks (comma-separated regexp) #hide=sda2,sda5,loop.* hide=loop.* # Alias for sda1 #sda1_alias=IntDisk [fs] # Define the list of hidden file system (comma-separated regexp) #hide=/boot.* # Define filesystem space thresholds in % # Default values if not defined: 50/70/90 # It is also possible to define per mount point value # Example: /_careful=40 careful=50 warning=70 critical=90 # Allow additional file system types (comma-separated FS type) #allow=zfs [folders] # Define a folder list to monitor # The list is composed of items (list_#nb <= 10) # An item is defined by: # * path: absolute path # * careful: optional careful threshold (in MB) # * warning: optional warning threshold (in MB) # * critical: optional critical threshold (in MB) #folder_1_path=/tmp #folder_1_careful=2500 #folder_1_warning=3000 #folder_1_critical=3500 #folder_2_path=/home/nicolargo/Videos #folder_2_warning=17000 #folder_2_critical=20000 #folder_3_path=/nonexisting #folder_4_path=/root [sensors] # Sensors core thresholds (in Celsius...) # Default values if not defined: 60/70/80 temperature_core_careful=60 temperature_core_warning=70 temperature_core_critical=80 # Temperatures threshold in °C for hddtemp # Default values if not defined: 45/52/60 temperature_hdd_careful=45 temperature_hdd_warning=52 temperature_hdd_critical=60 # Battery threshold in % battery_careful=80 battery_warning=90 battery_critical=95 # Sensors alias #temp1_alias=Motherboard 0 #temp2_alias=Motherboard 1 #core 0_alias=CPU Core 0 #core 1_alias=CPU Core 1 [processlist] # Define CPU/MEM (per process) thresholds in % # Default values if not defined: 50/70/90 cpu_careful=50 cpu_warning=70 cpu_critical=90 mem_careful=50 mem_warning=70 mem_critical=90 [ports] # Ports scanner plugin configuration # Interval in second between two scans refresh=30 # Set the default timeout (in second) for a scan (can be overwritten in the scan list) timeout=3 # If port_default_gateway is True, add the default gateway on top of the scan list port_default_gateway=True # # Define the scan list (1 < x < 255) # port_x_host (name or IP) is mandatory # port_x_port (TCP port number) is optional (if not set, use ICMP) # port_x_description is optional (if not set, define to host:port) # port_x_timeout is optional and overwrite the default timeout value # port_x_rtt_warning is optional and defines the warning threshold in ms # #port_1_host=192.168.0.1 #port_1_port=80 #port_1_description=Home Box #port_1_timeout=1 #port_2_host=www.free.fr #port_2_description=My ISP #port_3_host=www.google.com #port_3_description=Internet ICMP #port_3_rtt_warning=1000 #port_4_description=Internet Web #port_4_host=www.google.com #port_4_port=80 #port_4_rtt_warning=1000 # # Define Web (URL) monitoring list (1 < x < 255) # web_x_url is the URL to monitor (example: http://my.site.com/folder) # web_x_description is optional (if not set, define to URL) # web_x_timeout is optional and overwrite the default timeout value # web_x_rtt_warning is optional and defines the warning respond time in ms (approximatively) # #web_1_url=https://blog.nicolargo.com #web_1_description=My Blog #web_1_rtt_warning=3000 #web_2_url=https://github.com #web_3_url=http://www.google.fr #web_3_description=Google Fr #web_4_url=https://blog.nicolargo.com/nonexist #web_4_description=Intranet [docker] # Thresholds for CPU and MEM (in %) #cpu_careful=50 #cpu_warning=70 #cpu_critical=90 #mem_careful=20 #mem_warning=50 #mem_critical=70 # Per container thresholds #containername_cpu_careful=10 #containername_cpu_warning=20 #containername_cpu_critical=30 ############################################################################## # Client/server ############################################################################## [serverlist] # Define the static servers list #server_1_name=localhost #server_1_alias=My local PC #server_1_port=61209 #server_2_name=localhost #server_2_port=61235 #server_3_name=192.168.0.17 #server_3_alias=Another PC on my network #server_3_port=61209 #server_4_name=pasbon #server_4_port=61237 [passwords] # Define the passwords list # Syntax: host=password # Where: host is the hostname # password is the clear password # Additionally (and optionally) a default password could be defined #localhost=abc #default=defaultpassword ############################################################################## # Exports ############################################################################## [influxdb] # Configuration for the --export-influxdb option # https://influxdb.com/ host=localhost port=8086 user=root password=root db=glances prefix=localhost #tags=foo:bar,spam:eggs [cassandra] # Configuration for the --export-cassandra option # Also works for the ScyllaDB # https://influxdb.com/ or http://www.scylladb.com/ host=localhost port=9042 protocol_version=3 keyspace=glances replication_factor=2 # If not define, table name is set to host key table=localhost [opentsdb] # Configuration for the --export-opentsdb option # http://opentsdb.net/ host=localhost port=4242 #prefix=glances #tags=foo:bar,spam:eggs [statsd] # Configuration for the --export-statsd option # https://github.com/etsy/statsd host=localhost port=8125 #prefix=glances [elasticsearch] # Configuration for the --export-elasticsearch option # Data are available via the ES Restful API. ex: URL//cpu/system # https://www.elastic.co host=localhost port=9200 index=glances [riemann] # Configuration for the --export-riemann option # http://riemann.io host=localhost port=5555 [rabbitmq] host=localhost port=5672 user=guest password=guest queue=glances_queue [couchdb] # Configuration for the --export-couchdb option # https://www.couchdb.org host=localhost port=5984 db=glances # user and password are optional (comment if not configured on the server side) #user=root #password=root [kafka] # Configuration for the --export-kafka option # http://kafka.apache.org/ host=localhost port=9092 topic=glances #compression=gzip [zeromq] # Configuration for the --export-zeromq option # http://www.zeromq.org # Use * to bind on all interfaces host=* port=5678 # Glances envelopes the stats in a publish message with two frames: # - First frame containing the following prefix (STRING) # - Second frame with the Glances plugin name (STRING) # - Third frame with the Glances plugin stats (JSON) prefix=G [prometheus] # Configuration for the --export-prometheus option # https://prometheus.io # Create a Prometheus exporter listening on localhost:9091 (default configuration) # Metric are exporter using the following name: # __ (all specials character are replaced by '_') # Note: You should add this exporter to your Prometheus server configuration: # scrape_configs: # - job_name: 'glances_exporter' # scrape_interval: 5s # static_configs: # - targets: ['localhost:9091'] host=localhost port=9091 prefix=glances [restful] # Configuration for the --export-restful option # Example, export to http://localhost:6789/ host=localhost port=6789 protocol=http path=/ ############################################################################## # AMPS # * enable: Enable (true) or disable (false) the AMP # * regex: Regular expression to filter the process(es) # * refresh: The AMP is executed every refresh seconds # * one_line: (optional) Force (if true) the AMP to be displayed in one line # * command: (optional) command to execute when the process is detected (thk to the regex) # * countmin: (optional) minimal number of processes # A warning will be displayed if number of process < count # * countmax: (optional) maximum number of processes # A warning will be displayed if number of process > count # * : Others variables can be defined and used in the AMP script ############################################################################## [amp_dropbox] # Use the default AMP (no dedicated AMP Python script) # Check if the Dropbox daemon is running # Every 3 seconds, display the 'dropbox status' command line enable=false regex=.*dropbox.* refresh=3 one_line=false command=dropbox status countmin=1 [amp_python] # Use the default AMP (no dedicated AMP Python script) # Monitor all the Python scripts # Alert if more than 20 Python scripts are running enable=false regex=.*python.* refresh=3 countmax=20 [amp_nginx] # Use the NGinx AMP # Nginx status page should be enable (https://easyengine.io/tutorials/nginx/status-page/) enable=false regex=\/usr\/sbin\/nginx refresh=60 one_line=false status_url=http://localhost/nginx_status [amp_systemd] # Use the Systemd AMP enable=true regex=\/lib\/systemd\/systemd refresh=30 one_line=true systemctl_cmd=/bin/systemctl --plain [amp_systemv] # Use the Systemv AMP enable=true regex=\/sbin\/init refresh=30 one_line=true service_cmd=/usr/bin/service --status-all glances-2.11.1/docker/000077500000000000000000000000001315472316100144625ustar00rootroot00000000000000glances-2.11.1/docker/devel/000077500000000000000000000000001315472316100155615ustar00rootroot00000000000000glances-2.11.1/docker/devel/Dockerfile000066400000000000000000000011001315472316100175430ustar00rootroot00000000000000# # Glances Dockerfile # # https://github.com/nicolargo/glances # # Pull base image. FROM ubuntu # Install Glances (develop branch) RUN apt-get update && apt-get -y install curl && rm -rf /var/lib/apt/lists/* RUN curl -L https://raw.githubusercontent.com/nicolargo/glancesautoinstall/master/install-develop.sh | /bin/bash && rm -rf /var/lib/apt/lists/* # Define working directory. WORKDIR /glances # EXPOSE PORT (For XMLRPC) EXPOSE 61209 # EXPOSE PORT (For Web UI) EXPOSE 61208 # Define default command. CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT glances-2.11.1/docker/master/000077500000000000000000000000001315472316100157555ustar00rootroot00000000000000glances-2.11.1/docker/master/Dockerfile000066400000000000000000000010701315472316100177450ustar00rootroot00000000000000# # Glances Dockerfile # # https://github.com/nicolargo/glances # # Pull base image. FROM ubuntu # Install Glances (develop branch) RUN apt-get update && apt-get -y install curl && rm -rf /var/lib/apt/lists/* RUN curl -L https://raw.githubusercontent.com/nicolargo/glancesautoinstall/master/install.sh | /bin/bash && rm -rf /var/lib/apt/lists/* # Define working directory. WORKDIR /glances # EXPOSE PORT (For XMLRPC) EXPOSE 61209 # EXPOSE PORT (For Web UI) EXPOSE 61208 # Define default command. CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT glances-2.11.1/docs/000077500000000000000000000000001315472316100141435ustar00rootroot00000000000000glances-2.11.1/docs/Makefile000066400000000000000000000171111315472316100156040ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: 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 " applehelp to make an Apple Help Book" @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 " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" .PHONY: clean clean: rm -rf $(BUILDDIR)/* .PHONY: html html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." .PHONY: dirhtml dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." .PHONY: singlehtml singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." .PHONY: pickle pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." .PHONY: json json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." .PHONY: htmlhelp 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." .PHONY: qthelp 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/Glances.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Glances.qhc" .PHONY: applehelp applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." .PHONY: devhelp devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Glances" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Glances" @echo "# devhelp" .PHONY: epub epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." .PHONY: latex 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)." .PHONY: latexpdf 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." .PHONY: latexpdfja latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." .PHONY: text text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." .PHONY: man man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." rm -f man/* cp $(BUILDDIR)/man/* man/ @echo "The manual pages have been copied in ./man." .PHONY: texinfo texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." .PHONY: info info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." .PHONY: gettext gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." .PHONY: changes changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." .PHONY: linkcheck 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." .PHONY: doctest doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." .PHONY: coverage coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." .PHONY: xml xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." .PHONY: pseudoxml pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." glances-2.11.1/docs/README.txt000066400000000000000000000005171315472316100156440ustar00rootroot00000000000000Building the docs ================= First install Sphinx and the RTD theme: pip install sphinx sphinx_rtd_theme or update it if already installed: pip install --upgrade sphinx sphinx_rtd_theme Go to the docs folder: cd docs Then build the HTML documentation: make html and the man page: LC_ALL=C make man glances-2.11.1/docs/_static/000077500000000000000000000000001315472316100155715ustar00rootroot00000000000000glances-2.11.1/docs/_static/amp-dropbox.png000066400000000000000000000711311315472316100205320ustar00rootroot00000000000000PNG  IHDRf%g6sBITOtEXtSoftwareShutterc IDATxڬ}gTZU{0dQDC+ajWx kv1?!%1sP٬7R3FRrƹǵwbK-v)%g1T[Pˀ1Drs`jEA(Hy@,Uк <)Ğ8-*EFuc)%.DH[5v1{*|%ZqmO/g?EgilI/;`R+HJ!B)gcwMϟGT)EVތ1H ƌ9 9Id3dA{k٭q@"<%@x8Gc5]$@KeP5uRJI<qD {7|d2偬 ƘѦ]+H2g @KYꇂ3 ~T,ZsHB?5!~ʝ׭U14Gy2& I_lj zRd^0r\& B}RH3FO16@i~YU&wa 爈!F,_(IE:a2U;c&B7YP"rΕO&β3Y$pKJ#VD 2BH2ldҸyΫ%'8ș'- cXI I,T7ot832+ƼD O(5#'TwLp6.Ă#ɵm<\Ag)3%@) $ xsS >:`2)Bl*$)%4$_1蕏7a4:%~괅Ad*ͤA!*jWEQFH j$) Ð$YLU>)(pUoʒ%YūdQwxq:`) DGxf %~1D&4qe FpYdcD2ǥ~ >9q RLFGDJ WB ٌHP:N#L aDNRJ!EB !WjaO[բzVMJ-(Czͪ5ޖ FcS҃,׶4!%'w.Sye9稬E&741__ZpK*i-ĝb2=?}FKҔ%}d(Nmp H}ψ)s,eٜg ؉l|۲ЇN:aB.f6xJzUQ*"`jzWq#wTŅȸPtxOƿCS#>YPGW9ED/.2KE !8羟r*j$!7M)nO'EIKOS0*7x3*)BDoz,Ȍ*"Pldp}e6P<|_f(ްMum3jw)Z2lB{kv( QN1yS9 М:J iZږ3Q"邫 )$&kIIs1o}H(?KYho9gt-I$IL >TDgMjĢ[7."à@ImaWGߝh-7}3*xDg Rxs/MP/u`T47<\o]00UHNzy y~YKIa QrEqˮ "*sv3,/x_)ի:H&047QpfIYX[>4& (W>0gҵkwIrƍtےvvuQJIB/`BV ~`h"X4{dmu.S2X䃛j[ZnZ UUo _ms`H3]}z=^KJ1"`>7PD?^e-(E% )MAL!^(Tsj!Nq1rľN=:P趃c,Nx*TxLŁO3jw+䪢FͥG50ctS3b3N{3X>>Zu۟ٿ|l.IWj6bɂ[_ļrMZ:Ň^/[*.oݘ~ٴjQ3` +W}b 2`m;>UK׮ɽ}(R_[|9߾ֹ^r&.9cXn)o.[|tłUK T]w ٣v; ٿykw5,U1uU_^&䝥֭_v|ے$ G6\aI{Q֋zu‚+m3;e1^Kf_b 7_̝G'!D73Sʏ_5qƪCt h8X r~,{'OM[r]Y->\bǵU-,잗'"{EߌмgVI+5e٪K'?Ӿ&d_ Vz\r)SZ<ԅ VG`&oϝ ~ɯK|e}C36 ?O]0wv._oOKg}#m.:o-R>gϚ҃xdە/˖0"ʴi]q/vlPrm>yڠ|4y9z}yC6/Μ`KǴ(5Up T" WM0m^6s]V"un?[_|^H;`u/_͝^u7>$*zoܜ=Am+%L=oM^iW-iTiD|MVݥL;lؘ뎥8Kg?n5VwD" ^?<ӟN_jҩ/ts|{$,{݆UklWL^o|tKgگe90(ݯh\臑=jK_}7n;<8g|q]ι9 v:x>B!B0c"(5uǗlEVRxd֩ A&ָeeTqҞRKi染A̫*[6TX_2Yv /ѨmnE=+ݺgR<:mT^V>E?RF]E*KKM 61#N(L Ԃ%AJQ`DC$xo*bxR%4Ed:a4#9Y$Tat*~ZxxjX3’ W+b`{b3/t-viIe;w{93㽞tã痿HTxEz^_Ex|֫uo2y{dE/jԳn7]6e6%p{GnfQͯnI0 ɤDջ ju=nӾӟm1*>nhNrϛ+?3!?v4M/:* -}En}01 lt7]6g./yBKwrUsͳeZP,Q'7n?-S{.I-<2lXÍ86oy5n=:WQczޝ'_U2<Y] HCv|nWǜk׺ۓ"B=Sy}[s>cw:egR}}zKקj: 0q^it{; [rl5ekosm6W= ,R<#-'di(sc݃o=^jd:YrZmcڗ;i٢mG(zt*[e;=7џ~{ jto7=gݮꪛ+Gܾã0jWgn뮎7OiM;hr̀k^֠ewp+MN.wt]V!C(ۺWiQnzYO}z4Vͯjʇ~9LPzGq__폍>pðTȫ|AWn{m?gr"0-돕mZT 6P7SDHGĠc8{{STLƘW S$4Ģe9Bh_n߽l'PjD#c+2̪W95^JYVf78y:Dr{lhMv]Q#%i,_Gqzȸvj/+䒓?!lϯkZ; ;v^j-ݗ/u/ ^zە 83~yv/iπWذ+{.=ڂBުѣrZl?q4(>>]O2ٰ"MlxFЁQm;Fo_zم~ؙW ߐ);BDDm0r9{aKRspd8V 2wnvĨpm۾tǥo]vd΂o#ط=__;t jkœ?ع@τ j" WJWZw]z.o;'nTt?<1qr]aJŚ>t+wn _tˍKwo]?8a6(l1F_?Dm_ ?Dpñ7O|cx+ǿ׭z8|.=!%~=K׾+K&3`9t[ߴ't [7.r/}2%8?O||jEv*gׯvu% XEmRMg_8*FTdON"X`/9p-w[3vXXX @ZrQ/J/v$|+_Ζsy[KX7s~nz͚]7F> 3<ޥC¥6DM>p: )r Q$DPJ7+ȩ>'vG(-3Ĺ H2[BXrw":w˱D%@*2²{2>cq/Θ~,erXцw=NS74ՇQ# )޷ (ZrϪ%y~c+_ĖWjL -3O]0E?#A~y7Y" !%NKQgFRJpH! &U}!@DV N<$yy٠ m/[FFν5铇1 A"oǟG.R!m}ϋmgx)g5zگXiٳW'rdUYzܲnq?mAqPN@Ұ1 IDAT2s1pK/XX>>pX]}˳=&o_wqV߼aWc &7Qt;;mE oNÏ헬mg+{1m;a/]qݢ~Z~0W'A2 /0f2^UFC5B#2MC>EH/DJ 8wDC8>FIq x#\aWB]\Vb~>[/MUmPqTNQ1Uoe٬. !CF A]2cL&oA#hB"#Bhʀ;"Atǣ DPThO>KDdREm;0)%mCD")J0Ltx@׌ض|3&|1kďl1f-|͒mDxRwϞ?p*Ҭ*:=@"0UܫȲ:,Iޡ)jƅ?b FnqJ`W-&sDi=ӉȹgPKߏ h4o&@Ph=G"HR8rbm~|n:sqX+*gE')20zg+UZ#@dE-<1G$UYlǷ-nO]nv22 f4~u+$)z2+j D"Mici)Iٻ?TY eT[:ypiccY S9|vOGKG1. / ! fNijt'e!M'^ڨw!i@knVnǔ>Ǹd$O iRoGVNw<0 ۖ{'QUL66TۧMZT /Ul"0GJBXD|e 9yB1/QgMbdg-cQ+|MXOSac[Mb_iA@YzgYTY;L\봐(YtZ{J%rtoAx~o-t!jDqjУw]qկW[.<0qDKRv 0H]%!$D(IVw{?r;pI*ݧFXџkVDj&|bNvΝYi|YiU:x>g$wX eMcF~lv`i 4 / _+YC'"3`@g|ƙUU{nwtV^{o$څ6JԑRH2\;-/)wIuL`FKԭ]dH1%jB+"~ I{R3̦C?}7\Yf(\8vܼ:-$M#o Qj_sxB,Q"CwYߘѥnvt<:8ԾXk*HOOpV~6=a/?ܲN*5/o}grΊp`7_b7Ҵ퇅:5ng G7U:J[޹.PEf "HC$BJ!  #\!a C* pBKH̋ jI8OiXN7{{ych- V0GDk*ff_Ƀ+7w08w`Ռ>ޔٙ SVq[A$X|'>xw,J] ~ !I~C^xbbpv!6Ȇ f>V^sS=wAL&Om'?ܖ^{i.}+G49Ǔ Gm=╩KqXf`u~ge?~ܾ5c [ e;mDճGc5 E<P^2uk{0~ʞ@Dޟ~C>{>g{]AsfE">vZǦ}֭Jis;߿2?G3<یSOCj=6S;N_,1wy*dž|#'v0.ld#+궸B!ѹM<>(>?E2H/}UU`y>|pt_^_4߽=|k_~gN̞:q{. @xEدj>?Y|Tn(Fx)qd-NYtr-ʣ",(,+ {}Yi?* &:͇L[XgGC0,{o?Z!S[~~9j2?_N/{WM䙓WNCd>A!^ Q_4s^|έ{G>wQ?#{GBy#g2yjۜGo;/L]+]ۧ/[„HK Z\ EIRBo,zE1aY'`%IsqU0'ԑxR.-Wя[ޛ $,jyu<0&m.|ן4Uȯ KaZ ,oR %s7kdžSBi@f0;oiyy ` ŭj-&""@Uæ>y}n HԂ$pw <'|ɤ0/7׳`)GCp p8gx36b ս"(? 0L}ޛ&f4M69xD]2bCTnD:75YI)2X24H|!u+ cMΌ=Bpa )@Њ4 2&֍1%UTN :D&jntm[iRY|")Yg4iRE_1ybr,: #eKJ()Z5mI#(u@3"F컈f Q(M9( '7H܆iW\ߪgQ{! !VEDS#M tIrsڡi %y!RdelS\E'6A gEezC;m$-LtYf!#n֨wk ztD)ݮD9OKOɤQ̯[h6`xAN Mh CCs|ލ+mٓt4wGK.-hi.zf:M,v/` p\&obg(Exȗh]i`ڝC>V]t&PN}A j\rlƋKHEPgw2y'䐅qeZ!C{2$Q |O^đq%=d]pHuRqtz`B(  %*^Qz.?=52q֘v( ̠2Qݣ*9>Si"0Bt1F=GR?a8WsS b1qRBAξ%;8P`f'2Xt #X4F5ʝ :;1#nz185c5MA`yfL_* z":$RBC !d1L:-Q$W:~cUg~vҞPIa NZy,!u[rs)U6[bnXF BM(\whB Q긂'VRV(H=RX]!SPј/PJ|`d  -*_׆ǽEiHa= D@9ҜFY/kէ Y2N˒|X# J;ZvHLR,|bp?_%D\R.v("\Hw8B,,WC!#L$o H"YIRuoo TFT0Xdkv@!qX%ـ־!D)87F؉6.98% uxњsYCU*p@DB "4t<$θ$"tgD\]i Ðq.MV" q>$J:1EQUMȐR&c>LsD,R"j,ϣѐ$S $ )Dh8<"f\UGGXuoҳN*̈́`s [_dt#"Y!gyܩAD.D*FctS* W6alfcLLŴ E?IM/1%BАk)%vL]]XZJ-MRM;3-B,ЖI֋ةrdD5^ׅUbʠK&+XnE'l(#)/"4! S`8rqUE%bG41G%}$7#@3Q)% `#X\l2"KSQrH$-P{Hۨ&Lt1M;z-\93n`]ԭkbcxny59W  !Ӆ7_J*ՆeZc9C$e8gAiqvc(Ƈήlg& \H- R!UU:R$˝Pm5(R[&i0[&@jq4aFyvKuMGoyVfwEq҃BXlځV啢ts#l*KK!LqLZUގ1h8z眇j t8H5Dj(83] qZ>AI fA+}l!MGhw> QSW0 oF'wQ2 K-[id*$lLI R׌D ,0ȁI1ƣ;nz 6Ix\gD$e^^>c"0ƹ둙sA ZV4SFB)nFr4ek*3GqD9Tdl&ƂD*pkIJ +/ZQQ)Skșs"T ĤTd2q5CMє$"C}h0s&yJcV~ ҆-2F#?R(dZtA.+AAj(] 1 JѼXKWE5 Ձ*ZXTƹyƺf: g<4C5aϩA 1''7TeVLا*d%5Z>[9[J,@vJPZS`E6SB ].)졨JdB^cs1%oh U|Bt!b*Ppᖸuj._0 |;bRk M$|C-\nrEz@70x\@Ң<35)OPn2QI]RjƜ[v !}Wm%٪[ 0By{>G@kvzl u= TWFhf'uh1Dͨ&b3:rV H)&CmAfa FL6Z['WG[$Z[j^4ъRq4SZj&f!r|seƉKJ \yrgBEn6}Octn>!C$rsssssE(jBBFRH!}Mx{sƘ" ;?Rdu\6 &QNBI4x%#Ҏ1H$G- i4?cte2[Zf#I=YJQhfi$XY`JcI%i֘ԵOa23[ODkNN+dM9р$36/X$`S jSC+B8Ԫ1)wDU~"!J*0F?I)"y^zz:< )BX=we䙴w{<{BR*# :S} 0wG͋U*ai~zrt؆hꆶf7Eh 66pC=9V4Lhz2gʼ1Owzp,ަe*; xkse}D͛.mIƪƫnEo{~/_$ٟo$׻>K{i_7Wi4mӷ#m;Ү3#ƈw+P1>^v޸^{E+_}P7o~o|>YwWwJ-9s%t_F 9F<yzz9㲛zX$SKO݉{#[4̉YⰗ^:M KZd}?}ߊ.+C>Pq% )fbu}[}iYX\bǿ n+g%$`plݷOq ]ѡ/J:ߘU ?`~~)ڊ$&Czqۺ%nJݸ,.D"PH BA9xd'gķ$ Ljr$ιَ8DU0DBuˣKĠ۫Nyw>Pja33b ĻHGSEK @0BnUUn]g0dR%d\jU9c)B?"Q0vv:A h4ّ) v:/1tW揊٦Z;-A !!k8*QmKYYPDBERFPQ 4 )o&̒e߲iK) d^y]Q4;}&.sK!=oj\xB:gWqV/iԇ7]3_;bHݻ_hKcpjʉ |[yNxxrfj;l9Dxו2#릾5_RJƊ^scf'׏|t@-㾹*p?_@ZvB5F<ӭI`/_!"VǞgJyq/:Fd 7CfuEZ d]FG>W{ pۖ5 byEԼG& lOeiẉׄӫ>~u%%\PQMxxqJ7l;?t#/kEswv )𮭇"7&kHٿvڕvx? lwi7<һ6`l߶n!IbUJj)iDkWPFz+xUz?Z} ОϿ[itn΁c6s|~{%u7zdT„nYό^u3':G@8`7U+g[37}U]E~ԀnR߽2b_urRAYRu[]zWW^Z۸7'|Euzqw_=g[jRoSg$43G JFz|dgJ 6f枤$ɋ:th5cpzϪC~-`zLMQ˲oz喞Jlǟ~Պ%ĉ&s$xol#[.~͗]3_;|A]O+wT[z_+*7LO+RӠAQSWML9xV?lkLDNIAD{suWT?tyt=# =;M:UIJѺx8H{E%MZႛ~fN&UIRI!Mu,XWptk1SFUQExGT|Kki HGvK4҈ZaE*,W1!CKShGkRϢ#AKoׯ9U慠0mnw*Na|ϯ=KFOo廌lYJח54쾧dU6+wuɝz\$2=9kz凋6}d+yB4tzU|o׎euLSad F<$df.E@˶:{)v`GTN?xwoߙM~契't-P ;=4$ϛbKonB֢iуsL'UXdոܹ-kNmy%؟TP6IIXn^ĊQ,"8y8G`TQ\Va HV+|EĹvxf㬰ЙJkCHv9]=6,z>oF6o=6GynΌ7~;܀Fz3Y^Y ): U֢% ֠"B "ja\^uHFWW)j̈*d|~gqiܯN*ʥSNNR(wBh8ITJ'[SqDE$90 f0{ukf>~U=\?k|1t*uu߿f=mG^jjvØft~[Z6e}˄T3M|@:V}󓮟vq9=tѓq'r /HjsҔ93nWP-pʃo?qV|l.q[k4aJ'x/5/U瞙5CWIo=߸.VߺC(l⡝yU]Wiy')5֮l +',FG F$m$ȁ2\>!WRNZLtl [:cS; " (G-# A%#b 5Efs^%#*aj %P#1` Ai*˹ŐpmৈOA0?.p>% {?<}ض}hCł79ѿeUB߽U}9VF)*Vi/G^[1Ϟ_ZÅGZ23vr8OPJ0D*{\@ܻ{̯ Vl?lݘ9Q"8?9okZwCB ~{tĆbf7_DR5 .\N`s{l!4+"!krN1~odkxȎE_%_4RڕdN3t jX;{{Xͺ@j\j9{`DRœka|no͂h,xu?5YO/zd@kp{aMCο߸bζ{=TO/(_ Ժ\I8 y{漳fw޼뮉]-E7Z]s/NխX"77'k'QFe_MjyL8K |AXrtٶuoN.o-Տ]]~pk6gT9Vҿ'v̜U;}8=>s/<^ 99?M\Qؼ;7R^&0 9Q31EEb9-f#3p!MzydY i MG5a>R+0.FaX:ᤣzP΅):=Vx !AzI&MŒ-0P-!*yDL4*L8lYb& 2E[Yd*#goƠ*\kӏvp6K(ss@^(>ꋣ˞teͿھ[N\ F .tR]ɡ#:@p4p.C } A5'JzծmPJwSƸ)FGL$6w? %?"ZWfSW(EgN`Q{,oSqɽPi_9C;{oѳq3-d#"\է~|m{Y4apzՄ{ynvgaJw]FjR+1ZSˆm>=C'^Q2Qc_z؀[syR*?fW7QѺ?rw3}=SF/ Nrg(wy^+"ZwkwϘ8d>i{woݱ׭52 "y_Nx`{wG9yIl;^{dɳ+WvqۮfbREBfDA'L(bUbv_g-xݽe?|qmbXʵ22DUY?Ke$Hi_m'bzkkM9V^p~9,byW_Sl2Hbߢ܇bDvѨjSDH!5S#EjQM0YEE h$K!4F=tUa>tU|I j +͕ڼ*MB]Y%jjkc,ߪWnV8{ Vn} B"4UF7iaQEXJU,MR<-fׯĝx.o}UփE;>xۗopw=f3<[v*/?0UT% &@0WGp.˖s*%ڔL7Sflyۨʊg~iV>p/%7n[Q^>{l<+D@T[)Uo~~ʵyE"N?ydN5] 2S[7oS[PD%uIw xy`o**{2(@Dˇu+3ʧ샇.H Q7sIhatJjЩe-_u}"~d kmߧk aŀ ..P;ҵV?xT! ݤ- w׾ͱ:n%'1TV'>|+nۡmo: ,hX`C#8/nvcMԍYp-×*1;[ws}=lEN`e]N9\M~~>>)i ""^j߻vݳ injoOsֹxR&b1I'@<Јa^{`ǧT$蹾]vm;t9ݯL`]*Tꖆ@Bf)¨vb5$;3q}H@hЖ[&hBrT6edUk)́/w:i$l{*6C+I{O!֨>g㧋_7hg%ͻ6L1'1Ɉo2u'uPA\Pj1IZU .a2nEG|@hA[1xX̋1~f5>ik]PUkRؗ/ug-zA@1#վpGb@DCV<*+\Q2NRy–(tgKD. 25T]&[Ex25Q$*B XFYA1 "b@v5/k7U[D#% mb\`d1ݥhT,j @zB1Zo$7k# QORGٶIj5w]Z4m/dMqgizZwyd78SIH#gwvW\EB$HORkK})^eg:<;u୍j׾溿Vxy㸎+}=,NMKeZͯmPe,b\ξgMMѡC $G?Xdž ?GktbVFC=]QUUԳڮMn1'~s'XFM7oڬQds>@!з{ vn;DP]xަ5 ^~.^s\ﻬ\&ԯ 7mR$cG>uE>)"oWu&5j7wUn'tv}eLR7 Nz>}jwm >MK6"0zH+wɌ.cDtK{Wo >5kkM┫:Zò_8PxOMkx;k\J&j|`nyN/ɒ-IMd0mX;ois 6o|uwL$bRGٮY}vv%٪IDATμ ՗rg@; UE??KzӳGNArM;6jUޤSg,xؠKZ)1/cȘp4-xI {>ѫK'PaA[%Œ<$"57MҿSOMu]{שZImR 8}|2{.X,D֓=B yIE 45 XSMgjJA[0kH3MJ>dX^IC4!sA`Ud2,܉휑g7TVUJ!PҹC9caR^ OGt@FzUCZ(eFłsTZ=: e!h"sg>gVnXlNjvWf:FHg,)Iz^7g[J0r#P.xѮ_zj(ڸJQe6L5Nz=I# ?S'79qƉŹ;7|w:h&ŝ?yqiKAI~/*Y;J!f`̂zMWrij??`<*cB3ɁQ״1, v:v80Hj"={λțﱥ L =13!]7%!7g{^oI~}R%.ߺd[E O145љyTppӂ !}2?M?Jdɰ;uߌŏ {CplO\ғjr$+6aǼХ$ :(ܳp=?~ߦmWƏ`8(^{y;nxgMǫ4~fuKD iE>T.=V#A:U(kߚ 8 mHq90q6z7|>9sCɤDw„A`Pǐ5[X&UwB cE/ʉ]eZ0j@);<%㋈\ybP@W ,?Q =>d-HbQЩeY(L1Ed򨌿 u}JD"c Bpp?ND 4a_ʺfpb(|dRENGB S U48셼B1=Y?0FI:4O^ RaMsi@ 0ʆŸ 5bE"'wИKUdG {iل{"'7kcDڶ ]Z:ҚRVKQѧ#ޟ0c|;0Z.R!<@Ґz>DN#HlOA,-(cBc}Iy|e)ln}b%@d_WcMNݍV>eƖW 8L춙O5Gr_eMk lpHXˋ{"cLL &0t$:Z:K$o*PLClp .@ tγ*dҙz,̚"ׅ'l'ʆcBa]:?t*ӔV‹9FF\s$‡!*]'ߦ&qb,|iB!"Ńe3y!TʴKWejR<WrIʹsq=dI~YQS?s(-~D F, md#1(&ĪHH!YkPtb lZ [Tz JJ7WKCĕ!ĈMr~d,E3A@8F(⌊_dvSV(?e8 V*$.`HNԖv9j3!1.c, aKTȅPXbĜtCCIVw! 0&8)+MUX>;ÌVV 9Jwch8uhLd4`Ȣ .aiK!#y u%0QhĻa9=&dch(::= ^NaV_:\2Af !dq(]'2LMC0 =` -sA:he R0 HILDԝ]fI OiQE'e;|k(b+۹Vڙ^ (@8WeoT9q-#56-jfItrI-HLSDD9&ošP2f8k <8~j& '&#h*iwMHH,(:$cAYgYi/|k2ENXBbeFB$Ψ4!"`VJm`%Fh뚁h {׺ZdJ"?Q(h}JR4$!>xz.C:ݭ2&DN0T ЭǞIENDB`glances-2.11.1/docs/_static/amp-python-warning.png000066400000000000000000000224021315472316100220360ustar00rootroot00000000000000PNG  IHDRhB"sBITOtEXtSoftwareShutterc IDATx}|yUvUvg'+l,Ġ,! 3"  DQ0"JPёU ~!+KCL;['餷{S5ft}sT=SGD 0 !CDb-[kSi "!1 3""XDDDlVHQ "DTT,Kk{(1H-[,DQ܍@0[k]9 ۹~Dܷ WzDDau@DIJpEpq  "nEEoE%= ;^?~^—_5<~u"W+_2pYgZYɘHV(m_ixYagZ#a31EQE}}ZE!wf@D_ Pڲ,- C"""ƘJBHmZa"c g'jjK덁ȝ´a%AJKT#h13"0}IoJEv@w[3) "o""2$` Ėo6tߓ {$(>e~@z `$x-iO뜇A0>l/B$qF!}DOw!B} !#"atˌ &wZ8DI5#NfF[;nOP?)uSGc\#A3TD_]Wp%HX\8xe* d@QPQ8H)0朗 1=N6$*KFEY %e#'Qۖ"!Hȫ-Vёu7!G?qGArֹ7u(Iay"", Y؟1 2 3bLևV2 LQ4e DJ 9RHY+-[E>qHȃIL$ẇ)KvД!E )(I=Z19(#l"#G2Ap' W+DX !# 9xJTZ6]j (ul5'݆F4> PAÐ H 6.-C`Z$xPwNpc6AP4(l y/ zh/T|-qݕ\p&agMj{ffX.wffm6roVZc  p;"2@$jZLGYIJ6MӇnJΡ@t81\" ;$)ޑ !t b"R+˲V>y+ܰCg:љ9 T|AnDa9 B D*Ly@bfMifKR:@) H)xX?LZ"Q2&IA$/e&+7DaZiW.A#"[7" MX Ʉ"8,Sˎy11iA߹!Ԍ!zٖL,q. XJZt g~QC=XdrU Dr*+<>7zO:]Wu ?ˏwYBs}宍+o^i-G^t˗}胏9g]#/z^O^yK*gPA#s PFv~y>WEHŸٟg?9k\#_,yu7L9}TS/={WIbn)%3""c K4&J8(-o4NOآEOפhM9o_Lm?عK7qޤmK֒ fʙ~YOmWL[wۀކtE̛5}^fC_V"T_q3۰2 y_ݝƒ֓WU$ʎ Fѣ]~"B !/Fɇ*<#C$e#0rt% (/$,$x y @!^kR=C>h(RK/FQzFL;ȉ{Z{nY6iyŝWBNXJ\$;a&rNvCOŋx7Q64L/9u w\<~m[U\O^/-ֿ7'}^UZ{aE- A%tfSv;{Sϴ9*SRX[T#f[۳e k#5bWsA fHCW9ύVo$U*n6׼ a8.ymƥ ~η઒? gG _X󧎛~s޵u>4q?~7ݯ#g5d#? E0~9ߘy寯9M7 m|W>3\|:k>j-/x [1D rgR,J e[9,HId7TJWZI"aŢ1*&L|)$lw6?M}ǘ KbPEǐУƮJn0rD1uܴ;6o)7UqF=d`v 5r8]-AU(w|駼+Yw}Sbθ2&lYU-;w鏛N?+s.^ 5h{,且EHA7 Bf" iymό{ϖM}Zf- W-sيsUҀb^#aoWW K Ȟ%4C{E9@(S?y>H&&#(JȹSjP걃DĴ[ yΖUMTA,&o4M]޵+׽N ׽zyNma#G4Џ.&)l4mՋEڱR%y i: ۵v.Nu$$[tMRiGH[_}g,1F{!GEܲhB0Tҁ:vL t1?:-@., l0#S6N9lVm\yﳵ3nW{t׎3aXתjS[BR& ,rUős'Os,_̸$Z,r4gfӪ[K'ʤ7<*2僊2^A7 xTOT޵竧}?6?л0ç\zzB+1+)Jh?pǿxlI `߷rϻ˷8uCF ~y0~a>uر]_|v( c xUKyC 2Vt8tꙥi)/ѹcV=؂YgO1ul}A$MQ]1; OiK/Y-3q!gHKhP r:ȴQr4b1z5? VgOJHtJu`&TJ 2v\Cs{/&HÄOyJMfeeϮuo6?AYgMh_ζ1RpgK7U">m,@5[JA޾fkς{3qckmOw PT B-ȏ x-e<xt@IXGD'xUX0]QCT1֞POTXCT} GDk]׭6b{l Bt}7Q@jAP0F^3 s iOY5|ٶ]<SFD-nS? .=ehzO<>갋!Kv^WdY{ N{هn]6 ַD2[[,|q x۪ݳ`Ux)KZZ\H@(,_fYXrU[`Ścc>!,!VA"pD'./nM]ɮz{V*aSxSt$C)O^h#kj;w\S9 Wn訖h H d=UIoUeIJ"B ւ`ZS1E !a0z Q'sAK-(<qB!ړOLd`τ5 w>upjavZ8вqy'¯{Q1"#V:PpYL?a+ȋ\6G6پ%piz1lY8fzEtU}T=[[l"8ă[Ic81jW7-ыN>jꗚszś嬅qE۲~KmpcW5:ò,U !.DN|N@l XkUobg*Hzlfj `F83Col.VIL˝;;(j~`$D@vPz~^>+n:sGtU3ܥ]>ؼ\V˫*ᯨ֊Պm½m:;V7ﶌ`8 ƽ()[v”7mpŒa-sj D"`قaJ;U u=uZ*j!Mb#d"`n\XIBw\ F,tdT@Ib]9%je9eVM+eu\Ҳr U4ޞa =}I!IU4vcBwaD#M`al>,+|\zk_Yٯd2,A2 aR b$Ew^~h`"VielGb/6![>v0nmUGH1ta/ .W;K&.eGOokCw GLۦ"ѳ~?Sjز4nem_~;bƧ?7mOu7α]׶y/o4M)e0guA[b2ÇHBxʑsigAL0[@<݀6SsѨ,-$Y~c3hҌиy9y˛Z;&~9طythJJ]Ga:YEd(]͏ z.喾Q|؄??- 6^oS?ڽbO> 2+9g[hd2[xFSk[;COZokѴ΢'{Փ-%""wgri敍8usFs.k~s lYڲY(P WgH\2Eab "M.TEaMS~̶wgֺ70㯹lzۗ? 9dܴI#`i?g֮R*M꺳kƚ03lmhSJss[{/ 䲴V- Mu75'}m+ZBT}}&"ȺQgtwGx̴)Ӡ/Oj; GA|1㙞L)0(U;GL Sǚ_Nw8ʔ(Yyը j!DLMyI@c/vu =ᤋN;ذ>z+$$nP0N#)Ncsg~#ܵqœJPUi (+~y 췏 ;o3Cycp>Lα9]]C; %\쁛_@6>i?|vNJQT*Z'r!J݌$ʧ5uٕ2iTD,KMabW%z}O7"SF-]8ĕOX  0 -mZRvf 6(#S:vuB]Ȼ|U8]o{`cB;;93MH`O U AVxG9e,O܄ي$m{jrv?3  5z*>`ei]?8hگ4+O~~JC1=|huXUfVݖ# M8n:=d&t(`  󱐨b Yf;9p@:Tmܔd4t3?C\:Ec8uъeQUJSR 7(l=3ԩ3 EHPI \~!dC>QhդLCETcTf@{} >!pb| n,Kt;dW`] k_ô7ri$]˹dD[EFI糬3&6.F^) -ΐԿGFb֪5)p)k2pE)ǔ(c ߪA$Ww>PvlJҨ+ADpdꁒR b*e\ 0t#fb9IDAT2>dC7FQ<֡ $tGۃy-@P=NL.EAxAlIN:'aeiGn(-Fa=p@FWI=K i$ػ,DREeԕRǽR?H`ur)kNq)vGI\XX=cs#8hD"@QZν!i9o@" 4Hjߐw)sni|JI2B7nA2]|am5Ϡ18wj߿,[ԏW~FiZ 0hd~ `&T-g@I=i-֪{-?%D0dxzͥ }DtXw|d҄AB]ex7* lf/% : 8μ # 1*/p#vŤʷαn0/d$Ow'fW4$ZWЩL<-FbƬ0IZ8%jkK#Bu w [TSYΧvzV0ԊW\wcjyjiaMvqM=O;H,"D@OylSd.U:-u ]{х2hDV'3F`ac^Ɓvˬr21"JTt]Td +if0l)IS7IQk~Qk~BNax"$B^~ffhQ(R<-1!:QgdrgĞwt z :S;:ts&X! -.ц2[4&9 | d4mGg{GJ\GY%2!u e#<|֨ ̮Ȓ*2,a 6lE$E$xho C6yf;v؊*j!bjA;WDH<MSNsU}* u~0_ L&?~|Y,J]3 Nv0/{$4AD"y'#Rx)w&b*ldºl!."ԏUԹ`K[+KgB3<0r-o^7nn|AIENDB`glances-2.11.1/docs/_static/amp-python.png000066400000000000000000000222221315472316100203730ustar00rootroot00000000000000PNG  IHDRhB"sBITOtEXtSoftwareShutterc IDATx}\wձ~[X" أ$bb4ƈJo,+\\cGc0Q"5zDFc) m]v=3|M~ɲ[Ι33 #," ̂  lfcL.(" H "b-#Z*"EQQR,a0 !Hx2flٲ """7BDq7@"q"lewq:n" qߺ7@^E"fYD6#" aApFT$숿Zx tA#rX1,,,Ɛ1: ,oPD |Oķ@BHDiM ;B$q v01d)( @YX$ {hDJ[`a "cHDDSTɲVk"Ld!DTVmi1S"$W~o1`fA$a/8M莾[{afB4EAD]DYfg0M@lY@F;kC@=_HAs_7 #~R ^n%Qp& mˎEܙLg!O>AfDe<^֛Z"xdfd @KCb ?PY1q4{z 10>?cpOE H9w!UY2*d-ʚ,)C>ڶ AB^nBntA >!|;Fȭ=EɃ`y2ȠC0L 0 5^P& @%n\~b] u:py&=E^D|1 $4-,v@)DG9L /aaJuhY$`>\ĵrFYHfrʥ)C5d'*.`FPpWș(BDZizX #.FBOb +g>6LY )"gHhLDqNGF)Da9 ;I_!H X@DSZ1PAAwg;?>G6ĭg0)<&$*g M@BmgwAt(h9$ OCM<=$sEuZ#/) ' Fafc{wPXC#OkQ\s3;kR{00r33kčxҪ$%MT1h݅1"AVb:"mh>vSrͭ0Du-aL% E(H4PK _ZYҧ_s^ޭ_\ _G"0:3S!/Ս7"X醾}A!HRP`Ay` Fk?!!PRvǝe `1/ƘR1 5~μff5@xx}d+2G91B"t/y0-)h Dϩ4E\fn.ޛyk|o?嚏v?=.u;mޙh.z9`Ew<=$1ˣ˽-2aL ?f6үz,Q.KT ? J=/}1k/)dx3*9YI<98ԟx1PjwgyqKLC+4;g~yƬf~e_sIlg Hwz[@2C +')3'"!c' ).4?Ϙ?.e%&W'w6]eVckɘJCC+FCD>imN{m [bi޼'N\1zgo2oKo[oq覕Oxw>u1wߛį!g2s䠨/8)|k;&"n~珡i1Ξ;[#6 ;ʣG 1a 5U裀Q շq}Pg?Pa!CDmCu䑡3:ղ@X9:]W Rn!w J6$!s@!^kR=C>h(RK/'y2⡽=b<H>% ojeWOÍ~Y\u3](ܿ3>顨UD@w:[(?oi ߝ9qqxѸ W}9ߘ4 p9""böG_:ve1EWsǿcg50MG]rR=';7s/\5 uLjVLQi ZԒ$_Ig65.dM-%yם5qa0ju@jkw/!ߚ9Tj904V9#9{x&Růt1KSK}~qKuFJ4hqBṓǎjqF\pie tuh_|镶I okw4Tϸ`[j~?Zv޲B]9h߃^hWN_?] 9]mڤ}"RS3F) % [9, )x F8J˾|#IWw^$:XTC F%ۤ/Ē-צ/sww۬piM+T1$iga &~MmK/%^O?z^ CR962`@ol_B\ۦTǍ?|-).ӈn$B&_-vge aOPDܯf{'"qk!`b4d/^zGմE<^Ͷ.[DkmV~G0y拟GJޛh kt+nͅݶ<&"8@(58CzK&֞U "iصf1'D4%Z?M_ר[4#6 zk+Zxh#Ȃw^k3︢ -\ɦB훆dte棷wg]MT0@c=/o1|~n=,~CV-ͣ>ۛ}ǵO/vC.{~eo64c[5+,#H)괋7&]BUcw'Җ^Z:f: B:/%^4P_ BHp:ЈfGLyaߟ~}RD$SPè8@3bTʪ_E]EqcO,X'nwrD.RD='2{}h)E0^+#:>r=r~qwc6[Y}ֆUr:1(K`kSRmWN~|9N8pW>pᷯA.9[;D._QۿI@l|>Q1Wn)vܵ+zJ,~iw>yJMfHcA{xc.?~ӴO+VWvItgV>*[;,iz@xڶa02K/Rjj}#@: G~Tk)%q递鱸N*z`88(b=+;)=E>o~zQކ7VKcΌ/k"e&HRQI`-f5{aHsIEx8D4K)ƒi8:Pq5imNǘj*" N m_,j|)~鋎k涣b`shEGJu=55nijeWð-[ ͹[t_, \Eh -*8cWDMW*Iӈ}w󮏾pAx|?k285RP6ssgn>^~?<}N%oWÍ]! ˲W1@9!;1`E@S>VU>쥵=qd[}6ZEg&]KʒjH˴ܹ󱃢&0b9 B}vî?<qΚs9v9ɛw,~7"R*ս:+BXm/&\yrAG6r۝n1Pk̕anl ڰ/&=xhd2;V,YZ.bK2d俎)1eA-͇ 5ZtP !UvVb+@((E$n4kOb[t|WϗX!*Z[}sų栃v< ,-FշYx?k0د_ԕV Gk`x'f nSԱ{%?t(S"!'2%JV^D5)ZSSupK֮s?7q˫lBA26J U$0uҢ 8O:뜶w/Ru'3PU֝r+soK0KFcH7Ozgy6ǃHiR)w9ɣHX2yIw-0l۷ߺ{_Ŭfj@CoEZ{2P!k̫T" X%oGPSSRDVɈxȺv>㞻G=%Ļ[1D@d ZG-r *8Y+m]}njXD+!adn~Ƴm GYSB(*NN@Df8.R&1 eb)L*DUF$cˆ%[/rJ*',q DL|[^O]DL6qM)RgzzTΕYwzceezSڑͩiB$]opPqANa%wtPrA;HҶ&+wi3㛠!ΞPf[Hگ)7 \+2c{AD7JcUA2#[u[Z?S(,@4kICȻӉT%b+r$B1Dd-sPFOc]rS_}xjmo ^6r g7Zq֡, YiJ 1aUҖ't:u#@9PjSm U"N$ Qj L.?nkҡAtjQP"1*T3S}y !pb| n,Kt;dW`] k_ô7ri$]˹dD[EFI糬3&6.F^) -ΐԿGFb֪5)p)k2pE)ǔ(c ;J8IZ)y|xu4 1bP#QWHd@BW@ttgC"4 #jpUi.vR۷?ؕ}3||(AP~v#Ab (u'&A"Ѡ[ $'24M|g7ge7\L!R.%cI%8c"IDATJoRWjJJ Y}j`(:EP8Y (JR¢&WZ3U5v-X_@QZν!i9o@" 4Hjߐw)sni|JI2BWUcut9Ad?^ܩ o.y&'ˬ jf@?LzZ΀|z6[8UZ~J*ѥa020esi|puG6(M$(Ե]&وwf6R 8̫0B*1 7bWL|;OX{&J!o SJFqwbVqUZIcI{ZQj).Fi̊sdS6$Y1"!T>p%djz*4N ZjTki"Dޅf`g]fm2B,Y^{SM&=pXگԙmiKk.A#>6]ac^Ɓvˬr21"JTt]Td +if0l)IS7IQk~Qk~BQ!blKdvxukP&EQf(J󰢳dDz"Bt"Ȱf=Y=Ju 2>Gl lڹd bj,aBޑ43 $D7pD}Q UW`T7D:Tvpj߬<El0ʧ$d1P٢1qf_jE2!;qϤtB}<߫ݿ{?$QRTW3=d{0wr,˲̬@$&nJT$HLYq(I*LgQe_Vf}R -7<v o{I(|pg9,Hᶹ%OoRn]?#bUT4#*haWGx/ξ V)"(wce?T}m|@= Fw&ϡw@ESEke32JiZɲq;R{]b[LR4* &&J$IOLد ܏*C QB3saTq(b=|(|0+܀bg%-'6>ʈCbc?DbdL^ O|bb(Hbej٭;Z. q %Qal|qt:3b92ڝn30E0ӄn@W߈#03i4M,Q#NVme¼YW#iXGT*{8(J)Z\(^_`tfݧܯπ5ۤ fDP*1/CUjKYd h*qu0P~_Ka,.^Ȟ"4Rهja> oxt_`/uCbJ)[ݘTKv(s'>Yf^713۽gwB6 uo1d%.1%3s̝Xd&%i$cY}ie|6*R%& ([y`(V8laI3oكjA{ĥh&"!"2pƱM|=,lr!8q..<^״N54qQTT6d?-Bdj&6:(CqmLĈJ%*iTʔ.igK\n q?EQ(qPbm >܍"^Wh4%Wbu/.CvG*c6y q 󁽐ؕRw31Z |! 1s!z@*Ƨf?m|h[IR얳_fOTS!0h&`"h*TP"dlpAU\l@SAO#џ!`JAbZk&8K}6Ae\\ bn{ O"2WMM;ˆx5/ h )" ?Wl2 B0?bͧ vuPLO  O{|H-e{s@B@ɓDd b_a @5JqQ|[+!`5'׫9*q|q1MY"QlH(9\+uV>^W"oCFH˝ψnD)%aY* J!2B@\N >lHZD1ܕ"*,2RH*LmB[B{nӶGRe6;ߣ^P4M^ji3E.VDC p@f `cдD%Zy<58aOɢA?Ą8nE52l|B$N+[JJ3 hp$s3j>#% ,$I 9dY3EA)`~Yp>.q RD34O}"!uƪZ`Xb 4qD@Q[lv ԢCsPolUjqUR`Q zCku~btu '=te‰m),B~-lO7@kIFo{|5]d]ZLf/( {|f FQ>0)1dȦY6䋖/K<*q̣̇qydȳ P4/+ P[LL@iFOȵ|i.'& ˛}Xg3pX -s3LT O|h vBye(JI&R؀_vC'A10䂴qw& }!90W u.ת"d0ʅ55ݠ^ p"T1l&u<&\AU}-y2:ykH-( /yz]|"9*9 ؚI28t}P,)Q ˯!25ACʴ6׷-(< D\cK [VRL)bOAw,y~y00fA=dt}h l9DT>6F&O<"bR #?]<`>%dIl(B6121ZXVK+0eU!2)L7D3Y%"l8@`A`*LD)dZaI0! .$)JRx5xS0e㧡Bd$& V-BR͇1l~N !VR6yTYbTꄎQC*! 75gr*A37(3/Hj{JyFmG3DfdYVy.lfQq5'ChZ;![ Yb >NE .a-7rhx 2cHQm:e[p _}4[3Skʢltfx5Y߉zl-97_ɋo}y`}3t|>{W@.'}Xt<g凓7S݈}{{_3uef#s"J$QL\_7ʓ\S6Ye=#OW&^n!Is8MW'o|ҥ? q/n>frS+ńYS qoy„ޤ ~zs#-N*8+.Xd _mJWkB aNQ rC2X1ye4wK1f\ ]Uo'cT3m %)Jm~bC֞`b1=uC{ kn77I2#s:PktT@U),ЈhL&&$yGDϻpjJG-}t& D&_-͒@a'&gX P!35^E-՗\BI~yZ mhgtٗђ yOTX`R7l~uɋȯ~oy73Ovofv8‰TP R*Sb\!ั4lw `qd޿/(DҾ8k;a?߳ϚL"&r2v'IC]gS& 2n8 d{6eo瞴͇_ 9/Jd 1 TU@V| TEd iuh &q8Oϫp:_E۰*"D9T̐vS6kuXUnO9xF};݇to-ю~pVt>s<2r`)=~]ʨMн|xndaGg|\~MU}-ND8(6Z3!)Ph!7bTIb(עme,`* nc=+Z:GC 2Y5fǎ] N D82J(A!"G}~frH'W.YKgeFd(O!22i׷׮-g("QQlo[u L?_=VTiq/X ?e!-ǐٰU}zޭs bz,YvF2D%z匷h=<vGS;.^Qk]T&b[O/i SؿovϲςrIw΄-7:Q-h ȯ9q#ԟtްq7U:up|Liu%l yf ;p4Ȕycs8/!DC%4Pu{/VF&PD!B_9OzM#^BLnU3UfO-xͬw3cVo&lݯCsݨ0X!;G nXpmiM?s=Zgf-ZCu 3'" @*C8C}~ODL\N@\[ E)P9LB<,:zC,34 yl lQBD,.57]!fwhWxDI]!#"ٳ21s:lKyemrPI F=\enjxwn^ɧu,gѴCwidݫLk{-~`ރ<3rn|C–ߞ-:=c& ޚ,=Fl[Sո#FN]M,yƇ\^sȈyoV%(xM;cώǟxa0f,v{W<,^}FX_+l 5,"J݅hX$c+M !$w+=7 Ucܕ`?+{SE1A`p=c!7+UYo8hmv7yQK;c\̵L4㹩w6Y i$ $棯>Χ:;onR( :ϭ`zADtȁgwdT^.{vLʑ_c|?9µI\;u i (ߚj/k]^-,H*/';ߚg)%p!jP@#uD> @ֹf{39y5<{ Cn9.4$Ub-CHK)b %)nEk*gOH+746usYٜۛ>#w;S=tϟXE 뱜f7yl~Q.> {cL]|9=yC-t]u ؅ M6y8sc z0߲o3tDۯ}}/βK 4IGM3^sϬ5Q^LiMALv*tl׷rl˧~z Ld9mNC޿IZkYa_@Ȗf`%V=vZ 4;\0YS[*/bh쯷3VdT"ˀqow>}ܖ~l`?``,YW7H͇~-b)iߐJV"*؆T"_rЗ%K,VK6Թ>5h} -OXu,j*CLZ0IXH!fujdPn  U.yWROu HhW#~rA/lQ rE /ı{[=](tH`T Tx`ZR.ҀNND@̻nzda^#b`ʴ$ M≣lF0g̟)mA11CwzS> .t{]vȞCf` ~ƻҀ0fe ,,; 0iD)ffUj]y0m0Wv2 cG3십ƪTHuRkpPf]8\BZ={Hs(FoRc:?ΞJ~{ K|wY[~m6^Ge^BYc8Aĸ7`a3b>V|aQ)I0bW :q-{#)- fiAA-'ap<7YޜE{66@53ҢOo,6 D|COS3>K:_:6Ks5xpi/W<@LύyN:rwg/jI|Ii c?""~Ί=2GN\:tU466 4QI/"'MYe~g#ؔzI鮖Er_ J)ddW\z'>:"ׁh{ӆ6S?o ySOem#"풟gWs٢NuMW/Y UaR Ri])g*UE=c;t%ĤmQHGE9'q.EF1"^`Ẕx9611Tđ"3vc/!N8"o{u5lR+:2a4ԳrlSbI4M9o76vas>eTlַ_A{1 W.SoL_AH^QYYr탳-HW#m"A@3V# h] lpzGZ!"Hs$QG("*PaH<̃5 fszi aHz7Č lC…|k}}Tf'gBaB [鎡}OoU3o$LLu."SQyM[yF޼&@([j8\{hTZ?yΛRyxُ~Smj EV50RIF|D%PRZ'_*IzWì͎p8⫟\j%AP7= WQʳ'=ܟ~r|#BՎwA t^O\b,{+&R+HJT)'T&zaMqw-VZ~?lȟ`N+mC$6dE56F&O|^ƫq3ZJiZ*$_p!0&A,bJR,co.YQd38,Ipl~bh;@w ".En$5+7a\C~#F ?E2s()DaI&I2"m`@Ĝ1xy%YAΤ=8iGX̸"Qypкm&g'13 s5ubxp,rHf$b n0͏PK|1 5}cj]י6"u1q|` @,e@T!+DgzHhDdK e*%RJfX wtX YuQڃ N*\IDIpYM>W/4ra {S=ę֔eZkҚt:no*Q\䄰гb(TcKG09~mv]G\N)R$=1i&̜L7{G* adRC+]bD 9|XtQQIM&7i;A9UsN9@ %N0HˑP5F3Ca#(i^9yUf$LWNxe$)3֨Ie 3IXbV>XY0},H3sqo"8*;Za"PzuwEO>d<%UcmP1/.zM&I, Gq{o^ TCl1BUNn֓3+D,"]\UTf]vN|DU3_X/E"(4h򪴍6vP^>Is;j{]a_.`FRrmḡ{ AnHNo~H *GZy##6Dp%(];+,8󬧠,"BZ*"Q[{qF"J,B 'B9&Q!fA#XhPNK,AL,^QPv$ <;6@a|CN|7XWPRH@ZB lgv+szɼWHvN&!= 2qԐ ;DB7!_9Ta r Qk\X>`i˲>oi1U [h0%?4'+ fš,=$1%3@lKDV!9DV*Fꅈ; Pٺ)w.4YK!o0y NM*ܿ{`^Z pX7xF*  QWc  p2֦ vu8PeNX?iYL" FFpJ)BD#wA?Wq 2 NSb816j9P6tf4KRP"T/y\@6(7l,>xedU, A)5RKD|D,s ł#>9`Ri\G"IJs<E{OX|RQIMsCA$"ZioDW V~zDol=EDSg&Ҙ$..xaU<:ʿuP¦&Wa\q>F/"7?iL.`B^S|`aW3:dU870V45Rh);DYFTyvǎE#$p2)5s`ļV l9!I⺤@vjȑr={ir+1%`uS-q .8(THڽjg7AdiAY`.ZlΖ7, 3ZG|sхDIÕ0K nb$`E2˜rg&] N2ȒY"ZkɚD9&1$)7K(<|2t+YfK4>ș.IY*80ČTm!=0 )GYd-|C^jTm<U<>nTrPps# Njy]헪Uc&hUGC!9\j,'9=HHرCVkqeo ζBX}WM$Lۡ^oc|0!kX(EbdEd|ڪVR PݱﮱkwwCˇ,T}0ƅ;JTcz^l i2pIJF Ec/Yd#A-qGbRÎ?͡HV@po|0ydC&iL/DgZz%0lpRnz$h}]6K]EeLeOCGۏ|z)hx,vseЗP{Fq9â9)#2G X X cov(Y\V(QĐUHnjš  JIZJCP6o` hP5}lelƾ08;6IRtC, ^3B}mbSσ8 1-q߈-#VH =QvJyi,s Q)Q%* QVݛ+2x;_ч;wJ)bJ)LTTbtX VshzOo黵O{u^;C2kn>)ter=ݞU)Ts!"Y0 ($m\IӀshU#B834( []GA=KVMe =ɉnu1؅2,<0AF|PL2Ǜ:|--Aeqa4GhnY/*{!'0[v÷*Cɗ9,рTSlq "sazU0.s{vT *w`"DӍ]y.^ >$; . ^Z3J4-a h%!w9}"_6P\bjSmXR-*D1 nВYc͟R!?4VX萒ܯ_5?urǗs!SZ%&j'Y8i z~_"TВfUMؘGUtFHtarٚ9Ovt,{1_Ib؍jAFv&426FTIJ%0Ɏ§ ^Y\Q3kJAGN/ªc3Vب,g9th,gqM2 9 n<0W\+0\no <KEŠ8B80W\;!]\\;ַnoB$L؆״İQ4q{ounQC@+VӅ;:u{Nj Qgk:N^QTlW5G(Qe[`Mb(_ˤPa.)1n}TAa,X|މ zc`1Ψґ{I̥^z߳{G=39ER<ڎDH(pRr񧍻}u.(8zSN;r&}c[OW?bAߓcf.{y뀣=@~LqW\w;W]2=/qѐW]wO=b߽_떿A g9wF;qLzk+wA\9e7o¢)wtV2~3n@?uO|`{Fo,|ymTwאRHܸOn; Pms/[΍}̳0/v,cw9b~A6tp~wVg6uߧ0RMwکGM=1?cl쀳!*ݯ> +e]-oJ:M-; SY3 R(mQm7%2ycsޕt ˼!" AMv)"3p+V->?IxGmiY)|~^ԦDI!&V,f|'? (b V1XRcGz"u\ 9!v8ɵgRf- 6bMl؈>VS 09cKTgԘ Ҡ{zbNW {CژQ:5n@Z( uv.(w?U)QhA{%T1\e%u-,/gu[Y9e{sƋnKJ! QNBcURFyJJ E*1ER5~ҵz*ʸ͍1cuJiAcN\l/3kW]Pז^yMO?~)bAZ04ԅC>C(aajiAQvT aY##@p4(a%9s&fiGs>1mϵ'P"5bp9Lsr U^yXJ1I30֧i\˒ΧPqp2i֮ӑu%]T0s}bJ!uXGzƚa!#.3ެ0OQDƗ)q4&O;% (F{~*8 e,CX?JL;)*ɧ;黾8qw^5SؽS %MAhm1 / ab j>d_x#2C{SYЧ 'pBT0s=0!_GzTMXh^aނLl ŀɳ^J$M2*mpuO)QEr\*ǀ@ϻ_lA7lie×v;oN0- IDAT/^\?~s_qwy8+o|RL2D-cG$Umo;ϔ赗^30hΡ4}"HfƜK$!Q~.; 1&H`ށUcKj#2(4/vGYF }Vk]Ϲ :=-OݾvF2r|X1x3]Sg]]7+LHtfotX֍g484Nud;`9qQ@P6?Y5;0YTLla<rf8 `c;|0j!)C2`͚WϙtζoB̶ɄRs#@@m'jM`~cɲr7n0-6W.jh9 ΅ =9κʐ' 7&(3$hEm[Cڨ7൚mydC8z0m)k/b-lD%ؤ1QJXԖ1u-lmVcnd96oM,tۂq1F7Yg7m4ʕȺmqoɚǑDF5ݸWTDS,'5bf=e[0-3u,{7F271k[x̅i T ի= iJ| ;=$Ij|KOjB?w;ۧl+k ak eȰ' <05\,~;=e?Jߟ{C l>0Pɾ57ӧq2R:^i~ƻXN,*y?ipjm0(|ptds2ba?ٽ4f^d'#ɇ Z) *U"KoF)h3GL= 'g혱0|'1Æm9f'jF=gd7;(\;k~;2=l5)˜ "7h/_7v5d㝿qN%?3VE`dc;~?|0ÕMr?~w vУʗxFx lZbnɝ;#w5lct۪ı Nܮyܕeчpı ._ަmު.;X%I<&DM{nOꅑ`y뚼 AZj5UfT~uf4lnɞ_vF|]x\gj':"?`t3eY:1HdڦDy蹳ibs}}u呖UܿQu lNWttO{a25 ]{8 >x=Z 2EAJ( xBK_/yXݗ__M9k5s~Mo 6yM>`_ȰZO~ypeOt3MFg /(vM'mjj $K;>ֻ>+3p&D̖>xi_qsߤ2j@n9^uTT~ړJO>ȡ;i~+6*^⊩S:*52b>eA:T:V2 q>݃& x!^nI4+2R.FA/ ›7tN 5pPNI@ sQ.nTX);^Jń̨Bc}S( ,Zk3 ٚsb@!M[f~0"T92XD,4ik䘽jʜ#9^YJYݹo3ը]~1Ldi(Oݧҫ'6EA%)BA/ Z5¥ k]-B%˜\ޅP HHO#?Z95ґ#>pQf?Y+CMÀU}bF2ȞjAqiN]qN EK ]b8p~{ %2<"3ix.Q<#bX-}(5; ޼ij=RCkD, B кwĀD_p,xo #jt_[-)-0(n~(`EL 0"/0dAp 7O;{`mc5B ؍ B>mBfz|ڨazNZ] bܷ,W=ܧSC&PkR&M۹`81&:y(*. ?Ua>:8;EoΑb?(%uğVM<UHYŲ~%G#E%647{"TYG#0UgZkm)؜@R9*[SԏJnJAg9ydԵ+dUL)b0rr2/qeLtW& G-8Bg><11z9g†S% YfXexC^{`+eʲ,(x (I)Ly6 bk"Hj)lRuf7!Y "ƽbC tFZ"2)wSBA_dc'*KNt#42.U0/ʸNvWEbMR:&Jiüg: pk jl46`+!›?ZRc"f4gSр 5 T+eDa`b~rAN`j 'q.o# B_(c,#Y߇ױJG;"֠ C䘸W+/ KZD@N>4` i (֡u/&`̶F35;y^@5;aF@!j)"cq1xTab(І鞈RE-YGC${#w/%XxgAf\l yv3Ko$#/01]tr|ݮQŪ X~9ȵW,@wgrjAYDde !د򷑁brʌq {dcAX[7QIIi+X2hi,!W}‚#>|s>Bd" Ŷ@&_VLU ,T*UBc],74 f !l\ zRBL4<"Q>XW*Y^`cyڡ0䱸]`"G(P,RixL-H/":Dr/A1:3bNݏA%R) "y7Hҹ EpUQ595_a42L ȚE r柡%h Eq'Kvß08whk1)尫PhGqf6jOчR'(L\ 5|98:22Yf& WY($j7$WsfToЂrsTb`dX'^FxDx"mt1,HJMyCLvQ+n+K٨D\m\mfV?BD!HJtڸifH%Ԉ} .R}=Ɉ?K*e볧ZzvIyS ս'].z1Ram +b⁧>pzܰߨ3&}'&Py%5~>2]Xc}A|TxN@J:rdꨊu8X3`Øo| mqd?U\W.TtzP䑽+Wy2m>=5؃,w0@5 FԽՊa+| cG9sΙ zYܪEOۋǍ3HK%%~?mZMUg^88̞r3j ⸛HxGÖC=q̡'۶cO>tѵX&o9 >I~x-N!wwpS?pO<%J򘛣E t7'nŐgW3`5hN=k֏_}ZE,BvtH3 Yy=o> ]-zɀϽij{͖}r0jGtn9Qu/{Ňx*i;퀭/ۿgi%fJroA aZٳ#EN_oZlB ggKFQ Ȓ&nYR_M}Ej}I)^XUGFd[L&!pK3 `HȞWCĠcM;!iO)cK:*\p\2!%ɕ?0]xsnOvu> dPͳ#CmV궷uUK,?(1'C)KAStb ^"@=W77f8AD R$}{}w~L]2j}wE9}''H "&P5!(*bkAĈiYל@D1`u͢( a`"ow[]u{ސдc邵=f$v4, 5SۙmfjI׵&`C0 㤾 @h;﬈=jUwCS/krpٙI_<mݐ'Lr~.B۶rJ9X;_{ Z^qXΎ70/Z@M{6o ro}dmƎ Q̾G9IHjVRq8#oKԩi{^)yNVtZuHHc8,xBP(?3 &YFJ2iebo5$G9DfrI_LE}+qXZkwd,#RJFDA}B-l)ŒG\G?lh 7랗UmY ".?fu:CcOn9I>!B֐3;}ѤD+z./:; 7-ҼU=7y/=?ѯ͛/>!ðƟ{LEm툒^)&>}YsN=S^C}{g2vGҎܘs^?g =k ,q.Odp##cdů<6k^@~g^?yQZ#v,X!]Ǚfuʊ/dm}s}a蔐k++0gKS^'8Һ9{އns~!sbHTfHpq"`Ϟ{aNi=Gh7?Wny$w:nyGNڒe ^ymѶz'oشܵpG^ ['aӦQ]QQ=~=VWq79_pbj^0ϙ.:[:YzFt23%]gظmwÎo8ٝ `Vr\pYtv5a\zo0#W>qE<ݓ#{F}3wU@R!c.gҭu2sbEN*-/5wP!WU3]/zKc7Ν݉tG+kuʉm翾Is'L}Q! ӺheXTiqyٸZܰ:70{K" JtvHJajDnXpߙ{Tg~s62 HbPIr۽C}w.kڵ'g[q_lL}Tzz .-D`\+0'EkUj+b{BNG4"H8 Qcd4)*9}N@s5%4= כ8wL|]'Z[~P]з%>2u[*S;Ή=˗ sa{փos}j]c+>w#GZp,@$gP']Qr_dճb֑W|Ng'W7ܽFYbS'OOs~/'rJedf|N T)FK%pMW{ \Gw(i9sn/QncnYu;.)NˁOެ|;'>B}M|'_5~甧TPRnyϼ*闍%o܄3[O IDATӾzzY=ZiuG~^7dpNbk8"/]ap^m~Z^L jX$t6ʲ+r8~ܘ.>ºԜ=ڋ+۽hd:~hW?۱:~cdk;qbsOgQұgK^pa/?ȹϵZࣣ;oW l$ׯ:p#(ݸc^8Pmu2XϾWڵanl͵=Iˉ L@ QI(GRjB7 )*^39B@Ի:DT ΁(玐I9f8.= FO{i=~IS{u<.w߻u ;0Oodkhϫ Mh > %zJ}<w(+Zߊ/f]iٞ?ּcw ؿ~e6ٗEI+6˰W?}O]S}_6T`zxE|7hwC<]M~c%e :!ca'0Gw4ҡS 0џ^{_l<!aFCUG1wcnۡ\٦j@D`F-NynX|_şkلyQ ֲ=[$kJ[O._>YTqoߪ~9^ݒw zԣa)Wy%f`,uץɟ=5gs X$€#o/Vt=w iiXq%[}M&li߷{*ʋW}ns\p!Y·>ۼk:yZn!A?F rǤThlyܤ_|H/MKbɨG$畾4i=OJ:‚N=P]UE#uKr\ҺU_% |C %n_TĔD Ӏx׼ 2]EZkG`h˙K"jOCN,!)`ߊh,ZŸ`juvm@Z1xhd%)601| 3%B$ɚ_.9tV染kRzgvk]Ųƒ/gSz 5{ʑp_my6ABrÀ2t2lH|TCBKdFa}r-xW̗+"i G~zwMÓ1wm-3< ]^VM-=Gj֍+/Z S "Kw߳*jjWUؽ]Ы*Ȋ_UZ]f2FZ'fJem 5+b-Sѩ}ϿvhWe߾bl;7+{?a.ūJ+sLM{,ueSn\iǖ?-]_D`Bǡi lJ0ݵ[c\UDw{y?f>:dɫؿjE8\;UƜ.BX +Śot^׾-e%[hظa`y{Z?I}ѦZ7L׭""mOM* E7h,Bca,-{Ơ QEm"غI%"Rj<ƀ(6aڨq y9Fj 8]j#g3W<0yC*11UYso>{G9Sx75 ! VJ$xl.ɫ!ݽߞ.j ȮEoHSs7uM?ק.cfW}jMKh`viia7q_a4b -ô3tj^ce”N (,[8bK~RZKb,bpk"MoOqI{>ۇڔ)E+4!pg;副*_G/UH4A [E4Dl0 C vՉ  WtX2^:/zXͱ\_wO\ڣOn}cyE5^}ĵg'ݸwĘ=5RͩFOuΦ:QyWBr_{9QRϣR7g.c/CDյIcPnFEU@D$о}hWN+I,|0:ֿY^\߆mZL*;]szM~ERV"#u/LFozeSA-X; $uSU^f'H!χПo%Ȏ j1)-JxA:TUy?=(zؠ”8%hRyM& :^D"ɺm eGO~%?B@ Z8V褵k2 E!>欭Bm`M@rWs"vqB8D۔ձufwӢT#9ZN9I@fw̆]U_mKvSb5]I$Jv!q'îj؁9Pլ*Ȭ9DŽd7ܲeЇ;8r:ZTK{);UJTٱs^WZD2 "'(礶m%9fY]v$#@4ZQVjl&c. 6WWI3h@DĢp)I_i0qbX!l1rv(,lmw*õ Frg 7CA[}r+&]=#ztlӮ/m}Q #mݱ1ל%AWL8‚ zஅY9#zǁ&^yե>yHD۾]Q't8 x~Ap=~I_[>d}ϸEkkk}}츳o׺Sa^yfD`ݐz޹8Gc@T y|m="_S'o7^oʓ[/lW:3W_} s ,mo-*~_Sc\RnM?_D``FhӺna] $ yQff;kBmqE>^ 虝q]qphn\@瞐g*Bzw9o~jB$Z"?̃gK)wL0?.N+ةSǎىT˝yg;_¾QP 2[Qe݊%?YjeXE礆ߗy>gHHן֭'2>]y܈ KlyԱ ONԕ5{d?\{PR\u^JE4&$b}WE Crrn;(!2yYp`,+HLX#㸁J #XXQ$9h1&BFMb^4#40N=BۧiQGH)8*wB"FHÍuRoEg{I ]lo-oOO &L93]~ҷorL5ݾ#eI&#Pu^`w=^{z13;9^ŖoM :"ջ-^P'm7&s5)&cpE˧tjEʯ(dJG?j-E/"{,E?s.m>.MC*~oNo*Yɷ{ p`֠э>ʤN8a$9š&?ﮉzġP2wލ&1ٹ'?*i+7?pݕp Wny%mx.;dkuze W$=Nͦϟ{eupʄzSf.P'n&#M?Vsf3©bU~xV4k{Z).n?^Ϟ|?O>-[ۚ0S<߼eKqruɚk9|jv-_|ȋf8ӳ>8G{ťSɵF+/k>C芩>{U_`KCEP,ñ'#tÃ'׷\ʦFO~ݏ-_=GQ`{%f IOpM1&asLٲw]55\3o sX$\*up!e/<\uGDGpN"ɽ^Z \{f& Ĵ azy@[ɚfD R@tǰ ?,3';VP [assv y!Zfd};&_T;58B].e&Ewbm0UFm "].9\ T&B!+B 0εt朻+5O:[} %ti^jH$"*ǪՀE\u\D89SEq95,)a$!MEMS&!PJ:yCzS&YimտMbD4vF&cASK/L A3Q`@ƤF\7xҤӗ{CN:qjyǩH86̱R}Ov]&"H="l%4ԁC+b(0谧?+? q혉"q8\cGgm<8IB'`]"Z)_6 _hg-$H`  F BBpwV%Q4AiZsh.0! ́e魽>ɴkFA*r6M3!1[dJw+ @XF$U-(KɔN8u[F E OݗZr!Ggn_ 8.q;;!NfPIxRЄZ*lɉ2lBKB6أ`S dž[a4`2dY3DM! \qd7?{ pflduV)iDz 琚t_"dB,bߝѶ ʝ_A^nԈufLPNB Kum 8'5&a1θS?m] q$!_2@qמK+ȒXW:Sȹ1 L VL+(C-RV6QfӉ]oY9O+rf6 Wc)O#|!#ņ/OrmV!"G!%h ItUc̊@S/{ZxђzJIhKU(?: "+sΙ<B(41 7~I"#؊IM22+ph{0xd2-3(e 쳜7ЌFj7iMŶO/a ~ɩ)JQDx RcbBqMh4Ub뺮q,F) ߏ@WO}}d,!!H3\\Jt443$fD7sX늘,ͅd+6$Zab$*1& -2g{g+D8^ |q,f)ߨCs\gM!p%@,δU4? 5f" 31֦;Pv@t'Q!*Q~Ֆ#P{VY7719)dLNyFrKM._x@LO9'b ch;` J Fquɜ "RfߋOזOZ} Ec$K'ݸd^9^ݍ[b!Uy4(jM@dcH:L Pgqֱ@AlL:bc3 Rp& +CzSc4=*PbJd,?kSy}"4怱;051=c>TMLk΄2|s\k6NGdQGR""JpcQbs$Ix0 xӄѢv` |h >T(@le%Fcgw{gm"₊NX6TeE2D?~3-(!hEjvnD͍4<*c.T,/౾?74H.UWEGTWLh0"'M ,<Ɍ0O>2q,6fzĀ0X]Xe43Zh|9xܼRڂPq'Ĭ3VTPR}@Ғѭ膁qIcIԫ@c/k!`,XNWY3#|EѾgsAB4~ЈZޢ͜ў+tA cQ_bV^YLB>Ӵlʂ)@<$ "C/a{%7瀱Cin6pBQugBLCB~Aٯ/3`H 72ٷf8kNKQd c-9ZFEH{pƪ糁S"X;Wuܺ,MӠ*<$a왏ABѶ H$C  AsuQ,strlaL>nY΁Yt34nc18daj2!\|wqKU:f-Ll67+NN E.bO\5"GTzLŋPR IDATnIڲ—#ȫ f$(ahIi뺮bj¥- C0<"} %tGgh؎X) )!GX'6& <]61!>0/I̵'\-dV#$DW.U]=`ag\u״f{Cvhf6(BHp)71j=:l+gYeH=:^?7x_^G 8,V' ҙ,@`2'o~ 78I7";([Iv*$ .L pO|td8$nex AxwO20F = am|`ɉ ~5ufYJi Er`$" {J;$@`nX= 2~y>R#H֠ô#$ac \@UFg>XtB=1}M v]WKo<(8RsH }Yސ޶On >)q>\_WwlPr"6Zh~f#Q@ەG~M#{|xN/& 1#o8v ڨ0u{sJJWz$oy]ه+UݧUV:yw܎gÇivwyV'4?f^怯b& 6^yM! 4jdZP]0F7fcMWiR))^ Qbځ0ɠ@/ ZD70lQXZu73:AkE|ob8kׁytjT՛p}L%qprQI}/K8yiN9bDhf[~N^)I~HJ:"3>=#Efaf-.c~ɾdxc8q2RU.D/&/c58>#~Wx6m S0I%7T%?('Q^pɣZϧגx_?.RpCP/]!=S_|S۹v(`j︶ozbUE}YkZ7ϻF|#oLl4zYճx~#v?q)M5ԯ]&Nؓ3iG/uHbow7nҕn.qCߘ1wmUZS3ʝ=2Yӟ\ܾQi*~|eaMɝ{֛a#_>c^4ŷ{^G]Ͻe񥷾ԹIrNx北xnApNpi-L{njh1;3S#},Q6ЍE (x5kަ6f( ;Y=4f \R\5[3aTH19'էРVC8R#i$O 1HPJAW>QZmcSnlL%s)j>OʂaeSS8-wѺJ"ذlϥoa>ZuΨݼoIYP)+#bc1{ڪq]~wI#Ӣcܻ:|Yuy#3 K.Ve?h}VPPiw!=Eaӝ xSkx]"Z6IwHj7m! #/<=ǘi'ƞnrnABݍq߳QƨڲZRˈ-=ecjݖ+f.讯3kj5Pq[[7H:(Os!=ZeD<~meO0JcDdJ -g4ZZ}R#P,q^IIݧȼ^, )0,֌AGs ]Mj\J*P|Tf@:8cRsU7JkE,hL vflX:X)P# Crsd,`QA%!HՊ@E 7@d4!oe!J(24vd 1\\r1hOC$Ur! XI) 2@_ch:juL[EO̹H>޳gV \uCk/]xÐÒv~ؓ_4o#TJ^r39N#/tM?u mfqELzM\#"sm!{GDXcJ*9'bd%2eUXz 4my{ʍKzݫߠ 8m)ӿ$rl'b4`5nŝ( g T8.]YNQ"-F!)FgBԜ1<'[ JZ"PAm"U8buZhT1#  =Z3J ?gJy/8ZT*y{k~Q]W #5#B"}+FcN9gXNwsҏq0ftX ,@9<.d|}tci#(cDb !(V2"A woэ{']o"\c0 diҶR #@lFEJ6;0ǐUK;ɓ^V԰{kujn.UiN*( =]1o5{|]/Z z&3Gjim`Fjػ6slɤ]bef#a9ObYͲb!3"-w~4ņ1~p7KG:P| P*4$EQ,xQvh- [ЙM,""iۧ"%8rU=|0Szk1ޅk>qc![D7Y"|ߜ}_ώNW%3ǧL܈DpD "ϋĹ'x^l< -%24s¢`B^6~Jqaha%ztI9:o&#;u:բ W4OaM{V-gԔۥv=3߼dMQIEk~w:K*bӮ?ߜ;Kwm2S/8}*;7%q]SKmeCM}.Òuk?WuxVs](ZX@ØgכsGp1[twa.97 /u,XI~U^]}qFh_PЮˑ0k~}_ly˸!Zes ]A{UvP40inVozyC.<ǎG/nӈ)F="mO} Zv8B5Lh}]]bԘݮ}aiLlѶcL- tovڀZ7r #0v: JW)yGq=fX΄Xعx_"7KK6>xk,<-\ +vF G~Udtjk冶-DHRg Mm3p9qPs,XU#2r21 \j ;Kehln nOPpEA #_y;[ Q`^)%#+\r4/!Sms`_"|&΃Xຈ[}qloVJc&VThȄ!S^K/tr-[+ԵPw>=+|*`_DڏzdI S84X[!lmM y?=gt ߨr4R`WO=N]t^Z~O6~{T7I1P#dƪF1 ?d\~UZ+-c/D-ߴ_<*U,{#`^%Xp\[Yn]yŘM]? 2@2A/{2Gbіp? F=NiPXX ';97ϖ*N%Aj! #ho$cOmAO[ݚX/39jB%8790X% 6X[~aJZs_/J*Ld3Ƙ MƨG)Ԧ{ZݗcwmF!|e-z zPCP(qN0 8H<08|sr溮G Z/yGVwss#8QuГu]WR/ q]q$8)8nLeN;sayq4YՈJ-#$1d=JKzQay` b*2JĹ/ʾ@E6 CXn\꩕뺑9ŇUH¥_}nq"F,f&"t,l2as}j >90d0V5G L# &L`3V!s DAFYDFDŽCahySq s3iyTJW~r h+W,Hвb ﵏H\dVh VG13 {8DG}=O BL I~گHtk;ncqN6@kJ'Bgۄ[f1FLd07Ag?:kFӌDnj FO˕cP,50eVԚUq*I)8\NMUdL*I!'͈C=j< veQ6خҥ_ 桘$ CAsm)0Dj0њZKŀM(-heu-QвَdU4aX  B@hBk=%%өƜLjv(v"!]6sS #Xf:DhY8SDx+(Md|oXO3LPa~ieJtz"Kkh1d oylG[ BّƵUƄ&ka°a{Sm£WXLM-ʂD&"BLCU1#A&Tc$%΋F"=Cqq6Tb~|2rL_NWT8m6KZ\jMY'7@CdYZjDvl?бz4:0T1vCL2:̀eG8p7ai6KmB2CN]6DC|L ig08 .qHe5;QV|TNyD:Vyaz1ctrdG1N<'b*TxHF6 N!f2MtB#)CcdX0 og9P *vӨ²>`*&̎{qdC00I+E+ 顽p NC0H?GVScG&XЖnfG4Yւ\ /,?'˱ց5!_L oaqǓEs,^ET=YW," 8ʗW/l#{kY=\:Fy!9vi&a۰14R)KPwb 5 /M *tU2k+CMZd9i3_:P Aj9CZΉsq 8jOe_&{Mzg5 $24e0a{hBvB4YU@m2`,FACDuNBTyQ ;LŖv ׃l ` 5C^ dyssCGKItd|M@)Kf >uw8qN=ZMMWm IDAT(*2qPɐ{08G0Н+MLxE"1YF$+ .JFd |Eb}8@p]Ri oIik&Fm;Xk(ޔ1*uڧ~t4ro }!1I]DTfa;wIY(qeJ4]PF%v`9K Xz%h,dYV?OwyD۰iں" KV0)\}45g",i8cc7$mVЬ4ꑙNA*X ÚyY f#0.ו `obh d"d쮊 遼(!U\eaQ>%6489%%XpRH;$BShu"p -f|xOe"K!M5)2p#uq=ڟ ELNqhwU P.A( ګ^ G@S#ɸ3!2A ho1ͤ q8ìwBUN ?pF?2)4~!Y`8R较<)@I Ug<X}5?`?uڰ݊p)G}?m^>B$   U~B[ O%cЇ_AU3QLУ"0+_~FΚ96m&J>)|VNP5m NDr'C@n Ko,*3ׇʟbhLقAY[@q6}lnn'a1$pL0밶Ŀr07#d7"čD\!&?5I0%R^vx5YO> Ibv$)}F+sa,N;>"V$8\* !!8"XB Pq荁H(u,*HTGvX4 X V$T]lfQ43.eX8`!j{B 9[/0U]z$!HF q] и10B I6zF[?E1sA#$?Wd5}!}~kуVF3PI 7"@:BPP/4E7!s%&O.D`%&65$%Z{NkYL Cƅ ,!HL{J~3QdKAC2wx @]S .EU0F#<,"ࡣv9W,CUY78!Ȧk14 ZnBU}䎧\~cډϟ}01O+6~ -' ({53֝rNYztw@@uܝOS6}Qd8 E*צoߝ⢒z>ު?uԉXMyT\Q mq׭uZį'YNԮ/A2}{8nT[oZ#9οSz'}r}[xWUNۑ=~H mk[_vr+''[=j|=ǒ뒥wqםgmKī?q7︋/?g`Vhdz|iy}ر@a~}pLsF ^]-<}ȱvO*7}+-3{{gK}D5Iuf)!Uoxǿ.#Fp\Lxt>kߟۜ1Ǧ|<+M!DN1rS?!Dr=f 4gNKƜ= =뿛b[3m0\pv̼u "Hx%cFY^̜q1s}t^$͛fZdKNA4;0e#2(s# Ejb_( (s_ah[NZ[m>fCBiyrDd0Ȋ|fB('VD`!dP Ccʉ3H AV6:T@$ V ! xţsa #~PeS֙Ӟ^{0%kJrѤ_ƿ&H~5WZ e?]2ShOkN8NvܹvŇQFOoΘ*YW_vCUɃ߈0:`_y͕i46>XrnSpU^79:ܔE}asEB~GLan>/Y=<戣sSnco<1ymUzs򖪢)-|'gPO&7;od~zͣ?גـj5c{n{ySkkSn 2uM2EA$_}vy']{ыW<XRWlWmOǖҦ:HΠΥN,;F_ufNi\m!Σ^w~g.gNpccì)z *ƮI[IXbQ1؍1&IԨذ" dfa޳ms'y;{{ިӽv?#vftNVC甾D~rˏ|ђ#.V:_yS1GZVJu 8ÿzu~fpH vgMF~緬43NnoAk>#3oמn/_)3]ڵqCKx1\E؇ɲ[aQ8(# Z ,S>GS00E-̭rо<9[NRp8HDJi)>4%mM$ywQw25wL o@aA 4ok 5g_'77]uzZzzviLKՈ53_nͷ-)wc5Y_-[ݸ/7DP6dʡ?Gf}~O_jM37^v{O<߾{mwjzOפgުE|~4y,KG=vSǏ0n}휧Tmt27p洽~NjZtGo,\n͒znI}w'|&%O=5_6k)w}G֢.g hn^rިӁ*~׳_{vJJ1(Pg ?E߾bgub,laNBːҌK'S ݼ8@2>DB ﵱlM'bCL5:W0ڹٹ^ F)PJa7>&}\:v)8g2"M$@&P2"EbZE!Q!Yy(ƕ19ͅ/Es܁Ҿxe:(m&-JU pgi3o>y #WTO/wTK}7@m^AQX9kަmއz6Ͽce4\@:]GRXR_ =Ƌ`1̪1c9259 rrt*X1pDŋE&{m?z5dHk 65Cs!$_לuۭ[t'3ߝ_"jʦulSYe+GM9CQe>Ԕ u}Fa[r v?]g^}F5+B~l"=rPyU_{6w2?["QMj@z)}V5KӠ\^57kM]mX.Oejbn@R׈AU}}"@~ͬ~YK`ASU>Zy7\E˗|6{ւ(:#u&r.aAib\_ns=,aCQ!ƬIX2f? OA#Gd@fp d#$av8_&xnX$K~2(At(~l#6ŅhB|( ^PZy< &žQk3rkht#\]%;ɵbcĕZg(W^0kIICWZZ%׽DJ `^/U9_c:y;CW(2Ҏ}pԠ7!z?m̗O"oO?#ZKnx$1>w9j= >y]׉C&2`Wq3"T=w}n|uxg +ji<+RM)+ZYq0{1w?{=qml,0 GY(q^GUԼ¼Mz q~UsmRmzjFՑBҥ^4M;JeJc{)P@=VjpAYFqJ=`#h[P5_$vUNjsdkeޕUӲUzaYY>}xMTZ4Vk?ʿYn+Kx7Aԍ%{XKԔw,lKn섪KdߡC ](wnevҰm ݡ]3gT5>;Jˇp}P{}}wػv;aeQKKw=)W Ѷv9c& oz1{+x҉ 8lⱧY/7蝖UM8d]w-++5yٰt̾cgI벱k:ݲRHy߄ `n'NmAH?|j{k_ ɀ}ڳy kj=qCzWsv;gGOҿQO9#G4|.{Ke^E' ǟc' wIM=;uQ{=p'K[{:aH9a~/,.xiV:S0_A#'N>#F`)?9bϑCU˞c76v[NoZةwײ$gjla{ u1k@SK0C+dØ1N^I%/Oc:+-2˙_nQ~:ʶi_k&c2$O>X;*,o% U9iVB*:$IbdPnjZ UfDŽZ -m!ʦ5@a?KXY+"BϞYNI*5Vu19{HtԨݥkvL4&#U訚[)hctmh7ϻ.Ph[0攇teO|Ȳ;m^h?s> -u ?xY~AJkѠ & $Z?_w[ںq\UyJ NVsO O偩}Jp&Ҫ2~%mR uo y?ZWؼiwvLk[>|)%Marӽ\ :it_%OLc)ǟۣm ܋6/~'~ԫH?ڪ'^snW{߳?qqg\qX%W~K P{Թ.qOº_q]>?<(BGwdrAW~ϻ/yuRq\ [,2>B쌤,6x<ۖU$~SפVR\Yi'PZeVzZ*lWaY)FRHLiJYYC#>ki`>5.6rQ<$&8D)Dyy9"y2WVT^W&fi2c"bHkϤx"H JU)e_ i ij7ySj"e!`Ʀ+/}B1RDܭ:UGFAbo3Sᙦ6{M'? MLCJSӥ&HUj>5q.KvKJۮ6& ;xQ^;+~RC2h Di3c+, 7BБϻgOdc#s`PH *D|.@B(tdQp 1wO'.) EFzb:`F(2!lE;Ed1,BF6,^0Öd~V1!k]PJVV[4G(4%\Y4҂Vz}-)[9!о IDAT$%K bF B$h-,J}‹^I.!M|jXp@Sdܘ:3]ڇRGAwt ߟDJ!Ь]‰gaY lTH2fAah7 soRCV+Ͳk6]R.f3G"k12Ukwi[K%}C -A6^ \-JE`_7rTl|!2E뮩DZ%$T[ph'NkR]'E.n S4cĝ}X~LS*`ZβU;[yq+|s"ʦi0t.`3>a"U.Rfvͺ %@dɺov0V@C҂)Hꖑ)M( ,1e h5@:sv6q/|HzJMۣ ? Ibem1>c;btS  4Hc&fY8zlBe$PBD&J+~r4= b(AB|pl… s6XW+ w8~%`q~[\h+Oh0yN 8*5gufPW;b'L@eQ+T{A/%)DTH _A,5fm&~QILuγ銢ÇSox3A=WN|anīt)2 G_pS+2eE v@GK;MFEDt>۬GenKCKijiy+p~Lg=%v#i: V`,Ԧ=d>fyRH[mmhES")Ii܉iIaþ}$1BI1+yLd䒛XPwCplۂṾEX+enf[ì`ˣ&J:Lb5edwP0J)\˾xQ{LDSk@Tl;po Vb'oA9G:xΒ"iB4<:CjK 2mFt[M,Ae":Mؒ4;MIp'%K'NTPX-W;lyX}'sٿ5zhyGw Wlw*f-n#-3^=6UMj5yzux9$$4c/jܬ{M8gg]W_hm{^Bl41kfPbqa^.?KZz& REoUM{‘g[[0+Kn/9U\چ~gzmW|cq8Җ /Vz}Bg44+X/4rǎ,[n\M巻M9"^ٞ^]Ycr rc3Pi7LY8-}R?ytHmjZQD"SnL+NfkB<&:YXɍA@y_kT<ʝLf7.a*8!h2&efNш[ Tl mtȪE!!bANda.P5RboyN"^ h/-/d i╜ALf qZԝ~3~JT)Aڬ,2%r8a6ڝI ^-U^ Q |} !MٰCQNبt(l41=:;"6Z1[ܲQ$ ^Sa_ozly;GνuQjXզc;xku Y)`f֢Wq hoL_ю`e I?uH!t׋6^䋦.c=|(ʪ J%bRo;yvk;B$k¡;ߺPpѦ;x|P>ÆY)E!p(վi$ϸ~aҝʕR BpߚBuv 6[7o5T`AwZHN4 u=,;jg3U؁zqG`IEbmX2ϴ+Gːi"mR J K *Ő`cZlʅLJcSQ؉]Jip\]@2U&6WͼZU<`wFE=cE_4hy\$IBJAm||B&RX!B־?#VZ3GfSppPE?j7}0%&lW|{Ym"iIMǜ2c>KFT-{ŭXP:\T/?9K6/ڨܪ :Os ? ca"af2 V(Xd&03%R hL33e6PmeD|Xa3>ɧeP];.FϟwyYaEh:7*!@Hb.dM;5dMTǀd1T- OIRTu*82 dTJ6;󦲝VT(z `i-Y[4y.;xAI%i9AcCBX"~tv{Xph㽎`4fJ\.Mڜ.{љzR*=t>eh$Dc1`I'DE0պfyi~/;+$Y6~ ?ӭ nj*ŝS6Է ֵ5+V˜;N=dWE9'SRH3z-xWmw7 f^Gu5uaoԨ8tK|0yXk ^"x3ݪІQ}65k \ޯ0x1`  2q9 KdfRB%,CŘ )VDw[>sRq/FClTzM+1v`'eʑI8m3tF{͡ehao%Q'KM(iqupּKU7ڝPeoLw{´9م? 7Y/2 Q`iU=Riܸ0EX+'J& F ޝ@Pd-,R̉H+5=ɍ FOF%gbd*ʥa?mO ;$3 :Xw+Ծ:.x];}F;EÄT)ĞDv$wAQ/ϛ:B:wogV08 A Җd\2Ya' bJ+I`igeumBjU Dqq'mk>uvcdfVkHں KNVb,+q3ܔ̟!,P IafB=ڄ7|6 ]_][6Zݓ 0a&3H,̨1Aʤ{El1R@`n7V>)ȥD7JY$[{>[\^6pSOwyUWOu+<Rx;Vs8{mZ^;>lNN}yvzWOu+y`ծ]bYxI{>Ӝu j|07j"clq]SGNQVoK!zNf#r= QB)˘!"jJk$J(% -ae1F2c,$Qmd|Έ\^$e"Huq*ov.A +)ecGuxJe>v?>n4Ŕm)-]J':aڰn>wFwl (<ԼاMxp&$ :IGƯg>8m6%h *ذ/?l {'vôaѻ< :QwZowwz0qb2Ʈo4sP,qc7'Ay|Ƈ k !MF&B$ci*ҜrI2G0`"@Th%x{p L0$Ib:reaJ MJ) fmު~ssxGPH,d$*Hd*=l@V.W*)D|>-^,d$\NTd󡀤I.BJZфm$I%[2Â,C^ 2 f 0}r3LyᢼJH3 .4o(( k%IKL\@&E%l+#fz$ijb";&az. Ld$7 a#^9`XqhrPK0X*)ߣ̃VA9dfaVŤ`OE".1'=f&-)Maݳ6 D>Uh)-Q/17VOۼYJXu@_|NNy%bO}݁ nXD; 18>N0q"Ҕ:{ْ؍J^\a=HZvZfdP+4ao].`oCg 0̯ծ n! 0iuDsλ)?xZGv*E,҈b;';]K,axY$}T{VrV8#F,HXG1 #A6,km0sUEDޮ9[4i{*wQR&ٓJBo`2j޹fy3Y/w5$Rd9n̎*DpƒCpf+Mbi|# ݥE j,rs0ez'?!7>4Aҏ L{{ ):!HL2 DЯkwj* tm߸_ɰg5L lI=' /Gc tȊ/l 4J#"y7Ȼb&QZ((! p/QꂠL[w1MhB%DcR`!bsO=r8QT fZzz?t m2+Um"A0Jk>?6k-C/|ެK=j|wL]Ofu\ڟb}eJy8O,d ]yS'=~TOYPܜt ﺤ]a_W~hlsX f4n;Sϻ8e#Owqn$/0b]!M iRn1/qQ)A1)G~w7j@~BT; W7OZ{yi3dpb)aKN|]j3h0и|Diҙ)آ3M^u..AGea,V0F@KWxܥ i S"=6|O}JS6y"jogv#w("E )*x//<0}/j~_r\\nA7.o`nyE}̄2\.I\YYYYa}zq+qY_}a>x \6@H9sJ2*\7-؝c=U? +E]eBe=Dz囨y>B~ԣ/lE̮y2ehF*8@HNyl}-κ>w1U f 숖@K.:;g(}3u5"n=vH  ;2sLY4_8ڭ}uX"$ #]av)\h$tg5C>𺛏[gC~bլc?\:z~w[+ e{tƦB?>FmG~jGdG-:Նun|ם_+tBk~v1TK͜yme. Vm~ `w7F3^_~q+f|:GH|| >GgrĎӕ_jQ^Rs[ˊ=斖CH?/|Y_^vLEh,ӡdd 3茖%ҳʁl-;y&b#>.)qYpFM`+6f%S+D.`k&DRHmOJT)x،_C2I(r<wl"b}3Md ba1+%sUVl3Π>[e)$ZDK;^;{f+Gt养տtUtڿqJ<.W<2> ^{}?+{{S9U ϽSϹ 5z9rC=koGwt/𞫮?MpAW4(J˜ ӫie=G¶fʴfCyҺz+Zj; s%\^HӶ_<]TӗMYlJyO>~l{SιƎ Bמ#?z/q{]'GU}x~{ӛ'MH!-8[n!9Pj5fujb|SƲGRi*~e:HT(,{[9 : t|zYggYQ; ϾqvS.8 Ϻ&3ο}Ռ$w߮~u{pJ]N?ẛf+O%.;`PB 2;rmu_7 k6U<2sQFJ1egLfkA> аSkҶ#DT@<_ Q؟|+2k4ȥ`Ao!q^;l \)\qF&ݺ_L S&+L㙰) d.WBFq!\Z݄|ՙZi+YX{NTa},#h2/J^^D>WW=z߯׈v>@1G\z%L_"j_{ lX|./SN>z9kk?zOm!D}7o $ʮ]_~W3]+P1 M4ꪁ8~; 9i*.Ϳ?|}\ڣv~" '2?(Jz'/S/d{&=M1}O 0EkbE<:P XFG`yE1g~t ȯ|ɧg~lUcO_|lؾJq{R(|v2Z>vOx㺆՟y:R49RDU~h6ҳB5,Sغ$s6`HHڙ+`h1[ƻ@EN^|[DZH_A8RC;4Z'’Il p}y($Hu$MޔyZQRDAc qjo# Fxܦ BHSw`Ǎ  kuRb,_St1<V}raJbE~gcӦ13ر|{1Pk ˁ᯵*tva{?+CC`uy XIt<Hm\i@D˚["(͸,g:jk 4Mu?{es;>C׶QYܨ,FlA1S2ECڴnS^T鎶*sd>X567!{g`ɺX bL6PLQBThX렾Czu{ 뻾kX9꠩'{[Y*"5jo:YQYe$S{7Ԡ@`~ 5>p*iC 9oR՞c4n%y+-Aj*┚IPnY* "_a >zA@WuC^#&"%Bl3$v+!>v`D [?Bi"QbB8uY$ UÚMU8| LXBTV%fFgB xH\eS4ga=;F`Iar&VmZ]W,_Sw߀ל?yA%׿Zo\S9nOa=W:06L$[4kʞm5I)3N8..30^ n䁫?T>v.Ԗj&bISA_,4h.#0KMd3j>#$Z+s}›t٧O @ZHSb ٶ̝Z׬o񴼶u ۠tͪV#FV־6zsS - (Uaq`4 wd_@彆~D={DZ67/-n2x9j԰ִFti);e0la[ 0 'oi$XPmϨs2zß9X)vh]\Oz_'! 1Kcq-D)?*ZZU$1Å7eKFIJ\,' @4*5wZQ@ JPJfZ0۞JBj {z 7=#͋_lG1 Gt 7+oUS8U2~ּ>rĮ|G[ƻu ڦߴT,_pJ^]ޫKˊƴ ʐcBOO]zFޕI<`sŖ8׿,#& 5hO(C>+twv aax QPg!vayaÇ@ɿi צ~]66@o\wz$!?B,U0x}%]ϑʺ!2B[bNܳ.t5] IDATm/Ko􅖜]W5v0hA'ңuxc(}ژ%RY#rF1cVA<{MwW$&a+sI~8Ng~,窄&VO /b2zeպ6 ֊MubG6So甶Mx; @~|˕G2vƭPony~6}'xoz-mHy47}:@ a4ypY'{!jm>Vi (YA,`D{IGR_|/PV) Nvo#[IE[wxXLYH38%xP`*g^Gvi4V @4MM3 B! =@BDJu1!!ַh m=`$R5)j2o 9$ikNweSǓZ|!6f{v[l=a\Yu%FIP0\,MS QH:^]jHip6tpqmT1>-Zd I.њTzQ91#%2ua~}BorDVOx)0z@X>6o2 -ilZڗ}zUs}~;kfBHfbV$l"$X, Ң+[D\кĥHiUPXh?U+R a {2$=q9\2QB74 WP: GBqui̅n"!V*pՊ`W`^Pcsuf4+, vf,j}%^e TX^kRln3ƶq޳eC棚^ʫ\Yb ӂ$^A qLihjwPw Pq[gh:<+nBf.߻mmW=m@6/JEez @,yJ >TΉ\bSG`Y)-=ȔYD!@hb2N Lҕ5WWH+a&-nB3I @F Č_"x!iKeCh<@m<$B[hΩ>}tۖcy"8*#Q(Ɲhx1.'*ꫢ 9S0}j/n}K cG J 'ÌBCɗ,(EXCd GKd δ($܈}ZTCe՝+v2lꗽH|o~;^BkJ?tEaߥՈ(#iI~ SLTAWhE,3lʗ|ۋψwگp#,]ne#76vwVsnʰlVπR\]fbRc\U!8 !R3ݻsj51 <h|"C v03f`R6gFVBb8Dk8ʧE\,HKn.92cђкk,NsmK8<)tǕhɦG֡$T&"!( CrqDaXP QR/ D7j&aRV+ye0]T; BW+%k:65u)} B|v VvP ,'ZK;B k0i\nK$}k)2q*)y8 kiMDi 8D7K{(xFu+@[!l R(JhZ*1a0]EI@Rn ׉ O#Z$  @4qYIHHz+Zi_x+¸$=" ĭW\+@)/lKu/I|ԑE9^@WH}JU֦RՉaZszfP?i-|^G V u$#T蛫/9/UhC`*7imh>jaY&.囅jDz+2וQʄ]P3nI*IC"b !q΁n[5zNr@WήHQ"gt18$.K3gNHb՘`gvtޭt!͗ɮnS| }Q,M'vj*T.gZ%{ j.6|Y3sr9RKy#+$~clƅ)%rȘ+6"Rؚ&hk6Ɗ:K͒hhRz RJ>L װX}r *նN)I65*yPEAb(ϹAőX |*7I=~JCC 9q s>z.;SkkKv]LN Ū w۪Pr$-_Kפm^cgHP(a`(OIʽ,K5FBcdѓEyV ߑRr8hL1 3S5P`7l/=Ə[8q5d砇A:`A}։SIWD^q7X|q Zp:Cst' I8,S)%̙!Bb$[zZZy*)*Y--K} ,d UpݻmW[suCԺJ @BIT>Hɞ,Ejq6)כZ=v{WȩeU ._C9cLŚj) u9ELt̝M<>ir--Þӿys TkYC^({CFSGvz>|z KVY/,Hiv>۞@Ö:qؘLXshJEw+m|{6S<Ħu0peh"b(5y|}Rnfig}86o O )fk´=b^dբN룒N-ÓZr}-bnM1TUB0,BZ k1 qB|l=<w< OW''!LH@uQփ2U P1jK~V'LKr_-iVIE:I̬>߭usgnamhֱ}!\QLB|׿G?#?E F\lk90"C̿θW xC'>d+7?|'[qcr 0;S+x=k9 na3/b(LЉrVZ'.p\j.Uڀ ǖe51IBR 7a\>(sm0SSpM{ಎd7jagVGVncu')iFW-ꃡK?ZXFżhsgd;Xq@*,S]b9<}y?;}˷Sm^al !8q+!2Y̵h>e?q0DDJ)Q_2j140{㩜/QǗ -qեt_pU? sQFdsp9٧|T&l%U:Ʉ)sE mڗiMJys\1ąb!Z p-_XUG|O\򶍏 ߰;\=c3rǟ'|'_Xt W|[g{w;yy _|WK~lv AF=Ox c:7G_}v>wMo>뼸W[Yb@@fFg.ܥ'S̉v* 8ل[S*(YEڀ7]?y/ )'f4_ADT`%`@nۙ?v;S[6D&Hu?sGӵ1%fv7e/][6̧k|͵w.w^7_u=5ox֍o|ӿrwqWhRv8Ed^ H(j u(K~"%%$ef)kI(mC%Z,>sc A zlK'k2WS4gulFR>cGTmQ؛քApt@cq'~fܐ\*wCQ (th;Bls.U>g^/i<)qbQЬ"gv]K}?/PN oS\>45 ~Z,8|ڳw*ٵInz8^\[ccg3=敻/zY_{9߳y)g~r>x߼5A}_WPs O@Yx2Ly 5<ΙQs_ź]'$CIu00KITj[yݧ9 ;|_9r}sO|L{;_yw `}Qn=x}%3G'_}#~Nʏ<_sN^w}p?g?G\W17 1}R Zϝ0( U8-XSIuhBc}e{aԶBqKHf5!f\:뉗=x|37ܾIO7X4vKRi%O[3̻o^<_^GoF#orݍwXSkR爒-rgsO_Į(g)Y,G)~o}U6<=9Yd aK_k@+RJΑ ձd0&Y7eת/6G[[Jϙbp 9Ȃ( !8 MEfWDgYFX]q$.͸a7ܻ0;x|#ySveQnv0> lg/vظ$`8{?df/w ` ިߒe%yDq( ^n% `ۖO]E?fJtb@ZzJ]h֨y*u4gm.!I[0g @Cʼnϼ99d><' MMϷѥ$IaGocCj[NH<{NKNUBH}枱nOD vNIW_LHU*/?1xw^aЖ6I؍tm+uvF#xcP'ͦ#Q֖we]]7 lD M} a>QwlUbylP D["'b6rk|iUŝJ \+ ;b1ee1KC-m$dq<Z|s7l"Y[4{ЂVIt Aq ݶ׷xGn!WEqL@E@E R1_6JZ/:#lښ5`d?" DϺ"Dlkx.D]niwy\Ӄ6K 2F2z-|ikθ /zᄄ\|?{OuyL)Dcj{.P?# a<ߨsʥ,G_$,F漶X%Q 4w{HXj1-q!'' 4J) -?SPӫ! @ɵV&ֺdٌX@ ߻UIoUlCFsQ;U|H/nIcg͚HOFVKS}&s|hrӧ~n8ofzǒsE\6AӎM0 Zd8& q!D圗eު6sO|D8ys&w1!N3a6 CS;_t?"w*s|xcQ=xǸRX}'/]'gn8C"S,ԥOj.ʮA#Z~RPuE:_NwME\"-3FsJIz!cB*qw?i}/O0~w n]Eb:~p}{ƻ8WKk㮳v^4U[^s(]bƲn&Y 1,K,JĴXVYj\wj5(jRYOPARRrO)#3m{筭{3Ͽ{?eM)Esf! Bd]'p%W>"  @@⦅J{#w$)vd2`8ٿz]}%ח.?OoƝ>~Ɠug>9h '0T}CJ9%D`Z圥'9d=X0D x`]$'*3Yn!ϱ7zi#*lzqsr}Nی"h8[6U; qMUYAjd)bp78>Y=O|HG=~hmW=뾚w/gh5BsoGP** 31ciG4XgyraF* u\^U^?diyz\Lmcr(]d=! X@K0&qND@q~ }7n}meOxn 93{g|˾g8q߾ ]ow`|Z幛3833RQOgj Q3p*l}AEVhm +i>n)-XűjfU`(P ʙWy=?]Ck74Pyhiiύyэf9ũ6 䕁J86RO$+@GmX@TjftMٰZpD`ˢmml^ǗxFm2Q8B5Dt!\8Da1+q5Z.ݻYX ؂8s!́lB\۲9ٿ#G}6 ptU,wŭR.dm%P ay`~AY"RU7w̫՘swcvAWgX Jh5)% X"ۖ%ZVCΜ(N-SRR3#" o;}*1,Z+>b1,r\fW U׾zٻA۔%F>0{!͡DYDON%Z,#3˔Sa0 )>EnI(:\jg) |U2)[:0rj.SqlF?=~vL6%1Crr֟9PA:K\j %AJLb񓖉M4+fT3L\(5ҼjtƁYG,`hI [_̂O '-Εҹe6QqmLj" g񲉝fr6SN)qJ)9\Rf'kXgRC 139";Ԯ 5[hVUJcm٥3aKXBÔ@d5o>=]\yv蹑lG$X.P3A7zgºHB[ ,(GAׁrY,'Gpu*&]u4UM[G=qL[ q3yVYhw&R;wJ( D/M~'Ha}TS<ۻ# RE]o{^ZT_ JU'tMƖ:w~FS^VHnuX Er8#@!AΌ)\-":m/,fuS\B[YIWƻɀlo ;Ԫ2G-U!d)PևEz-gܱIЕ;Qҏ: LLΎP S[ TpF!FB,G{3*I!20K((&N)g DAdܖ$TZ_Kq7k_M~v9&(/7?7w/|h2EUlPHĬnЖk''k"qI":ke3Z @ kvSV5'X-*f*c2y)jIFq](QUv|ViĄ΅^Uց^m#" Ԍ9}R(0&DRx\8I^y$wvz3nZ/3`"(Dε#wS+8FnuE|fcgB\,4 6\)-VwBΫ4fB(=S^J 3rNrÙU|,ԅzJZ(ߘlF$513DmIFT,݂e%B(3jKQNH׈Y(./y'Y}-JLE=)#9e(+Tc=yfmr6ҩ*ƨk:E4ŶK5CCokE')#&Lcʐ] g0k/o@$¡ vOR(D&4'T9'el.B\6_TlL4';[a na.]MEfe6&د5圶1rKa֕:1SusL);+8>&(BCqȜWel%AȜs眤 cB D!N$aQZ-)_HK %HXA=U7)zfhI3v(^ٔʍ D)ܽQ}VKٚ扮UG&M#m%L+圱nvd V*TcޟGYg6IScA3DιCDʥ) 5)drNqV&%^Uj~8 Fez9U_(=>_6RLbIXry`q}M@bVlMSj 11s |ё|)4v.A~ץك;zc :E{1#VӖi(+BYhLf])%,-bZD"ȹ :=\5p]l*3nEB/1x$O!٬ޢ ][m-݁>o)N,d22"BK1NDj8R;er!Vј_}5tCAp~n@#MvEq6M.*]iye-H4ȧg/[pE!{2v6TWj~4‚JXN)EZ<(Tnѫgɟ#$|6 LgՀ%Qșȹ) *18]-^QrFdc5ܣ&$Wo9})+*r.O"D,wTɥ`bHB1~+F kYe!s"R|XEQ螪QѵF{=ɗBqraG\[v h/C+a'S\ݶ5 3D):5$qu\W-nGI닃! qf GiCbEk?v"ԋ4(((q(3[ez+^ |!FSR~2&V겶4K3R#o?H;޸?6 6D}ݛX*XM^橡ߖUZ /6?дiL)'vfv3$ PKm93"V Ԛr|+^PY<0(ѱX?$lXT{%Cdy2 %UqTiF*Ff-=83@[iz"sж: +^y22̙4%j;s)ܨTeM0Q vƶQNuET}{Fˍݯ+?̙BŅ*<'94̛1̽<Ԓc$U@nދ ́]dGor9۪`E[2\Ћۇqj?j k.ZT(J!SȀaЫVס6z6cJԻO==g6gO~C)35c~TTDX+SF"16m=⪞IENDB`glances-2.11.1/docs/_static/aws.png000066400000000000000000000331341315472316100170750ustar00rootroot00000000000000PNG  IHDRN,zsBITOtEXtSoftwareShutterc IDATxgx\y.v H)Todvb;9Mr웜9y8vXGŲ(*)RbH :˞})RQDȲl/<3kޯoC l ! `XJU~[UR}X*WU|~@׮R '_y{$q|v^X298z9izJF |2蝽631y͟cx*ҺΎbH l>xF,E) ;kKMJ<ϓ.jlm5 T>]2M3w_Mu- %6%s٤ov~ڥaW$jׯkb9Nǜ#W{1 {c]eqN.Lعpm|lt֗XHamkh"%<3W][ ^f v壓a\U\m0A^i"^s΅ۦa^a\[k5 EWrl.򺪪2YBl.YsL.De),)2(&Pd*쟟 ƳJ6U TIfϏH_ԢVz&f<euEz1 X*/Ύ.i^A UUU5RLL_wD؏{Dbg}:u \@kjF,x% D޾VS%dӃˋ+ʬZGgYF \WXQZMLm5[xp*)Z˺|`[}naqo]k7D:0 ~3Ga?)Wwn'T.aDK3ot:!Qֺ偻n1uYpꨮmm/H1a6 G)#`9 !S߄/z)^+ZHPC.vj"áoim7+$*85~7諣vm=e:5"DM/^<56q"a6h:Xc0Cr=pǕw6$9Ca(8~շ8|w:|tB:eQSۺҲb3/D. &e#mij-H/@7uR.-ư\ghUO%:95^CCjhYd-)3νߖM=m%Z  <ˇsBX[v] l*^V ""Lp#;kKJ6t%eT2:q!2jC7gr^TQqr.S8-kPk{l8&Z +@.F`E-x@zm:图=ՙ[-6Sxp[N? g_&#![{w*kh_prChG5?cz7O + j4T6)$@NVX+UAb0$Em5ulTOs >bD'wQc%wܴ>kEnOQ\pp8Cs"SM{ZZHJ'\×qUUmnohqTE@1To2ŵku?GR(.f>E / \83Ҟ=m&I37uՐ{33CIа{w˦r$<2zh&928ynleoR +z݁LxGo-nͣq<H dž|鼼|' `T\t=6x|0"]*䖥"Zn˥OyeW^d)bhر}s:_+:poȦ}?/enVT?u|h2"G8QbvrS䩛֮-jJGbرkOCQ@7b'Eb!^8ƑO3qϮB32C}SMs{I$)+t`KG~q~nt~Y֨&^|beg?F],ojxM풢&)6 6f~H@>%.V/5pv\zw$Dz<9p=+5)`G!T[[:{dDL"CEwmwF?eGs<*65Wn! H 9}G;#Bלʗ !v78p*+5ٮ!GXFF&q\TcPdfz_}ǗrHsXIyycp}}L/ 4Ç {MSQ2vLCK(GHSR}ڵ.VT7-ʮ4)W"Bkc • d>&LuJd @E m̺@fcK]TmoQsFueU;lS.M9,q,A T۬%8n\+ܾ͚vNe2N]N,'I2#–* ޻njTfbI%2IiCI7[cydGgyjp0/b>Sݼa]ZVxsafJFi/XfCmyɬ~l6\2e8HрnUWH0.*Y䲌(K*Li-4Ǭ/J__Y͋`6%hPmF,L,bRkq=zprCiMe+UH<[Q2Y;F{YG8^Q8 a qΝw z B3X0^%ļן \򧲩"SӞwjMUv"*D\YckFXŽYbO_W;cLR fgYF*e;J7q@iB(%j*mXN[\[&ѳ~O;`O%p,)TP Q,Ét:^@:9 GbkIi 옟zCO€0).pV^"r[$]3Kƭ=C ͵ %OXWS`DM (^>չt[$DrY7ohluY+EXPa(msx4I<ZZV;|c#ѸD72djhd""0g[bQ-Wv> <0ygdѷ@*>R?-$jfDaߝI?\}SWx?%^lb.mZ8C󚆶ZkU R8rKc si[Wۺ/]qMO؃ (1L_epw]uǷ殎.8><;a.º끯m!K.:|m" OJ =ds̅3.ZA0OOF DX:LėɨCbMIeyka gБct+mݛj/_ 2KƲwWdώ 2(waȮ" k :n" Ώ{fjltlbљi>Ǝ˟f~wd.^ぅѱ<ݲe~I.M9Ok (^2ܿsONO'sGu]4x~Vf woi);oLDڶiú=?rdd)!FV&{ >!׬|םe??oL;)tp0\bW+G|X0&H}=i)ː<7p~t"B"TǴC3XCKYDfk˛9!מ92KPt"OSyFWĂʅCT2ɡ(.Z{I`6TQX0D2A" ,rD $g?S OdC3ҠJ HJD,G A$pΐ C!!Uj9+0$ɐd&rp"fY#@ O i(\$h"8Osr Ae|$.E1vT.if?1݀@%z :t: “p[c8<-P\e.xN4<~:a2SEqڄ̕+&T^4ԘK=Y5E"}vEaXd L4״ܻw%27z=hs9H^Rl*'o"X^޸F]tGRyJ\h)%q@Q\Sg5W(Tk:;H g5r3 t M#D}D>Op9!;}'H^ktZ7-6#3y)++.nR$gyPZJ3|&I@rرST. "S{GM%h MsBJSEYy[gDp.YR٣KXºZ [ t(vá`!o' `  ~%L' c2Ceg=.\%{w)Ǯ ^q'y@t!*Xș?Fr|E!DXA`ҹX %?2P4 @ 0C`ZSUbKc4ysQ F``xoAo,dm]ˡCaɒso{J *a INy`?JD hAek]ECdd[۶lcsga@FBW<^2Y$yN zRm=hS:2pM;~kzwhvt6.j]=Vwh+eBAg eq\c_sX*K-(kvܣih>SiYG[m6QH˫*:Ztt|+#DTڷ[ yQW\Ucニ3 A@M[<޵ƂDekK{~;C`% %,-2Ռ/0!*SM'wFAbVvZRQ+rXT]E;dwಫ)ByE+FsaN/Qєv6⼪ʅ&'#i"ȓڿIk^9 ٺͪE96?3] )t Rx6\.q$pϜ{]A0DWb\DZw/H"!b6Sfq?;[{WD0p-yN;MzwJP%ޥ|5qS ejB\IDRѵN"~!w2A%JZʔh ]S{!\)?=XS/;p͗ D*׶쨑FSSR=ܲ\:7"~+A Tj),WhI_6PZS^oD#rϦuFf&\ix kLl)%@GD"Yt9E1X-#xd2^btZn+E(D28IcnPeqm\pd" h`*RRn3(%8|&q:|1Hb,,4U |*zݞP<)؋M:G$,%_8'O갲n޼o\diTv긠{fd>z \-6TMY>tz=Hp]f0-ҙD iF *RTfߚO {C9zVRi4kf!IR7 R%|SIǔ32cQQRPd( , TFQD&|qoJF$6'hwE"} G'fG9_n)7)9$cCUvK,`B5TGt,Gn1tc-`دF2BP P}yyi{Unj+ͼ >?Tݶ5c7;rvc:Qk_x{wf?ԙ>"^Q`p~ϼ77!gWhW滞7Y!0;{GKUDdÇqZDT/޾ܨ0\;w[uM_vtr 8?'5ڳ{Cһ~v=oGN\px'`*|d{ǖh|.)*?ֳoם_sTA+ִ~/٥=M;mʵ@N]8{vm/"7JF|}sP\Ӿc_l]q, xIWc# QWNP$MeJE$Ajt+.6%FJbp 2XZb/ѨԾgcq/F4vτ(=(H$,(t$s4%'$#Xj~C;7WhEp*Ur55zpMyIPYgl>pRcJix s.1$\f# ~W[` <]hνwW*5j-,!A( ]"1jfx&1;vj u4x2[xٗUjFNBȳ8uYJ#)ĩCYD_dwlGb_:&:7"TM{e 8\rJ.^}jCž}ع)O0lm:R937tjPS<Ti<'ɴ;rXn)FVȹiF,V"L>&kYCKO$?܉SWylyR)j˧gz_m:Ir@G$I{ٽmMsXH:UJ'q׵} ѽ;Z7m7EJG3B}q/Nӭ[J#}W_< J @(%.*8k ,ycL8[v3jJ&uW%ӁQ+Uc y:(K64ܸ_3ۼ ܳ֨4D#[UmH&BE& G*"M8?t"g^؛'^dc BAr{S,\(;ʋARmZW B܅8 uH[LӀbhet q }IwW߿}7.rt/X6ַE#Ł t_X$yVl|gkY'޸z8:IA'W ZϥrDEAiWfgHd6 e% JCpj!2RR iCjK й|>NLk*Ҙ*9dr%l.tU}[Tlɺݎ3uWXE[c*:aD+ (j$ҋ %o2EÕmf ,"TTJN$D:!Krr9s42,OAߜdS#yDt*Gy_Y  %S84ߨ)RX 5cnw Db~`y^^\Tdi4}gl:ZznP4`>U ,$8+;b&abƖb 1D:wۣ&-Ur4pL}$שFSUK,-[iV^U@3dP Imh7`bd>N\:C ڊʒk5 ˝HR+BL/^}''x|0y,;*2m{*sG_=~|*|$\$r<MSaR x5Ϯ)ټԔN'BakzXnESYLm) X^ZVIx9.ϾdL&GP (*`HHsq1'IfI2lZMAQ*T*o,HrN_=xAX)  Cg x`:p>ljDE)`mwD>Sf+Ѵ#6ref7s,Pׯ󖪨mCDW=w\ꟙV2OeB}}g#Ȍ7Fk9ZBPT%yϟd/1/ >/>W ^i\rƊ5 9xz/YLGn9!Aq+n\da ,Bt GsIq<|0XBD"K ͔@˦B@(E gRT p镅E0L6HqL[, /k tTX׹=Vˀ oP)%\H!*UB{.aRPt(@K Ԩ,VBu\6o??3 ^n6k|v嫛TpcW*#HZsK@aQ EQaFP Eyc4AE!(b x70Sy׆M-׆| T,9ufA'd>ziRR8?^U jUZp2&% 3F%n_0̋!/[[u'ҩd6TG ;f{Z/ʳYlO{UY8ð3[I?e۷DC 2\Rhr1R\Eq n{:0>I\Yna(I525s8mq'8J刘wbb߳о9I.Og4/"ā Gnz,vU]e&y$Bf+\sMKIQ,6[lJfݑ'B~OZq֮gd oq]MEr/}%_VU|)"3dB˦bfkR\C >VNb:fX*VUbX*V2 IENDB`glances-2.11.1/docs/_static/browser.png000066400000000000000000001262001315472316100177630ustar00rootroot00000000000000PNG  IHDRazTsBIT|dtEXtSoftwareShutterc IDATxw\U>{{+ T$@J3 X HS(HW({!2g337g wf9z"75De} # 5cD>gq‹z_r=/d+bUe4>X9˯IεF֟mR.^[v%~{r拄 ŞĚN|ϸ r0QsœW.m CU\{aUi1UfmX!*>笴B =0!M%K>uT) G[Iu/\8$Nܜl *Yim5_7Ů"a0 3@{"[sLfB&-׭zƅCEפl4 ]g_\n+!*b]`&4D"YYIȪ^otx-5)i_G1$oef`b9-%y>@#ik :vܗ]@W>אds2M#P&v0dr"P(ygLo2. ֘M+T% ϛ"p!D6A+ vH/XRWp;t (f8 6/ҿ[oZ닣t>uވ"DKn޵fQ&i?WXzߩ LE%2(U`W'x$4NEE! 䙱NEPlRgy;*]d2<OL&`ǘ0dAb\DMvY2{Dw틠ҍ X4,#c ohʡXVRt$Qע׺wA杣9/f.b+l4'q-o= ^$ePKS#7†Sp$35y%bcC8mNY['x 3Wl͂ !ƴO oOXL!f&ӷ0uşz|`tvOl`9|bpO*; rw*9/{V^NdM@rs[X4u׃ӸB2sc ,SӯG(FwSgy>FxyQ>h} gaAX`\P%8FT95EN![(B ʁ C|BZ2XeFۙNЎ2^"8a`zr,ÆVZGH@``e4;#.R| )P;7/e?eMx.H{4rks6gA&:ec8B:0鐅*$Ӭ+)%oxO,Z8nuyE{};;y٭o[b÷,cffv>e6G_̻&;8 k<ܰN>-1K|j:odf^y7Obg C7|7?p5_xW9l(JD\=s3y~\{ӿS;7 x?"OoMpSݍ۴j] !(φ~J宯n/|a:euܾ"@_׏kz8_:y ?:CSbJ9WW (**Wʰ("OG@tOfT!X.^OKЄ8;@pn=H3(G b@@w2[pcuxSI6R t}S:eF* \gs)':@  @+U]e"@/}=U0O)h)Nԩ39`{q}ͿHὫYDFTدLلO"/]0n߰+ŬO_owvN XV6Mf+T@a!iqהȦ5cX!7v@ 7F2ƤTnnǞ;aTMb5;~5уeDOTr&v_?=0^'<5' L!EoD %s1_4!4 KYh#^; ƽy~p1q¾8}qF >f2G1;7 `[G6`1Cy:d\6nAսF,xq,=1v8b)|b^)Ke?zslw]JN:}6HeP[/5-2&5{]A;6gɤAg$ýlI–zQcYLS[ YMgQ:YPz#h'5y=I,}:*v3=B3u҄C@|֟7;NŁ%ϸ2b%RL2O?.(<{V#b=  _V-4-cl:U a| !iy6&Ux,ɪ7;h5 &@Z xC"{CVzî/PzkX7y+xzkp{`Rfu jZ.~# zξam5Cv yN?v~\4"C#`61;5/f6dym=0`jd:t؊K_)q5|K,eĻ%xH\;ؖHmODm#xf8=wcʌxfO5$gc&]0ִ.ΟCX+\ʠ~öB46p;OzᠯC~ ęucFCV 6Ft5SI/pU1$l#^LY߶jKx<&0W &\eSP=+ ;4QO8ϨDD,,ʱYVxf-Lh'qZeaï4VuVfS"&s^{ oLK*R@x>  | ZQ'W 62ngu Ux8ftx<~Nջ `Ǹg{>׾MWC}Nxf,](>>L >8^s=zKv{6&_{]8)''V=u: =ụAػK8Lg͸1b h?`4݄?6w?^pv?l&V4fwi~}if⟱L~q=q8 ٯ݂?g%_m36)w sYpga.ڦ5n8e X _u}ݏ;7- 5W6/1l~w92Utc~?ڈw-2))P?r^$Z^IgQzU\%9oν\ZP^P|YhNOkͨ\ȟ|3y)y\ԅg'ĵ:z[o[̯tͱФė^-u?zT1]k&ffn̕=t>{G:&qμNG" I]utW>?}>W18Oԋ]_k ש7bO{E̼M^d|Q>qA|ɿ_a=P!ADas![S)~.'Y0GK8U5aI(d H~cKXfFEf(ƴFO")JZ'MHhd$#IXjIbr܏|BĒR3T`x1X̄S;!TL4M0Ol'w.IJHr։VۙN;KUudmCXa4b{Bpѳ82pUXs $s3DB29t)pε5B4T_4'e 3H2[tU E2w?vTK'(a dT/ro;>/lU+|1`\F`]3+2bluP)QnizP\vq Ҏ4U|}ӄ, gE A^M*&Hzs Pި`]t:&a1phĩ$T !^xRO1_E ٥cX!bӠ5cI=',JXdgp AdfY(ڮbˎѰوs4BsgT$!izpN'*y"ȭULg $JxLKq B@$=A|J 3@fpӯ2)N !e|CBclkrHsPó|d*ԁNJ1׆] 0V**ԝ<IF æiY X?0-եfM &϶r(ȳH̔S.P v LuYI7N.Cĝh?]TJ9c+bZIa;Xyc</0MhaãQ<ƮE(W+ 4VݾIfޥ!˰W"kgrOt:b)8ײyj '&Qg0b .`fL9Js>N3+Am<>u &Qo|ᛦ )0ٞX4Bc8HbqgI,JB~GAt IDATOw4E%8ŮxR IyW%-hq9`;D$ג k0!ޫHL3vLPnpkZxوE{ f*ϡvfYq f:>ԊA΀P$@+醪  & l!KIj,n@-+~9PI1q:E[@lV$B!z _/YZ`>M2!w8vZ~+N: J(S>#5I T6+%} \^# ̇;(N"'kQ x终@()2+# ? -E98Ћq:?"bl˜J:`ONRi#I9hgPP˂1 fYqP'TAJ!1*(PO3wV,dBX5 ;-YK#ξ"ǕST#/(6U99H8V"u\F"C[Q+A4>"v ~[v(qj *_SuJI:QĶqI.CJ5iɏR1}lB1S!T;MEi.*L Ε?*9ǾJ(IA籨dAfC^ 7xu'o>h2bFPNw}&2mb/B̎\$_`cXIa|+̎Nn#N\F (@#z[eFI>P|# ;|9D/FīQZ%URo[Z'_FďU>T?y1qd a\Wc{̫2b1yRY-pxC{V %+ºq 5fItH @$Q IB*ǫf!QЁu}{q2|E6/0ڎ%S/U -z62N Xm"`lļ@*Rp&Q̺GީN$5%o--`?**aI!Lrd!1`ҠZ^<%uR\T[4wfDv\%D_ͨ;v TIi%BPJ}FHv [ /b :dB}@|]RZҳ^)F%2–cY%_k!:c&'cu͸JL)My9Ƣ+ c*VQfWιq8=g=]D cuacНU eё0 "%\2m`^YN)6lbDB\9Hu8D1ry 0e4wQB " زJ; 9`ېCre>?I`EJ9UP: ';ǗGգ:\XlN)*QtRhb!%]0aaXt7?wsI  \QYBJKNBd{ԫOh J7;IC)8zUԁJ$ =DN8\Ӛ=b#ÞDy既?kJlzm݆O`ްr(>W,EĻnB ;}tqE4)EBV)kPjzBV'9u)жKB% Pr:?Efx;l.*S%PrIOχ ýH*(dY0h8[L;Fhk4744!0mzn(v2ėlI4 z@YBh"1|®Ia}¢>rI@ /Ž!c)hpTWcTmabǗ9f%xV5EZ B5RC@Um^tw-[<)~*,g PD[{i]-^*OIbY2v)6k"5?AZj=/ƕ,O,[%B=dM s <}JlWGX$j,)єӚt퐯O(/>6C(gIfkJ-,0gx"v*8. P~'f~L/=AO'"^QOrz(714mͅe$݃LrW!Shef g2̜H 3+3N>z Γ#@>QXFO(' APO<66v?&Y\~u`GX)r;$rJ.DUp͖UpJR P9EvxP!Kgu5 iٵ. =.TX힪rq,,\̽x֦x򵜿g:Wv¡R飣'J\&[ M^af\uau`L8$'I k.$֩8R"M2ը1A,$i~7G<J:,HkKQ6q8!c|ajsJ"v#Hz5l?1ẝeD-%kc+ Ѓe (TTcB-1 ґp^P%|NᑌTvubV,bZ*!K6xW9*4!ҩ/U,U2zaHlМb;!vr=b6] b7mdrO`p?'&K5%PXFJ#7l;Yjp:vO1ky5A䷨1yU*q n4(֥DC>2hyJ~y@XgEOn0G]p pͤ@1tV7%']aVPiK2øXIa$-lr9c@1 WV泯RI^fU9ktKM;0`:v)w`&W=.0bU<ģRRd(V DWɐ` ѯ/s#XIZ̴חԅ$KR $erP9MZeKj'cl*L1Vy ዁Iy\FU1Y),E$ci٭K$Ozҟ EC%BTk,%L 6@ZAtO+J!N/maZcEST[%T,I-8菷+FsB^(xrƪ(lT;M(Bnu&'E5tfQ% 3]R;'>ΈmʢD7zKp*l_7şcj RqzfKWQ}RJb\Y*ZXmZ*MӼә!Hj\A||%F|ޅ,{BT;Is4RPqʙD ӑ?-Dق+ X*ƑS.3l-%&FL6X$`$?G}zeGzYE=?WQ2CK5"lnu>nX8'me,JJ X V) g7Bra,c 8kM|y݂t`߅KaQ .Q8n,vTެQDf(ea(l* {y#g.ZFn@ADW`pVO%(]aW`3#px i U$z>`^!{1˥`뭯rĤ; } ̥7V(+( K؍ۑ=F*fb  äX1Le![ z]g uY/EOR$b`=^$-zb% ** /%K.bZN*ip:QX@U2]Y;s[^s&CT$ zЭTG&;gxNرxc@Ê&y+Rh)R~@IUʃs+}N*KDھ2+,X,S)hI--9$/J[?Fr'5I΢l"0!dq؄`C '{H d*bO(~2H⑞@q:hR fk?,tKڱUX$;bb(D(eZ͢;.K- a STGapp[,$r![l()T@x¼Jǥ܇YC[QK(7{Tc>Gpc,$pZH-m[r_ve䲮 ʳ[X&i$kM_K\}UM5Kp@&>QԱ rj$E8jº?~6[%K. BBW ǝ;^[z}ث-vȖE28ڊ|MQv8_Q/#CiނO8Z&|cQVcEqݙNG\g|ZVEL{gD]_ CGq rRxrYn,]vؒ jZo?NVB}(g2L(ɽ#|t@T~lDL=:SnUeθ3|t@t9i4e2ؤQ/!۾a-,Lkߵ @+CZpXQ"?.Y8ܼ$?~Xdāu7gˎ,?yjDpUicF| $FCxpbR3$YM@HY`uG{{̽cLu!V5f5G/S6ǖfDk'pYzZJ8\qf9TZZ&(c޺Atp ^ TEYU{LT%;*x 90%*[^'[6⋧ p]㏧.B0=`tĈcE5;*oՌ#tNSx J6IC_D"م6#/3<&LĐf0w1}Azz$.)|8OE[g܆nŵ-a&mP7X###Y43>Êm^ol!|_ɠ fY_?}'&'k~pG@6kf]f@sga֬itEد?߆]{7eѨffRxE[ŧ0\_Ocy72e`ǐI쑣Evӄi% c-pCK'ǞիDJ"2@$O|h]?#jr>1X\uN%1z%0<v5PR+=bF;`Y \06z$.=xOĀjKsbĹǫ"EF6)°D=Lym-n{3h{NEXn_eaus`ѫu~6K%TcBˉOhYIVD\~t[Eٿ#:9ljPm`!=uS*AGbHFs{Ԣc&%NSe{S_"ˈ{ \36>} m۴o_Ƕ#oPS5ڶMcy}+M{@Xiٸ Vo~}W:u߼Ơ!1h` u,2)ד_Xtvi &P(mP9h UFs(&00vX t8`SLjx@3^1l%@pHإMv\n3a#!}c=KǑxǨwc萐LaOcv t}`x=8塺"eM8Bv_.1MI`KsFGs.?hx ~'&^Wa;lO3]:}m8pR<$ $G&Y~Z*3KO*a) ŕxrY/Uwi׳p@z)!vP=D\5wc?59ߚoC!z\퉣cx9t$[0S|B*MM iW墟9mBmfc80|mX]ΉU5h|ԭ@qpj]M#Fi^QtgERh3 QϿ0h3f9=:3=>%ZOӯ;z ;p(Z BEwQҨpŘQlp˳mx,{0tHѦܳ 5+8h*%} df}g9@fL<|4 s<$&4}I a\_EX&3֎jǿ"EH[ ,Ɠy> u6m瞝mmSiUsil!r.䰱'֌KGK޵Cɮ!CY@)*"T IDAT,p8;#c^v_t}4>8O>3|S >}P}.; }ʱ81e@o⢃)=*Zѡ7QpTɯztG[-VXtVڳ-:uv0빷ֳ3qv~f.5zlDRqԽэyUw.]Cp o9sQזtP t~Gev7 _[|i8OиCXXKX97r=^b O~U/ ׳q7f/$+ L‰+,ŜeaoakO~`P9BB罎wd!$eowq/Mg>V_jHS[ΞG_/+/4Kք.;w!.4U`tM[?*5Ton=Kǃ`ݲT#tjæC, &2}_aHh KIl2<{KW 6o˖HD i= b\}y7a⹘=uvWhMЈ&Mhl؊&Zн3oXMxcRO;/X}ٹvD/W,O(LeʶbB5Vb[c黯 ƜYu6 ڌV匙6}`kiGW@4 G\>Mb}NõO PP.9->SQc?M^r}}ll YJԪzZb.*plqgހ7>FEk;߸|1.`x yx޺+yMpRt:=!{'J1 c3ye{{70^́No3[o77wV[c!\{RMJHh`Tg*–+ @]ϝPK{ЈU60u`{q7}Hd( +mFs5L%QEg$a1WkZ}ƧpD(UA=4!R1h33@78|{w{;5g|׎5n/Lkt](}%6M/usz8]9K#Em`6k΀Wk'd9]E><ӝc21o P{OpV\$Pp`ga ɛl\x B}^ӆԥ @JXy((ONiP=v:.<[c<,Yj8s<΃g>UHIf϶U0x ӭ|:w.~7|'?LtdY_vjg7菳fb1`-iZ=Ԏ={tL:#n`5nW{,46OX|>/`6; AL{pϿc}o?O|޹ցMgǏN }Px}8th"5X\@ 꾇Njq g̑أ#Oiʵoot>7aa}m|dqǹW c_ArsN"aqZ&yہOQ6"|!#^icsܩ;CDO$X Xm~s]tXSU8 &]̊Z:N<Jq&i)/IU|;MQڜq{^$xQGF͋Ѩ6zKس1鄉8[qрpm͸v?)6m1/xVy,֌0 ].LM#WAT̙;żsOuoZ/\ [Fv1۾' [7.0G~gd|+־v9FX~xf:9(E =y+h^7x/:ufoZ 1adM]xufl]:~Oۊ !BjڶE]M#?^Ҿ%tU!@~~żY6NPWS H4jڡV!+#u$WKt7b"|4u*>`+xf^B9-4qW{xeCl9~lֵ3ڷ|B}Ok"SjZ. )KMeol+.~MGhu8pf|ԄsoK.[Btha\c:_|OV?={L^ԄT> |8mm<ڬ:Zbz|P ,;_ X요ec$k) 2e?MRF{y=Ġ3hƲ' 8'07u~qxp^ZfpgCp}aUpO&|0[O;^A4b;w㜯_7 9_~Opl$l˛ե1=$+8[!-Tb R \(2'K{ln荿 P1A=l09Ǭ%{^%N,Lՠؿ[NQ]FE]-;=&bq!|a2e {iʃQ2'.4yOB*B7/CgE?.꧇/o߇%iSĹ/K̢F$] .r~i,e`:)݈jfcX3`ƕbQRc$܇@TӗB㼆+qQ|{vk0h_?2a{3%KKW" \SV `SeޟHCTYJqim-BZ{iU*.lϥܾT1bgDD&dJa &u!CδìX7 ) pK \~HG Tit'3 K pEhG>褶W +c| AsFw.Y9\ n5%۫]ICdQiPa'}+\F}#jy2"M ]B0 $o fSC?=,~Ny.0(u`^ZtINy>Gu%[e)55l"RQYk#hPhYٵԍ: H ! BOq# (,Wb3C$1n, *vfwR7< "\CP\f'HM2b|'t紤@5U6OerV=JZD8y$l{AuA()/H8|!"*8RmUQ#p^4CS[d-kSqG_t1@XcQū2auC$a^tJƅnx œԵ̲S[Z2JtcB2ub(HŽ9ҡ߸"e_u>y4,@,!@PqԹdX(! (& ӓ@"a0̕:<S x& )TYwX\(N0$A׈I!.Ń*<Ê_ PLlzcR VK**.dC`hOƲbKcD'^lDSiِDJ?XQ%[6s{WUث lva~H+(%vVfeJ TޠcXZ\AIzt˦ 1DD VB/I~n,6~GcI"+T~=Dή ʓ\žqP2D1U3cjQ+v3TrEpk!EH!#ƛ8 :i򗋆]2vOL]K˟^k]3,'5o\b`-`(RFe0Hs(1p=Xf'mwН˞Y[)SDR!CR6ޢ4L~c_e{؃ 3ٶKӰdب8BM?R4 _-᫅ʡB\s ^#^?C~GD8tDGcǣ`1^RDwǷW'(<9$L EF L9R(MBZID; jpA\bCKkL9lJd9ģ5p}-y~8W1>B7u vn.`.D ɦy( \twtbG 6rh.1i^[ `Fkzal}jV&"r8m sWǭ=S;e4ܹ\|)X7!C&5F%8lޥ38j?\g.ύTme5txOXgVǭEipw:`.UH1|8;Tc#NC[jƒ_\-r='??6{#KXܫf87;aUF,^r5^9G k 3 < ϛkvaT2MMsr" i(áG֠2X2<| ,@?}+6o+ K.O?}Ψ~'7+n?Ta~|JWϨ7Qކ6/̑K&Ss3D&ĽL,/#BS뤏E#nR]K^<Ε?]%R~8< oĂ`;k{aQ]g/_E`ͫP<b;j`̕ t">۩|zO0,XH ?~'[ߌ>o~oGw 㴷a׹sh̔ƨk̼,>tʤk4P,S0ď_I{_7ᏺC{:w V+b 3>Sa,g!VlSWS:[/Ǩv >mgb@zE:Hx&\ SkԪ0?F4`sSnǥcのP#"#sJtT/4 x]q-еӅ9 /ClH: wI!2 li?Y X ;g^VV߻G6{4vh0N:x C5Ko{$,{a-f̩BԢuV:ECp}mIUabT;9^6kbi,7`&lq1]pQ5MEh4v:7~hVnXoTX?{~Q4F|рUФU~_keǪۺksaKy8{ @Xրu /u[.E+TW=NlU[0MXi^d:|M?2UV]0ꆓo銮)|`cw/#E$_ MX5[Yrh[33IK앫It:oDT;:BmkG'|)cu9 <  iePv~4wyd̯[%"îjn[S3)oۉq ]1eon‚y@]QTC)Mo n jG'~墝*&R񯄼T-$?^Ƃ-,J upp@5UhmܔBv9T3>cLy?޻ǽ> vw6cCʤyxzj pbĤK n!qzWJ\]^^^ W2о#`uoV4,~`i0qDX|姸 >!WkbZ؊O78gj_=;^s:yK\[Nj彾%_UC:ahG6`[8A~|7a1о.Lq),4F-O/y1T s5hNꄃ7bAsA3J =x'yRN|p/#PO r:;޷-zH{a֡xk56n”æapѳ;еF,&$h1ah=/숚xksR jt` %kqKpP6fjvX.]7F=~Kv"eۯ:أ/Vk Mh{`vh~q5oIJw}ӈbnSV!`p.8~">jNup7| ȫñ⣻2hq3^=w>y3PO#]u)U9S[>86 V<b%mkoL?kN݀gC3Y;-N0񺝱Ͼը~f|pBլ95ŋ#I^.Tc=~&g*i.i ^ɩ7.sfn34{֬J꜖vە|6ŲϯKߒe_13 X0b fmeP +@, @{ mm@+?JNyKhe]g?BwE}O]NS\g8(ܨ;t״1PGs/(_j^sE My[}M4U_A45Ŏ'沸>`{!%$`pmd%TzO.5ǵ+6N %ѽږhe-Z/#%r/w~qOl rO/td Nw&qa7Ɏ/iS.nxw3x4][20tϱ\y,Z̙%2HsFyN]}nNF֞ q0XԈ9YTA 9Zn9ؐ&ZY7b|4 +}I6+H6p ;'(8xO6|*7|ͳ&>yzkO&1=iQ aCaURcѪGđ=7mX۵P("$B9Sp2ǜM߳ly&eg̸/n,ĦA;OtK_MM{sǘxo'~,._ng} 8]q$M]R5bRLYUT 3+Wb^-Ӏ?gzGD`BET2sA KWYTgJZ8j_˕].mί5l& 'c}{->XWj JE|ˈDs>bX68/沏|Tf)HbkaX}llԳH!`B(`6OZoѲ/?‡ی5o/$#F7+.D]&d ` vs300(ؙTzM;]Y&$,x\  ̇4}ٿ}mIZP\s4_}u |)`ǔ3*ͩ7 @ %cevצ=t_>5'd"H̲W\'ښu9ĆpF^iytDt1ANr{ G 27l)Ëms.t؃i#нiNQWͮct7ieISl<(F8%V+aUe)2AD_*|}dd.Da>M8ĩg&I!찋>}>SwLgi+3KRǼSh:8.kjfϋi2|Nyk=HrG,[fb&]XS˩%a}7ϛ*}9KCAv}lήd"16߯^W[|jڋ|^Wo&/WxW- ,"f=>GĿ{o'.D{F8̭ZV,Gv__8CaHv$r\9EMy9踿p )7I YXA>!E3x"`g?{)`p {mC]9߿vmam?7]He#Bj]Y>[fs1clNv{Ol{Z" +!芓gv_ujq =_bH翊 PuRKQ@8Ky}7n妯1b*r3WdaS%[peO7bt3V&4{ϐ*۪~s1j9c<_7EMg野nQu9]ncIՉ-7'Bgy:Ϩ `TEyr⣁Fzr܁ΦqVzys~3gqc;A T*)Iq%IŦłg\Uf/q_⫧!8*|4/U'dW7# oe hXpy}Xq}4]Gׇ;ƮM4ʾMc.QQ1ɒ6Nl@'bqJqS3~>MxP&Oìx s$9+ZNfZ*,/K.'Ѓ!Kkx ێ模1;r'[UNi9$||v>: w1naLh;u4%ljWpp*y`q+Y4b-ߞ do\ݑD%92JїcG 9qbP;? {3nUk({,ZO }LO\kpL<?8 ad%me42/_67UqHܶtíz.~8âxt?͎)^0ozV q)27mnqr8MU 끣׉+'}8$ྣ97;xrEvT@0'RQ9Oqz]2+8'ݗVB[sro{rĹ~ξ{&*9|(OߙbGkx/W3N*`Afc<"^5O?D5-y->G pq}?ʱxvDwQ,iz+<16PXٰO#ŧmwEӂ, M042!j>k?;JKc8[c=ܵ =4X1'oҳ~i&Mݿ`ۛl>y==Ο>ʫkO?3H=p4No0D5a;Cà _Plj'ǰ6qz80@g\"ؔiەJ`g?t`\4<\& SAQQI:T:9:8+i3YR~T礬0srƅ,{4kS`g-ͭh&|~>{{ᒯC!MfVɶr_J z|n37楼C9^s3S*Ƅ9ícPdd-er.1iu˹(*צ<[qks jE%,b.iEtb*dR_ THc:0qzbR{ިdn$MYEF%VKbz9H;$ rv\_P1`*k׈xN0^Q*|rCUEÐvcrU0yw. Ė>7zKV^M1<>Hՠ=xG[ [ژ/| yRw95L&Ów4!S{O q@46izu+ŵFuz^"hFQ淈,jJ>f4xXh)r6J3`\z`X" ~?[irV &D<"J]}6&\j!StnWdS'ſ U~J̛ Y Më5y w|3B@a4aR%39e gLkc=k+T|6\{,ֶƥp,+}Ts=Cg=4t.k'/ `IͯI(-4W DZ+=%1aUU.@SLZphvi|}شs;?2*`d$B\e+Hchb6@4E>BK"`)l[ /`5@D\ao*#Jѷqk{9d׵qŵ$U;;_{?llfj4Ο_Ζ]y?vq䗠?,QnWTFxkVy׮a"zl(-eq,<}n6W*1 106ByUqT*Ů;z90 SO]&p/nFګq5Ԩ ǝ_bw?$NXN2=ȭk.EV/y ̻h>qI=:8WPS;5-w8tfQOۚm+c7r8;c8bg\aWffE%+Һ*^o~st{ );&33wEKcX/rӶVji⽿YuSL|ξ(;pۡS'.p.P{Z᥏fs;y㍅맻k#9 ,g><7ܝQZoV?|05<'TW)/E<ԳD۠z IDATɥ%\Zz.|-_6[3Xf; ͫ+r1&4|q7ۆ*sf`8ѵ߻]C5nĒe{]w*P%I~A6zJ7l j v&?a@4sʊ bYͥm5X6)c9sзQ:־9S9FLmwo0N{9e=^7%rEy4ґqz1<^cUvc εhݖSWǬ|*0Ía6>4LmχF,š0M1Ȏ|L1@╜z֞ q/4»?(Egp) 5:}_.;XT4jq2z9,9!ՙ^G m7d*ȧZ8i.Gׅ<嗿,wysT8b W(ojI<*92yMeFk}M[ .tVe<|, 3^ x6%7 q[xnC_(e3w7r3 YW潵F_kV@=ğɽL`O{?Ł,GYȢ<.5Wot.|>/ɶ0>Duz_w{j{Iv#E3)28('{Bz~nz>L®;ևا͞u/rG3̽>&e%qVRVbt+EM,o|F.b:9ͮIOȩH4 E?֜&^n{6L 8fnO:h倦%$"}<^ʪX?es.!hu8;y p<͎`/Z^ӧ[ivlͼWܧ`YC\QOg7=0g{ ĖM) L}4LlcgcV>ߴ'vT"AL`_?:Rُ3RSڋ*~}KB:ȍSj9X2op%⷗'2Tv_ ͟\՟2|v6I=b4 J {ȕg{j.;K?5r;7ZiEQ[sas=a.ϟμo }(s|Ym쥈zNZ)hp?Huz_y[A洹\v\GeТa+ddy,:&Ous7F!cGg8nrӚxÚ ^wts]7ӀXk!Mpn~ws/*i[nzadjUhUGg-30u'?gK[jhm[ؼa K4;>k_ʛı ׯ~|)g宻]tE)o;{K)i ٭'mk1&W41hi3k6ʈթФ*aaVmU2Lav ]af0#JJAŒzfl8Kb<>_ac_QvShQRZװ'&bF#3ҏuN0ֳ* 2bLchbT!\xbޜ0g;_,6~pΑ)пXG]VO4dQ$H~ YHN[?XpfQЫfͩ)^|hiLuhC'o9gϟo;ȟTџ})VΔ~uu&νf4r`>0]9kQƜXS(ey\T s-/NȱZ'luIgq^-Sh: Q77[=K%ŭp%;ǷqcNZx e ܻn?>nT c(KVjnJduÇT^~^YuT K?+~XQ_ަU_A45Ŏ'粤b!M20W1tb1:_c$Q.#VG2\z-X!%d*_ƂMAlB>ە|6ŲS1O5GwM>8āT)%6C@+(zXUITs;QHaEnME9O']'dw:Mqx.浐(T0($KYNdQDT1PGլrMY^zӺGxrg-[9֜|iݽ\Uǒ f3LD^NcYgҿA`;w-6Nmv,oHL(zLl}h#zKܷ H6p߭qnb[Z |iޕ 9@w~;ax. P1}j>k dS&V2?XcXwS5g9/%|r.%QHnYuڕvɿc}/簤^s'*SER<7&elG>1&x3M{i?,YXq6>jxo_tEK ,hjFg|5ZQd'3J_2,$f[bIwĭO 44pR+z%9Ѥ*|o>'=9Es\=NCX](4:6TIWEE8M;o@q'%Tί;Lu|cS$lXN~DNoOwh|t(wJx}O'>weȈzOmPqe$7I'u~:'cRa'. ~Rv26MUW"w?RϚ$o,Kγ7!SY׷(ISj{f-FS]f~~P$h'/h 0e#SBhoiz H*ŖNc%dǜ +bv $b&]g{y3hAWC۵k1w {$  Qř5iB|e߇1*5KL*f&H(81@8 _},֜qrβϥM|&kN /A?w /4^(5'zʣR R;9<^n|poDo|0'_em1:o;8FWDGd(_&Ԭͮct7^{'Y:O}?S;v5g`PSk.yW)2(y} ǐUƯ#W'[) ntִk۞ p<..J6$mIZP\*^[cT\ l*=?v5o|/6ի󿳚O5w&#oOЦf"`ڡIZ,<*r)G%dpr jm#646NmZ}Y 9ԞVUu;qǥ0'6RJcŻ+צ9(mCSү҃o_֏Cw)L{F8̭g 5#Ɋ{lDC]9 ɢ&GWF $=]A,ƌ@b/\r[s]*B䎒l(>U z$wpn#*Õ=а6-!Ih5 +H~P} ^Ϟ>Nj'y JRYZmtQs֌N<`[_'6X=-x'!> .EV3~Sihf]'Ηw$ܻs(^?vz抡\\C\Ă8rJ!5{= & q}i% Խu<'ܺzw̹Ŏ{ G9?w9 =/UMtPCb`[gOa=ʼn@V:?`]cq\@56~<=~r2Q4)jym}3s-UrG3N!JMޮ8negeGjSE%myASm-X'^3WYTqׯ`M5۸=xnP| \ϐwPUtK'~w/{hR-|_mgr̹U)̕GCO4swXνk9:ʮlS{ W(f~v%xksG64LϞyo`oܕ~ kqy{z?ǩk!=Cԫ ítLN{{5/Ou=AIOX\)M5MBFل_9C%7Rȡ۸a+hJs7?vT[{jڎ3nt?mU#U.I4:2ƖߍbTӺ16߰fI^x=\B-K6L_ Qc' ;~]Bs#ϩeɩXy_g[۸GkĠɔˤx3/q=cbQArӧ{G~n [_ѢPE*͍vn%-+4\{\hjZ+/"YMSV처\2Kj\\eY:!_ C6P,vrn-+*t|{a|zY c;c)dqd7?mvHQΏ_֌F^{>x 15*,&Ar"M.AFx=<>s}v=5A OaSBccOur/GITFUq|eWڏEjͫg;ӗBQMǷsmwW;?ڈCD{JV"EGD{'}yyZ22y)h_BWl7 OƋt,]\Is=3|}#߽1bRUbێN}J0w{%QdЃW2L緹'/{܃b*2Ks KW:Q% B\p"&G kBfJS;\scEzo@sg1.*VTvWG)>p%_-C!bq3*2Q-.,7yD\MﰷVArv]hohjܙ\5m* 8'Uw#v[MJ,]qI/V+3Ip"4TxUqv2ʘK&6wq_XKc uf .IXHex_(*Mu,C7YkL?jD2hBo JUee)/UN=^*hG"8a'姏GX}yǧ=6QI'+%=3%p17Һ[eEC 9Y %qǁTȮݨKVmoe&~YE/ HF6=9f_Sl("bbȔqsՠ-*U' MT #14S>"'0~+~ ;N_ȑtZJ| ;*E6rDS%ޣTvPƏ*Q;+3:Qz).J遜U^APIstKYtk7 %Hpɸ cCP:ךv|1 o;+W=^_ۨtn@FB`XH^a.?'%6}n[{"+ bt"eGZO7@ 0-H(H_0t-WL\nEE:HH}Mpb57R"(@+]F$"q91 =;qq).b)`)$;G:SݝH) ~etzai:"OQIt6+: $S EUEMa%M v5Xɷ#}R98;h[n~K΢JvE₊G-(B[S|Q2 $梔:ZUbؾ?ޣ!We57R}1InJ$R OK;ʒO܀O[U4h4lބ+&);xʖ1ItJ_LνT 27K*–UGQJMc3)GkatD eoq1^L31"*:NX\I&~QYҕ*mp(_Yo_ d)dM؝ERҐN!B0/eQi[xJcRFW̴ aP!1 IDATq<חEDFAqވU/cR SCT |E3ZVSBݭ@I|ssUy]8ֹ*ETqɔ)WG7.ͤr^oL\[#eg MDŽ*!JR||r>*WJ pڲ 7UZĉkE7xOJz%8H(/ǘse$imQ(|a-sF3TqI.^=AѕX/Ki:}sP"-{\IʍdPm1KM*w4D0u-SN{@v+wJU_#9I*K e% *M(Ι[ Msi+#S2!(@EH.ay>)1:89s> (?RĬX~۶] _*/{d4bŸ[UL4fb?7ŗ-K(G#Ttdfy:8PKv/O^Q4\ +zFԱdžeFLJ0)}|UBd |0͢F\2 5fG Ndم=.tQ"N Y#Yʓ5&M~L>Y7&5QUsoQA 3a % ӫS؇D2и[#: anld2涮HWNɽD )cQCXt`ݔ<^g$jb[5P4&u),KPK],ux.[JS)֙rT=͔Җ/3`@N'<?򲼭_q` &(u|\ $ؖZ\pwݜ[ԍ"zO{4PdOʩ`7 ɨ tȥɟ>[Ė&/ZgZ 8zP'J ,gx8jG"/7(3nV/8d[fxQFnx]n(^^2YqmfT!eTyRJ{ݢӾ,<?UՀ' JK̫fUc0zO8 U%8+xH@p"lO<ݢ7b*CqP t TqбKm  1 aTJNȶP0.~ ,ޕ"gl>p jK"o(OEE$zweAs\:N SXM{N5KV|úÆ`S22y~deY(eA\Әee]Yroh; w 2"s*Fs&'Ɉ[(Z2uKVjW KH^QS[r/;KܻYs0Ra>+/034 0tȫ[ <%RfJɩo^D ˮuRK U9qrM(?"@QHvYu/V2ד0߉뾔C*w* ~͡}i Ep?Ul2MT3Of*ʡڔ[q%S 5ǔw9jB)"+jYX,eݕi!mK$=S.Zo\eH@/Eh'eC[Jy%pH| YRUNaQf+`O w'n7O-"tQViH01WRS;^ y$%K瞤T07dTȔ J!B'>ΝzYmVq9hZ :uף2h:  ]&0q$d{F,/RerTuX%\5u)e%yK}w} mpG<Dz;ϊYbl0(Sj+. d-AI0X"CR[__E+,4 2K{ )tgGW3ȢTS=\ X0+^`ՎW$m+^Q%FFbJ4Q"V қ[m{W'a;9sfs\$ 02^1\61:F 5`Enc CFFl*5D7@&a=Q!N;(bR0fق\ME3 g",Ta;\ede44qܲFT2"Z0 [;41av+x?gƄ12[=0 DF&5[XN~fX6erb?L ._63?´I[Sc 4M,?֊" SW3 [\>CwXuO1*7yˏ'eg16{lɡZymr?Ӎͮ[c͝di2rOP>ƏL1`j YuCYd`$6Yf)!Fn!ʐySpe! 6Zee#J-߈#]^[Dž-}^B&wul±vr&-f} ELâ)\-ƞ{nWֳO'\H&,y639!n돀$<hD*Xo~X7(27 1NbgV>l$;p5Ȍ ȨossƮ-y>v}NK{ɱI[0$` 6s+Hb#iyKKDp 6qjEER}>XXV'-"@20:G+x}݀ñٍ_θ;4g}LGõG3()0fMӓS3bz ÓM9I^FI<w-=95U_zI% ;qtlF.~'5#C;!TON8Qu׍枦$pG1NnEBiI(&*~5>X"q$~H[ c7SCkeQgoOHJ}pn68+ 1iI)ǦMt~}ֽlj)Ŭgc"sJMLI|x՗N5:{Á'$^KJa&<>2S@]M.|}cR>3*I81W};KH^Ezm> s_WYYqG|d>fS#V ata !W6 ylf=i!o6/]z?خE,Ķ6gW%~7;aXTĀ`@:lQO}䆝䩌t&,l/cֵKݽarpn^M r&xq[6b&"Ml4ir;.k1.4"=͈Jo%"t,BErK}g]s@b[gW%uv+i\zr1Eqnw΋X<(q)#F[0&DM`Ă h,Ѷ nզ=Ĕ1YhC~+%`0Ggo\1.Ki$9 { fAdnjOv̩,i}vQoh `#6+r#C?"k"7xSh/.A.v}o \vƕ@~󂖅Ki~ پ9e'W'6={_o;<]xbJOoe\zux͵mkۧ$X'ԓUx[z錎l눑ðn͑HlZ.d Ҿ}pD?H_$?dԦH@>Ō}ή"\ R53B-@??18 +p*ѭc;"z?t~yg:P߫W#s\F8uQ$BfU-/c)6mRnPpƱ!|Qg;žQ=zN 3zw]QA={N:Sz}]zvgbA  ݹDc%%q=U"= dESCo]}7S)r7 @UȾ*RkLG@x,q@@:dDf)*؄޿ss* 겔unAm$C m"muiqFTCF\_y+ik0EQ>/9:D_xq~)~ۧ5-lyM?aD_s/3.fV߾}BWj 'j5~6w3wnj(2Jpީ  $8L.}5$F>B{3Wgk{:Ɍ鮿_[H0@jAԸYЂsB$=@я/3yRhWV^=k痿> D]J:8RG}r؊*K>VQyez}zS74;:4it:2Dō~:w?- /rƖtA?g`?xj;wh%x~be~պ8&(r DJ#3{ {+unWkGvGl @XHڌ&}IUY3&j{|%BO76'(fF}33Fn?0 R䞧>Cm.K:91Jtu3.F}3Ko,@eg7M|URIXe{6&|k\Zޛy2.MJ$rJ+;4>-G3_xF~"U 2uY :#ti,P {F5DC1Xl+Rw o+@[vuvz0Hc А\[RI[K|Z#̸5<>󗰄x߬w$zJ@T?K*Z:ιt9oH*_tޟ6h8CS Q15g5e @UBں y]U*ʥYI>Jvd|ǯ7FC0~WQR uj|ǭRÞ21W@nj}3+(Ղjn5eO 1 ui&%j*FZ+ij$p 5Ptm l)D?'j k5:իA*2&Oa_]8g7sfMrqi͜li3f5paa"nŸ4GMӳgacK@ڌ1m SWq uwN%[V?f@4:m!(U؄iH<:ٺ5DQhW)K5f:gC[򉙊mxCrN.oӊ5nЀFl.P+=bfOR;jJ>&ެ3G|-vkw v@ܼKͻ~!]gJBH(qo/+i 4=wlj7L RhVBG Pk͜.X N)˹`1 ){+@"ʰS7%00 Õqw\=|E#rm~WVr7;awlwZYqwP&Q_4JݬRW6vB@gb>DOw‹}Zrrܳzcma>DT)bl6NPL4OE9E"tt%` SWJmmavm!dȅZ59!"@j[s7<.Lu:%?  >!iz=ҩ{F/z5#f^".y::$&1@}?i+2ۆN;?Q+U v!KQ#+G4T+ cDM/➡=_]$pQX]JY=Bu>[-u sP'n(S[:k w.$dAJ5B)@GQbullMZ'[/WnkH}Eƛ15#l.-E~}qo9z<Q~'{ OeF$)l|F2DQigsK]fG"xՏ@UV-QV{ۤjk1[t ejЪM K"ǖB00@,$P)@dQh\HzH[.m~M~g.?Qc"{w7{++{饶yHT vޮ^[BfH]4"i?w&߳szRKl"ʄ=[7i=۲z1#mtΘ9w{GO9*1bBmo4+ Sy8WALF@lE&t 냧Iav=Ւܝy 7' H"hQ]yi٢:֯eBc;]s7{\WnzHT vn[]ҝP(hٶ+rtіkT_=fI8T? ҔCiKӪJ)#{up8Q\KXU%Q:8,~Kq&%ӄ*_=tBDk _iuε_J yx}g#!ޝV][y[V%gb[XT(Yg.;zY B- ʌ{]S;<`ɨJ$=Կ(O镪 S}&(j۪J,,빞NWYq*3샺zOٮޛ͸F:}xg>%e4ޠ"Lhۼ'> nf (vm #J`a鯕 xTMu1{ZFO%PCnSogI[C|kҰmyr4!er >/ʽ_=؝DcOԕez{',Ui5Mj*~͔/o0n3E~:KGw*eiB7UyGw"M8;O3nYN*f-O^4óFD@IB >'Y:9{VyAz:`NVvdC{q4:zNY'\ϬPw˵M,l y6ڹOFFc7;+ߣȔ>~ov&u'4__c| z Z_޽o)?t$z4 roI$Ȧyۀw%WN|w?=A2U/i![N)¾^25uG-_nd;@5:2jm@QPj^_[O$7/ٙc+b\|\f{r4mt-<*]"sׯ:6x 8PN6圈-?V.;'5xfBݺxhK%r " w*4MJjVVUh,=LP7ޛKi*ۦ7rJjj–#wsT6+[ n~ hř;JM%V  .\}7C˞2!^24/WgmA[~ҪJ5ĉ>1zo6P|ǪEFO><`y;gͿ\A AmaBD)Os=Y*dd ӹ?һ'_.2&@%Xhqrh(뮼B5uٛvs~FVvlʫ%Z9%ۆ ʳ6ʮG|ӏo=Y?0,Pm YwN_R`ؓNP90O`Vp5Ud ?>6OPTwL"0M33_1BUqr5 IEgsbe\4GzX סS.ķ îVx޵tn䨩b߬]_~6Kj9-#'gH;k O}]usoOLW2DƪIM鵟go[D`ČVW8|:-DgK|#P^}]T?=@xmlpHs3oMoz5#*׭8e͖3T}Q-p9-xh=r]=P؃2jf`iLM] WSj N,ZtقDM5y u9sH$sA1qTys1XdSFEP'ʷm7{Di0ç-vŽ*ħAyLên Hּ2ʖm>Ta#wYy֑c^œxNQ Kd) apƳkLZ'iۇξSYቆQknךf?Ͼ 5Vhfh  $o(2CwG ՎprIDATH[L'T)woFxKFHɨ"faE%[-jdMaVHW=ʊ؟~nUOKdoWtbU'“ RAt 1l=XZh?[:&|6W#C]6 zarr@mv[Z)d1& h[\竐h/nxٍf '[t1x")s]v; Ďbb$h4DQ-j5^bƆ Q:ҫem0.`@?x{fΔ;8p8p8p8ph~ZB : ƾ(zS8Q_p*ρjinTدpBjix_FXjꎎ)tZˑksYҎ_V؁jָj7rKz i~OGt׶:ϧ?ߊD&=mD >~ݧpwPqׂ/rЁ-Ȇڿ-8Dv|9H ;{H/S>yk>Q=Ck]6H%c$F_3Z8`۵V]@}R˜<#kG["G&~#F^5]U~vJK!W&f]'P8Vb0%, dUXk?;|Jia㈐R5aS7zԕZ^᫅e_T{C KgFn\y6SH(iK{;~jwU]b}]Hx2$\^+i3ʿ1OotoKJhz7 j%r}/OƤU3<~/Γ~&J*e΀BVȕ 0s-OL|rFLL7!r莌-' sf-~ L| #! lFU<}c+M`J/ {i˔'xZSra'ߢ_woۻWܖΕ=ԅ8|{oS>0CE 7o8<(#KS+FED#?ݢjRvN[r1n36"(O[4К0*N}I ,}mL¸s.zIlJaEYˇb0kU O1!Bui\Ȗ-/MJS}#g A㷼&muJnő 2<(ڟ\~~A}2E":N!l/WFS ٦ O{tTLPJLz&RTP:La=xH˗JK'Zf>INNXFK_3ݮTY'z]F`E,ҹq+&лQZt%*?\}Mn+xV{k%ʞ73-GeJ>]VRէ|ֿNsI#we lGK`i@o ͷ$ ] I=gʬ[Cc3yKU׿ɢ8/ (wM="Ҙ|i7%dn$ʯ<ʿ!džfû[v6vg(u?qb"c74<ԍ j]utdg[:3+/ t"2ƮV?`D[  aҤ W3-{wg\\F~-Љ*\r#[ ݸ|uyX: FUx3-o̪ҲV8[:w{1[ Fqi,8}WÂJ\S=o|BS}BZ\Y}5IiwjïkuV%X qȴ>Ϗ,|* GFV&^94&tם`]ִ2 Hx<J%SDX[qAEVuFO 3R9@ :I`a*òm"Sk8 L x4i`OKQE8* Ԣ=_8=tV=6Aten2hݫqmќ]G>$ *7s $W3jчc|'Lm=vLZ4mNk:A]~nBHTKU ט$3Q]loDgG~R,Jg"O:v4zMG'%U5ҜЭ=_< {ZEӧiѬcTIU]LIaIW_>WUzh-ʅ':' ?8wҦ_s]*s3IY1a6&`&Խq!sEjy{WT_.s(O7:fu88pa noqV+8p N~Q4]Hk|"Kwfܖi_3fFHLAz)7 k?Yx{]'ie$l}}O䗑[41yGCBUxf)g}\G~&?xx fXy'`laDg2nX!AsISnTs\rʮJvVm?8sa/"*NZ= ԟ_uHRs_2V#=E:9 ] ,*Ll.\:D] do HV $.Av6YoA4}W߳i7~׫YՔny1=VCw \~W/v*qڝS;gTa&QE|L*Kֶ}3hב] K8xk.<`vo46q֟y\@"~^]H;;&*쳡3 <߾YaY0@L%<|Ӭi7 `vFxI',iژ8Y9Gy[`gYA3-7!{fŏS%Ya?J)V{fQ)seX>_5TV-i a>@zmM# +` 3s}v)n<5gG ,41qVeclȏۿϧٷ+gVЅw/[~kKPv~}LS.<(ٚ0.,UHJ3* d"KLJrI_sGO!"^ # vq3[ΨKcΝ0Վ_Yl&)k/{ERlYago$Ii.UdF Ч99NmcE3HOTKcC"s"2TN&q4& M? (><~ʆFʻ c}O /cϲZ,> KYolj^~ c=KXaM CӴ1" ݻVä\}yUw{="צN %FF FWEf"NiodjRF}2W 31q T #UA+}0=_܆RW,MBcfĬ< M R*Thb rL:;WC KgFn\y6SQ{-g+I_oCtGl;z%t8ua:Y( zѥL #02)6@@h 83(v70$]Ov^L=p߿D[ n>7,EU#=-u55XsXT^?jPbyBoߏqjpE;/kM@yAx!ӈgyuAPq$!jghul9a=i#ANRE66A,uH|[{x%U^w"az{5%P"9[ŲkFJntkGwGm2a뛷XFq) ŔcbC'UPt=f'ˤy *&_"rr̤6:+98e#֟xn*'71c꒽!?|_zNvvL9m2-y? ^>lݔrR8~Ýr®88pz-߯c_uhcxǁP?e툤,&bl9ā8pnA{BKz|󮽇?]̂΃Jb~SWn)2Ά~=23mlwV"&f}(v4'm&Li̺vpIMd:/L8# t5dlO@H0w¡Y6_K=gVcOl,>7{NX^>}&a|լ)3<01o +t2A vuDq0t ?ep}jb0m {KT[%#})s9 enyPTF5ЁvZzy^ yZb $"BAݏs1 20P3*)rk ~Fax~>qPL a2b; A43 >-~q5R7 KB7e?ld-35|ֈG2%"4Q0kj6ȰL fzvČ\`{I0F:3Ov`+ٮz|s]uwD=oի-4)x?<:`kH߬U߀[bjb"))zIVz$cZU QX.S1jLE .𺿚/JF=} sIDAT'/Š':DT :@ :ZaM=E}d2iQvUGE-h . [5o3v:`=t8{Jgk( ·~w4FG5{N#kDl 5icflEH?czOGhfF`WW4I6pL~;gL)n8p8p8p8p.0@LPIENDB`glances-2.11.1/docs/_static/cpu.png000066400000000000000000000106301315472316100170660ustar00rootroot00000000000000PNG  IHDR|CPsBITOtEXtSoftwareShutterc 4IDATx\iXW>3IHHB@Hw"ZAUஸU\*"][mEV@ گ." UDEEE-=$$#@/<ܹsϽ3@tAtxm Z}5'X2aOȊ[Bl${w )GM?xO}~|j9nA=_o+X&l-`N|Lw*H+0ȿ> {G|Nho|,^T…%BG TEˮkpPC2LVy7!qU2Y]Ftds1:,[_]dwueNh膘VxG8~̜n6B}ƣ1?0@]ٛw2r;{=:kQP-ǚ1|e3v㏓m[9&,ƭ0յ`{ x6Ѷ5KRMS/>cקAq( ]xԓgN掜j<#dH*^F8ڡ)5Ai~2>^ @Ӏh9BFm e y=")@J ^zo e$_ԨyimF QUϲ,1|7VGAl{MpygFݪDyT=M:p@3m"Ht+.8߈ PSVj i iԃ i=|Cm? }<5Iݙ(=iN.;o+稾T4jTPœC?ԑm /+D^;t^'w.I_>MjDk}P }|Cj/e=i6ܽEqy+?3r]:r[%dKnʈ{J y]:adL{S>q(*231jqma=B;RpAp%VZՊ]Rh+.Vs@6h|2GhRPQJAdyZ#>| A]x:Z Z$ӷH9otT2΍ @72mbas,V1"J-#( AWOz"sWZSM:#`\s&N*',9T/%3 qZYUx/1:UnV2}@HF4{tuv֪$O!.tUQѶui0 jcΔ{&pzZt:H[_\vׇ~7G:u?o= 겊~So9Rz3lR' >C!H]35|s?v{iu_fo(jpqIxNf'eNj[\גa*J-I [[E 'SPg堗ңV]n7|{R0|B`:)-z,3eޜG5v %\Zbߐ KI`y&Z;T3EL Te;-Woj%(0i^Ӱv`Y}6BVu9az[ᓬw5NCmvI,Z!ɹDB>/-<M k)xU,NMVv $bL^Dr{̉9u򔷓WMk..TA:X›#2[Dqjݩ;ORozqm޼ @UJȞ>Qt'7@FftR0IP$I)(5`hO>߼t3-g4sG-z:8z\sso"6/{g3隉cfyȬ6_ڤ`;ZFJ2d 3`T. "Qc0v~v$n>}E%wJ^p5f߂f}s}Ncv{B!#)iOy)_pD;3SVBH?2xwɯ"HԕM_ S 1WV@)ɶs9<ô^e^5EȾy)Ro?$cE[ģn[M%~\k=)"Cgc{(.;}M[vQ!?lX۳%ܿ\EmSpd_'V7oYԡP蠃2:k ._s>F:bZ{ w~f{=T-In#t(eZ:mI`D+}_vSE 2Վa;>FL 1޴  6uyH,g=Ӗ-zZ5n0d;RH錤&M`=!x9{OݫTѕ^0Nn C*lHziᖣty{t絲H&N2m jy H#՚h(p慯@"{bGX83EOVz5OJQ3xVH@`¨9~7$}Y8Ft̤WSM ~Zo9eЪS~,g\DO70BNtsPzb|PM$gʳG"(OA(B*B>a .CW1BrD#_D }Mj*ys%D_]H "M=@b?`_B|&do9CyAU b/3BQaׄa=_QeP5a.%ml5Ë (T6S1WDPQ0fiPLXS7ILeS, O 98 )/S" Ro `aR1L$T%sIHH!JW Ru9]ɮYr >P%nN &o ggtl X9J14}{ԵoM;^)AyQ,vDi%!jȨ'gP)sۚ'"RF}Og,V9' Dɂ 58@˿?UE)4 }S-)W|lO]}f}]ߺP*RWT_g٣X"JyށEuNxWi>PѴK\JKtDpKucZO}gӹrR ,/mIGcлnRA/ŇBPFkm>vn_0i1x US mj8°Z;Fսi՜khey3f>dp:LٍφIH%3`;Q^9*dQ"j٪V #esW  ځ9HJ~oB[a@ʨw:^V CR4;.yzH3nLgϦ~ywSz ЦzPws)g3e6v27 yz/*Uag6>#ƗxV7ҭ־B&Sy=q(G~(AÚ+>Vctg-jܙ֣r٤fnF`xc[`ʄwm-}l{=jAzH? _<1@E?6c'#G|H?U'5&L}Msޛ?ess*0. CD@c1tOIӼIuM-8Ru5=d!P h1&ɩ*geѴB騁z@:ѽ:X X]Uq4Cc. ~n*\˙^BG-q6KX5Po=sm0P^ƶStR c j$*j7jK21ŶmԨ Is6Wc Y緕;"5e_ 4t@= k_lh_M IJU0>=6h༼2,\e:<Ս;_^x4.O8lٝCӱ-M;4/Ì-h`%֟fr ŁP2%k{͂-#FO*eGnÿ=qA|&=PN2<Q#(rmӡ&+K{CiO_sprI{֋lǴc_tфJ1c,0Zɺ4Ig,^{~,N GyvOF!+DA%'W#l8e3@]F[g*5ԼOu?46F?Է3ut{tOy,mo~!!4H:L _J~Tܿ{6.6iݱ !Z&+2/?OdɉB29fѺ᩵it3x:}bhC:i)d|ٻ,1%`@vpF4jdϕc- 'hnWuʠ pqYY0tˇ椛Lʹn%!y 2Z;)t]Z[]~\1 \SбNz7w-;ΩlߡrHO5z-0<8l-_ : Da:N [}aQ*> _|cdoǎ9 df/p;,/H0Q8<%M廿~ۛ>arqeщ'Ö ޲>)Ua)I߲_[Uq2ꬭW) M9V`RosHYUǖ}x=*N7myHj cK?̉s lmy.I* G1N==%4~t{ v/ jju۱c~DӾ|yάSf:Xv'ݥ7+3Wv n)Ea6͠OokϹ^Ƣ4z,- rt:`:\@ܕ 1kˇ*Q%aG2$q lGʽ j-8vY% D MCyRHu%Q%D7􍟵L2NA-(kh=nG+h} *\raE8-=N \c4nFnu0"4SDFGxz9Qu:xv cFA8N\=B IijágձNh]DhEq'!%<L>eJm4P4 \^I[yV37?'nץ]esoY:/l{n\H|z}ll^dz’0v1۱N" Şj5og4/֨ev$4H5`6~Ya 41Q%x0R4C&a|N&w"syq|_4֡9KްW#Ք`GeW' CɺK<@'6m`fa҄x;5t$nƯL7md>4 S)ol7;TI3\\c?;?Itk2Pe E_5TWd|Sqp/9GK^uwed&unMR=}hސbb"y>MŌu睹A1_{둻$Krՠmv?ʓQ׾h&H9֭~.kxWthmXJl˧+=eguKBY p!vF>3FĬzΊ"^`RXX$mF_vLsxWןa[f?\p`#epxUk+Om>crkC+f |P m*w%%) x+۶H|Û !?ҿ{ t6Mu9/4I rJy,1?:k۽ƇzuM nD1㕫dG'aꦻr;'Pޅr#Om\v;Bw>jLJ~edX-7:+qmp2y̕|τ^>PЧ>6ZlrѮyF=5⏯XU>a-ynWٽx,ENN1vо^V:(@$9>rd\l히=bK#vOG=BD"]ZMܞ{[CsJժ]굟zvgQt!| D[V[= tOEen- -dG ױ‘GqĚZ)bwavM:_V gfKYQ p8ΰqEO;UotODλ}ިkC17εžd0QRP2@u6avb_2Y@\^>"& {1wɔwiK'9E [>>cWc&)@cbh`.mhWqݗ{?>& %)g :Rh)a t{}uou{g e:{pө8a{9oXN;VIѳy}No+>aZw; Q0-M=ϣ(+q (v$m G~oٕ=_8Rʊ9 sLg,YYx9 3I y}7 ('r %T5"Jؒ_5wĽh|J ~oQ~z+kws?>vAol|܌ 9n" f3#N2Rq0IDATubg* UNޝm0N6K)ܽxYW&~<-W.yO<LIi)֓=}7ϾG3&곆}{۔l7fU}afwJCHc@x0?'R\o4xű_zjL*՞%ߎ1,`[fE_w}zMQo8PSuv<3uNSRQZ^N2Ѻ9NчjH#7'-ѣc 'A[6{{‘&oku(z7;סK끫ұۊ߾E+Akj>kr-{}wDZ]gmͥ< 2!sBϛN:Q ֽg /14So߻4Y㶞 yܺ@C}2:"*⩐U(˽ +I-FܪyBJ{«`{o t[2݃C>(p ep>Zo۹z(0:Lơ9ߏ?ô?oNˋ=x,I%t*Z[_4@\]J2)d9cJ-uwzm; Y=e )~#Gֽ)4M`*u #&*.#COtسg}z94kOhYoȺ1C<rG:s5.#"H׾A vKk3dqHq" ?,hUtF:Lc N-cZW{HޝKy:S2T%'o뿟7ih681H̯ӷ}ٰ87kX %ѩuU)GI[͟4DL'Uaa 3xsV>Žת?sO }ǪANnϮ%$F?uԪu,@w+ZCz[3&N/ڻa\e6oqŒ{#ۻ*Fh*KWh>s@wR9j6qNiݗqflz2kL[Aqmc Z?F)?}v]m>z_Ci _9s_Vٻ2g\RG)%L⟿Hv@[wx:@&7>'uX8 hGYggߐ4Z:~;.:@o۵;njGY 1/^ _ ‰2QeI;gu˯ߺwm֫n^ֆS_ݾR?mGй\{|hbAvv~:q19a{"LЩk`9zw6ruo֥3U҈Ve9r\lE?VHrϋ*@.}ذW l4zZ\ݚuCރt@Z#|Q/#E+g^E|ڸGgQPg_+piոkg.F9:49^j\` uhFLdܓcǗ:vڱlЎNo6R{#Qwgպ}=%YMx"$uڹ:@QNs US׍΅s?qQ=-W{b"J<|<5xqHH+n_phDz f^H/i5m칣{ą17Q`Vb:Sf6A.zeBkjҢ0RM.z jo؊X;;sM<|s`ˮ݌ Z k6t[f,hPP#WdרF yc]ɷqqBlCMM }2` t6J'xaˡ8k*M9g(9sɜKطBb~ Jʗ}B$ȲmM pieBmh7lsW(4wxz;T@VGO8]/Wf]wȽW\5k]*NeD~Һۺ)}p 4[wf͚5D7ߦ͛yQ_X,QR\F~=S##J-`pZ},RGөOz^CˢFF g44>6%1Phn}1_"DCMT=S/nP*FG:>k{&W>l,Z |4 (a/¥hy8X\{>41w&.~LTlĵ+~}O+j xubcb/|Ѭ;"2Qu i?#6{=?#2: #ԕ[*vd.n9|Jȋ~ӊV9h[#/^ЍUz~0w둫W7?"b⭠})OW׎w\,M̌N"j2y Xrش9]jc#Ç%l:nv1ӱK'- :vKj-q*n_ЮY}&`nQ[dˢ77/*F/8:2'ϰݻ{N=سP~Ǭ"I(z=6%%CWɝ Y/8hgxr<\s`6h<'MP6"@;7(YʙlH%j1ǘϣM̉-_/]`g'RAJK6n*e הh{ˆ΅=4,cu= F@fc` :4[C/]gZ_[q|tF:'6K< TDPeıЎeaAǟ,,iϺ-G&g?ʼAJ_WtrGd.[aHCW+47OCG7=%6~zA+Օ+ $ţ7Lj^d]}rP811-7ea4njÜ?B1?Z*@)T -IF[x:82R*JR n}6L?u]DU+y-ͩSPqϘ}aj&zJ:|wFֻ4m'$ !Hd'QD8u󂢊(!D&!2d^|>.魫ϗLMLѳB 9"ͣ}i, Dp'xXэЭib&Ij/(%u1)P5?ݰfp7TG5Lˑun(/r2Tn9YJ$|>۸/ %1b ٥lWʔY-*~wOʲDHX%g ]hLW-?ڶXà+. ""嵌fgh8zw/tgO/J5hc/rKTȲ3\ ^Sk4 R>xRJYh*p9W(4]S/W=@ٵz1OyTZs[WӴ2נ_9\'iMڐj= *XEUG3'WWPm#|FK2P3 K1iۮSi?З | K,gP1R] :-|>T)v4?JոY͚)帅*>rOY޸R%ypQ}56afwGT?m4lRjXFQjF@Q5jF0j0 0,˫2SWMkGSkgoN,&쒅MWq*Vع,M3x~eS+8?E~ZԾ_t @md0hi ~J ULXxiiKj}Oʲ]tI\ c/Ii# לQBghP22 H^ phޯ-0·&]ySrsJRAʲrdVJ}wBϩ$^ȒYrB@[[[+5DJL&S*QIQPVC5^ j1,H)5 E*² rrBIAYVkIqr[x(5xIh L0 dA[6URB˲ " 0\8+F! DE>! pXj4*n2( e D"8<{<7%K'ڍT7J\\]?2RX @eX.DD@F AeAJYJ y$h>T ,f3#>Qr ?V@L&S B@NJeX eX 1>5T|b/(ȑr%PDs}T_TDxg/,EXv8=-ANP1  .'? Fu͌]P,E@I6"nuV֑'jAMqhKR^PʲT�,j(aPHYdYYVJBY̫h¤bK>ՙ[N +8zV{ (π 'M @-O$7T r0 !Ȳ,C媝1Љ-R@KQv50Ճ X }M%!Ŏ Mux 9d#Y_Ҹsw@gKA3Xj4 0,K)dL&W( \.WrK!d2p>)7(E {5Q YDy8N~F պ+CeƐsF\8}A_JlB953Hz{)(R ë3`1 2:5KQhy LnEgnܼ}j7}O/''W7Nђm z4(={/ >}+ƭStQHV) ?̙:~j.6j^75+g_9N>K)˲/! eywnY,ò,2eYa ȢЦaڕِ/F 6Lly?0كX̞=L|H0G1)ˍNQm>l#^<}PCGF\:޺ egt+עY>`/w"ڍǷ?F[?yMZ6g K -g("j]?_LH߳"Џ[SxNCG5RTz)1ޢR'~[(r P`Ø?0/V8e >1)C U$173M9C-TǬ0!'q ȮpR]F~vѦ ġQ[QjDuVB׷ג@"*'K(xqMjd`Ly6IDAT@'"h8:}k^,*IVZḇ9@YX|Pq e2Ov^r.N1Ti^ㇺ2Db|$XcX+ ĞP6`s-91Q0V?[:\l>^ qy<* e"K(r.Pfrx eW<;1o~0~ &Y#!26qh$Tbl!43Ud>E-}q?~V|2PvƆio ׽k6ޟyC\y^MVsO8wi2-\W,}I+C_0 e.4W({p9&}QPIW.a΋yj.ݍ"vV2Z9'(=$$6|Ѥ&,#:V )6ӦiV vo܊kvtv4N'g +_B1@Y]@s1_ (#ng};ehmZze[0W/~BWԦs. m* &K;'=_NzMP~`iRD1s}STLes6'daӕey@Z~3ݞ@YSk>[}bͳ% oT# g4YJsE=R6c}An[Zݢ )3f okUF͵fU ыAwSQME>ĘB!ADF,ư#!A@5˒}UaX8$Y-9¯tXCavHQk,Da@Bllmr9˲MD;_G $ |"QU[sBIENDB`glances-2.11.1/docs/_static/docker.png000066400000000000000000001130221315472316100175450ustar00rootroot00000000000000PNG  IHDRvcX<osBITOtEXtSoftwareShutterc IDATxu|WIrq!D EB!@"JBKK-Ví}w'h[]d?.].lvy恽PA/P j+<" (ոllF]@=0XmUj w5 faQ}if,p5)\gުf *XFAAd2@!rp#5̿Q2Aݦ+CK6r7KXĸƺ31LRRox\{lJiMih9 R WBs :ư;\N9_5ˬ: TuUD=Z 釤<ge;FBj 4BP0-w90 & pf&#Aiu @e QUpQt %ƓeB-7oC l> ^ɿC&n~uEOUO- Y54ҿ4(h4l9m.#T9qUN*2bjAԭJ4E`'qwspsX&,dvAC) ,UV 5 FV^i{3 Cb߷#&T {DJLa@D!1HkŔ@#Q{l(7 W+̱M=ΡB!sg(LPT4dֳm`3s:-ʌJ[aRʋ1#%J|J>Ddԭ bHG07;nAƿhbfgdQ׋H՚z/hKC3~=E'n|uAQ.kUJ_1i *BinI:_ d#Fє=C}Nf+cjA Ui`ͫ9C>-)L`?4 - 3NÊew̹JU Qh`U]d,ڈC%B 7x`\ N@Y&}9&-(~fVh~:CQIGyA՘\>~,7{@:PUS_hbL@tưld )7# )P%A-&3[]JYt/z&oFaB*:G-CZ(ev|ꭍ "!Ha ~4z n\Y ]Ռ5hfhTOpzPo;%"ʹDNo^޻&S|[wQ&к/ۇ+.g1Q(c)tdv=KoX0__s *pPCqԶ|epJ7vQc0FJ6AӅaq PZjU*Qf⺓Ob23b !<Ƕ|}kǗ"j닌#ai3"7v5vZFOT?!!JH>I۶["[߃숨ݯ3R! KMm;NMJMTܝ ̼o[!|o2RRކ_5]4swm߶yw04mIe  ńet f25,R5Ʒڵ}[wm\`mݬD 6sѪm۶4J:ݹ}K϶-ۦ)䂎7sm6C kZ Uh>bTPA}vN63)YK&p6 V`S2v:yS44F r/ PSI).&U*Ϻʭ>xzvB_uE@l]y"ppkg]'|PK%GGEMBDGQU7њQt˒˶{e˟w,C|H<]Ⱥ,/Ŵ&Xd.^pyh.4lbn_O.ѽФ;ܺ20&hj ijq ""mOsEE|p=L\͇.+֦؂Os.qpD4L LH$ 屜ᔬRU?6W&B:g;ʝ; /| >~ڒk3: 'ݍ{Nsr gT< PⷽF^,Phףݽ%صsOK0;^M !D9D۳z~x<SBEl1ڶφ}=:x x{B^F`נ[-y+*qv?lv41Y(B6OEצN>j_l>/![la%ˋ|x۱{ ~˂Ľ?Qיw^a9!8w~͠(޳,Cێ*Nۯ<޹BSy.VQn80y/\'Rm)5va}`#g$%D&DE9=a':況j;@Q}5FL4ddu%78(K<džLkd(#6cŽwwG_b |~05P)vG|SK=?<>KخILA\%U=@-ȖLvAN&5byŔSDKjl,M-&FFyPy%-j'ҥj2,TюˏFg>+$ z{BLzy ${HьۏZJWQmuQkbwnjOq)K9T/.(ˋsO(ոRb9]Hk_kO3gt(eN Du͚:^s4{yWl}OϚʤwi.uŏB%DgMmyqOg>ozsi5ajm,=^Һ@#Ƞo \S+9qJ'w>ܹVs;7]~UL(S,1cL`܉s->]Է𼂧к938&qSDjzʃNiq^s4ij fH뾞2m斋 e1v8HQV7lhf812ۥI]ћ$TfW6u Y`1J K$TxL6B1,*QsR{Ine*0fr|+aE&\ƚG=͈!I RݱUA tftʙRi2EKh( Qu5@$iH_G?/] juEBK["Biib$K2RiB) q8" ZhBHհ+Q4EB8l#FV?hsD"3X_! r VIckłvމxyiw{j?ES/PN] 5_{:@֫9.K !h,cߕW)w jY d_ibiiFD]8!`_qh\!vMC½{JHsXGP;O>qh~ɣ'&%?z \H=z4w]OqKl5?**"<ףUC7:r0B"$(z?8 ߍLʈ{|:V~~%+ҷvMw%vScQA<4T4ͣy2CIKJDQ R󈋷wl}2{So}3BsWGzK! ǨD3wk3 e,DXBu`ti+<&:u<㮔 ~`Zvn'M4s8t%Ot#Ƕ4~nB(ΑTݫQ+/BPQ.!OVdO'I? 8{c%uh1웾6}!F>`k!J4(K4{¢AO_GG><RM*ϵpOeqQ2>)kC{<_XJߵ^-͝ɱ>ny-CB!X6[VSo\^B"͎"|$[Z^j^?b+ &+2Xb}qԛ,J{Oyyx6J9O^w̞|7\xٳ_!֥2z3;9t>Z/ ım]ప<|@gWgE/N(m4~‡|==3rz<풤/ʚ JVһ/zqFI?j]M_~_ٴʍ|ڋ4A|k53cĵS+lZV=R uSya_}(%P}-n< _*!^>>Q{4h/_c,~o}IUûn>#|BBjtl(:sٽji6C9=](|^r[-??Z wlP>9}fpv'ڬ&?qO7 fס鮄F#y #{7s?}9EBĹɠ ?'B8J>26DΩ\})Ow]ZݿגONbK̕"y}Ա6-ˎz-c f_|8g0֭ʋA _]~.mYD Im>y^s")v{ayrBgܸ"ԇZaFvᏕd߭pH^D+wY6yG*dR?K7YmmY}5I>5{48MjA\[rʦʿt#ɧ,<wk)LWPO `% Ԫfn=uzc'DÍLڈeʖ<)f \f <PY}ƿ-YXArgj3FDϽ(m Lb fd8q06䓲_2' &f]@-h:$a:Ks('uNۋ3.'~TA,]LB=d|$m+2Cz QwxPW=n^Tivz Uj8p(t1˩6u.1D!5`\zpL573(H+AFp1CkbY Ja .4^ֱ4Ϡ M"ARP_u_8ƾc:gBY2h2tjݮ:yo)V賬شtC2V.NG=+,7Šf ιQCsJi7Y9XAw= TT kJuH|+GLʌ+BWՅH]-a0#D^m(M=aVys:pT搉#Ȑ8B0 J4@f) Oj.X,(Ęn"`.4:c_͉ QW[hfO,3guӏ tblϐ 0,LV%PTpSSYMYÀEA_& ,|rU }M7,EFoFWXr'Vт&ĦIt`uPiFd:R&iddVtЫay,(K T?}iSֺIǯ"d!+Hd ,Rd1q{L 32.n=wSN2ÓP} 3Zd rXb&!Fj`Qtx_kFi&kꜤ-Ch#1 2R*AxC_W΁6p;ߤ0qE]O4ܙSI6]lK5T4CcxrEi>51,Ldc b9ޅ pI a5[̦jQ#!iR+!4_B՚k RGWd3]ݨdLe7D]޴ujD#2-(K8Sar IDAT} V%!GTX7z+ w6G Z3ii.$8C]`tGaRmt'StL@rbҶ&`;W qjrAD۔qj .>J"LT.$3 hл^ g f@`@ `XKuխGSs"|G]Pf3*jS8"z}u* ,;rj*A U>{P=0)dQO4lqi*?:pr*ӻJXݡ69e4=z6(g<=hj".*`Ӈ5լy%߱/tXX/0=V;ҁ墆Kxz%R8L9ъmU$]Ɗ+9z]tоm5юioh$C_=L`@ 1tdc}jwrɀ.7hhOQOf~R99MU"Vi-iu*+G=NiB%TO?gѴA*v^ XYÞԾǼZ*f2 tFBĬphPեl!(<5eLf[V(^<ja"~R 4+`Ǡ,Gq$P3,4t2l]j`eBes#T{ *-ФNMXm0Ri%Os5D]<$ 眣CX^oac٫|'* ChCLMIP@Ѹia @];έFjS|N '0\pCtk0R”U!YJ& g6x{&ޓ,)i,,)fi>5*MDŚjez`0Mu@NFT"VEP Zu5U ~T:CGr_ `ZДt*HoB@gk1D姑I|i4/1ZJW[ 9ېoHC@L )u&5bVcIuՏ=$(vmo PU;Bxf԰B :3ywmcYL,PlDͼvT gеȵd>˅#Y04YuFȸ c 2! %לtzx@Cbwu/h R &JXZ$f 3>bM_jYSXԻ2iyqj.`Lzky/EPUfB2x=#[(Y40Z mIc\e,h\![S@K>ú2:pUŕ 21F'A't l_-_y0e.&ҷob.%'ϔ,K0= /w=Wt?]5@hlK¤ uplGwRӕJWY5Uk=gE<&/J0݈-!}ڑu_9\_tkI2`Fj泴4}Y9<}ǁ&;1uxv n_oq=~~ Z0|#9wn.si.CPd j &Ҕ9h<yvTדnBhz߱LE&`tr| wWIMZI*~qƉ\ {並,hb@]˥FUæZA0:l>hЗaٗmڗd[fYe+w;>H q识O<  !D7軙gBo|,#l 7)3W](|T?yl/?ibË23fr|mNJ :I+^:_訋hzD<o/\dcS܏yV*.(DB@?-~0#SfBUbȳYA_OΚҁU@l]wO#)2VXq68r%66u8oծ% iP^(Ozpjb|~[a޲A~w2C j7wݰf/N`S똱Rq+[v>>ovkQ\Bv5eLz6_& Sgmo-),j=&v3$+J+!Z|ϳ)[;1!􄸸"P6 zurH>\IwúѽD>"YqzjJ$ݵmpnViŖ+!]xw7=.T:ƌ}meˉ)=bĸ"E x+# w\7w2dv5|AEKGs~iYv-BnPCl;POK[W.YqFJr$68Sx7Kl/ꞛBzZ?qO[ »ǣuzR:R.NO%P7BS³L/4_ΐ!UE~|6Cm(JϮWcٌ%ټ9{:=Yt\o+_tT ߥ'c i/'>8gh1kyŝx\Gμ{~+4SNfNۯ<޹WB0D(mx,ʭV49bNo]5Ǚ ~R{cmBx6|?hC=DgOmyq3WlJgȀL Mk_VU4F4W#A:/IQ!:7Z^O9ISʕդ/>4abI'rƝݶnK?5Qmc8k #c/5k沍g,|5ygi[Z*O;_߿}/7F~,"0Z4C~5ko{&աybc e"/Jx-n. ڵ!Ox!U;9~ %*:?aT`챥~Řk]MP`l- pɜ < r*! TсG~ },o*Kx.%ˋ|;>*Py@+"K@сG~?D2y?^xzN0ti=OJFw|ټ9K?jƨ;}úzZa=/U/FDسVϛ5{ɾǵOVkz͝łEF oK\ZbgKO~M`~cB#c]$ʓyp~'jD`ش䩷.dY\s)܉F4vN&DEL<"Yt|c5 s%BBI?p˚~m=.$&ˌMUӜX*%hupx7S{ќM\ ώz$yٽebԋN(;>}5vGI~v^/cs0;'#15!65jXIҋuro@c^څ1MN%IvλtJڱN&r* MYC[uꗜ 8yٖ&/+&.6@ 637lSUg`a`oT<A4vQ<ŹF#knzC^sݮHb uuF<elVfd$aB lڸBH=+˔B-Yw\U ӁdzY +L(#Cw4B#ua ~ ~K~.nXvn;+J l9uxR)"HJ2 BzDt4?۞GWzv]9&k%Ie/TlZ~|5nԸeoXWԇ !`]'#wTu!e7Cg}pIg#}Uj4kfp0 dđ(CKz/5Yiy{ECѹ@k1 !rI^B& AЦ&32-,}{x[kP3MBY_[I3?_Wёo~#'%YIvݽmυ5 H+JP}h/F[wfMX$G:щ \s ߈R=ڒ_P߹iH{5j<{ҥJxn=,CN ljx*fh K=}:CGI;OOa۔ejZ\?=%!(-"%ILi߭PjVB@T} qVJ/+()ؠXJl@ny=]J,Ɉɑ#.&},VatsCTc=dj>Q5>cxݍV\$n,+bY䁥߆6jٴa g+92ȁz ge =lxL^pBlתqnFN !D.i\*'f#\8y SoR]V[%&Sց+j1)(嘪S8OLlU< (ײXI¾ >pytaj ,[4mؼ`X*1Yq8( 0.ת[f6/- Erd < l~e<Nݸey+d peEiI1ĤmM {$%uDngj<.Ut",ڤeF 1 'R_ O 3<]6J6~ڸU; +rG2Amw[ɓQS;}FCxϒ V3U쾁rj er7u40yΠ$C1dϙ"z}S/?b D>J*":]+͎Jy6cWLje0}+*Mjma+*`arĽIv!=]5 |e$-Ukok=PǪf|<]ZvlhSUF1١KI|5s:>uu7f`i4!,_oЇ|j7206<LL*I%R"@/ӱ)u(j9[hOM[Bl=l@Iԥ{E n۸爏}]|S\ɠo։Gqlaig9U>C:x8Ц@ ³!hi'G^_Ts(%Հ?ή xtsToף۴sOZ#)}{5ay  Yڐ S%MĻ0M}B҅/mA 7:h'ԁe1McAQy8 !-7"@qPJNLw5ۡ9YB=\hYLnj&`<=*!`Huġ,n0R89 !0Lx$81FM]*RZ{U\k,!1MT&#G(3]EQ"@f\ YO` 2' 9b~So.8br:$hB|ryPCfHid,f $3"GCV>B2 jtN /5`pJZIh"EZ5-qv5 g8a`nt>phP ƪK/bC!*"F#hi [dk 1!IYiA2Tw҃r ($DW4VAZF Z H03PD ʼ6ЇCt_S,GcvM;*~YfiW7kNY6ZEL|>KSO߭뒭+MI}N]e7o,2{~YOɫ6mݹmqEU n )q4lsk]s8п-ش|$K߭+>p"wp~n|0+u]y1m^oe XN5x.}NYiێm+cكCK.0~t4Z]cOO]ఁMwYTVRh?`hw 0C5۹` 3SuthԠ?E3ߡ8fh^w5*C=G>^ҁ_deoH'yΚa, ZI]ֺԵUwV0PNczdrO ]ۿuXTׄPfOz@^IY!`]!7O<6sf1; ;3@N9s#şԉ;ⳙP#7w4)x\bkYsNgʁ^w[M); [hVST*}@(zi nmUv`끇@}!pkɤ] /IMXU>i.5A^~ Z8\ tzT75>X,֢ d-,I,O]~0YЭE' DuJ QȕJKc%S@oohay<\y9/"RR9TI?ZV9/# R cES8- Od]sbmr[1)|䜤CA8CV.+Hd#VԤ=GԵR|௧t- uW ;OP}ҭ,ׅ])<-DV1OXKLy+;,]vՈ9vz֓H9MoסWyRJ6(9mJWIoroy $' YFg_= |cw.gárB860uг/hzu )rBM~Zcuy{iֲ"$<׎Wd}Ƭ:@w*t1f']DϵcO<ݣs}g^= @BϷ)~kb$ؤ!dwξ?ɕ?_J 63M-ܹ_{pwg^~.wdLHNs5ZLϵO !՛>%P|{]/K.ԞjQEP34 vDc_<,~qt ?؉!Ԍ˦+ttťVAց=6%7gMo}YsyQ)-yHݍOTIyqy gi.>VQnV/l9sôz@?nKd+FvlP܉ǵztK痿B350fb@MyBLIt̫62T!&u_WyQV(ؐ5v|kQbwWB[F(?_\:~2&DW<8GW\;LÎ;4\yo JqS&]G^45eg5Z 7\5Ρmeʔ˂D[biPѥįB.m{#v)vo/ߴbvKϿ4%1vŭ s >ted^zҵrC;/kV'rƞOtZU.'O4i7byvB^=,~WsJgxV 4~I3F !Dҡ^ƒ9ݺ!oQwfɷiVu>Y"Hוι>tm$㧸 ϶͐nv:"׮n*nS?nףfo˳-߫/\x-Ojy"B?<3Qڡ^9ܺ1h,(GEȻP_蚂˵_<,Zv螒BA;D6n$z6@n'O=Fӆ9|֞>9_d8uiֶĔ[ ;*+ V37 Ƚk'%9X7jT 89%"k"fɭP(Ww&HT'$ɔB4ML>mp)I|מ Oy]i2_\>S^]^Y`Ƃ4ÀO׼GZJk[bj~Cv.j-='\ŭ%;u¤ĸ5grj|jˌ.ueG}!&VeDM491v]tj# wz{X3^RFؗG\>tf_^O[ &ԄU/)-o`\ =yLncY#HiETx$$خtB$J-4(*ĐWy nUnIńI,g,!$-8]/˘4}qUKd..惡7wz~~IR[uOL8I؅6VU̺F 3bkHR`z|Wvg-2B!,˥d%ImUl9'eܬY(8v̶kO)Mp-2ox-t[ko[ ~_^M[!in `ɮ'UQP,;[R%j̐.1e-3ZY݁`R1%16fZa1LjV͸g93>+(>qbNoHnOYك7,Yp NV/nxinߘѭpGSSΗRtx{ЅRa6^b-  +-n:yי)X/3SGdz#/yF-aZ`o'ZjqO#ei1q}}BB'"Op{c`'xT#dJ߯ J&}!הҳ@%kmoS @kMnRV ѡ\&H}z'|}϶߾x?znR &%p? J'$e-:yL %lJx\$͹2%pWpL {QώU7v-PG++THdJwy3G3n0m.J} B]<Lu*DhJ^OMWk1Dc=ҟaQ,H ؇EBJ4"ehch:zEҸ<_8VKnm%7U)[Y2[FQՔJ9l0Oo*Tbk=M%'eDJig[-˖|{˗j5%t-8)+9[bˉ[DD롖ʚR)?-<BBA\e7;y~q}0yI&1 IDATl/ћ?=+4)ĕFx06SڦhG'-ɿ?fxءrNb;GYl`Blq}|><8 ٣#oOՍ~[a'YJJzhQwo CXJI&VV2EJvlfbbY k U&'{Cdf2HWYpLmHW͂r )'0DLGoS&m%of[nsMB!p-y ׌ic3g[$huħϜ)}C#{MVyFX.ӇLfb 9&[ӕ a><#Ď6cLsb?-mX;Z[J|zϚ7.4פNl*:}xFZ0 +v،!:>=`h-[RT NXlbb|L b:eOV"%VɼoՊF6ʹs,PK!?9߆?TQV7'>o@ei9njcԄu3?aLD Ǘ^RxIwƦ+ fⲸ'W?<`^@3dzBVR$&}?ƭƒj5ة f ?>P^7.bQfv5e5B^Bd1{'(O V+B<BxWH xcg?ȸYBϜav%.ӲM5B޸zF>2v3k6 n9QA?|CcȗF>/2g|FLdbIO斝)7=jƲA{N  BPР&N^'lPη PtZb"&?ψcg=x| 9}j茱O *+6˙, ZJdeN!DԞΞcCΞћadN/6,&#遁yͭgcW15,]_{? τQ^+<ŅG?kPݼbD ܢboCA <=ccɞ=1Tw n\ESW[!~i ރqb9cj߸qFzkv۩^9rj['o5OlhDDT;(gqlk2(^!0q^1ܞܞe!#5-4\ʛGj{qJf/ǹ-ԬjʛGj{)}yeZU˂LJEtM[sk<]*![+)ƱwozQL@> >O.WI:AQW[BTrhyFSR]g~5Wns Q)k*/,x<)p4O؃48*c3kTJNtK(v︴Mm#볤_d3_dG^lV-KW7@?X#`_GQb`J* X{OqfuH&/͘H{kqV ɠG|B1Rꄧ.k1pdkQnQ uKTM$B{ ȉ XEH/(ōǾ G /"/so˲o2)T6rG񇳲{A)F` VUi8ӑ-X5 5WmpNpMgɆ7~c$\ˣuzՠw5+qז%7WOc%o^ |_.cJS"WMBUgm8Vo!={5yɇlE^4At5Dy fj2jwk{|rAa!/mAN9oɧkgj¿~l\v̌V&gEr5zm^7vW&nnjCk6M' y"s}%v 7j7)kXf,0dP&mЌgH2ߑeAAh?ydRD @&0uzŞÖwF\ڃ` $D?Ϩt*^axO|z+v f1$wp;m`^4tx>' ~䡾ϗ+1]pS'Df%}q<6҉n|m'W6p̛ [9l+l6D'aKQI*:wE^o(Ϣ? YbXy`Ƿ/S>ymh6AGd %1bF^5ڧZ!uw{IjaoqA77Hǩܤ~F7m$'݅=y?] b~fcG>92 - \!viW'(8[EBn*t,t} ىULHaDQtL!ArȠ3+/lZC+V^?La7:mHiʑGKp9U܊ X;9Xuޝ%DmJ[A?y{ ['uOo]֐ ^2ɱW\L,Փʬ CrkcuGtჼZ}ԃ,Aݢ>\߃WTfW1[t1T#d0TLpvT+= n1 #=(wyZӤXfS1]XcDt^/{/J5lOC瞐ݿ||dNMɢnQ |W˸qia;ӻWt35ǴpG %?Զt Z kfXN gB#Nx[6÷\ v˪!t /t˶ݾi^7so~}NcRf;D c}ˇcCWoxBqXD9GW9dz& h}b3fG[JN}i7ofȦ?gsG1(JG!;d&6w}?lv+}р0!aOG2ġKY;aCWmx|({m7eڼP&va 1fXu݄0cFkK@;|O.3ÆٲnB9lsfXpRz{1i3BS#E$Cԡ1g;Jgq;f}jS#HVg"ilVX^zq{6'!M8w]5GKeYĉ:iByE/&7,Î~wI _~V ̊Gk4[hc+>OzD2*پHі>33MTٳ}ϕz7ۛF%{@0&V2`` b"5_AT Qk 6^Eb˯Ob;WoN!br|t#F@CuzgܻrdvԸG#f"YQHV;v²_[/ظfՆ\_ϦO?D6\Sxs)10BD= H;nkO?;Ν+N8t=vԐTC 0?xֳٵ3L >KTb2h*]5$ǂF0BXo[oi+>zuŻD ߁˿YnɁ Y/L=rFB.Y=f{?\S|bsw Ƃ9ٖ!aF๫&(eӯζK~Y.=p%2h;aIui%.*2(h֨4']5=Aӳg$Y@Ra nɣg"|_+FIshVu]W8icu͓'Dj ԴyKW_SG=-zC]dž}<2+r= 3Q_`l74Vs 0DLA^A>ro랭Q%f˜zjcB7pj ѓ.4̸#cdnD]9>4+ Qe~;>'mP;sY5.+GQvrfji M;6֍ʊ?j15Y >?K2^ء&xzytQCz߸^[mgA&g1`ZMn>E#y?e)WW,;$"q.rfGKTCW|d)c~vGE=P nܺp5aۄޙÂ6Th:="={hye>$طо.R 2?>vٲN/-Dx^|urp~p@ %~}g W\WrZ "*nt%kv]yg,)X9ow H|}[ O-^fߘf20e-X[9p~ NQytezSw诮}~kVl߂(6o# ~y_zŁ~Л~S_dDz\W0ʤ ߭X!mX??>w>F_8(Ȭ͍B@˱ /[Kp&NufeB#B"/H ԖR6*$0#:5QwMX}Q 8:ݕ*2'|_*K>h _]|rsRG `1);"\=3ɿ%{.$rKq_jF"'K ]M+DTޭ1:qr(#B"_J Ԗ_tQfOTztf]V62bGex:0g5bN ꚿhS&Po>>ag>vCKK|4Bzu}GoN fZm}bVߐ[ϓ|ٷtt>+TaLǭ?.c~|7'/ t<$w3d{ߜD<( tڂ~&zcOnN//rp)W#Kx,$`@X"!O(U[3#^Yj?;d`J_}yB?7bKY7G,baà Yf{.sثaiF% ܞQb:z(,z\wᢽ jМ: ǘ ݵ_j^>Z1C%u*Bp$~}#,' >xVؾ#eRܵWa]]:fb> č=eIX{ȹZ 똉< aNǂ<2WjD^#Y@auCmSFe,8hj%9 wlqtj}E]^ Μ?t8Wj/;+&1ѩQ|{~嶺>.(Rb ~C VY~jק?}|ߟ2pXĐ?r 㻴+}_Bx]Y1,3XOE#+(wrw\ݵ&W>Oޙ==,kއ y;9?o*?q¾;btkx&5@(|ok U;8-k1U{O*L/ ߐ@.RmH76n|^?r T7*s0C}MR?[>EF q ׮UQ_ٟoR7vAP|b_)#3;A4 SbǼ^xoE9{.4 nGҴ~hj?uRKZX%->yʨ^3X36~Fga8g_Q]/Oo>`m0Oo֫I^;ʑ5:Z~=+!L3# NAjT\9)d%$]j= & >Nal TXT.&ɔIiyЋŐc1PxdVI, Ns'SIPs3q8)cgYaT$iᲑYsڻnLkB*Lդxv]ª}xF(0ϙi/%Zτ@@H*Đ1S;Ga먡1P]!U+B)86p܀ggwώ8{F9j@ud:IVXwE!~DQooi0A|TV5$)TC&W+{BCx> 5~$WktQ~IDATPQU KDFQ_w_e$ٽҼ& f&H{G72 zXxqFPP`uE Ϭx.Yő؊ 8 H`ĤجvJLeb uD0n2s)4秃WImW?#uXcČpaBK`Ht>@A^3<)5_jd:@\*l T<ځcw$<`'w9c i=ÓR"DNv6TiATo: w@W_uJ(AsS Gʼ焏%e'DK ӝ>X5GzRn1ѼeZ/]so~&+mdju{|$ũQidj 9CLOl\yśVu!CY 2S^ ?%FCZ\/υrTMJ&{*=ر}x(5 ݧF_ةc{]Wg=#s\ 6i>lA^bufȠ2暘Z01yMq4Ȫ|CdDqʭ:}zNet'KIV>VdӞnc9Ild}ў H✫/)-`/ ZBbZL_o ` &ɀq '`@@ʪ%kbZf}+4Ɉɷ%[H"{|GDJ)v $>V%<\3:Ā R;~L9U>Xr[7b2V~=u"%& 1>5E2 +S0z `D%M.Xš1f1s~ -5z1=&:$ Pc`#juNIHL?7:U>xm#y{oʕ:0+Z4;pN)0nDRՔJB,^ZSYg?,m\R)7[e*u ӈ%QbU=)mJA`R6*[£u]޻[r֯tUeHYI^nIJ<`*Ή5Rn\ F(2}` ̐PW;3Ju }6Hvpb.rcCYe`LrY% `e])'Lo|#)Z0!IqѹǺ&VVߕrZIo*RVx$*gIuH^F6Xv,*gG7W8ޯ?^N?0 [d5lmJ\ENn'n5d:6s~Oa<;F75( NOْ[:zF/;:}xF:Tc6sL8OPznlBqfl/7oh߶È.]ߒ1#2r YX]_*7 NƘfF=Ԁ܍޼y&Z#uy?ǖ+ҰpP^挩e95~O *)0aQ@6%&qA}3{&(I|V1k`W#WMXAQYۯKJ_x8(>֠w^C )#$ "ޯ{ :yO4,#⩬y}D fPӤaY#(8AG~R}b  &N= >9!1|y̎xtUa>1|ޣ dGYWs>_2~ʜ5/ˣ>ۯ짛Yѣ8b!SpB(csU55Qd33OԜL4{.xhz0SFSrjTC;< ߶Z֫M`29}j_ٱZPԌSʯ]+)wʯu(vI|j޲كJd\ⴣVN;')>c+JovQL@SwY G! =JNg`nҢg~5i鱒!)j~_FN_XW^[93+wkMؠ?x'_Cd0'-̺;j(;_ZfOw[O-zvt+WdBKUƱǷo+;նYOW {ED7!D+}{Ą`&ng!r #:x πIt55.&-U79;,OPљ|S <+7OuX(_4 M?d ONTs2>~=#HF:5]69'i&36u^ h8q37VOBUy6[;|i`%NR> 8d:[^iLMT@yKJj2j'!={5yGlEm^nb:ʁip /MO,YVغs"rQq7W5Wm!g>8fW|K Q缹z\yb8#~({gE 2-=;Ot|8Y\@y=:9_yA/H+Rrڰe^*A /!SYx pv_6촴.]ߘu DyP(Mu[Q$vV1i6Wʫ[< ySjG/])8' tvzah ^<*&.#;9E@{mmb+u򊊉]vLu*S6EZ:uY<>9AAovP1J5z*K0&DwN%"WUL; nfU1Y^[xDI6vݚ܎-"(d8U>y"Y𢎎'>LI:r:a[ȅKJ[ jgxnyd繤!-iu#{y8rb[(=@0(LYuKH`Yk,lctמ>EEz0o \[uQ\8SVIC^A!DyG[x;&NMS2p;CxVAn l݋AQ}s@#\Ȫ}%]j4y'dx vVA𞽀 Jg1Eze4lP)jP)l+!ԡ'8/ ۀf^R:a_ <ΤDKMD&uՙ[ytIdƜZ܉Y~; mI+~aGqvˆsA&.\:-$;խk״=`ꜟG [ u6R܉XzֺO=b? e%agҾ 7a0ANNH_v-(K2!#qsHrC<<丨v4[{xh~Fqq!!~5<~i>wg" vD9g @Uv#,qD&kv+ Z> dNv"} ]z@Y~ Atv||x'jLjpۢiQl lrh]BWOqe=Fs{&N1#'`!"ʒLs `SJ 0DD &F-knpށc1$O`DDh >{]WR4N̈́*P46 4,>EI Uu]@D1Nc1Nԧ]d=(¹l_)_=y"_)9FyBP(m4f-{-PN/8?I[c:։h#nO6Ir4b#|o5)J$4Kz5e3xH̦ϔOn6B[^*\-)|:`>k!1򜑘,i<0rhflIB!fODxOCɖv* YwK^Y: )}ׯ_I ynƅ`rR0PJ@Q5]ԬPp|!lנA 7h9x9Ӌfպ&NWYHѸրyY١% Vrt*fOjgDK,Y$̉I"BG'(z|7J|sez ٴ(x^)TՇx`^1H@oRrG𫧎_@g{- : v׉kv@3.JtL"R:lho48 i7}&W o`8CPq*urmTYlrG&pRI9G]g2ekNJp 9QE'LPG$]3˒^1V\ð$zp'Jjg]@ ry4y;hPȃpRUnd, D./*0(4#4O-J*.ndIq6E b)!5,@h_WeJ3aqCDmR["2U(qϟg9%FY;J@bbL𑣢b8mANyۅV5뚓o~|]vtح*ĂUڊ"YLpk"%3^Jh8 (12 Ŏ65mv6~Sb,_>OSKsO|3%\8|TyjuR%s~h0xn5XA~_җulWw7;HeRQ\qpk*1#CH?ؼdO_eԦQ2.;VgDA\m XkqV^k8\g%#kmygx7PNӶv}9'U9U/XŇ>%gޛ1{iw=-S)%,#AK%\9@FcR6bzl@8;n:!$qrH\!\%d*ܠ+/S @r[Մ`~H (b*̈rd}ۓ>y; YYZ5mr@I`|ٶ_6uwl'9[ma+w핤KšEk$T∈b˗ߴh"2d Ve-Ue^'Z7H l%I| !onN>zyLf sC-kkwm]~.=-!ͧ 4<9N",9ZήbEN˱ʀЍf {Pp&S}1b J4z̼R23ZPy% +F;l@óҾxRiR]?Ze)ؚ̪m{ @ڽ^Mtporvdg׮Ա^䶐 bǰ-oȰ:T/Y&y(" B*Z_BG25m(X&KWQD&]Dں)tSx#?U#3621cmTìQkyݓ6C?n(Sq]$ '$&dλtP4ZO[:7OU(;|ƺAfu ds%l19%J`:huuީ?2x0ĵa-'29RS'mDsNЍ #1Ee7aPZF&KxY%wU? ⢎{-i\)GLkpbUȿ0@Hrey-XYRA(O'z8g6WʓL8:~fxQzvj_)g #'vX7uAziæQ$L*K缜iː bc|[_:{_z{WvW, R~ޟ \XlQ^6Ns&T,Ђ߁vgH([Ϯx%ٗz@'\g-aYKCFCԸ2ʥK?mHf4gYŋ#8lhznЄ+=0LVzqN9+X8F!C}uU&ϖ)!.9ŋQ+B 5Do?LҢMyTa5}|Sp81bޮ,˥1\ Lpw4as y?mCĐIi& ȅqHs7}}v[T=* Û"=**)dKИ7JGoWdb̏P]R>1C3%?_٣խT t%_xv&uy ?w74RfS(G*z-_>UNE 4zϗ  nhR.mA^\;͏w^.]An;>%&Sp`*ش/ߑV˼qB 9/۷ؿy7uOj&w_/u5 פbcѠ)Kݵ%Ӈ7!F'펲" xnO8b+gcG~ߏ8RQ?oO_*Ykuu7wF ഭV< :ҰAT<'pԝ|dƟIedB,f܇w `g& JYBޯ&wl3z֫mben{9#:wsiU)WWJ{0^j{l uƷ.%]J>Ze<?rGm ڀ; ocmug?EIxaVԿ#g>F|g?} >5>}O7>ZG!d _Rco[>?{|R@J7ƵK1^=7gw"f(`v&~5O f(|y\8tԥ\UGI* s3 %4jQhۏ ?L"0Zn쁮i_CCp5d;'}K̘֣{[}5+gRPpGz!ϵOm[gٵ`n ~Ufš ?Dxf߼Żu?&ِ!UwZ|`9 عVPK+%mܣB \{o~lΚ<8^g"2ߣ, Y9추h6]o}˾~~ohގ |k$[$L?st{Ѳ (XHnxu 5wY 7G)TO^ k<桚q'Κ{:_t\$;o"k4pm![JWO d|d>zdʋʟ"@Vc,Zz=3Oz)uݾC zz;_&:ʗ"%K|{>92@ᓓnEȥo{Bv*M֮cM^U4C2/h' #OfgHunO3! `0{@8X]& ap6џ--/f^@*Sh &1 z{.M2^47-G r"XFdLo!iN̘;\Ye=lc|]4FLjm^^~Xfg<2F+NXtD3k^H&n97LMcK-1Xtb1FaC,8-HU'Ne3; "ҺS8 ޽MS8vE@1-lr7:}ĝ FF(YZ +vWgd/3ֹ&٩F$9 &BwDܝa"q@RFmDN(g7S^dEL*hjd04$D TcJQ M^7)1$.j?>M "r M(6 ;0B1"d,Q$l k}ˋ6@K#-H/խ]gb\&<ٯߥ OɂbF=NF0zCmٽ - id/!|o4H,{]l|hۆUtLы 6?% x?|8!Z >]rdhHs"ITU;L>[lHPr n5cSh 49!"7B>ӻ-Y4md9ĹQbku{-D./* I\ӈ휝}onu} !8'mp@ڳ!йZ9@Dc3DU?yEhC"7_IXdcG )97G@j(CFQ`f$`$qLX4~AYѷ|F[R\9^`NOs,.DK-Y@ H8yغl[P\$Nܜ_h#)1fBkPr yGdۖ_{G(3hy~}U]DMQ"xC4FBbyoKE4ݮ1pؼ^I^v(.hg=nD"m Deƒ D4i`~HP8qWCT9g 5v HI킻~2c!@XQg4f]ڛl\}Xڟ<7mrv&(h[ewoybm6jѯ-gΊ|#O(OȲ\7̘`(vilg8g@ެb2茼L2?mCzf~t"runR'~Ÿ̭fLzC&hF2֭  gғ!3Usyk#UV=8"rŵ\t90 9Y`$s&I9pYoH^H@hDH9碞싖WS:p'"ȴjc݈;UEQ$I24wMs5O\S#"uE KD@,Y?O{7t1"fhSo[u9 ȕ׉Ͳ{lU$ xջ6o߽) H|׼ &{y{6oU%=$̬7oJo_=ӽBXƗ_;j2\m׾vK ]?پgs;MREbw]{sV4uX}Y%ȅ7o=}mߜ{(~gK-ݙ$>\yMܥwoٰIUUʵ{lY/,s'"UUՒ./Zb'd(K>~ qq@\0` .`08>|>EeIQE"#c(ILOG8X|@+ ,A^{q-޸M/9ԝ@fDP{d#c(1 Пܽv0dƕ;=2XBfR;⹏ƷM;@}ݛk@g\c3-ŷ;;zH~Or3ב_᫿r~_{'.,J}S6-nh}TR9]XBAiԽI:4JǶJ@DI?g_z_uJ$&1&˲OQy6@\\\3>>>>> 4aEEVEVYeY%I%1#K cGf** zqSjz7qm EM]EjmNPx4 fTOgB&kZr$O-8v &`݂f~˾g:7{S|h^A2aɿM(䙓tUxٯRwzz+ޘ9k9'1ب!*ksstڶ,H cȐ1$Lb1YLb$I$ r}d[t\æUr0}S6_E`  `0hEdCe_& јWOJS֠\tlGwO,!$I(IL+5l@`Q/+]/;PMfxDlJGg䓍/H- 12UOesmvTmW? e J.e9SPqX"ʒS| OrډpNMS|>E "c\!'3 7A$ Ƭ%>}ÛfK^jx[x]s*rBeoj)/NA(GJ[W-a]&tzN~-,Y0ʀI%"r4 ް th-!Հ)+Ar+Rm3~|`O|!A'"+Q=7uwYFDI2U4<>.'&|p]:{0 |aoOٝ|/|2q3+kR2~Ѧ>?۳TT~;'rlW8Qd1s쯻ڼot`]#V_Z8%L1xXRmHף,~pPa杋)*̣zxp!HQ%; KKŴ"b"yl#o踜tzكcXHhRvv$껿iPDK#. -9Ms_s`}d[\#vv,ݖ% co6H!v?1wiE~DDumBZ "E hWvLB0B,*᥮ 9ɍ'q7F^R l0.|&F(('?˄C8VY]Ǯ%J$8MH'Sb"`=}(&NxEEDCΚH[6뙺IENDB`glances-2.11.1/docs/_static/fs.png000066400000000000000000000253061315472316100167150ustar00rootroot00000000000000PNG  IHDR:7tsBITOtEXtSoftwareShutterc IDATx]w\?wf 삂("hXŚD-nbhL,آF5MQ)4{)6DI63 ,j2wgN93E /"/.w|1)m DBEM&!DhG "z1m," ^CmdRJ['_tT#$З]_3tHJR@ܵuHqOS"PJQWnuꞔs5o_ն "i QDR m-Q쒢?+.QJpd7WeB>#0h}6DD3K^@0a0$p(>|?F^]|BoSД%:iyDmm+ CAh\N/1\eLaSC~|3m?!@q;b%Œv/ v(8a*B^\fL-5RoĪҋ ^ڽdPF)V![z aaĎ0Z^< &lщ[AJ)0kB?jcHwwUS4qw3š7m?iUɯmyRD?f'?~I-ܔ<w`zM7Rr>Nkվl[pvs&4ܷ0ꏚE}n-yNkE$ 0H)!Ekb9_fYyH)AnxEaCf|]?." R"^hzg]un]N/{lb Ҏgyw[vG ;`A+{+6<۷5.o;^oD^SaXB( ZfV"2 HaxÅJ) n-"(U/Mk5؃_Ŀv]ה} J R%(ދK(V<^oxǶ_'B>> z@.I~gkO sض%_S@_q:XxӏH?T|C =Q $#gL<`G:w_8o<=2QK3~ٜ{Gg2h4!&"-J)q`8@89J9qaa! "H BHyP8?1xѧn5Wﱟo/fnYOi|5}ף=֯ߘM T 2̭ſ6n~xC7iNKw-}4o9do)2u& 7L [.z[Ę}jȴo#Z9 2`BI\+ꩉt؞f+.+1]P* R^d(9u_^/VMvZ՝{ }5 'Lj tBgF*lʞgivy/Pq- X,8G9J RjX .rX8l2 Fh0 Fh2&h4Mfb,PJ-q QWcS_;c=ʭbC |KM5j`?׷b9 z͡)1&nel`&ƟCKXҒ'%=NJz𴄒 u{c( B(Z)8lܭgC,!@wedY'c0?r;Az&-lRJMfa8  BDǻ80X_Vjo?ܡ+G6 yRt\Tt\ԭ _T^UԩNhqJLũ+NorZKN¡ӗΦ bB0?CW%6-:Сëŭ;l.x5Թav&: 2Oa!2)" 5?}f 1-bfV7f^;A{W7B飝MH&(NuҶ7WX=HKء#:<~p5˽Y癟8B2 &[,JφSH]=U WKr|)moDŽtV+pk۷%[Tyw "7,s Kڝ~Vq-Kު|ҠVڥo{i\e/M?yeZb; 7.fZCa]λÌ'n'ܺydEx[Gը\Z}plT­;ee+V.[{t|}څQ0jVoWԩ&j-2j-ֲF\ZVqfQi V[{jJ͆ӂt,RTO/շ=w&4в,#-*φsw/fф ߽+ߪƲ Ym-օqضŭw ш-&vuИ?1Ͷo~uioFzo"'fZy4l]-7\Ziߍ?ع?F 5֧c<ӯM.ƭ%v }7xi#Zv̺\nz!gT m"$JIȡ`rE U(U Y"j.! aTZһ@쒒*-Z!{E{L7Аs̊>NdmTR;Tc :v>֙C>i6V9bEawSN{wHU{6G9QyT!Ϣn$<ͤ$#~$GhA鏷W7kC-~}Ýk }!nVwe3`RSP"e-9)٤{*0˱͎ Q޾tz%~o'rmNZ?OߗF٦GM'VǙfmF}#%y,#`J?\!,kkY.C'4ios-Z~uFzANR@2eρIv *\JxUsb,t&N jW ?5 gԿ] SǦ` q#ƽE]y#5MZ7 K"?li+?Yt!3S"Zגz7LD NffY#bD: Y*U<f׮^9K\kv4<дaݓ t /p,@y)ݡ|.*v3Z]Z)).ݠ$4-ں߈Ε:;skfu:/١Ȥѓe9piEMFh}^:jQb|xӡ5ӹrY͛b~f~׻o丷kb]ς"c xj\ƕ}wk=Eh5[Oz/ZŦF2Λ]w=2ϜN(N/.8UggHw#n:/]΁6AZ>.sIɲ{'щ(d0(8_S؂TC+`IM6YQ(ɍ;~q/0aphRsFsc7e1S1eܹǃhc],-hyڼʋÿ35=gsQĒsXˌǯu;n{f4aY;`.o6sZ8}7 &)╿8mFɘ@%Q J8r[;-56wmlEJȻXb߈6T$ uؤZBCB,ϼXJzթew8&R~F7ZLEv-iF`HC$EBU$N/xwlB)?-L^-C[ŜTqt2eѧl^gwo3cP,\`+FB|銣.1#HBso$~SklD=cWKyzEkV(BF: A? Da@EE9ƱSBC^Fyai$ Id|jKQ/"RA6C"Zȓ rpGX~X/1~|5zW4-HIaVbU*5|4u-?~jkWr\duO\۷ @.22`WI([ "&rzH9 !r8ˤ 8a~pHo"-6jS$kPKM@oZ_^.*V'xB R[ O-#EAHU\~2QUsg΁[=.Vq}ի l 6;0{DJ|G\qeA]I_e>AN'B`"U;.>̹9eo!f0DY sz.Gw*4%WA42ڥn̩NNȸ VIDAT]jHΝ3=cDWLql>q1, @Cg-c 1ɧk?sƷ0zc|fzG[5kֈYȹ۴krPt$oϯ1EWo0}wL6ߥ3w`5~|X|dI^筰2xnbfoJ3)2ZAbTZYm@'~~/T4+ 8eH)G-0\/V6^ۊ ժ]kooqO~J+3:Wn܅?o(*L|1ɡ6H"$Py Z\d7LyӇ} Ostҭ:됏Ѱa5~Y-+;q?56և.u~{d(mMܐon1ORH-84O4*Vj5}ԂUn&=M9;=; X j93rG$FʏwzTW2epR+Άh, UZ? h”\ke(oĞ+*,i[ǜ|Yݒ ņaå3ƌ] &~qL 2<=FgNKQz9~>S+VgЮDž$'djZժ^vXۙKTU+j3] YBP]ao֕r3*@8*(P*Mַ_woeWJN[jE[nee9dt뼹jU^Opwx{c<&\Jaj# +!>$eHUJ?Vlz0JVhޔrj$n@ UTaeS'`:ΝZ =yaVކcv?CDY$ln~(09Blq)\ʼ=[jQY_RhM܂|!܂r,+.gܫg5,3oH#^Z>YJ*3UC`r6iL),ˆMe"+ņi# AL $ գQ,HI5x]vAU H4*DƇj~(T5g%kqۡ>v$N,#,r!K y]k@j0[If_^ApQKD=\k#5LPQPD\OK8S b8CAI@ZHn JY,WbePEwqKŠȶ:k/Y4ӧNMG77Sq6Sc \ 8yKۚd8ɂ`]S Ǝ[,K7yin*gn6ThyXZrg|SnTHbr>vsi8J (ޖx=BI~t| 'L]`0%/MA{!+  35Lp+1n9hPUG]Z / qV^}AzbJ v}^__IwZŇQ~}F;:X!v@Ϻ./nq<_ϛ7}u3G#>cռ|{>?͏\ﯥ.=X&UW3Eޱ~(~ǟ1yOcxضGj}|hjuĭ}FL YquZh03eZeq2hfay]~쓋 '>ۺ>h ("«qL%4άl]N޾_C^C&Ycϑؓ.\PëC |$x+= ڃ٧W^;`\\TP|E{(h:"LTޑsǬzYrcJmѓ PJwR5*F-s19qk|QeR;c!샔y6`"8z +@pIUJ.]AN'R2 =#7;pr(e?6K;WR$ _JYu]Ii:*e(K#:pw(*~}(qn8/Vq =R#F*)P1̙TK K 5 NL!6O@D*j&)[0DrYZS^+ޚXҊBR,MJѴRl,:{J9-R-a( )E @ EhT^^ Y'EGl !XA #>O٣\D); )Q\= \*iY"Nwg o$EyKE#"+OYjTP((qU,|IW'^kn:_zL+tOd]HuQT!\qSӲ eBr#|`YZhȢ2I BG95A?ڠE\˘U: gi>ŰPj4ΗƵX%"=7Ԋ-f"-ɅMA*Bz/ױp /nIENDB`glances-2.11.1/docs/_static/glances-influxdb.png000066400000000000000000000222741315472316100215330ustar00rootroot00000000000000PNG  IHDRsBIT|dtEXtSoftwareShutterc IDATx{XUuBlt,Pm2وrJpNVdөg9Tsvt,3Stt,å'T6%tB/{BPA!ُ߯bwkC  4@@4@@4@@3    @@4@@4ԕ!㪬4:@(///-iכ -O^^eϘ1c6{/1 @sNIf3]\\;wN999Fzzl4ɓ' Iah{;wN%%%l:+ƍN]]iV1 tvvn_8 hN/PzzΝ;wrqqu]wݔTVV֭$ٔ &mA*))֭[%I}uѣںu<==Fm@ |Vk'N\ծ nyiꡇRjjx M2=ǜIRTTz۹s(lov?nai8qѣvg0Ǐ!\HtyyyJLL\\\秤$\zsss~zegg+11C%%%6Y_z=zӶccJҖ-[<ǩcbbL4KBVV^ :T|}}URR jȐ!ڵk|_}}ҽޫ0ЦM4m4UTTHN:%'''\R^^^z%I;ߺuUWW'XB7n驑#GXT]]-'''}:tH}k.g?bQ^4mڴveǎƵޮeaaaF\\\g9@H+"hJa襗^rwvv$]V||6lؠQF)++K#FPTTFM6)>>^555'/խ[7=#͛7[nŋo<<<4~xІ T__%&&꣏>RyyF 귿m~zՙ;w*fWL@Nɓ"I ֱc#IVHHrrr4hР&߻tRݻK&M'x2ӧOb$w}Z`$I퓧\\\ﯸ8ٳӿQQQWՆ+hGDwx8t .\p|c[oe% h)4$߿XDDۧ}^}Oál2͝;Wok_,ϟȑ#էOB+Wl_/رc5uT\ӦMEa♀B߾}?OYnM Ν1b~Hx GUIIz)!~iݻճgOM2E]^s:uJ>}TZZd޽{E|[mذAjkkuԩ>T]]>}Zeee4n޽[zu]wЧ~UViѢE'|R>>>_R>x ͟?ѲnnnZx?K6lƍ@/'&&F=9;;kʕ*** B=9<<[itzw=vkM}GLrޟ}?))IIII/ŋ-SYY ؊xn8l/^@g/Ҟ@ޭکZzC ؼKte>>ヌ4F4UVV^yNDDo9sFN2vy=1uf)""_ 뮻}׭^O^8fl٘:uΝ;V1.0)(($4@M&;v0@B@ЁaFEE1@+eee4MfUi@]=İ4@@4@@4@@3  t"\Bnn댌4Y SfMMvU]]|IRAAjkk/v]www3$$D*""*YVhh_555fNNvUZZBZ8""g9?/l*44TVU6M5zvTZZZC,7dZ,&3\{Ԙ ?Cj>>AkTwVnnnw?kn7322{nݻ5rss-lZ,o߾X,Z$zSfkjjL.IѣGUVVs_7y^AEekgZ ժiӦ9q(((P~~JKKuAB,-_:{n.((UhhBBB 7Fv1[]]59{E3͆YPY,?49P֢srr|f] 4N]phZ4M7Nv~+.[UU%'''8p?̙3 &4pc[NNNNnE?Om۶6ӧl2\_^JLLeddhРArss$۷]]]˝={VeZ&wwwEGG+==.\_]6MPTTV^h_WrrrΝ;<'eggC@@V榯qVTTΝ;tUU5`9;;_4|p0v+1c6mڤ˗DJlY,}Ǻ#gi1c.\[a۷v]wi ƍm߾]C bQ>}"ӼxJFR=Խ{w髯5zhݻWZlUWW'XBz79pTUUMOOWLL㾳Իw&=c EGG;͛^{M]t$/ƍgyF PddRRRj*kڵkcIIIբEq \\\TWW'I:|ƌ'|RUUUڶmz-ZJVzұctQ)99Y{^z%EDDFӦMӦM쬚=***TTT.+WӧO$}i&L@z:9_ٳUVVN HΝӟg߿_cƌ$^Z?񏕘.](,,L3fp|JrwwbџFV5dȐF:_ҥKճgOO<?Pϟw,s!_v?яt!}4JNNfg-gOWVdd#4w)'ƿIfϞc*55U#GԄ \-\zG[nѣGL=#իmۦ>}H미hzW_}Uwy[|@1Ms~kԨQ4iRex79rDt=X/wz>W KnIW/b 4M͛7O_v}yyy mx~4k,=o. =e+VhNc:{nnnJHHЊ+;hɒ%-ھc=$6DǎӐ!C$Is?'$}Z˗/oykСS~z饗h׮]ZhF-sNNxѣ*,,/͛7;8!!A>F *//OΝ'j̙0`@Y . /oٳg]O=$W^?1B3gT.]a|}}gi͚5QFE~~~N `Μ9:|XM:UD饇oz!?Yf***h"_^Æ 飹sjǎl=oVIҫ{L'O=#ͦ#GHݫHjذa***$}>|Võk.IR]]&O@+11QgΜaDg)66ݏѣ/_8TUU?~\?яTQQX~ܹկ~Sԯ_?Hv!6ڞ M6);;[iiiMS.]4i$Ԩ_)))d@@wkMO<>HVPP?Iv>@'|'Zt$iT1cLTBB&L ݮ~[cƌѷ~?P:x:$ooogttqqqk׮:r䈶l٢L[n_ݻU^{M .詧ŋwq㕞kϟײe4p6n!O<ɎP[oԫW/SNj:?:u㾗?."Iʕ+_:t̐檰P_Ǝ+Izg4c ̱AO>O<~k7e|JKKgJ6!={ǧMp(n6}׭ZOBBVZ1c(88XqqqW\GbvgUVa?~\jXv[y9;vqbh߾}wM4Mڴi 7|~5]tх 7ߨGHunݺJfkkkuq7N͛I&… /;ʚ{ߵ֌3_B۷o겇֠A.]$/R rrrR||u|i"@'pL9:Teeeʒ$!oooy{{յ6l￯m۶O?լYZ'NP}}7WEŎ[eeƍ'I7n222TTTJ/zn.{6lX_EEE߿\\\n{K.F35k~h̙TYYk508mٲ/../g2ƾ=1 7UϞ=^=o߮ĉZhGaaaMݻJWn2K}OV$-YDO?]V'Mj3gLTϞ=w Æ SZZ6nܨ㣂IOu]x;oϟ?ݻw7#Gh֭ oOXgnqHv3{l͜9SO?<<<ڶm[٥ǫR!!!7nRRRta͜9_W_}U^^^Z~,Y"IZv-[ g?Stt,&N={?T[[@G7`)##C111y%$$k׮c~iΜ9zٯ=X\\9s8wAZZZmd@#NOo/h[ʕ+UTT￟"=zٳo>&ƍu^W@KlܸA bbbnV 4@@4@@4@@      hh)Ieee&qy 0^nKIDAT-*&&Ff Ƨa4[Tbb$iڵƺu]mƺu̵k/ eZ9s昒4|#99ٴ턴$n&''7$iΜ9j52K||aXٳg+33Tdd[.333{Ot{ 2Ts͚5x͕9p@*22R>>>߻,++3sss={Ή4i<<}fח`7}||dٚ|!%)''xuu-[ZZVk޽ BCCeX%L,~n#BpE      hhh4@@4@@4@@      hhh@@4@@4@@4]:ݻ'O4222LWWWFgϞ${$kכ /O^^eϘ1c@[AuuyhpY,6E"hhh4@@4@@4@@   UVYU\IENDB`glances-2.11.1/docs/_static/glances-responsive-webdesign.png000066400000000000000000010754211315472316100240650ustar00rootroot00000000000000PNG  IHDREbKGD pHYs  tIME 9Ϥ IDATxyxeWy=HGTRU6` f:@$\2tgx'M'tf:M v$`mˮr *tqqґJݾvnV>^ڍ^ݿ~=V;[󪴭h:]et:kz zblCiE5#z ] cyu;}~AA+mȨeV_Zot[oT,V?y~FixhCM,2Ziv fGb=o l_`Ôv:&:y.AA(T{稝VSZ6GWo7}BE;ٽs*{ǧ@e_wYV~~5AA :Tފf vvtJ5F]!Uؽ< 1A B~hqC+A2^KJOTCo)|=YaY!O 0lkdw7/ّ;,cs6)ΑmZYX)|@ޤfRq{;"W8t_%MYsJ۩gs>/A{Rmo:45Jx}KjJy~ eNVoP5ՏMgl;#6b;{@G~UN7ADM鎿w4bgJf ;Yg 5jN 7R>;[+yq"]qTκwo&TUnPL&AQpo{s% ,/cZ;iVͿ&0 1$b1&$Y XY$\NqxB1ҳ4MQڦ:AikqA /(I!ߠ?AAADUUr9Y %0M+ȓ(&tӀkHRHYrj͏$Z,$a Mסi24r,rE0j* Ài88 !?}@ J$Y(eV 6.nVZ MAo|RIiVAg88i@U (t: p 6. nV!ALSHHRHH$H&ȤSP saf~f~j4j|>QʋFQEX-N'\'fn/2AAQ>C*B:F*bi=h3]Opfd(e" B9r67EHW* S@ 9;U|+n+fj&4h``H9,&@%m6n yƨwn,.7=P  |zDD^c׹a^3"lL,ntnCL $0M#J"Lbs}cPQ+x{Ȅ_0aBu9DO` 30ёF]]hM"AAݡ8* 0iaᷮiHj$IjnǠw{qI}H&m DSr}_MӐH&5<`add>Zm};7  ?t pXs3䑻?T Dn{ʿ BI&FX[[ExnI=EQHS A=N"N^) }ǰ8xi Lbey+ SqzƱy.Pr EA8EXm6x<F0=3!|#=9n~LDڮr{8mbmڸJ1SV)^'JqY-|7vhZy~͖C2c(WֲʛA$Sg'P]fA쉢r4MwY׮e;CdDIbp:\8d8t]7B|X(9$\s,VW122z.BguDKz -SjMנ4RI~,\^0==)ݮBKAlSR)d33iS鼀әИM^r" "l6+6d4a+ݒ$`E\.Wh.XCQΡ tMCNfx^ M9?8714ׁ0}4MDa,--bRNc 24r2}84;)OL@ee' E! LBM0R,Œ1kL 2$Ic!Ӎrmٌfɇ+xu4 ΑH%h CKaza! c$S$q,/ЍkBI4NCX Kz1>>qXl{i!5AA* ! ($}n\nm + PsArȤd2u>H Bb_ȤX^Y˗!"+ơChiƾ4x#L0 x^$ 6ut +0M6_^1V<00Va$͒k,G5n/D"]Ӡ ]Ǧ[Lf#AH\_ Wٳ/accL K &B ._q92) zxb8tF z] vIy~[u!AA\Ϥi~ɦMHۃ! lA0>> v>/H#cllffC5(N{`!c8`s[_ 'N#XOiH#aqq\  *kMp\vAĒFtBNn#C81|drEQNH$ !޺Fޛ \NBXZ\ĉ'q|G!r9$R[nV+%$ "a}c=,oF 2&30V+$n100as}6+l`sT ~&.ascc߃rPYe kyf(`,?sM|=[ST.-\Οp/ QI$HO)IAB!~^ &z1>>~{ [Q8VL/"AHt خEŅ `Š׋1rr= L,9L24 I`-p9p:$ `$IW)Vi%EU qpg,Yui$<;M*Ĺ nc[*Őǯ} K108H/ Aqݒ就T"7Ad0<4LOLbyiw7 +{A?_8P{7^~+_^gíݎd"(B$X-VXm68Nx\. ;p rCD [A Вz0|REAQTd2i$II1SiqYhZuqG ɈF#xU:u+fgrS =bmll`iy $ S8Mr`k(7@!kd3(ԡ: Cb" 2,a6v8vd2VL.X,}[c?s?|ꁾ`^<~s_i$Ή6Ev.xx<x`;t8`Z!KRq~Uגݖ H|<^viu D"xBX)F' n v*lZt:ST5m`q1atdޡ!\n8vX,T0^]vdYbLӄu d 677Fu8^:"n6>|$[\; "+-0 ߏyz xهj~;G^i%a1 ,//!Y"ڨY`|baDQigJW(^+ RL &7˒;۝]XͮŢ ):p>SdH^'_ty;18Áuq蝏alS4 pffaxx6(#, , NFFGq1RIA`ӿx,U`.m^USx,P~;LTUHWFL&i AAAx4MÕ+Wf6Frall3jtSǦl׾W0 |뱇LމpKxK:=nW. ?/ѧ|X^ZiƝ~ b>=Yi៾zr鸯?brj /O+~whiS^.w~7?c=zl_*b"V(TI ecT~ν3u5}ja|jSӘVo {,.mß@՛n:Οxw;v 6[~iX\\D8V++AqcXYYiHc0lV[G| J LĮyI׹ə^k |uq}oV__?Xbþy3A#av v3.c}ew߃af"03³<+WB9#>V1>>ix!HRi}cǠ9U,-/ [[-9XG*B(]whWB)YXZZ7``` @Z_9b4N',:X <~6|2ÎC8dƐ<hE!0BZ2+XMAÉi\ˉswcos޻|H՟-VOޏﹷd7s>IQp9,,\x pdik/~3Ogq:#?1}c|l?sǵ?~<7+zg|qhv._ <ûB9|?F/G<Ӹp}hziy<|#4n7Giԉ"I;)L;%\xH6V"Nj/t:׿ X\\D0Cǵ577IA9VVVv^/2cF5U|3-3 0뼯 Q[v'\^ċї2u awHT0 IDAT bD\mb9#9uvw$c o/ixo+Ͳ@x_-}oU wm;y5=\}ʜq;m7_xۖ;e=i_'<`c}vb{^5Mի-&13s#'l,LLLbllsXt .G";ip:pE$ 9dIf2pf`A}oF :8jEVM On=CƝA ccmxmvx%y:ρ76M Ӷ{, k9=}eK>P}݈_ȻhV Z/h-vRm{3F}?O៿Q9l{,9onb2aߨZmc1==Aw߇DQ1sΝ; 41QM{!EWVVÇ  L&2|؊*OVXl6l6[f3=}hÎCx0cjcoݘ>o@<~K SŠ_$Q`vlƮ[cX_[Kg^lKgN'&KVWpR1wǭÉl6?ۑYf`zfKO|q/_wN L'0v4jۊ,ٗD}EN#cáCp=-? U X~D?I‘#󘘘Q>8;NX6<WRqu81ᦛoo|3ছonK  nfw;p]wtr2E Dx0@&fja~(a;cdX hǿxƬ#5˚9<<38K8KuDwyh(Ks8?W_7 3醏l=##+n}o}^KO]Z]oy^ąW~3ԭx/JnQnf<3߿ⳟ}ӛG~_ w܁}omw{ _**j L022Cf1{|}I!ݯ8μ"VVW`Zg/9.]I AAAuaC:x {fE,gV:FވC5S_ |jI#U^qw3vt9w#{ 0 ;aM),W?xb`z?LCoaH:$#G=c8ҋ0L~οrty~Q,\D"A1:6Sކ7M}X} Ë/<4܍~, .̋/ Th"ͳØ? (36 ǎ ^~e;r\ËVW 111ANAkHq'J|>|=iRzcg 0ëWa-*6Z咜xYx[8< o,r0xzCgNa4R|b UWk>oZ7s׽{g>5AQqq=v b,`>ox{d2pc:;*Պ7͸۪b|/uA\l*W4SmmUGIkP[3Zی%s;spz7 bsc3atbt|Nw!Xe<%hJeESũ4jn!u `UnvQgpE,T~!Kvp1L.Tn.Uoy>ծNx DI7k/l;˞i}tNS߶:oX@.r`0Ϝ)$I?I qv;gfp = KMA,xfM30)X,sÀcqwTRfI# w֓D1x f.͜\=_TU9]1tz BbO`$Kg^rd$Ű _A E   zV~^ոx0;;RKrjeð-63oqÖ!H {ș9\,aykG;k >$.gM7u8ΜyW./yu:7`t| IӸr2\Ud,d 0t69" z 4qR<0::}Jv 1~<Lnv, hG=6 {^Rɼ5ŀGǾD׉Ţx%0055'N`vvN PL-Bon"L4}͐fqyL(!Ar9lnfɔs{bmXT!20X"LMbPe>yvkvб5uC:30sy'(H?,^nn;W[2VW|"װeŸ9=2krWbmmss4JHAa`ss O􌣐;}3%0qnr[t#Nb"H ΔM=iT4r90V}m2n B eod .,'܂CEQz*T/^l6=< b휭b!'&zjKLK4tcnpcbLM6tl gJrYU4M$ ps7qw Z^tb0}(nSdY$SI EH$dze`{X]YA0ġCA{J&A0 Zibb|=ߴiȡ.iHLU6U  f{, Bk`0WΞoz ffAbkN0 2dYodaebccEHRTiŕ&HKK=AF4ll9X% ST38 S`$"a:f3$I깺/a U8].~ǫ04U"GvTS)3ݳ蛸BVo9 +׼o ;וX_;YgX`XP]ADf#psDX~ c- `KMӐI+0 FFjy!šf,pë_LNNB%hK.!ӌ -AXd &'{.A+:f:.U{?OkUG`;: Ө rA\+$ V+ffuo}q]8^~e+AD#Y$S)LLNͺzs3{0<ױYmI$\boSUxtvƊa&|}獟!A}b4߁-,//AD3~ v{`:Z7 ,gW/Ű=1`>Q)xF{a__ū,Bk [a_?K.! PA a-<`a 7yN`]٬+ uz62u0<Ʊt];Lre]B wқoXd* )DI؁ ujqM߳|%N_jY |X?ɤ˕``% ۡ@ VA.t0'͍XqhC>}5'z&\!1`-a]ic,&ﵧ]* &D0Ȃ `& 8~K?V?n*NHŒve?7q&~WggU_RsCMS^7bgݨVWn^:wrP)`#mc+gmd۫c6ҶW{bYɺQպNoĺo,x6^/cZ]dt=q|Oe<C,۵}ttמBZuLDRܗFmmf/淖0J Gv0-8ը(m Zn3Ml= viuL#egv]5̛mo8/o+&H(0 cWGc ma>oS[{/b>qNɇ XwxuB]Qrz=@kTU eS==2ARm$ևmS|vFo Z#ҭtoFʢ ) YilMYy zyn{:]#J`UV3´f5*ͨYKI|A RgB`{=V3Xήt0x D+8V!f 1w̃jo] %pq\,6Ō}'p+*`)2441#$bf3⯙)ޱ7+xnE5sL-A^ڨi]k'4M#n4!#Fq=׍n _Q֦2:t-ɩ8( »'~| 5V،?ARK wWw(AQ,y滇zRdٶQ F. B@R@?f ̝)W9 Rņz#4*ZzGw}ccMɪg0|mukiڮQ*~}SV[{'ZY)FW >8XL&ޅ_2RF(|8-\ͬm#oČ}k*/SHj^|fIe yѹr977`F0<2zlDDEXeu1HkxQU#팪U)<5E/ek[a^#a9蘦Y6]عS%vk?n vG-nOݽq09۷_,VrK#wN$q@m#x;͇.%/jj 7yNMƬ_?XZ5y~ :bgʟ!: @xk K1xC?`Da1Y>kDp*ސ7WGިdSΪs ^'mnqL bM>S&` %UJ)QYD-vaoMӨ:9 h7c5Qx8?3 cPKrR!ԓQla(p,ނrJcǯz066oX AH5駟ƣ>3g  "ɔF [5mQf IDAT}:hJכz}]e+^VjƱ)nU=DQ(p:p)(IzsҮ3v4~緛z34}ծ_KU"o5:W-5~n>7tN:sn`syC^|/,?7∪1o9M{pu DD"l(.j`dde?=|Wz[鱬e3ۿ+v˷guϏrZ 1! ^'| \UUK. /dY<>AQG{a5ov\QLu"n&U,jo}+wB$( UUK F+ fŚ=vѭݑo|5SJv >K;ۀ vohkw.pfےE+0 UU08̡21h6zU?TX'zfgXIhmLӄ,V ͆T<Ń>qZ @u"F(z}Jo3~I1ڮw*CvL5N4M?Μ9Ø0 Nl_bo 9NBrFOc)Tavxb$C>[I>PGvI&0y~@i|bc~ >vwP(Y8z=$EH c{}Hӻ:`"wj[¤7㸥^_ktD,v;r8z$tA,˥v+amk \N]Rf[J# Ts}۱G, `[va6Y;%9{J7tSi `xxcϧBCLӄn5o&/0 Xכ!A>sX43g;hxlD|kuJa1r9X,Һ]I WWO1==D"Q8O#i$P q-DT!ő3Hi 7`ZYpHvD'A %WSm^k?x^ &&vgNiA@"jC=/~^v#$ ?(z2eKKKXZZяF - 9N >0|a7a:B]šA@!0 @D[24.&&&aZgMii0 |v}ԶO=i?"!ΝN +⺑~'UھWSE~G ^z'$?rӸtnF]BQuf3 1᥷DUU$b1'28nLOϔ:AHD`&LWU,-^)>MUw˲\QHD bΕ+WDrvBl/VЌQמ\;!^olMӄ\ beO<9VZCX4JH###Zc#$N7i;{"egTn'}}om/I0^yh( A}{*,ַp7BhAJ#b4͆GS [}>/)a2Y/N~ﯔf6Gs^e3妊\6:h8LDU'3ߋzO<40X)4 0x>ד$IqtQ;s = h<+qPtO)C wCdfeVeUꎯYYw'wp]SRdBM`1K @E{{{ܺuk((KۻE*.&]Yn}|:y eY8Nm=Maxx4$ iQyfgVt7M0 hI`lР/6!=ݛ'͒[ ~_?DV؛zU}7ߝ7tc y3,IS7gc RJvnb{k6QԶƀѸ4h1ah9?y`ubC  :׽ul$:_vYl,Qa;"G7{q끪(899>(sl)Yc}}Zvka)mLeײ |B8KFJ1*,&Xi&( _XExeY^׈]%{wwMѻŸ,RsLycIY|phIӔxDN(0 r뱻{kg !d^RA7,3+!?HߧSϒЬJ,s_C}S.fZϕ1>ޠUuŭ3,0ׯG,Azr3jYXmͮ-lYXB5V}ڨZ^L}8`>GNo~oY0mRӷL_۶tY7w@=& 5\K[~ ʪyY8ſOܹibYF8gfkjye;ɕgi+eHsgmIV.*Pk*o\2[΢(5"gc7s7m{^ORk=!2,˚YgIfVڼmvf%6^7LkbnM=EQ̏gO0ml|3oܗgYUllz&D$It:EmyT'TWJQjYh}>ֳZ-,qy޳z/c8,L?s-WYy7&g AW߳|xN!syn ReIQh)z-)+ߋc4;]ۥ 5Y\Tl.yIpEmί*N? }0SU0 >ݗf}>qhht6e b9ώb6h(yctT[ mATM!"I8X@t:m*Z(J8{TUAYiy9NN&BLuEf* B\'=8A.-b4/h$IUDqJV "3e|o{.my:S|%{oBĢ C+d,H$QUEk gbyBSfssV=-q=Bؠu 6岬ιF}_ фpm&i[dqHZ*ڭ"j"5c0Y$@|K28Q*W_sr- OOa/x=&+J,_1ΉJ//k NخG+ |de;,+Z.q\͵u<6LT4taۢ24#N3ztCyhyNREE ȧJ1v{!avo;LG'X K6:d,+_R#Nwy1QHYUop]*鴻ɀ~=iq=ϿT<~rpãdlUUJ9swu]we WnʏJ5/$/Y1wvYmJUTeu^"[S{pڵh]*̽6h87ýϿ?X:>m_K ep]sʊ#O_TZ67(AfghQҊp2谱[m:5V _na!Ԃ\i{ iu:?pI2K\C IHVuȋz, /al =;mT)a8<Q diJnPAAIҊ8|wݍuVZ"{ܿ{3 /  p[vwv>nߥR9i9>yY]&ab;{O C Xu8'Jv!i |Dl[-66Ɠ4xA;wIBǏ1 )jN4e4a%n٠s^g2%XɢAɢf& #8*2\"m. ;lp}]gs(,(dB&n±$> :K3gV=mkK60$m$bcTEEN9E^EA^]PAC4xDpT`!nی1""GOYyg}w?<,o{t6F(;n" QB" RXlP2 6z~qtFom@!m<ˡ]XVI.5h^@ݮt #|8&b<[ɦt:]"'˳٪MFlSv!I2MUj^c,m ۩r.qpl ײm]()v8lt{=RLC<;dEow:^@hM ږ$Y![.Au,FYR r1[-z.2/=G͆ 6hA)Mas}T$-(#$bm}  ~P1diƲv= ,r^7m[`.hRx9llnM^TaHY)s6wv6x _~-k-vl;}VgncRi[HejX[gp4cPJ`VDA,Z g r!Y**_u0P9YgNg\L&3,yrj ÐxD$EqNzY㺴vC۝OhР! | , ,@& A |Z$F)8.Ԯp$,i C&E! J)T)Ng٠AC4j^8qhРAeL IDATe.r3VO^0d˗/)94.}hР! z@P&94 4hi@10:U^Pfɡ1hȋ/1Km>Am;u9 RENfEcL !lC#CRl 4h34bJ 1ϟ??Wʶm66X__EAĄ Ynz BؠFL3J f@4hР'CgeY!4RԵ*2 !lРAfIdʲg]Ysz)@kR!_SJyͤlp} Bg__Q':Wwť7:a_u/?ޢft[WTT:6X *WmZR,p $bo"]J]c),IU|.@"PFcY641uk۱BPZkp*e]`(UiLgvs I]tnʅnc'A,,QZ8iAg  PĘ:ш7Nq{QPN]"ضEU+j^uŶmV(u]EY1~/=[k}N[zV{pL٩}ߩf[}0(s{׽ޘ K7%$BeYF#cImǙNsg+Rfoj|9s^1)bf;o|y9i۲q\wmƣ*<(Kvl\EZRϟul8qKpWImɘ"9y3 ]z1m*+,!#4@qm4Ye]JRW-Jb{gq|tH!fsK(GEMKo8 T`nﰽOz`v Jk@z.r*LJ)j $-J(u.6| ݖ±%i \cxOsfm:-1FXfԅmM|% È(.-˪ ˶\s(J)&2@Je!ѪLW@Zzܺb(q\[-$*Hn=Hv?o0S\fs{+Jؽso7ͨ=+pm4bJiltZ&QJEhm^[Y֌ǣskNZY)1<'nwؠn)4I<)PVp:V^G:jUax4"Msuݢ=ϧ뱱g s&1Qeٜ.›\[x#n]rd<&IδyAam;?{}ʆ61[0Vg8 ?e'O99ptp ܹ{vx"MBk6ۛ]?8 ܹKBctؖ(58L0L^)L \狯fw߈²{3>KUOOQ@ރzƟןf0N"Soon0xyprEPv_|Kh`xBU@awwB! |4kJɐ/(;w_}KL>}>iVdY6;۷{k/SbaIA4P~g_ mY?)CHzoRf)Y^ d-dmmtG BwiwzpgAMBD1~Qrp<83>nǃ_ N8:>!%K3{>sf[~*0X]]4a˜R(':QT u4F雵iBdݭ.?GdƖbe闔m'Ƶ0CN#~QcFR)}^FxWAZ;G, q.Yng}iI_AFTU*Uqރ&ш8Dt]v:6`pq(/0ZqR`d뺗޿6h>hԽ"x}A-_ſ/PEt1lG SV{=^<_ 1ш>vU-!%}D389B[.kbٰX]TUAgqm*1n=Ѱ΃ǃ]٭u`ǣRT`Ʋ}o0^ݭmhy2'ܿ'xaa*M%j_xq81J1E&hOADoU˲~J$11t^QVyZԍ?2F!Y-C+\"ϓ8qu-{@QNl%r^I>$aornwh;XPUE4￧xO1Lo2x1)-\Ai2(lxid2$Oc NcKvq>q!zr]Ϟ2m4^A 'c r]|K {/& #JN7s) hR$"NS<'K2hB,`48њۏ~]4do8$Ҧj#MI?D.m#qʪ|D&q[?TY289*RBSFcƲ$YacK(I-kV3߫Qc>q8JNƤi9h<&lC*}z˲ɓ0B8.Q8(*:=߻QT'E&AMgNNPy* ?zD'pV_E?ey!Ms m̱{ HRpw^sa@J{ܪʒ ɒ^oJ){ !dk{ܱojW΢(%V"Rq\vvwY___Rt]68>:!GGp-p=Oqx . h>|xٲ=[^{j&5:Q=av0ҐmDQD4};3ZZzQҺpo%C>fU7V0~i[d JUOC&|lIPZ.h2~{7GS+ iAOW?>|u&i4goǦ*9>5^Շ(rc =5qr||c A/W$#?z4o!ݪ‹/s/={xOkE[zBu8ۖeq]<'INo[g2ڎSLc8>>^Ua8akkbeh6ze.#Gkw.woFڲ41c,s{ٹDW:"iaOZs٩fU+J[jj θ ̬&3c8/1b×NEޛ^5ZyB0f>_ޝHKmZLÄ͹[tf)0Uh7 a$ZJ={gnWݱ8YF339_;B"S9ACgKntXRrZ}DZmnm3(Kz\DR%]agg(y77.$~sk((|>G(>Gk˼>77 29kqwww_x߾Z|7KN\J0f+yeY π/q<|LTfmG HQ:1diE+hQI2x{8MTS4 |$ѳh7:{yF^6E1sȋ Ę8N̅(nG*2 c,'`1t:^ɳW{3[ߤ99>"/+llt"/R^52t7/IL~h|/h.I)I" sPZvon!@Zm*ʢı.vwȳ#\ק(2,ò$aKIes_˯Y|ۿxb;.w?HϑqNwߑٶ˯-T /;Iŋ{iQNoGJeDUd/,[w곇<'X7l3Z뛸&^'[%\x2Կ)Y )y7֚p2-c ve\u-sZZ p%RUuU091;gw5ƐqAmڗ.R9/ض,\]r Aa-la3 ĝReAEӧt6v{k}NbtBQdlvwf^1N5Gxa ^6:nɻ9 mc}}˽{E.6"p$L>Ƚp!}X! <ܫgԵ^Lunߺ''(Ĺ̪7BJ5diq-h~yh@eHa{- ~HTegt[m8uLK˷ N}k^[1bCQW ۶m{L,ec̰6hU}eɓ?-}g/xWTeYPTzV\drVnYjI;Mz{VgmZ#Ϭ?Q-.1kkֵ(/$`{.kPeܤ풧 YSO0leUvѦ`RL(f_G˲1h掳͝m^ZǤgJa6lFa 4i}P򡵡Ԋ*)"-{.$Sles ih t#SUA4%S8NpD]T8/KʲFW%tZ( JUtڨ"}TY0QMX40C&|? &sz~cۄ[ya` }!/r<_*?SǪlE Aץ鰱kYiB:P1Fl!("ڬM3:$qL ]<.b$%h1Ft!B*ceUI+r뚖eEX z08,V K 5ݿINgq&j_\ɲ6.Ēr +cnj'c,,˩lj^ZXS%97}!e{qJ100 &>R ӝNzkk$IxݖC8#gqhya! _UkkTyd8LFCZkLcɈ/ȓr>fAc:hYʄBg_$~̰, ˶Q8z^ٴ\{{LpN~Vμ>\E~/KZs;p\UU UkK)uRZ 'e)Y2mZ+BBؠEfe^PJ$c4U54ax+O4$8JP:'y?L?f:8ܕ22x9\[x{D5y׳DUx|UqrjF+b՗4K?2LwWTpmZa$0gZ)8"Nbٽ !lI* rVBsS6Ya.N^7Ox6_ ɯ'ߐ#tCxxqiYal]$$KQDQBO./VԄNNa>2 E6A%thqe8d٬5߲#?qkfao)}6wh Ϟf9mSdYaZCGP^Ef(]jO'@xń32[W.4KX3 ͢AA&)ǷS8ԌlXxw Y$/rTd 4HiCil:N-Îdwk3NN !nG!tAt8d8DRYeh$YFmF#LhƀtF EyNyoH{a!rLIi,+ " LCf9h7.JYhxB  2Y?%an19=~oGbL E WiƲ2dg}IzMyM:{YY|ZkZ1Qj6r">!a.# i4s]m؆7BnWh+mҲeXI_I/CZo`5:.A@4_q_7񃷵C+a?!h4APML&3=|7+ssޅa5nm~<:99Z 5Ygq(F/MTm]J'䅢7aJ`!-85 >'7j`G&#S Au~:eLx*ri4u, rkq3OѪ4[].8>;%H,#  ]._e9r/Z8Ш 8 r-s8BGR'("|/򗪌JZ& dF_;<lB\d%BfiE< \Ϧ|(ĴL ˲e^C {W~zS{*($s+ϟqjBEN+e1L5q+|!P Qf4,Co$yZ1TIn/Ź[k bd&_jYsx,z $R@񶐦I`<. V$I,$H9 |Z[ɽRRk1H(,s޽$oZjg$rHC2m,+7kȟ[Ee9'^hQHA-&̖SĔ\(\vjn)S"QzW"C^tBK8,j!$R fxLоОuڶbO)s.BSw"+T A2&4@4a/, l-YhRY;ꢗQI_xt QC_6^2_& a! ^),-OG(.뺕-R+M (|y\ E'^ik )Vb,_r-HuVOS&bQsMi8Fz㰳˓o.{avٔ^OӡV]9oyNܔRbj+p$u:5K8QJ8WޗRjY}{v^t:Y~$ {{t:E?ȗXQK:kkO$N{4(/UOE<ٹVXCݭcRA @)%~}_ +DAj9ul%7oi(&R^lAP,űA{_QotZdjccs!_(g۶Ѫ(DbI|s-^HE7$L.ڏȋgySײU-mr lLLXiT)YaBJ̳cK$Ah4# ܦ:!H $vT+s ²-3[1dZ#/r|X\^<έoLLo:涹sujjL&c& q|ki9ka.lIi!K¢փmjNh"/5̳RcRv*-›j2͘LDQx+^A z.ٜt{xۖ"rwB`YV}zKAݦ<׋:;X&^V SR)RA&o[w$~ TQٶI]k&J9.;;;GCӲoЬ~D^흇dGѢs4FJiHZ<Ք1OP̞[8/>c‹ ĔU+YR/BK9;;ܤhb&eٔ,6"-AKd[FR;0}+AͨS7HӰքH^). iq: R? (he΀A,+tl|>'/yjXQBdԭ0Jҝ9A!v~InzN+VaS3(-Qt:b}M"\aY蕻EAe9,OI2겻 -FÐL9nϛșy1Ҳq]4lm?Qlp#/>FiBD&NeElM4is2^ !zmA|># B4yQ-B`&e88mXĶmvvvg30$RLӺX4Y[_$ yE¹aXmb6ZNgy]ka7CWzخ#^VMGOE|w Ag8`mNKOY*qp3 ZG? B Xl"_g(nJR.F }O!A2m%Jb.0aL(I iwz/F!4eN ga2:;& mc"]%i9i&!YQ]0$BXE0/tNLe8( ^!y!i OuanmY~XƂR4I˲i6$IHhoAZZ4Qd2mܠPZ5t,ѩ$/Ad]* Iȉr;&IS ME[8uC]v͡٨QU&!Ze1 6iXT" R9 p2gOelQQ6APhA6c IDATVV2n^oIM)Ni |oıB "#H2&lZ@M3l2B%1Qh$ VOQ(EnWIBznu3_uEDbJIӡ,E<_ )2MRh4r jQB!mc6^oy_=zy$o0fEZ眄z{NvS(E_c?VM^zԢ{}ߊT %ͧQyhDB.=w]1qB5 RggI|:&s& YT:Glo6c:bJE+&qF4]dCCQVy!Q01ㅼ}Oyd4)=L#&YSgGi85 HUX䤽ƟKZIV_.+Ďc~q7y0bRDϓ<'CшYv+ϛNRXH0$I?iQUD1Ay)$hl2! <(\3a8:B֛N)4s/wWޭ)I2DegєipkJAͶ8N&yh<"}* D:9V)ILi]SX6-(=$Zpm$V!I |eh{p㐃(ɱM=%D<+Ɠ-p;ކ 0W,+$~)U$d8Eogo*BXwtX ja]|(CdY9.  r7I),AxY0k"$QAt!>c/PY&+uu;~Tttl<|I@.uOTB+.]U9w|^;> _孔??8Z)=5g *^%Y;gs4Q-~M}OxAMɣHo[a"*|8a1Bb Ҋ[nw%k~w6j_m5 JZ E.*oڄC^WW]yo :߁އJk˷0ˊ} 4}\lϋv+Sqˇ:zh !PB 0| {+R7o ^]qCP"*TPE *Tp{2UUPw4\tuݿ/ܩmϾߩΡ{0h-jƷXB *3\NKg5[)UVaאI=rFq5BMNjDw@$zwUO+a *TPׅ}F܅*|P *TPB ޖVPÀB *TP"E &*a *TP]%.s VP *TxwB/+4^8ʓIӢjʘ( B[-?ɲ BJ:A@^R2 qZz/^`PꕽgRBTvb $^W &֚*{BV=%?w] a'39;bk~G28<9a磏˜_|}^ɧ`|5s?,'Ӣj)A(ߙoG?fxvpz]@o :Bv7>W4$jAQV5Ja;.[ O 0L V(Fhp~bs:O4mPDQDF!{ ./~~Q&K%8:8?nkׄQFo}~ҳrx1y)Ikj29ATH 1gBfHVϱ9^*]q46~IcZMFO>6?YqCo}Thalt-fe::1yu<% C#-'!ɔڀf>y vmcd>?drv_?/l~ğ|F~.g_<`ѧO~L4}Zyy1Ly΃MC ˒Ysi5Xkg .h#}J2z4 ~D_OO?# O86O~+f~Jn|Ne֏~â@M'?~g}VM!*rmH`y2*  (ԗ(MݡnW=xccYZxߦn燴.};egg˰y7OnO1 BOv<;`H!7|ğ?߲۟G& ?w_Xz'_04%Y1oǿLOO6=~= Klk ?i0͂σ+TpOBcn"ox3zK:۶1MBd1-a#5Ad<$)ϟ=hM;ŨmDd鸬moi0MaHDAlsFU=vvM3LMx ʆnONBm䌧ΆHi a`Z&ipna Ã}8fiY8 [({Q$ĉfЫ$ EQy *T>ߖa}VU+wN4Mvvw, Y!-\yE+|P?1 l4fg N럅Ys.VKY5:u8Iӌ𝑦G6Q4L)f3\SPqrʰ)qd _~!-,M9gd]EgG욃) +gſ?gM(hTNCBo)5Z=Fqۏ?3MD!tG$qyK7_o|@g1l!#8M4 "N YnB|W`:c5 rWV9|4 |sǧ_;H-y3Mhl˲1f6q>i^74JKÓ#, |]r8I,=}c&u.2"ǐnZ~BJeBa4KaDƶkϳ,# <0LbcfRA@H)qul~,#Iv+U 8lR|RN)w0h+EQHhqj=4. iͦh]^Z)΃VMCR n]}@ c<CJ)E5 NAwaIL,kH)5B7K11QJc&/4e7+'ٲH* aR@k*y3$ 򦜞MD|.af7REaA9TQ dc(PJ@"DJ˰dd@vR ](gx1Zc5KqxR u&#<hLcBI/V/CO>!,d0`gwiyW_}Eee3  CP(8;=%QZ3N9:>"_ܓ֚㰻K|}DQQ-ft4$k-۝eOc&vŵÐÃڝ6fk1LV֑vjxޜFBNOQ^hѣ^"TrQʾ9 kkH[!N͡. b]E$IO^O$2F!'GH)D ,b}}4Hpn~IJI`>3MWal0Zs|tt:^otєl;;/+8_J5~FjEZ" 9͐er;Gf6>`]EAuByeQ7V+SJr FA[s7L8=9u]5L f)'>||NJ"G:eg9Ʉti 8CFC&1zfU ^v|2՛MZMJ)v\濩{w! NCD8Ow(j5S@KDB 1 ^& [+Ee ippOKBxu_xߝPR!ש#,ˢh0N}IːnjFY5ó3!EQPo4LW%4B&m}:nx|{.anwN&A@'28hb%]j4l.<'GHCh4Y[[vBDYDQD^9.oJՐR PJMU]L0oSx[4 2Y9;mЗsw~:Z]WO5l,hiYH24ieeH!PZb4"&qu J'$I R c @ie)Yc6aHVUQ+TP›hU)߇B(+id2^}WVshZGGKH1G}Z ! ijs=NON0MZFQ#|ߧn_&LYjWHwe42h440}R:ƌGClƶl6?{ocIfǖk-#{ԋ(@$j0I$$Hh!G3\cfȌ-+3{]w;}9֚7ꪢ(փ#B!9Z $> ZM*JZˬP H},Ȳ 1MT0'l6kL'gHn! ai0]^y鞣ʏ'5nz=zx/ImRF/Nj![ь dwwoϟsxpTJ?gm IDATWI[^.mtfk8a\$x[u|~f>1!?]糭-`XxEg~^?#w o KtS{Sa{<{'~ۉʹfZݻ! :YFo~ܥڳٽE)b1g~rҊ!J*F)iۻpa1Zk D*-', .1aF/~ﲀ?a[3yĝ`08S̼ qc: }rO QDYLSk~q& ժj g<_Kܻ$IO )[[ᅚhx&j>I283`:yyFxŜ,Ͱ $BdpA5pBEs24MYVg}Fw:} dag`0(kvi`# b)y)VJkW?xt'~E|B_W;{wi(MSSl c%Nju7wW^/9/}|[pʹd8" '{/wt;$8x4`>#$8xc-$!۳ YefeA<W<{H?!Qp8!yiTc RyGXX]<yxaAA`4p|r1UY'vI)+!Rdq0*bE<y{@ICqE?|d0  %? }ŹIM`t:rj4_Jn"⧂' $R)ţGf|Wȍs,:LϢ`x68}e;lo\ۧ{{wn'aw{w ֜!:؝10/?@k'ɵ2m1m]#d<0O!TJqKmG ϾMO{Qr8b<JKaK+=K1Ñdw{ddI -_}j9|?dk2cqpsgA(CV's<9],|bf# < ~A2mm?Y$<)#0O:)rSR60F[xGoB~Iצx8C'&y0_^ghAHlg0 cS8O)tc񣘇|0 Ʉ ɓox„eT^kD MpƠ"PESkN䪊rNNkOlyoJ<":pH M'e<9?'_eXA&w=9|{ky{}޽yMpr|D]H}Pȑ:ӑㄝH`OO't\ 9q)|Ww mOw9w>PB'B!a_չs}e+ˊ24PUe%ĥitM =a-y#aBX֛ $jT4UM]5~*Mɲ(nLU- Oi8>>iXTu.5`tP9ϟ>CXZ84xJ2OVCtC :|)H7kl|mjclǬ7Gn8²^ZMy{?{v7B > g{$ח,}RWFhMŷD|X~p){`]g~vf{.\vuz_swY W1j_ ^n0!?/ ՛$W}/~ ~^9[1!Bl[2Bњ>UY"GxԵF)E5fFt]QŻAq[H/$|Fyεw\[nM"$k&ϣiLi@IIG4ujn빔d245ZVPX(D8Ku #ohhOItc%ESխHDju݃JtJġGEsgz;ٟggHߥ~4й?oCީ}ߤ{vn7r|{nnC4^N>sY_gTi=Bς:ѣNjA{ 0F%gj#Y֢DVX|>Z )6¾ܫ{T}=%]45Ȼ(fohL_Ѧw7Ml+o{/yÏSkG=!MfRHZ3dݽ)/>e˜6=YC&p9G' ݻ/i ]<~jx0޽{غM7ɋǏG%sr7K e=zBأǏw`0*etqrM&<|5qP <|xKjCcotA4`wʽGPe)u$!q7OKΤ}/~ɗǨxGK>{|6YG#zSo_=!'l`Π9 lkG?Eu U0F8MH!fXs!!UU3LNm=$IL]ר `wo|`IYWah<$+J@ѣG@ /SJڣGO{8un,h@g{C<)ɳR[ C#U=8yBDq X- t?@ c\ww=ŋ)hH2cMRݣGQzG!!,e@ъ^*tKnF}>{|YN"z<#oKO^VFg誢,+ں<]!5OtAY̗+T$0ɳ5ujPƴGϟ?2ջ]ѣGO\:B,eZ +:k>SmͶ%>~?k/n7o^77}!j}-|WpUG{|Ϋe~txPy;|gGRʂ*p3uj`5|uUrpxepfx ѣ{Xޖ@f=z'=~ʋWdro,~Oշ~"ѣG&r6τ =z`2"xJeHRVZUj q:jZV]Sk}R $Ah!BJ(BW-|3O,+G j4bI1oQ!,McgXWXcG s(=k~FR865ycBH09dI֫YQZ80$ M10u@`lCQX<( 0fZQsQl6ꚬ(F$b Bޢ[)eaCy4MѺF(pR]J]6o~.Gw hO{ a=z`0/uM'98xl8|o٤-ٿo<)Kl/_g$I.XmrIB(^W_rx&)b9:<.+,kI[BwpogJ^gj#b}kR($ɀ;wpF)MEOH1uLGptوlug )IFc=|@`~ j\PP~x2",Xo6גhM}&-ۣњt=gɘ'ֆ F}!'/ h'ۻ{a1?I芲ԄA|#sgQ<ڽOZ:23 }kƣ* Sk^$bJ3#*kȫtPRī.]=zBأG?O 7YΝFa׏dOrtrBXZY-,Kt),Hꢠ*<5 f81YSsҭ+ ‹'IKïO=f{+a:vkX͏d IDAT׳UeƷ~E2cy4`(+jm ′*o5Vq$0U |[χ20|8 ph ܞ9͊oWg8ZZ)erݦ9YL"%++r` X5O9>PTYఆ!_SH!Jzi4E1kkɳL$8:9L>C*\ё,lrGGGTUCD>z&KY7)p<Ϩ@Z˧O8٥JdXP6֬V vfS|^"j(aS9:Y%Q0*LSTM7]bv;C] do^ߣǏ;9x_wM%OSۿއRmΟP8wLrܯbt^ͯItݐg)u(aY,W6]Xo~5}Ť72:X$QQm:rWF7N=%}5U]cEJDuFKU JqYJ+JUzEnƸ_hҴ9䘦iLsO-pyIYUcpm}Mtq8|Yʋ5uUQV;YC(rZ yQ`eXE!MSgy7gLQd<+i(kr~LUc#B"G×,OYv},3?]X' / >{P #KSOଡ'TEF5O FLL6m R)C5eɏ5MzqL9M^BsPUד4CkMgᴝToyUa6M``UUwdc,ȯ%uRݴ_nԥj9g)"߾i~/u]+ץb>(4@+Nڣ8wKHf;wD)ǃ C#b0_n{>:_s*#/K|?V,)1N v$gOG=l2*sR*wsps\<8e~D&jx۾dIFmm @ A5R)4AyGU鳔!"CTUu!%AvVuGMc)\RxAaB4lKZeI ]P<]PZD mlhRG4oTa`mC]뷚*'"(ڈhw]`Ay ksiSH)q"˜(!nu\yRuuk'gtc8)d4;=qxQec}=~p_n>䗼|Z;rxx{`/ '`ĽGRg􇆔t~9zNU?2 l6}T{  \SZoc.3~`HUG)9G.})ڨ*zB8n5%[/9ϱB2؝M9FW( 5GXsUlo2&p|2G ɤO5 gXc289>dm1n {{{(騵!bV#18!g*1}=GsLypeA0bf4HQT5 om٣NXg5g9gط#-~i/: ܻ(i{ߣk[( 6QGˎ ]{ mqݽҡ米{d a0sAHht]la*JZ1u3ڬkM$A ʺdZR6jo1o# 4 |DpeB!˖JJ2MT>q5Ёb8GYd8<630 $ ֬)b0ɧ1 봸ł"C*>z5B(FÐ Ð'_A/`0b:b4Ym>3m5f~2Gkݵs,i,loo̦SoצXp:c4 lS0N C0\ڈ^C4^5hϑCۮ~Ea2LDaԦڝ6Y,|F!Q1MH&5BN]#~A0iPkA ^( Z1tx2By~H!фpx0 I1dʝ]fRj tCcǦbPWc()ZV 4XGTA68Ib|$J8Z6d:F~ A$f8xAӚاk֛ ښ$ AaѧM(%ye{{;{MX[f4eلϴ㫯>BHWK #5 dLW5to91X/!mMQWktIiS=O [.:6$m2{IC)kH͚GYk0ď<& 8V%H=1BÈdB$Ւ,(]@ܚ %RI<'/*t)/LDY" B;S8IJ5U0*Kr_f)E>늺,I7+6% ]}?#5ru;Қt!pBbaY2=h{hD@I .s }&M2[Sk}yiVpkHtq|tLTuMhZҬ$6ܩR#pB uZ0?cZKXӐW Ӱ KQT80MfBWy) QatEQ,$]|Igci!3EpGWefs$eY"Y'R(B^.0e)*٪Z:Ӻ*x)cjyMyzuUpt*vưYYii Պ(k-֬ $UU>,(%߬WbKK\\TEɳ' B>e]51F?TyIZY/Nɲpו淿5'جSZ6a@USDm6VOa?c.Q9s՗Vl{ׯۿg?hܾ_XcmW,u?e3g(V9сR"1'g !PBhY{j,ް8MqU< 8URl[}(x3I޾FNp:ŹnzROӖik5靊'©jB`&SRb9=x z,USN!smx5cvQ5js2+Kt]lM_qM>+hOB{u/99=WѝmƧ)RJiZI>Xk.!^ pkݚ̟Odw-9RvۺjC>{o{|;w9|߯wXP{\|]оa_sk~!?O'YagX< AXc^ y8q|0L}yCy~n#vrM -M]vi ~ v,tB%N/-B"{gxF-Ԉ_vSXc.ʜ%F U4+9g|@W c:%\9~c^2=ovyEX!Wl!sFQ;~9#J)Li{UN{FO{|􄰝d7^; k.w&O^ !y&?QݻwɷOޓF<mxyY}h@ ^6miu﷼R%aTtH1LHgXWTCQP<6%YyyZA8T4MEbV%Q0lEL!2 " I%P8ʺ|LӠRb~VG+D* a{yq{:G ޞQlV̗k,T> Zs]!b<>Պ|KZEZCL&(%XTFy~+(xm0d\a# GYA@U;<89>f[fXYHFmt:0uζ8>95#+gKczbNkx/^P5ٌ8ZSUA\J߇hz a?8+e)f {ADI`0̈Ր/{BH1|Ha8`I3~㪜4P7ѐ7M+$sZ78v^t0uE9L;2F<3vb<' !;1iHC!H#޻%G/I7)xA{$Qu wc27$I~fݹ3YY]@ "hV#@O$]]Krr2HɌJ?@ HvٱΙN[kIxdEcRlE~8K=<#g"3גK?WC!l».B%1y'+bkQ )d+t 3u/89>D m͟"m_Y0¦BռhzUVm΄XGS$qV5 ]5|K=Ydxńk*l, jY|.*s"ڦٷ R|?ې1ڗ0JbhuLm=f$Rm5 k:td?~U﹭gc}ߊez-=miAavӘKߣYͭ~i a9Lm~uV{}[9 c4< w_K'*:x+gﯛ y%6̵?)ynZ=}`"9'n IDAT~B hMݠpH,Hz9==Lh=axA.TƴheY>PrQ7h//6si\_bSߛ<@pn (5ﶍ]ʳ6ئA@5nk,RZvn~ ;6!ooگ'WhWscƔuUQUWےЏݠU@KPJaZlo=/kvkkHRjMۀQF/}EYw #tUP\U˸c"BjZLc>Д"+p NIC_6:B}zd{5/_Ha,uU1o93fQ/~.e|:BŲ(T8h#~|,C  CeYJln`S"建~\egΔBoFx;xV[[r帱y34uNN99>H d{%IP朼oln5Qg#^/x.REHO0PVs|tBe%-uIYllnFZNOR1oW_S(ZmB*[;|o9)U bs='Kbt]JrFrS8=1l ]k r9zUωyr'a{eV3aw #( G){Cxdk1ke7+[ьlY<-ln)BƓFkS%B 2cX'yn7x-q׶w v~hC0D ь66J"OfTFw|6h VcE9>Jb1GztXNm}'KgMڊɭ_N =K=#gv|fZ'D*Aiq"kDIr<6X,iki(,ݚ C&28(q+~Rխv4&I"f)Mc zG}PU9Q=MY4qLDo4fk< vl)UX*ƣ '/SE2J)J uɛQ)pdAllp*V1=?Dm(4 XhcA/(2VyF-jxchtU\x3619Aos鍆llLhL q_kX柔 ލ><x':ӡCG;tY`9=Ӕpm=c a@-:K#|7aI2R NɳAi4UiΕ  .mʧG+OCϛ\_pmz{=aūs\coo6=[-WԦa8%z1Z\UIf̭ݕ뱱xcf6=z<4Ґ5y锪* M3gu&I B\/њ,4M5gi UQ8P6 tUKDz\Եyk4!mI>yj@, BJhp( uYZ.BZ(I^i8f>_2%Yq.G`?&FWZUԒ&q[,6'qP0?3?'Yjg]6l0?9LVYJUp|ejD)8^a&N'1-4\tYy],EbjAniLCEZcTjk88:')QdYFEQyFc k$+ TuI%%V@D&T%/_ɡCGKcbɒ/^P)ٕ"##-smŵc5Wʡ34s(_ͤ io(g՜?៱M}?F׼y"ϰ 8ɉ15y^b TeA<_P *C v~0>=ku:s>xڇ^O!|L?!]HAHd<kBb~AC'.IC$agqg)$f7w}9.2gG)R\F6X0yq !쭞ѪarerMFw5}q)g(Tmr{ߟDJUU7mv}1.+hsWeӿ6A{>g>>v=^wn')7l[c{v?Z{ޱgDr '$NSv|7)t {1Uw! F|WRgz{_ouw}2~Dr2zθ`]ahCұf}MJ^G)UT.񘦮(/)5#q$s=tU2_,6=6[Q5Պ4/n &bjMЧ*SP9'''Bjlm륨)$ucrؤ,3$T-OZәFA(%#OOɊ E0Utn BIK^Gf Mx>;;;)W ~VNAJ`4yN(a) [% OWIeYyai: *Ca 1| ű`|w{krgw2[,2$~orzDUC(>BHn?dսpujI%iS>k@ء,oA5|Ĵ69뱽6Cr|1l=y^C_o{8 {}dIY,5w<~JY'FB2 1u6Uq4[0!&Ð ao0d5 u( sijM' \~{d O/9Wmx!/ב@xrA󺸕ukUf 쳳x2\EL66yJJ7BSY-THHp_kʜτVi219寞rzt6(P#${+g ӧH))5RJǡ(M^}vCvhMk(<}歉 ƛ۸4$Ag+!R)XpQS۶kxT6篟%mtpkM朕r] ޚu[ EZh~+&#QLY,6 (MJ! {k >)m뺦i,硔67'AQfNgl~1 As]! <2 /3 8Q ]8'!~~sBh8|F1,pT6<˨Md>gC 񲜺.fG{$&=H+\\4jB/eA{|)Ҩ>AullcjCV!emɓ=Re‡JX,puϣgst嫉x v>-yY){wI|AZRKY֤y(qZtmXI*]K8zs NGAE+/ChY) B1c^fZ꺢( B ۪KYy JIZݮMC$I(]4ut\F~cg{%)j 4UњX\j5ynZKD2#8c{'D mV4>aM1(Ҝ,/R/5!2~ |#)G KgUֵF  $4 EZ(C\G{sfk rӬw<'KrUH* r֫PWDQ*8x h});K'YZ!TUf mjm!6oSءCv+2Jx6).)LV #OFu1ZYY\/4AKVTt&|?!I|\Gs(m0)p~mnY-io<K?^8.#IݐHR\ϧ+۴!W4I̧ eqUq k)hl#Vp2=jZ#hBM4#tE'ETyFAg%&פ) n.QaV Q1-ƼkyR(U SUyr]dūW-J&KV=m'4Zb!^ﱺ8O?-g|'H)T, ʲ"j$ސRW׊tP\@\DO#ё:BءÃˋiޛl,%Om5硗F7E]^iekX?Mjn&qנ iֺⲇ-׷uU1bd)Jh#Z.0ZcH!ϟGB,c1k} ص"m$p\iyy%Rs,R^l]_h9vJRgQI1L9;G$M8yلo2طhG;ta]=1</b/}~7A}A|W;aj^u}iHkχm1lcmI.#2d[gد-roa#^g{?{A1i~zRc$BHAc̵vIR*Z_\kzYcp֤;t«~SQ?_wy{|-PiWJA waɷ/g0%mDlH\DnZjFn,4\x!^jk[[y&,28I~0uIYVA@cP7aGԵռ:.FDŽ^:mZVYO/)4nYw&p8@ }#?h?OںƂc YV {QV} h8%y89EnAUA ]EJKUUT=ȏX#݀ɘ<֖&_̗seѳM19H~Wޕ'[7ӱ >Du{|nZKev\>Sϻ.BءC_& ڴzMv?O(@ا4 c%Rlm[~qJ9<}'o)ۑ!ф|%Ue%[`5` ?='yK|xۦ)V5XC?OVz>IϿyzy0d1_:o!+qs֞ A8o'lq_:`~7"iV" g3a~P1$g3B^0l;/~X_K89"VDiNca2=Mc#+{LFV>?◚FW jAzۅ.Vb5\;tkGG;tCi hfnZ#5;3_ nW۽lzQDť?2٘/_'ds Mޭ akh_cm z()k$~ ]HcA"KGO)*y>Mvdє Ss?G)Q6!񘲮lln1H?\֚ۤG9TG P#vvwf01/e;!d0Kxx8svX%OIN_р$Nlnl2 *X)YArRAo8fc{uA9EAG9`89m~ُr=ٺ/ {(ב:BءCgS,YVCpKH}u10Z?L}i-[,K8><ȪX&[}.*HZ0UJ ]ipfEM][׮*^p4ğov]UP1%F48[ẊTī%^CMkqomCkv۴{c%Aชx>A"CeH/y "67=a0Q.dgO{ʲB)؞ ?c<,ʈ%}|uqQd#:tC~~L,m۬ .@gB wﱻV_C,khﱋUURUhhS]n}Frdb {=b]/q6_B@c̻FmZ[V߂ݮonS8RBHX@Ik |kA)f]:K/ j'jyo)P6=[8J!ek#D AUWJ)X(5mm`E yF!Pl,hFߺ~UٱCQVx6ۭ2v3?)l :t#7y|gμ{S[s'=[vDf[r[ Vb*ʺ'~?~˿W'Nc7󿡘K1?ۜolQO>ś{?AD,+HGA8dgk^h_WXk) <}O2[%i$OH4/hSpl0\+iUFouY\ZWG?a23?=d:ƃq!0@Uђ㓷-{!{O]RG4M繭莮QJa^cgk OO1x֘)&upxx|?[rcRveo[wǦ>} Q}C?mlO>xׂTW?dɝ)"~oΌ@zyBkӆ `9xI9? !RcڦN">[5 ڠ2 zĦ!$4=hxvTxd16;k2h! 0MU&"5%VKm̙-48.7ޤ %uv?{N(.vZ,6z!E^?lQ/ O5ɐlo)H&шF|*].~3dgg"Ka)hՆ!ǧ6z_B<`{0Q qbk#[͹=wӴQp0uU}iQ1oppݭ1i(0G'T x^uopɆ`:=%>NH`ײ\͉~Q5mnW_F('<ۧ ~H%UE4ưey /_RVpēag~2@)((!޸j3Egx>:Bg;Y߿GxEZf)-ȳbI^UeƟ-տ/? _ŷ?DWi ?!R<5咞xKDʡY^CZa(kU(7`0Lrd р0u.7n,#{0gf h@o꭪r_rcxYUY2k~sF7~ c-OI$ cX&y f &52k*iG!P2{R} ur4,JE4EuKir]DiQ }iqx#9>.^$CZ2mw]&47h׷OG Ŏ}"~ !Y9hiϔnrW0ϸ{uh#m9[b F‘5?3g-s?'? wu]$엟!_@-ZqBn`ng"T4M!N8M+ &MbfZ9HPQyJ(I*[i*Y!DUOaϏ=op enswk^ޭN7:4gv~7cuv F*%^eɭ W_խdrrjkyueX=٘???Gz?ӟ=$0ؘ"O#z>2 =c3I*!ψYzkMΜ>Mgs WPR=15&˘8I:yDdtֽ1s$5ǢTu)aoL'!K+GG|AT)<.{E.bFX/߄Ttq,(Jthei974ekn^5]Ѩd20t\%I2jU\@,}aBQ2J!K"(Ʊ$EEUf 7N ME`pYLD[I~GCREUR/QΜj7Ʊ-vM1^QU':^K?LO`h*V 4 l ct$|6M1&&BVmWPv=4ULLMbkk&SSYfs+SQJ]M)J(۲L-\D^RGo$;C[#^%}3O0e 5˗vswv:?s:{׮? /??CJSiF炜 f&Zhaf0;3Kgc<ԘC&ǎ.=?סe mRX^\&uZYz}$ . CWLƴ&SUl"M|e(u@Phq69f(H{ 4CG &(d'*WG(a} p}K%rLqK 3hym# KAjLubA<{¼OORUJ&J2&E,_f;Oj}FFLMM!d&4 cPPEŗ^da9D4 j q*$iiq9'p{m~8NFW% KN, Y[8aٜ:w.ȕ29uXc8U !UiSy.ax.Nw+vdOx2rVty !}V܊NQ =Mxx͇3c7AÒ{t2 7GY]Ϝ<W.eUo噧`e5_}ʥ?v(izHOaWA5CG ) :2 8a̞8MdYn6PkHH4E~LFbG:CwaD#Gհt ,F3LlCchT{VǙBc:S8`!wPQU ôPu J'OqbvҘ\Q@fr㜽4,-1MuD(:a`82 i,ǣK("F6cj*Y!9yXP=AieneEũql4uNZ'u{HDRqa^C?8dGV*ZTnzAy -jAUKNY:! Evƍ9qD!RJT!"TݠZhZAy^)!Nҽ覉kDa@DJBC:~}d.L?+lPj:J, H$DA^" e2Q@mE1jj̱Zz}TU:*ZUqL. OS<%NRTE0ND.ɵv-sIÐ$I(8p{.&Ѕ0,r@$ }z=z!G硃:v{ldI@X՘dmu'XY^"Mffgi4ƙ=~Օe66֙fmu0 ZmoWn>)^"?4wlȇ />|YY^q*\|yg?O06kyAoo?<;w->Op;DZ ?os_5~Wݎ兹9~WSl |>k^ڱ˗r/wsOǹ_ߡnFF(X]^dCH n BQе9$ƶm}"{Bf=z, (=BYg.=O7<,c}mM͉,NC NhaW04AAs.\3REEiUa , Vz$A4, &ZkiE#}8/p{<2t%J%Q['':&Q",_!MR (s5tUlwK쑱̗ӈ,$)a>aL(U%꺆E1c#W^y$ 0`ei~ˤYo}47 }0q߾ܫ+0OdeiOwݷ>~l5?4'ӏ=Ɠ_"O?-@3-|f_yO~/A>OrKη{xDZeyiO|>O=yubKˋ|~`cm^&4l;3yEI ˝$ȚYsH _,KY[].FMNd׽=mq?)t `GCjiʦJ6\愥Wc%r$';0/Y-Nk~Z=<(BAr ^euzrd ']Hhʇn@ ' 4acmA^5uuZm\$QXH Jzl qC$H!(r)Cyw^OB{8mG> ss )eF %ͲZ:󋋅G:/crrڇX8ܫ<bQz|6: @x9>{x#T*Ωgyw//uxgy ŗ^N~=eY :ǿwȣoR:gΞ{o.|wpF8y4399wzqvs[7jn;w[5=W $)%vT!UİGl h~먪Pݟ)ؖo^ r+97PB) VD!PP#n|k˹^PqyI677v\^e[/GaYk+ҿ7ܧ|ռjF} ƴ-Lk:Yh$J.a395MH4IMp k+RDA߽dBJ&)ޠ ,j\eT)!!:`f8ȘNelAxq$jDq=F BӗmbqUp~S,Gf7t,J&"<>NLӢRqfW5ze]mLBQJ &Lt Ux6G5?(8i#[$1}̺*JMn$PTj:!SHU8$CtDU(jT5 M!YQ5p>ٶg ڒiZހP(ʖXUULFSWUjJTaa5oĠ8#0q86;*<28fIb&Ǐs>M?$]kmp0~ 9zG?y߹~WQӍbQc&qȄL*Ls啋h<}֚F^F&^(IȲT pTK#(4rYȗI^ܞT5?W晚!t\i9NdW}#"lPNt(rMmo3^mrpzƧq ŗ/ ɰǎ:re(EPks sWnٌ7#sPA$A.S*Bo+TL&1BUBa1ɹsM'iˮPYj󯻟!x饗huTyȢ>/t7(jmX$  |/($dByeUjU66V¸4cLƱqV.= "6^ՀP07;{<k|Z>{+K|Xv k~'Oz~2>W.ᨍz3΀]CG,+K>sZuSy ׿{y`6AO˳92=,oo(y#w,KKON>sgVtc b߼Ϩ=ͩQX$YJ}lgϡj:Ih GbFنc<#Eu|#"cq"zܵi d`/ferP W`C*jYBTS)ej:bc9menP;bUpln Ͳl Uk5TmšLLM159 ImC,MI6Uי%"ͤZ1K`a +kwu Ǧ&ٶ6B`j!Il#Sarz)[DIКi9-aSx1& ]erb$TLOR*P}P*c #kضFPk415=Is}]' \G)NƙӧhRoy.9S8 eY^f& FiTnΚQқi-o:GVnwl!uxH'd{pTЙ2_-E|;{vg(_w~7xt$IB&477xK_;ǘr8rcCy;` } ;G$Ib$a}}3_PN}:~j>}E7mM\]!>ol iQب]I8=IRAQ^xΩ$E4Ƕ1MrPd%^|uv}adY?c[X%0/>`PoYe;$Yw^X@UܞۿJ i!SԨթիXA%\fYz]a&z]4RbCEiǩ( a125(D 6MlB9Q1LBtTM [Q<̃,JAj^ UU!Ib(R"DaZ9F^E%]alA@SU8!C4ݤh`&aXFCN>B~6у`a:4#uSg~o~W?~#>';|7_ =on"oeue/~|~HC姟?m{#onooK/y#汏|m_,-/|~VE"5*DZ JE&ግcE1 NOԏQ4p}4Jn` O/AMB}\g4di=Ev1DFf:ߧO49PցWnY/u(+(D÷YmLB@9Kc671I>nBg4 @QɈӴ>`"μ3Inn.|Ƽ` J6sY_^ohy. ]e 7ae[nյ5S&I3lJ%^2d dyq AYݺ$Y]@ 0<MQ2za* M"VWPvSa X#t<*Y*Vfd#›a̞8"31L̘;{7;}#2w?|{ ܯ;G]~ )]^O<($>0o~[:w^z)3yͼ篾q~C?w̧>SO$^G(iFDk Q4\fInh4(I9n|at0ssWPA$;z~}ܰEB.l_d<# G+x>ld#h۱QAGq:jC4EQxGiZ[c|ȏŘPrܒ>%yE)ev!70 6 )* !@7 ⃅* `qi]7PUeU-3M2.r!e3{8 $TrD $M1Lud녮i8!9T4d.q enp}?6uqYG0%؊VucOШ:l< i;:yKWYZZs1mcǎSڄaaYD~EDR9~ aa&nlSNcssΞA&>ss qLO`갼B2 ,ű-gpTIӤPOrs$n )fP5ͲI>~@QC-Ν-O .}I3#4ld }݊CkNl{WTv+k{={}w~XϮEFU@Cao~ʶe I(* ԆW BA׊[((7G($e$k*"Jiݫ'v0 M D-.$I춑ʨ4GA HIаQ $j4q`h(i*j: (,ILM+gnޫi@AbiRUPU|sT",VsdRb6,Bc?B3Qtm݊f۵)O#w`p9w>G|O\)ny|}sQ!C8;St6X@!, ,WGo(BH쁬ǐ'M|sA >L)^z> rPkslz^k,DQzBűtq3͋7𶁥4i57>S*EcB=$$LqӜ>>1U6oHY>Iꪨ$.R 4w; awRuӘ^CDQ\m@0DH.%Wסߧ.aJP U$)P)G6"+ŷ{utd#{5tnF3#m)U/^"L4'5(!۶ vs8u4ame8 X(4]H3X$$e$q& Izu`DB%Av òȒ?lTJnaFB PC&!):*MI$ELk{,]BU\߃\}ˆ֦EhL#RpOىԏmo[=#SQGqHr4Mm' mL┸l,4I "O>S!Mb0#S4 CUU1u( Hc9(0Q&e. N/jqk:wɫsU(pֺRDpݎz?ehۍ=|}oLtNđld#@xfI45!~~;A[}Ν;K{crH L;Fg}oxC-&T%/_\/^x4^k&>6TJe|HY\X$ã;qr5gPR(E]f0(ISpӬQH}Eܳj1&Lji YB`b| ߥnߒP㌏!CUhnnb- ߚ0zs0- J;'L8AvOcbznw&Z6^i:ؖIEAln6IĶ&&&PAIi6Ccg]2WWÐubff{ŗ/h aT*Y.P804 :pI 'J*ӧ -Q2K &gx3קiOl-0!#\g+UMOLtU! $Mc:Ude6Z;63,Sg33Y /ir&s":vu 5[K @ IDATvcY^k bq, W] Y^yt`Yֹ*qq(S˿Ayc̍4 ] ?4jNFQc-\JܾKۅ4&3*_3gphR)Q* "i:aELӶVtM%ҭzO`((TľÙa lǡ>`tIJMUEUTKǴ Dac:e cYPEtllBcLD %v/]b&qadPqffghm=y2f15>]1cqG6m»6ͰZ)`uu G#B\02`yueExa4Maƭ|Y.ßSWϟRZ-Ixx$Q{H%'cd>;!Q!.$bmmNejf^װiBhL $J +Up->Qeǘi:  S88 mpö;L;-{Ş׿auY'Svk8N^^;k|/pi&G \{_| ,˦ZrgY]or)\fj<"ݞ?j!wҶ[uJ7 T)B>E #'; jN$veB; ى8f}eAxe".=T"D#^eD>Ij" l8q}۲Bm:+KxM67Z;3)Sڭ&Ir|<2IYY\n2Iaix.KS 2q]`0\fxW*!NHIɕKI%}"M sY[_% < tM`&c&f ΰL@}S8=VGQVyף]ie~^=a9/,/sGa2VZlٶSEċ(4/HjBd.%vAUUEU,^48{6(8XA~p QEQ8y.I!SAT$E4dy^(PnMI"s9ER ~LUVLV$sU Ft]#bTDSnOr@(,d$ɨO>7Dn7XWkw ʿWF7)Vb0e_g7>UNpfyJ -:V)]:B^bn.;1 %u(]jmTju,CBUיd1F,sW@9yciSQq E+4r8Feoi%'8{4Yh N |LDW&;H*z156#Ʋ,s/|2U]mؖ=Cz@MaDh#.,AW!-$ZHpn1j͐fwUU]>}xNkE QYN!Q9sRJE9>=U^jZ&Qb4MuTUg$T+&NbU4-U8IRI`%*s2^ː-B9Hb&痖z:,߾KC_ }o&o:yKwoSDADADHUS1M 2R0qpQ2[PE Ir_WQX: x{{H$&Nb8>1E1Q%ɑu !0Fi C)d*#LJt:}FFPl09Cּe(\; dIӔ$~4 zzVEgGpjވXfEQEE]QT,D0 b5L?iqLE2&Iz'1aG1i> 4UDG j:WTq]Tc2 T%DabYuVB"*u]DJaX%iv]bfE׉X?J)Y @852FpXO_iY3_nI'ȿ7'[[ܸq}QTsx<Ϡ< |d[dOdS{ԧU | 4MPF}; Z?gre3;R>Y eA1̅x`Q2vB>^-.$, vQӈAA-aH{,p4F78(13D%*"4q!cE RQi=.{[Dݽށ4M }p@kfscK c "lon8CC7 w&gXohxa =sҎI=NE`t!^'OH(nH $N(5ƶMaR5 >) Q$7dO"$R!0L%NGܿ&R*7I2^!qTTU%ȏT,簂BU9SI=L[\qs&_Aꟷ{.ABE jnפ!c&Ig&#.E=NOp^@XC2Ϙeb kagp H$1.x@<3c:ۛz($8ipO0ďB$!MS!qT3&.#\[E1mg dE%M#(FQ58zav|=MSǮCپyAf:MSƣ!;~b4! 3!}̈`8P8 s7< 2kt'4-`@S0 y.~ﳭ hJAB1RJ BEq"TE ) Y˲}4MQU@B:'cEɀResDe=pmz0x{Z,g$?ˣ$|? @8z|xQmf$x ii"R*(U"i)]\uZ;ş;?̈}o_Zw.Uga)( =Eيq좁D[N?t2y8M!N^蘏( Nz;Δ8)1I~O_ϟZ MS|ߟZ{F`& 7=IL۳5kSY{2ALSa&kS}C(̒ pR)%]uÐZF,DP^( q)R08N9,&ҊkgAsTG!VU^? O}Q@k:0ivTL;>D# Uf:IsB*\½^@gFA+WOuOX_ˈ[6'B=~(iʃҜ L&BԪ|嚕w!Y<_Ap?%7 Feގ}kXU#.ҩ*Dat1EE5(zvh2%"ĥQhҟBl@44U!c΢/I4Pɨ; <`&qת,̲-8"bTU~a+d*Xzp'YN:Z7ǃ39w³]8R9v5l {PdN1IM%MgZ/ уh8dwgo|Dyo|/͍rrݹ~N|.wɸpnqa@#]W !$QJ7o xx ?&_$Ns.U26Ke:dq}NNlc 9 Vˏ;QYf{+K>O6iQˋ 67!JAbyq8 QuC<~noXO2biv)IRU.\TUcUuuRXST+U:vgX? •kװ4CòX^^^i8#13?@^ |T]g{fkׯS5=O|fVܺu$tx1I*F.1 $ e?AG4Z Z`0D ̴I#4|˪RV |6680#ᘥE]IaYk˲}YQ(r&ӂ@y?MIR Mivc'1|ES)xD\1D2;^ @~'|܃瓏?ceZ}4͗R[Yl絁7ZmVD`*qbJ{& coDg7%3tY2k؏'$!TȒ9H\"tNyEa}>/T]=7FU{]|䆪zVhNqe$ U6gQհ4Wje("*+NTU Uw\?xn*ʹXZ•&.STz\k;SaUs wD T-VV| `ۡK7t5n|vMi! )4[ܸy3u Ts-qm|?Dt߸ՕEֱJ ]#2,L%?poTV!ӪQaB " \vvw-LMUkX$SƎ4JYrc6Pm(Ze^vϲZh4B׳$ N{gi4YӪbIg S7&)O r&OYɤLq{Ŕv/~+O=䯾$QoL]É x"!Tɵ7q{HE1elPUJ(BEyUŶG(FV S%d'D!D閙\OA%剢(F.˝;wðl_O}SeC4MckkhBAUU ØgB:'òIIg4g*FN,Ӯ;_D/g?EQk5 UՉrvB2Sb4MY_{?5n`04[_A,-mgwG2nկ}f5;M/ P#hEj0`VM3ijg`OP/sp\2>Ɉu2(?w-^Mt_컺^3 Cl{L7aDףnh 3g͜ZaGQHi8ɗ 2Y:U]%b4]umO=RO N8ˬI:LӤZr5oOWz:3@ᅊc?w8K-2:j{G$;B[PlAM7_}_ļ*^'>eO".4{뤓#yN#q쭷>8P*ay}Fl̳4d} QTp1v4+\5MK%iOܟu0>Y*Z0 GOe;s9|^l3%R՞^pn:TJAE09űf#R^o`*l_jNb{L1ѨQ뺥5T LC#TU#BlGQ,N*X}ItN#RJx<& ZJ&c;044I< Ddyi {У.," }0sK,Su-M<4!2ˈ$U$4oߦh44/b欼XK 0 z*[w]rp0R IȈ!TSxv%YRE~,.}`xM2^* _YhDOiqӴnn1=>tY}gd%N;q&1oܐRDQT8 x Hy\/qaܾ}0ܵ2+Uyt:?C>CqkvBAӴ:Pt%Wg)+@)> z|8N y12v'矗0-T%GaD%8%%J8K/3bM (* jҌYMG)]בC3 #8{̰G!pAc|dPU+us/Gӗ7oSt0ulwwr2(FGDqJ`8r:hݒ+ZoR$ڤhuHr5SeccpR.@zӋE Ea7ۗ` u:942g=hy Y,b'.̵Cg{n?)%FV3Mwݴk#&P4%Mhk9I㸄Y2De0 ]Ŷm |nPQT6S2 d5b43b:sss誤ǸiN3hNt:{DIaZM8C,ĵG G7¬|fE40dmme4M+XYK򵮠GV|K_? U8)rc?Ǐ.Ϋ׮ƛ_9r>ayUADDQi8KFHEjzt!E(`0z-6"K@بhW,_\J;CJn1W3<<܋^a0N[",+8.>99h r0x%rq }uȁIiNZ5E^}oDZm\,Uc5n^]ao{ ۶sYz\T5 jmSQ354AS%Q Jy8"E Af(UT-GI[8M+onGxK7h:U GcJW^K>Mcn[,5p\]7{P52 t 8 P,22VfJp]f!JY*IiZ#H= !_TgO NJBT-ڍ6z2s4aT VWxR[TZHjih*ZeU(ҠT%#tEhdL2 ?`1ΏFe&-g,5ا8gHia*1<)U5 4M*ahG§AP6nqwHAI1̵V-k5,,;.^UHMUrRUZެSUP0wAJHU*aPרPUqVRQo4L UQ!tLA,fvl (]NUU=eݬ9g!PUܤR$3K|%c 0UZru>h'̷O 7 9P$i?7E7c@6[O>%%2!rd4!i, ]G5 CFǤixP7,tMEôpØ Iu헗0NF: 1%ɀ0 .7La&@\~>G:q}Df r\F;0I^Huq]P,%fQQ<.aƌ]S@G}Fcy!30 C]\l b|aHߧըSuLQ629uEFmj8iP$V#a:aNIEa>2+2o4M4-ee#%Hl4Ϸ;?w~_#S8A̺8 #|n|,.< adjm Ca0b1N FCۥfأ|!ΰo59͖th4adgnkC:J; _NMkB zD 1:G/|/:0V?-,|JS9؛Z{Ngm(s~>;ۛ$daƱIw]=:;[vN0E <3n/p똺p:xA;~ .~"ެʥ9X#Vi!Y,dDMqXCEQX;aPT$E N#8=JX}!QU?dמ\hq˪pWi4Ƕ4wGg=|UʼnISrI/h\qI ~()e䢞"n0}YY:a Ahqt9ni^vw\X=$.ڞo@slD.{G8bx.Hp磎%%%u$P4I>ϛ?kp-@$X,$^7)46IYųE!"\-";%d.E];$S=&ӂ#R,] J@H+,ڙ>4ҥrz}-VZut;e#}JY8FUUe2]$59MvlnP3Q (/tOPz_ ܧo״À*W^] AF?%3WfPzqH )a3s)q># *,RU\ƵZα*ż4O2\)hV?,AdjÜ~Kuòp0wǟ\f6쳕 zlon^/wիg_E^s/mUz~1Qie얐 X6xS%s]89+~Pj;>4%Dc)CybM܂,Uu8 uMS(w\O yCHE>dM׳B?85SHsuL7 )(I9#r Op> XC oIK (Fzn9(,bJ.yaڐJY8N2SUsi0FQLhMrX1QĄuA9T$!PrP&Khc֦8cGI$q'E[ "siǙ0Y CӬĄoR%%"!A*dJRhG@*U3&,'MifΓk #y&06kOH*|0HvLOl Nis8AfIFDU DDɀ4H1KthYhz@"-~6S|?̟]Xwy!4RqR|0$.VvsZ(i Yܬ=iqO 9X|>8̞Iy]2'ojg,Ácg[ߩR>.CHqwn`6m|"p9깱+10A7UUKKs180 kd)Bq=8,jҥwMQ,QQ̣+$s [mV UỸFQ-o%G1~ $Ij|ViI!EAh(e @A ų$0r CL܏q- m}VWW JR''%͟S;Թ3@x\vw/n4-n*Zmu Uy=@#lPp}-N &`5xAHƎWƘʳ~p2Ǿf-cбZʾ8T9)R <R IBP2g-Q!Hkx=-D$!Pii5FWZ] &ףc4vX+xCF88"UC﹁{hi@;,dBG33i/fxCoo_W~b3tP sE $j( Sp?&pҽ}zGZ޽{Qivkk]>S߿ϓ'O2hmE$_2ZH">C|v]޽ݻwiY3 q&Ibf P24ƍ8q[qmܽZiy!Als1_׸q(udBw>[:S~ݸl) 3OsA>r84,Ӏ$8jg1 IDAT7'B%"*1h+fc-C]&}G#t]Ǐp]+W ,f.s R?.wɁǏяw7+Wxx ۶eBTXoܸVZ7w%/k|dcc5"L#=Y+4My뭷JœHa]%0̂jf 'i m<pp80m* K/ϊpk1kY<|H&P(74"y#\ &_:/o9sȬyIC O*~, q!tmB.0 X={vY.[DM4]/8''= thKw^oҪVKdv<qdȓ`a?LCtS~12 _"4~E?[|K]yK;Xv&H)K7 |M* ޺"ce@2։IP,gy4x)T,')eI,Y +YB,ROdkTŒ3-3.w)}AL/EK˫B8 S +nlP55f5V!ųMPZf!)U~^bnvjFCLVl4Hʶz!c-FQF\+Y&29i&"I'(`h{wL>^/d"QC74Ȃ>Py{3/b*n Fӧ^+/\{ۏ30u,n8; ᝂPTa 34ñφ^U5.]^&C>b/MS$Y5 3D %2Ly8/ irQ.KU4" dyJ (J m îlwm{@(%먪`H0LIPUQNEz}zݠwU-j:Vj5fTYe~!qD$cJtYQuM0-zY@ P$dI!TMASUAQBS^|\2ԡsޝ(b]ZF蚆#~`*6$a9Fn~! nܸIJ̝IP][k+Dn~$k("䂌UT2- =704$G!M LDHc$ {H Q$ͥh :M$`ei&vªeY[t607]Z> 9~ "k+H],JcUefjZҘ++K%a7Dsq]Y(UmM$a|>]!NSrv,.ñ{lu{mtH}DѢL<4IDI8P2( wpV=LLLrʵ 4 IxBEK+KKku\']\G C LyT!\*a$$t<z*dhm=B)W0*%&Oq"4e;|C)a:.$ŵ]\! Q #+#NftlejJ!15r@s$" YvE$TdDDrylSC< ^j(r|@g$a~')B:6=<CveFNO#H:oww zp׸Y_Y%iJU$i6?8 |wZM:m^ ]QqmsvW34fq}v. NmF B246 aȉÐfAxsl,~$M8 K@"Hc# %hQXgPFvq:^ȅM-{]Ij/S ̪] ZI^WH#o>E8ӉF4=qF#8}<l[h[=<,eg12:C}y\WV=}˺"HȳlPyEw9v^G M"v`]<ld#99I 6HIKlKmC$'~gEqFQn>hq\NH^R#~ų y:Al>,Fi6ӉeyOyc@f۟=ĹO y9EcEi7 /+K:.qYUJR׉NA4&eTY*$!'IJ%N@4]ó] $'j ( GT 9E.QI5ygu,(q!WÀ8MөX&Q`aATX䂄,^h'|% Q̢EN# *L ҢI/ê`:aމx%IƲ,$I(rAQ1MU0X EȊHJ5w!r!$I  fYvUc~UĢc-;mO&%BN^<DHh6 \.(̕@w!D&xe<[wp)+]ՅY[ܹHŧh3z]$R%޹FU-U^!)iI j X_[w{cPE'ʪ¥+L-W#'R0*Ͻ&qm]LʕkWyEp] Xu}8/r!s+F,+#/S<{nQC!DQܷν}zp@Y=yXܤ$IU=EҌ{cS#G VN>,o _& Y3s\{RM[_&ڠUTDEv٫ fEdpD|8%OmꇐG6Z)? )`۞ÃD+lJQ+]--1=IO@*V]byy0>9$yag$YML c5Vck+1.͓Fai!K2:(jl@OJJH ƨE{YU Ԑ%i^~4[[qY311~"+*}48C7 ̊I]XQvhD,B$HJ?Wxt}>c)$f[g!K /h$yQx qHi# q?*4EY&gT:mIzHl8A IgM~hG2yf B9t ԣV%DQDK/)gaTTٹ=Oi:g?8|ZAEjA}®m{&`?ߵ ҀkF$<'Ip{A(Zl֥H&c @=(t~T!!2Z&n9X~Dʼ+?\4!I28{ RDGdZC(B5"/9G@rE/q06k%&:'Nb' Ç-q>aZaɳo, "TSU?רk%턈$AHf$*M!>MPDCF$-`t;]jiX2b8Vwga !K"a!~$QTj $qL;֮݊5~_u/^ߣi|WZNx}41Bc^dzvO|h'Yx*~+Fq8N'𕯑}~ !]}s}\˰5^z5?ڞK\'| a}:"[^775v@EDOVɁ_*|/:?ޟ ϽLa½ivw]hF:#3hm095RAB* V #)'>Qg^/^RX,޻˃寬]?wmܼEQEq45itsin/}qgi8__ɃYܡfY6?cc;w660T^ODQH{oS鋄GZa|#FQH LMmh̶jU>}/W7h76[dIA2@ 0SM8Y"n+:TbvZF$[ U5jSsTu;x|W^y%X| Vx~a~J9&+Ɋ$Z(Vs9CVVW {MMM$gyI8zgyW;PynըX/ $&,z=<:@hضDIm;ln٫ iHu|ae\W7de+w~W<5NƽJQVt1Xڤl4h{|泟gz8<%PdYy8+MJR}j$Id#C0C6,S~bp'q]8 OxRp?@*a&^4͑$QRH0CҨ-{ ^3؎{% ;vۭaNA*"Y?qaL.EΞ3G7LV8C4E 3҄N$ɩIG%M6V鶶HFB"GӳBA5E6E$.)*R$EV5Ȓs͑Hb+xv(:5zǑsxp #B<&JY(Jg%%D$HL;g{ _۴{7I=8ɳFkWѬ1^~v#^yETED:fueSӴ;6FAv%鑅N~GQ!/sc/| ~O믲|+x`BA.A7q$;#Flv!~reed<(Uaw;Nѽ@l1/p EvB]7 >}7`anݧ66$,.-ܕUESM/Z؛FQd6V-8]V5H8u\6[<5|6{wZ4 GG.` |Qݏv lҩ+xsDzfi80 C0$sTUEӴgp;=QpgT9=nŧ8.;hgdi_~T+hH ` wo^gg>:ŸPX I(Zd;|zb ,FYsbr$Y"]"ɲDCGWtDgθ"فwE;v(qԇuWx;JS\BQa)Ϫג%kgIOb+I:6~< 7޶ b8̐ Ba1Bie:}/Gq>,`/]ݏ"W&^X/skSR uJ';Z),7>KܼyϽEytE=82odӄYv!ݰxXSv%*kkB@4[HiYYLg'?w_f}[Zerf~Uܽ"˨JD\qkRB)@  ABD&&Yb~vvE0"tcRW_iϽ2,LwzḺg]cueAHs1,˯|6}lUO) 1ob/hw㣏y~GGEy( F]jV<9*.i*o.xa×{eض:z!IHcEQtu < |Zv*PyjG;).rO4~ QYyQ WPE{4[,hI}b$IZ`aZuqdIwt;! u./,`ha*QcZLM&}IFΥ+W}4Mڤi XJ7Ccs<yMd]Yl.?n;Χf?B{|گ'xz&~hdK^&S &k.z6l<hϡ$U,.J& j(Vsˍ$9_AMyo.|s6Yz8qar%K[4M7\GVAnK/̥g0Uac.Ô22R@`nn#c}c,i7q^fQXnZisX,D"]'#f/c+UZ9xyH眸|GGln6lv?k7TRu_'?yٹ؝M'oz2kwɲ$$>}{mJ& zM0>1Av,W )( +PGv"iY=}AUQT07J#vQ] 1Ӕ IRQVH4 e UU ױ$}qp\j # 4!#:6I`U*eX2 }?0ƘG2 afj{޸#j=*}wG۴ :8q\|q'B| y"Ӡmǡ)%;T wv0j" P3>>ȊLE,hA&E'2YA&CDgӱLsdId}evIs Ա PUzش-IR%%&(! 9H[[MlERtH'\TE% =lEeDI]9sw5YJEdIZ'@3ϧߵIu * TQUr<7D |'$*d)A'nk8a^ֶ[Ꮾ gYEog4&Kܝkޡ9?yh4#Q9z/0U$ =?'+h+IW]!w U3T1#ǜ&b:|/ q5IW̓FpAXJף^r* US#INN7n&M"Įk۴]Q'?b0[|MAMbDG-اk;x^G (-"?BOtk|v0q 4$KsArVWfz&xFsho9?yG؎KIm$q}㲂eYH|rEQ05$yr ~[LR!M"(0=`njAX]]u]]6̎5>ȫvqoa!YFUTi?g ƌFaMq؆I.+dV  =PTv% H#@q}i.ay1Y^x\ 됥)Y^,`Da9^9ݾ a1x/P9y 0/s@?@^i^;q]|`Ԓυ=G]cp}K gPQ x ou]Rih(*I4$K=u\~~\J9gYHu:G7sxx0`ksoE'_ns^{~ b[iJbxsmQEۍ}ȳ RqRl{?0` "t?[e!Kvۇ_L^y]:QDŘUcݤ;IѨ}_ZߧV;'2_( U^KRoAxie֝2o8W'hKZe _$^PGwFO(ӓ4[C,G:S/)"?GTEnwhd᝟DkkZ85SF6lj&#ȲDӵ}0D"!67Xᩩy^amUyt $Lu㐚1ųiSŝ[w „VV{;X. LLL'1qcGê'rzIUUTxjjizQB2ƕi2YjضD?d/[Qz:#h4sRFoT,2LFL=ua'?OdϱBR4SS˥?wkϿ[/27aho3schi7x0>1"tZtBWE&qj:UF%Ya|ln?ӟ$V6&3i60:Uuq$q'oڱ-$N]5X5y#|}@{$N:IZ3;ɒ(Bŵ-߻_P3UN"OkL^4Kp6a>= 'Z_a%gX^M,)bXZ$L֧p.+=^@(kTCBNPF ^z%Wpgm! ):aiJomDH}kN YHsːU{AAF΁gSD&E޽ih5(Ks4Mu̫`iQ9WdV+-/&vg|h;7%_y}ژU||hXaOQMTqs0Q$ ƍAnn}K GQ8  IDAT4<'S'ثhp̲Tl|,y3>>7 lFU,^r!+ DݦZCJUUA5`$OJ^z\oi>e!xyAppCpR c @יPfF+,CU5.]HH$IdynZ\{yꦎǻo@@S3dضC& q9."jl 4/ aѦZcb2V#eE/EK\kIYU<Cp.e q`Qc&n`h Vn yD8Nf?Ц,\DUXQ4/]f<'Lu0c< TT!ϠAD7Lj5 Q!;-bAZ^h5x݆ýz}:J44~'$ * ^ց|׶-LIEr >h|'F;fE!eu F!V" }D$O|,9a!!* qy@Y􃱌kr{.[xaHӥfSαx;=]0$fB͌HC%ݹw!!U]ck}!Oypv Iܼ}0Ό΍lmlA붹̋,-/in ճ >ۛ,({\o+]ij˲0 usRԄ)£P-WDfcd ˺Z?8W<yQUJŢb(D$OE(dqae,'r($r Ii < C%ϋwahꨒHԪu4MA$* J,-<(ݾ(It2y.RHH>Y<&#dUǬd{6WqfGgeIFtttdI8}j'hwmU2ESt ]0-3 uSӌO"@)%iOK{q*:~I hl0**nCNO)( + vpXR仍oe}d~rui?/8$͍=WE3}qjlŻ7w>rnݺc ?Ηҟ1Õ|>]PRTgTSׯ_7(aJQ)vtV 錄4W:iUv*E蚎j\t*NlBE6W$OVB:=UQ ݪ"!2}$"tEniɩ2=5[aHyLNQU+<$&|\Gu 3K>^f訚r|@gaDȩD%I̘E>i$KȦU!yi8j~BQi۱{Ȋ nE">nZ1tq@ 6Qb^IXG||D A }RI@>|NTv )+tVb~BT5Q(^7vlǰ~ASZض,BHd$"H,+g%e+NIY%Z%8Y=*$cO`ll<ȡZ"T*֎yd~r[?}PDV{ }<8OѸ 0dvUUY__ݻ$$@m[,iਨ:>j)AE%]f-ʈR t\/6BIEt*YY$Y2vU)QX&b^HI`)GbB#cz.= J$ YFfIYD0&$qH(HgY%3d]G C[IDQ0?7ij"+E-XfufVQ೾h4;ױq\?ѵ]wd~GV**ޛI}?=3+h>XHBCh QDP&MFӁ&Ln Af8d((nC83 g`3=ݵUg{:xDRVtU73˪ϟoÐNAAߏ-( Q4A40D{ frBˋy(}P-F^YX߫ff?t[x?};X8{~]6Un\fu & +D:>˶A$C\£8I3Fu]nMZeA(v9P>Ggآj*o X_)J7n1gw R\zDI_9f- }VWVF'YݬC6(J&H!t:t;QVUâߣݲ|L-&(*"DFQ\WvH<%ILIljU:xkk("GF"~ot I"Fꠠ@el\rޤj:_%xlDjg.Qm0;S%ct;mo}?.+Q7^_#k/ ~ V*(cen(~u`rf +Ly9?gBvϣə*fΛo{>T*=룚Z,c*[أI4r77V4 \2FH5zf @H] ÈffKD9덓,K&fnWfYש՚T 4FH&gE4kUgOQou81]E$a\Wt,Q` vVdxO=Jѽ l5bEǹ|~z g˔+ZG/eϗ⨁mR>.X~beZGQHLGNa3bx}NƐZR;U|<ċLBWXYbl| *;w^rIvF!#bd#dRo %8~5` iT$c蘦A$sMPe L->u(Urرu:u7닜.CJA]NvmX@VWpzf~Τ(A/Lc6_ёhMSXa2Rٌ\`56nGx"q'_Wm W=6n4YZ3;;IrL{u?fn=ǜ )%O>8ob#3ܹso'ݴö}iQ1׿~$̽F<߇iQޭsE^M{.Q#G٨5p=);?0 )f tj eb,BS!Bt ~( n#e,]n}TM#_(LhзU KUQd͏=& e? Z4E#1ꀊB"j?sr+V^o-!VDh6kn0v3\Gc5y&kȐo`4|H~EHZ(:DٝHO~q٭1SxMͥav)/}K{\Y8}CjFZhTs8/e'gr@ng[z0L9 $^oFI|v ~}:xR}A<0x ub߰|W͛7򗿌m#t`?)aq@Qr=ɱ@?t8K/@̬EIHu gIK6bwTv"l'e-8e!P)q=6a̞˥4 q#V}|̩I6Vx'hlVA3Y_`T$IB:&woq( c 9;;I$$HWͩqyFMױ-((U&x%X1I,036I"1u$|;dy$hJ*&yge}sDoY(dLV8es^:r]j|g0^evܹw+g,ځ!ib{"af l[ ? Ѽ}/o˿z<c"I''d#vIs`?sI/$IK qims^uvϭ?~c简1r{iIAۃOVzC0HCTUˣ)O! H3if|DpC >xs 4@q(?)dLOMck!Tq=3VPq{tM;ЙΐfPUD0-.BJUBƩ6Q( IP.311M.kSo4-R%mY35sR1O.grȖPTA4(xPUtEIP,2{4nNs-[a+&&U6ju09(r4[** V&CeLRiVJ$VHTa|B>L<( -]Ӊr.O v.؉}F}vcy* ~ȟq8":C`:S(0SxXI^{Y p{s?wc;Oz6墇IN`[1"-UKؒ8~,+Cƶu ȧi%X__LK$fg֎& CGQTlt:b(X[]nGLKyr s{8&gA G8I2Y.| f0drY$UQҒ2`V:t2&bL$E˶QuUSgR2* B's5 CyۢP,ǢٗB$NB"D~_!)8l(մ\ysb'vb'v|_de/ fNͳrtN@aGI>Lzoʞ٭a^%*Cx̣7۝=>SG,AhE*!L($HA=Ĵ53QH V6JBYŬU;Ԛ,^f8}3nqѬUI]ƥKFw>iQAf*'׼ڝ0n(m [VɐLf;|R:ap4Ge>KMmcha!nDԩR$":N"Vo>>AA5)%V.ހƲmtU!cTMG]zmn^)@<@w1Ia)2t; }]BJɱ]jQJ]SS"{nv.KB( Bw7sUӑ2!t]O[!$Q4"_9; ^Ng;/ ?sG+WPp]ff>q qrC}6laGXYYn6ݤ-OTZG)Q~=mLR(1!؛p s(080v)1N7WqsQ$3p]F#ռKу-[O J~B }5Հ8A;; e?ȁPy<{aylg^:2 Rv>1ieU{a9vDיY3XG ;{3|"E&3Y`EZC9؇H هvM(@UQA!PU-;*q ^Sh_`~BAH;0 ]'I[ҏw qtlBʄ8Nд-R&MSq]pMgoHvdgW05u2M4,$XY;EQ1MUU ahH^Ѹii$0}bgs2T g$t:AQ*ôp{%yJm'5ӲetQddGOvT T֣loXޫ:J0v;G9_Vo $Kdl Fŋg{W|b//@l6™\Ѿ!NKe6'7Q:(<Ҭia8BRb6w+_ eaH>a?MqJ3~ޫ0`l(tRӝBh#k!L.i/a%`|l1No~i%r*iw{E4hwL,)XYz@Sdme:N]7cR SװMMS=յ5:sTݲ;Eζ0p}d|"xd3@',ci IDATt@ A6'k[4u 095@1a}ez=ru`znJ!Gcszx;eaaX^^v0 (=Ӳ ]VVðd3^0-Oֻ^BV:^1;#Ѳ* 90dvfG(j㹌,}*^/_v966O &g0_XmqZUD%/r=p4KKmlrq{qϓKgR6#.#Q,0lXzxs^O?cK_eƊ:]-7/x>.\hӼ_߼Oݗ6x _<?䫿ܹuX7ܩq.S 36Kح[$?O#~wz~k/wH7^{}{OͰYe i߹K>k(6_ko+>ڟ۝!~1ܮs* P*7w(JEJ5B)7QIC2mU4nraHmE={F8$I*!D bu$(꧛0 y6ai6LOOy1A2B8 e&Apvk}UmdT̴, "FI([D4e"FARUDR Hc8EAu(:ݮE= ŘS;nk=R6;>|> %'@='UfsrqD}C렪:BqtUX*ھP* F&CUqsjzaz|R1GNYsTz,q|W~G|_^gfn_Y]/huwަo}.ᇷ?זH^&/=ڭ&NCiX5RvR>)<,p\'uEQxjӳ̝qs$ vk_@&~>g&0>(" CE6vM;y qn~P!t<~k_q^y~qizO[;Cellv=_0qo5 -!%0p> PO@U8-i 0NhH=Բ8A&E L#qZ$" o8N#40fcʩS N?!ju뺾nl/"0BfؐIT8-VGNn_MPDT F34L |BBFD7 ^bDS5%-@IL蚁N!IuDAtdIC<r BQT^I'GQgd*"b%Ef1E.4ʀ@' (KEL&X~R*P$I$сϑ2#Ltt6x,pΟv#fg287kU{rgyR͜'<.}_כhk`3NJGpж3,9ˍkW  v ۶iO稈ǜee177Dž zcH)7I|{#ϳLıǩ ;%NRu1 (wnW~W(Jz=d2<#">|a1f+|ROiĩA cTUGSM*L Ʋ$ 1qT  2V2͆ <ߧR7{a-.'qY "a=8b;^RLOnP IV.aFC1L~7M|=J`YB|"t?$]FTΝ;KۥT*^LE,..( Q*<{q%^es$=I_QOT|FRbG cXF|[+ZS7ðly=dWDHXsۭqJ$vfwVKdp;7]>CuF 'ʼnc}bpvb@05=™k#fٹSI3]}dY|M=z4Z+\. c*7@&N3xJ%JhLsܾ'^=qk4A-CP%b1M3=HkH!:QJjd q* e 4SBjci/hg/ `Xyݳ>8 #BxP$ըz/gnw{ln#:0 >vm[y_#v<)DzRYtڭ=It^: 4 UOV5:as \C:΋/vט+zm,Q7zf ܸ 8)<q{du?Ix6a6W~#`'( C\~BzYg 3;޷eYs}*㓔 Y +t,{I 6Ӳ=k^y"( s9Μ>B2y'!fJD 1,,`YqPNŴ,!YZ\"ӧ1^)!l,QkuEUQQ&yNs;˓+SUe{^M#{cC:5~0aj ;N, s(3||*g/a6ϝe}cb :Yۧ2fS{OW1;?zm>,po'sffXZ|tQ6&' wK Q^y2H?C.d_`S423=9E,-$_(y}6WYؠVd3i#"p=Mӈ#;8پۧ!2YbGbV>GPDu*1jrYj+eݩ2knڤ,>i$e͑f\om4`;tTC ^k)FT6 84-T@=M)Ks9DEWh7kQ5ݠR`V磪R\w}t¶l$qL͎`Z*2ID7t(4m,SEQj*-|?TMWIegd=Tl>xPkRV2@qgDx|6`P\)L}w+{jR|63b=brCUhx~K%,$|4C'=.`栿. }o(dbBazLJҨVOpzz(ZdtxQm4ˆI.=:yМ؉}FQ2'SS|UqSv'0݆2))>іm"40 LUX\Y~'vAX"! CN TE%AHĉ0m4U%QX9+cvd26R( 1tiYEz&E#t"$Go9 oB> L `w̓@.dy4isEB_)ʜEW5 iٜyb %.ŌkWYɗ*\xR*aivP5 1Jj8{47Z8lg38Q@$x~:g: P;+Wp EYEfF'vb'Ճ?cݎv-}Lru~iԪOxGq$!ꬉJ%·xn/KI`>G||E7;Zop_lKVIβvd2A k$"T;S$q]8 65CGU4ME2ej((hFXaFfe{\~\&n4$Ɉu?0;7=I#=LM!%fl"C#-.ttNmeL6tV&K&C4P$шXbN605tM٘F$t6n]I8IEUDduժAѶPu8i6{$IDX$+P,SnŶJ EUiu0H=%%&y Ie| /] w%itX`动1~ Q\,֣ N/uYviy/, <{'`N3w#;UU'DQȖvG J?Qis"OӜ;f~;N5.^YM'%<޻*K<{0SDb$^LEf ^DHk4U@%a='%TT UIN 0VRinmu\?s4#(@ i ;l[Tt(?fryNP26^A#8l\ͣEH-#^ߣuъYl;KP}2vr(R 㐖bV }+cUe|z =:FPtLqcAmRAWT C^k{\V0I RD{R#_ii*zDQ 4$>EGUJu <0 CQL"<FQ4<6($8<-6/)oJ8wf? J܏OPhbChFwPfCT__oרܽWh7u+(>~F4Mfvzwi/,BsߩSgc!}/@tlfllv}(Pm}s9߽zN} ؑ/UƙcqXBpj4:\svGW)tU:T,Q.YY}4ʜKS2+*VUUPTI6vhIi\4E'3;v&LNLj5aیKpjfypQ%U.OʈVg BB;7έt:KxG.{JDQk$7];6Bq-!0ulKo KAӸ#y^Ra50%;68P`e#R&8h[NקV"=8s}=OfޞmR$8K*uۤnRu\]%=X*JG^wX'tx~Ȇs$$TO]T5h5uN)r4hw;h:NnӤnb!JU\' BL;GNU4CQF҃ Q,v8QQ\tSvw&wq><#DHJtτn8}2SE7@=[f6LE9x Tff*/?:~˕1Ƴ|TŋvRy6^>>fe*$ 8ڛ}[|+_+}̌_~H,noSgM\iz+vJD&W!;V`gaH;1)K*b^DB g9.Sm(K;!gfYY|D̜Z\cn (өrޣ9ŌML3=NE3?ǃdM&x{}榢Ԗn\<>+/_dscOk6S|D~_lP(p;1.Se Fu4ymI0as 3 E"?|l%F ܼq_;K4g&EHb +åWШUY]ߤPOQ% +Kn>z~Q[_ G97GR :f}W}ݽ/ cT9:V;x}j \7cZdK t(G@ajh!$͑5 Lo/$ #jbɡQ"i6N#~v͙ 4]#͑ &Jbg2~~uu x)=^-q<2,KIfgY]z@.LqwU^tKwQݴsOqPuDL;H@IξDF BmL "TMY7b0hTJcM8&Q366{\lNU2Va̒XX %cF)%q ubNTdm⇂3sV87#_(!BQ7,rfii~+)1sW[z)Lοn215M/Jizt1f椐\xG0>VQO1 NMvZ|6䄅X_l6Oƶ l"b" iS)f[F1hLNNs: |Cqrym5τX*_''Nᖿ}2l-@X(ܽsAWU{Ͼt~%gQ{^_a'cl&Pִ'J@{9gb_wwڟ' 5]w[y20 X\\#VR*tT77 i։DL0Q.fp5|m}EYH`gc}m'ndG}37F*iap>qUbt5JD^zM8dquw2dH3 +Çawm}ܼs CzF>kS(wwK+7eL4;;싖 KoSX| KavYZzEMK%,i6{'䌴 =ǴkkLLMI{zvIgs Dbgl8Σ%76( 4Z6VX5s}t;4q7+\ta_W\g|lϗh7@UTJ9Z=I\zq}4r@>ZzpXH}@2ЬW ?6nt:[iVk'#ekO9!|wC9@ lFMH~vWQ(d(m?{w~{.BbTfwUu0 n޼y`TU+_ .]BӴ GIFMn߾M;z?13I{rO9 ;뎦i_!o-欭p7sݜ=ː:lǢ|wr KCz&S> XfXɈV) oG ˗19V| "<ܿF RabrW]24D!} +[S(0.^D0j"g+Vck}յ11EQa}yR)8$LL>|V 0HR!ey.q!z:E՘_$NM{%2fgf1X^]Fq}0٨=7)2 KWR/,?ygvR)*ܣR*׸x2&V!R޻ƨJR!${q*`uk}0R%a19V\ +bWku'C J_$O=pa7?4 R{՘GG;_ҾP* |->Q][r5 t.ˢCx$y^/$rs~/ srQzT+@]KvHQjEN0cKQ\)n*T] /ɩi1tUbJ8vUr20 c S%]<ݤZah*iQ']z#2;fL1&'fW+m\bixA;-6Z9c12Mr"cqZ耐|Q_TdiVU4B)IvSdQky 99=f23.nJBJl}7@ W F_xAoLl/W>vHPviI6(ϣSxQoT"#Kwx?#?YYF(ʑl7~+OYL^ʅ}%S>w4wmodw4ɰ9tO=ۿE;gVoX~ZK|mv`!@8 YZ)¾VAC.zZ7m`+%-:\#=mt # @7u<֧J lxBJ4U!#c nnG&( ildYB(4]8.Oe?w$;[(_a6KG~u_s=M~Y1gPT$ ]Ƕz UM\*1b%L \ۥ> i%$ cv"_TH˵SB2958q Y[8!$j2 4 E2<0 U091A9pu4]Guᐭm(:gӨv:$YȌA 2RFOr|.@\>S%9" @?Z';q5 `ue !HdW9)$i:DŽv<~ԃ;= An!`uu4M։㐵e6 Q-6qg \G5)I@w;)%Q"H@4}ϑvy΀?Oo7 [E8 ث]]9##;Z|iGl/#g;<:6~ \x,.>8,PQtc˟Ek&{W^\딕GK<{?q$H{FhU*3gss3:ۭA*Z sS4'2M0bέWx^17@Y,U0t MI)%Atp݃nλ?~{8vu}'sXEa||FJ7,a81-y8f{}9>|FD'J%痿/tzѹ<۱I^^z '<\\$JRd拔,;>%bM˼˞zNg28:^pAl>'/KS4%8&hfq8,>g#6Ad3=%Qlm2w“{ "p\7 w,u.a"]Ew7I>eU=`+RLLNcqJ2ኪD! zvSt{}*f8*&1=Di255,s&C,e{s ПCU0cF^G,ca@4M._̠ۦQVmsxi$c:aoJVCW%/jƛoARF%[kK:J*jlw|("tZlwzdB% 9qܢ¢ 9L";;6^08Ft~!ÑKEhARѫh0L,M!$I "qN}i 3?7IQU5gE:Q&iN>C8;Y"b!( A?u?t4L(3 )1t)E!"D8Pi;)y o37UG/7[[e.kiHzE{  vБΣf4 o~M<~XsM^v'3b.\{SAHB:|vީojfFUpz['c[]RI%ZmNO0p\,~sqwP_LT z_vk\ϰYB淾 v2hoi ^0nVwZ$w7@,8Zk_~3&.kofx;ߡ?Sm>R-mH(Ο7x{hNFJf(0AL(vU>G_41qDe_le@xk(Goh}ѡEn WW's'c?zD*+ }EGKMd`L6< xM<9w`MF]8"I^YN;_R2M0d R\>s ^J$! n}=L"MH7KS<߼O4q>{6K#G'4]4ͣQ^3a0#j@7yXFaܺ}$=\%d{a;ӪP*]ȗa_8йz247miuoͿi)_{,MO_5p"ndTbh|RYas}$$iz@`g癛cE3-bP4ՒA Y4'&yW? tZi)f6&+kH$Tk$??;Vu7$OձdIvpkYB\ajbi"ǟ9Q2*e wioZ׮;7>~=2j,MPuLMAGw'u_*@x#V6X_;$x'~kːet:m֖="];mz=>,-#Z[H[v{DqDĄG> VVVt:$qL$)Ve("rк(i4(Y*{6so0ho(%^YBEi4I@ZR6Mlom*LMO0#/,@!DF34tfATex 妆5Gr;K0Qt] a2_#3Tk#?2VUw_J""8' gkj^22 ԅqvdMk}S$w=}3oiJk{8!")wIe$AJ1IimyR 0$Nb4;986YYF$AP 8S1>ϱY,MEλw$S 322 !N6 =Ysj(Fƞ_C}jΈmF zB7t4MͣB }w=xm_uk Uey"I,)c=M^%e} m{ǍO>s T*ebι7X_m%S;=/=soAE1IQV<'I Os#<4 lFHIclnk,Eħ>T8nFnk!|WDT }U  RH2Oh>9 )%i'$9>:àg7s[T!WKvpeq2ВTȤ8OJ gBI\jB+^]N#6y0&R/#q0A`E&Z,hmoߥ#H'rV4 9#h!dyDqaħFnR)W!H2A$IL\$JH"ubCe(DQO'g>vGNgHOv"28,HzHM!<#M3Bg:.Z2 wY}/@4/fp/){`MYwXX}v̠'9ym{x4״>' D!,`pg>QL9 %MimosO0v~G3Sν4~>ƉQL;0/UU%I=ɫ}k[*R1Tk 45' |oxOD$9@8:BuT͡~uqN l ǴAq@IG@y-3J#IDaH!IS͠!} *C0Q? 5H!^`4벩JQg0wD.e^U*)>>E+tZ*^)#"cڭma6߶Y~UcLH }:-z8U%\?MÅ'G?.=$P$o?\k?aoqaz7rE:Un޾,V`DYò0 TƷs2㞹)iy}v1ʅ{:1ƞiJ^v6uJlwVi6X- N~yx [@E$fpq(<~hI\bixTa~nM{1C0 NKX:͚p9rijwyY |]YSdϣۼ˟ݱՕe~w?/忢T.mԞO>s.x=dks7֙f.`J 0(-|Dz,0@S5> 4}W7 ؾL"oOvQ**c&^@20Qжq\(LMѬZ<\|@ paMS$S5]Lu CLC'IBz>gM&nLѨ6XJ$aa;!R8 e"MSC7s$RѩLrG!Pkb2=7G.Hv4B&ףQ _XJ|}M~k$ik6&Ҙnk /18 |+{12}8.a^ kgQRO1V+D259 Ko}k&oggXXzrzM=7ѓU._gmE?4v`tsIѸt-&+cau,,155AV߾v+\fI2Vo hTM0ddm%C<^!N~7FlD_W5}u䗹\0 qҕϹɇ|oAh!#:cVWN|YL2$.\dvvx37?GRB4t]?=@AÐb`JRי*pv^>bɣ[B4Mezz 4ju:ӳaYV!nذ,jS.Wo65 󏭣R4qfs\@^!0tCןu$)i.!Rep?!%Z2355$4!=0@JuRi*NoI$͔c)zRV{kȳRJ4MuU5ME RHE9B2Mԧ꟥35T?9j"E^{_=aRc,gbYV@H \iE)bw=Mrf#IBHFd|?35ӀTZzⱱFV^D?ve'wZdjnp2{ub<+\z§FghŹGj:sX:J1ޡ?clrjzDUz.aJfYsm ²,.\\8EO2kT5,=_UU##*f!fgK,,h6*(׮\EW3:CdR7g{N8(7Qs3#Lm^E(J}T ZE}JJR99蔥$h%0ʥhtečM{jT*%\O&g& !jWڃ*.x(vų/Q F<\X?ul_k7"c 6J[J/50<~O$i* LCPhc65B#Lc (vY4 CA@dYޖNQ8.ab)i* QCQ>~`IahZ؁*=SmE7,8DTtC*Qj5OL`&A\ M V2t4@^8T^?=O^8L C) <'E0QhEsR4f0z4 ڢoS4j:-ۤVfsUB:("z.)Z^RQh4ǩ,G3L!}Mυ5M'}6vvNGi CT,%M3J >ۭ.RiۙIS4II MS܌ EOPt}X*ղŰߥsL-0$[[خ_8&L /Q4 ߱"X3wEQ =BfÿC$QOH|p,>Y>wo|ɉ1[=Q0Z\:O3)wޥ>[fV=f]>[k$xD:cC f{kwzLNMQ#UP >tt{lԊ,=yDG,/369`ey} i.Q)*$pc1lZmN@A}(yL` ޾l8YYY9=(%~Rϳ_TQoCO_ 6V dYOoSnm   " b&S(@7M0' 2~;Cl+Oԉ;d$ }'CmN~@DqkgXےy (zascU@T50\;-}V,uDOEID$Qt`5r\" {'uIӄ8$}p3xOTi6PH!w|e2F=M(sV޹qy O6WsqIݫyC`LNRBVR9!B|I"i( Ic|o:2jJ*) nܼy* $U3uJ " Y*ԫ ]eki @(k3;3͠A*9iFF1 M#"JeDk:j00- R`scNw.Fn\|:coW$Z /^ni<guz tM:ƥWiVM6AUqzn407C5OϗA"u{co?{'Y9vA`i.qn$ic:;cgۄyuq0܇m>(E*Rwm^r} C9w=c_^Nl Awڭ5pgmAwHGVTp'w7x֙y%C>裃%\uLK4gV]r_.\;F9O=(Pi:?G,Ń{wOQ׏0\%ocHx!>{õdYC.sKB?Xd{`8n;UAP"=4;𬞷;R;$&>>V, lIخxD *| 7Leɑfi86nQ4Ͳ(<*RZRRll23c@Nlc$L)Zd R3G py^;)rs(^ 4 ѻ>AMjDsl$iJI'F4<68M% S(̣pIJ:o8XJ 'cJA^?tRgam]c,A7- =,י2q YJW ]/NԜ$jn6RIp8$H_OU4T@L̒k~0M\ǡb6볦EZmFRa2hVM7; b!!eN;ŜDdRBQDV'<ڄT5^-FgA; vֈ5&+ĝ7Ha0D|5猓$O6 4%"BR.ݰ\gx4 ,c:`&q*{)~xStR%OB `h*AavTwj0s E!0ERw]GU{0J, M3 ݐ)`~RϻieIYO'SMɒ3Zq@V!p9킱l?RY}~@x<7$.V(ZG3 yQEQdWHu lO%X2ejzx~Yg?=Suo}{yx+WˋJ9ܹ\@9 |uKU$KjB%ds v`~7:?˂wOᤚ~_:-&K՞GEI-*&G>cjG!6c~s&dハoW_y86Z)ÈÕ t`R+,>Yi.~g6 ~YuQ;t謵v2{ _c(k{NCd^Q#˲(/,B+A=a"(_Ƥ 0`/* uYLV!I|,>R=zCEOJ~M/dD>wniQ'U!Bn)B13vqMq OSPf)~ 2f LC~,v:ęV]s(#DS%Ndc{c ojuwZG8V0tz(Jx0L di)^^Ȳb~gޕ8avMZK*7)$Ib;t" < y1Q8c^㧜POB(di7lQr^g/|L9GJILzoL4x,ԈEdGZ3vɒׯ͛a@RarvGKT1 9ag%$*rwq̷>5*tUbO!ќd0I|{k U$ąQ*.W]&FV+ JEaa1?;Ň$ݠQuNif?AK-JAgÚW$Qľˣ@m IDATg.*5!.ܳ12E9n+B-;Y"ewsNI<5u4RJpy/]902^NwLNP6 0D( %@Q *u0h[=AlxA6?$Ep~kܸ ѡegs}kT`8dh(0Dy$YA\^h R :n6VGJ$B (g$N10JHMH#GbðV*T%hJEQ%1++t5ľ*{ۮ64%Nb&PQl%q7ߠk+3RHjhɪ._YHx\\wZ{iF {qwyH"fGKMRR'w&7k,Ϫ ]?9/tH^A130Wn67ao :h2^}üF$E!YۤZo;QhTiTF8ս£.2|ϥZb9.ms=4K>CV5t~VUHS?D`hg:k=H0=,#L}to@*ڜxFm[,/>deCKriٙmRVv{;i&K|@+",aD~Q^]!LHi4j8auvq$5ڭj=\#+"nHU_[^ 696 Zs5Yuuj.a3dkMr1$i7$ڇ%X1lpkY]pzNUUZ8R",-HEcQ"iL_ JPבň T rbD! v?L&ϩqDE@TTEEEV­`,' ! J<3ĵ䴄Pcc9T IZ,OBˉla}by- Q"b2 yR= ۽RwX\cM{!Y6]zK9L w!4z٣|17<Sh0%m@d~vYRYdEy|"Q.@ }i$ԪU `ueq|[ya 5z}luqܹ갎278( ADQ04N{{Ȳa]DcpxcյE|Aaa(57QB"aIqϝ{I] ϹL>ϫž6(1 >рs6ťݻs{k7 G /;ϣ/3|&yz`EJt7uxiǰȊiгtUj~G< בE0X0_nshhRZM X H(Mk'qU*ؖa,-SQUm9xx6>ӤQ:Au=MQvA(\@D1k!# `5=U@!pBx&찮" Fbԑ0s$9bwv QPq| YY穚P7 !ӝAn JXdll 4_ί~j:' vߎmc/8I>e\.̜Ln%T×$YwCoqg$sI+նM6BCʫK F^aDR4pOmԙt5j\9OfXlio?r~x2MZF7-2IBY^;,U(F"GGKsgx<"8&8趇yh8"hx\vX?"f{. Y`o6-5oC^Ͳq ہAÚG}lD [": Оu+4.޿c2`Z_%aI6@|LJHeެ;n ʲE|`s9sg=djmۘ$I}a!.^k)Ξ;?G ʊB:ò,Dҥˈ={ HBTfGڏx* tϱAK1Q\W[CQe|kW3Lq̭T)dS覅aZdyƯ!?]mیK|kZѨ׈'hܧmX"?yvu F'Ӵ]N[X@Lpz,Mvqt$mN ֪p5"Z }1u8+KpN#ݞN߃SgW*_޸ WX+טa(+\rSyp]ɱ8r{|Je\Ad ,HfL&H$q. ɔ2,~G!W(rn@3K6WŶL$n.R2Cۧ732Ai]޺~lj>KKxOX4(; 8?q-FsPgz%_NX]BEQ<-7ۯ|p~A"_*ϱtnܼaXb!K2 28|GAB>q\~?#H2=VAQ@ `L%E !+j*wȯDf}f%ʢ* !m27U=gm4YQz(b$l9JyLz84el[,)ML`&݁ޭvhTkGhG@*V^YP[/D=Q3;?LQ!h1j!A84ŵ f!!z_&QBB]**T i\2b:e/hTW6$0{.X6fYI&b4m,4>1$E虄*W MiPkq݀@Uo<`GAKA=K z{|85v5myfi6~Owy|@{p['4 0uVq5T:M&GKdȥh&&I4M 4ÃÍICX8>0d\rY \< d:E!4tAŋHBHGV4ߥod&p:t8MNWOx.W`brT2(GFy~n!; P~!2RvA"DU4tVWw?xXM(Jk$ b&v0ݹBpBAH[q`uw>us–'w(Q^l$Y[ z{yK;Lښ^.?K8,.wzB6pϴtaxi#ffhrNg֢]J4aзLwǫʮ3:6=~݇w4Oe,l֏ȷFGc8\G9<.`=;QM]UVWV0 }i[e"R_[JQLc $cZ8 $ NF@Fc3Y$BQ(t:Z-4YFQTb ckۨXwShJ^q:} )mYS)D 4YZ]8zȲO<)"vbl}~PT2E>CBj }@ǒq0LY$׵(ERm5gp ?^qNY22i08500 &N7TY 9{S=b]^z cB(TLS@1VK$(8hHO$pö- DVTY$ED|,uhGŐYQ |wa@] 0qdUQLsDI&0 c#x"k;hn!I|BA\CD +2nz1ִX06Xs"}^"✍(TeaEoOa *w;_e'&+VY\x,JAT+2-fsu4-ğI$9$FaH*`=F90:F E BH&M T m UqaG}J215yRJ(mZ;(;>.|/lN`$O$eT&,IBӲ4EUۏyIERl6 s#[Q|d3BG7D E y'd/V;Y2i \LLm7eܛ_9/kR^{_׿:wKW.#:-0)*0G*^!d&"ؓ(d3)ڍ j"xaIGغKesuJ{sē){w; ryOO̔][9smjݽ9@`EB' cx~@>W7>WX)0rL|ᰲ;#1M/w|?ћZ%0ǟ*L+˔"(o39B |ӟk|>h#ǒM.guiΏPqE! C%bݼd!8Y_oӨ #oD&%re?Ufcn>Fz#vԩG\~%Ϗ0Q0 ǡzQa7,Eel DzbÿLJPfg=Byx ML%r2cv Q&4UEI5D$J(@ہP%){47a]$YmMy ,q,o]+ zSmaxQGKL"M:& \!!J|(D//Wp\^M2#L0"M`IQ=x((IH, SER M&f6(]eBnl< 7r$u]' Cm8cjnФ>HN}b' y,FR!cQ՗?9k>+|X+/=D,׍}v%gxDԶGڛgJ Lf0b MԻ&-N"O#.<^OMK-$2%. IDATsN 4-NB$؆Aզ8cR!OҞ5DZJeMneSz{)cceud2Nݡϒȕ6+AiAuI MrҪWI 8A@ ]EӨm峴m6qYr,q reY85(<8Ta+i ă*8"_}zsˋKgV^m)P]QM> Tj;c!s uo]ɵy8{TrI^h 6F}ߏj9'C—LE2l?cw2NǶ|Yʫ\z>ǁSl@q=dܺ(ldv JNl}3EщCaC?q;b[}KnܸaW|=+z(~7)"rĂJDqȊF&0]|)7`<I%$TYez4]жm|߈؏DE_?2Y wEwϮ {P~asD"8=}|f~nVq`0 }'=w~{ogSOw@3a@ppWHSmgx]pxޓ==5G{{^:V8t}wAϳǴ OF4Z yGWn9qx@8uzB>AL NOQH/ W׹r""WEL3#@(J;,-r53tXdqEؑIةSeYmHEdyVK+IfJs$^^@2//\>x('(I*ƓE4 4X\duޟX-|5._' ϐͯ8Y^Y!k\ps(Hi1.D0 Íy-܊]pf o5ܼ͆P^VO~O{^F艝؉ m9Q^nI7sÿ=*z@hm:*GcmuNgH@٤V#+c 'izCS}X*M2qC2 C$Kcib4B購g ӽ=c`0؇$q˰ #fsy"VzA<ԙ"0Zt},rư>'E1^ +P+kXwsͱQ*yJ=̅K=7{Yܺ<^wW{-Ozr?xb58'vb'#5nF " 8(tX`v$[_]Y;hym~IvȚ; {q]?ױ'A"⡢ll5j|dvz(X8yw;,ˡQaC;N_{tϥ ؎g}F>/|qqy0;X_~NY,,-a[6uB YaZaxR9>L>jP@! s c/pX]Y,<Ci$AQw7(KȲBˉS{:( (<;l3L ʓqGq~ytm5]'JPf08D9Hi{j q#QzOZjZ5hxMpjQx~tmcS3xtr G!'`) >Fp^_W¹k,=߱0emoW>s.GhneawwHqAq߅ "CXFu{I~(u(")MB%r&&&h+8K[W跟 Qp Z _ VOnO(q~"b@U^{U<[)6rOk׮¹>lݰ!lsJ,׺hZn*(/l-pPmos3ȁo+T˫y7qa'1_LgrroLMϠJ!dVcJOKW)Ǹ}֡95uL*ه>wf"w]eXȲV-zq:)5dqXwl6)ɀN|Ӿ qΜ=3gyyp._}+KKA,sۯ)Ois'A85}D,F.u, NZX hixze^j<Ǣi*AD9Ci1 KCTUA vR*aT4tZ6&wQaR"t]dr\7@\׍ؑdyCTGC|#@@%>ic 4UZ$/4TH$$q0lhbI $IЧ(?5!P5B!TƈIq/ҏBJ@~b'vbOf)S˅ LN!K"SgΧب8=UOɩ$i?r$hLLNum@vKK ospLN>?+Y_'\v2NDU ?0 |l+ ϡ89eX\ ,>|" |$ Ez.iM!O? &+`ut\&YDKr5$2~?">&aC=&&hZ"| 38xAX!yz7œpP x{Ns3|$LLM4d-N>w|)~_ + r,x6Vs\@2&^%Ng#+NĎfcǿerbkW.qĿLLP*"e"*)$>cu޼'LOX(SUܾ@7rXup\DQ\eB@hdqzyBß! !uvYTc3i-Nu:.ᯒQ,4+k4Z=#mr"B`YXZlV2deqkID%h@JȤ$g(4͞΅i(B#B?pݭށNt űJcDɉzߡ3ea'Ov]j WDa!zBa(DtD3M<` xxk޿OXSLjȩ(295o&b[1jpW_l*Adyv0׃}Bb'dlqk p]U?|؄aHW:6Ww ~Eyn=~璈'0 D2$ ^=k4E?'B|?IL{s&Q?+Ϗڀi߻CUg}z zXwW׹St=X{-r{3 Ib~1G, b4Z~uU9f,V vh.`8.++G[_}F9ٲmݡZmzm,/3 y~?d\FU5f5<$BDK;qX>wypKbwȩͳMnߺIDʖW9]Hqh$@.ьV/Ӫ,nwI'Tdv{=V~8a1gOZm?+PFڃ6jp6Lg뜿xW_{o3y(FjOe1^^a2$xGZ':~@Հ6 $Y"{fd,(I4ni4ҍ "O,s Bux*z_aKgrdRI\űMPTAHgeDqS.1V^0#,Qp,rًPf@.'L>{$O4EU"`@,!n9N)A$04M\;?YY]e|D<\ǦRm/d)**mc`͠ny4OZ'nsS/NQ>mBZM0 T*aȲL[~ueYu]$X G!G}UQ6я[a'QQp Q]CG(iiţ3$i9ϟai ~p‹039\)5<؀G<ح ׶|7?7;+k}aKKѱѵi c֦30ԳXCG>Vq{{]cK2]SgeevxmlsKʶ_=R9k-keʋ6eGOP+@ի8!a{HFLU˲Ŵllۢ&~w$)6M6!`Y `q~ߍB"ob =:~  X@=Füσ %~b/A$ICB-IHRA(md2ZL0 Qq6@ $;@8E& hcE٘G`pԎF@nT ׶\X2M*hdiJO33=I"ﱻGvנLc8-gTߧ>{QRp.I*dUHdF+1\=8'9D #wxT*8( ~o.LXp͍8jsQXXdw[fRiBrNyi M8s!!8GR$ocC |U׹p"kkH8֟s ,IE{v#T ۪]VT~͠U%J*/I~GM ?j}@(p /]bYn߾_a@M~/w%3\FI)/FLti1yx"ALSRd~vt&C٢0q7/PEɉ ܻC:_V)j\>K?F̥LoΝo>jyb\`c~7/ W'!|M$s"}1qSIJWxg_WIS%+^Sk\:z$Ib?~;_ 2"V GsY? 乒+Kf #I2dfUeW[T+-jQId2k3YKJYY$IF0syz_-#3>^~=?y—"(ǜ;щ}Tpݳ/vaP=8^HeA]_S'#ceJt O Ð]"Lnrt],ˢh4ZymcY+++~! Ͳ㰰͛7YXX0 R|JvT*QRB_!BC*a Air MW]y (g1D &}LC'2k]'>N|\iFuRFF6cfzz=;ۥ+!qa?xf<@mQ,PQ,Imcwl#%hΖ IDAT\AHIqbʳ#Ie\ ϟ=ዟt'RQq:n&oHR(D*} OP\qDbRe"bu}v翺MRSOt/QڝTȱ]9lrjL&A͒AȐfP52ϖ6쳟bhCױGT JTM%e)!%̢NY&tu'2%dN2*:=oVgmI|cT,q\3idX2&NQװ+39r Qځds2Y|סVeZ[蔕e d&\:w,.\˲vջ/^ ?.QA W0f$099"|gϞ冫APLN*ZrM2lT]c{2׮Vk:kldP4^M>GU[++o{aytuܨŦs[zHŎFdy\m iTT-n|D|x]bJY-4ī KlSzv$[#QQl$2t]ggYYy K2B(Qe,-JKZqm[2EOdolhu^,@+T+XjLӢǝcŷ]duie@d*tN'l(8T l4ZX]YY1\.˫ ~yqɋɓmTru SWquG1ZrûF:vBԪpgL,]٪ud""C\?"BUJ2<{)訅Q9T+B(ƹv kk+,*{i[fȿkPO /g] 쓟OTbzz399ǏvڐpP(Ni6C™bH\hfz*N۷os]LNƚt;wW_a6|i*d7n AlfΞ5:ʏ);q{H{@=K>h VksQ8ݓA݁񐖈B y)'Qyd aý{3ߎE˕:-1?ZK+[T^e)=-YݦYKmָwdתS{jZ|n`vNwͫ/N}O?}i9(Nfyw0#}ɗ: ^w +5L+a(˥iZLO"=~=~((膉ah$L`ګPą٦e@H% p0"R}}#=Hnݴh%JQ,)CRu\yXCL˲4^GR!F5MC'Oj5pU1 tH$H)q]@Fh;^> Q5EF:2b@31@i$q J&l,!Eհd0}Ups`UyIl[{P;f3(BFQVsOyL9$:ME=$=a^?E>85*H0:ՑQ/:( B9YvT%<'@R,u]o qlZA4u\;fpFQDy^ CacB\E4$W^4!/~=2xu}gY֞,>eQ,|EQ}0tf:Azm337m,ˢ儨 $r%vt wt[T^8}dIlߍ$,wHP\@ˎ!ŹE& I6Vwbo+C@JZN=w7sF>d!7>}c;?3"O(OF\ajr EQ, .n\.? |f'7ӟDfj 3bC6vj$~OggQ"y3Iohqgq;ỲУn?irbħ?ރDR!tL_Mm"v?=H/:Pу4OsuΪ5/~ vn].)%1 Z |U=!b0}0ݬ]m͍uZ6BANQCU\=pK{,R"$:2҉"/fR=  ka8 벍>F A5:+"#y$ 0]z}0^f1Tfȩ]TU%_'T>)+_2Hi+bҦ+K0-TM#i4w%ds`ffD2 l^+1YqQ.'4UӘ373⌠NS<$'.l%ntWk<_C.LWfX4,>4c`xId'XSW'FFocsvߵ71C ש9qwu "cwG2u{(_5;wyP5.<|Ft'pV zF^({v8vA|bk{I&T_`%0C*Q=&l94MTl6Cdf ׻$pN|nHG J\o}ۛ9(]I$/ R;[,n09wNMvW+8T:v(p7Y/|q:Q i0`~H fЩ(M=ȡU{eENQ50Qth}A'/A 6XӤۖJEHJ 0$"k!F AtUF.qcmE(,&8 lmWǸ$4}.p(q􌝵E<t@B9T([_]z9VD!Ϟ<' <COKWݟW'Vn{<($":lT}EG8b"<ZA(Cyo^Y" C޻2R=D+MkHU :Ail TjD;iLNM\F|G( BJ 099A" "B_4>@@z DV"D2x zI CGv]Si6؎C:!_( ̌4 VJbYaG"4bRyB"X,h4`AUո[ d8(x&^|D`cm3Neﯪb C|(4ȤtzۓV9d2Pqm "Lc:NXAy8g&u$!nFJ%+q=z˵ᵟQtƗ ^n`mJLXů\ ُMW'F':RS_S2 Tx+ LeߪK)z$?;" dUP ' QE}0$ ѼϜRN5Eű0!抟S:4{)nwa|X ]K0x 4iu _ro-L'-n޺MX^];0BdLvA!"JХ $0)JeȤt6A"aPB຤IVVpxAfdƸ2+m339NcX]Y&+HJI&Զq\t6M&%e\jY-dJc rN0|#) _495X ci:AZ$~ ]&~ҬѬ$3SxNd:ō)|V #P5iIF'!a$Q:|B!PHN@:M#Jn4xdf/iHƬkJ%VihNVE")k Bh ISL Bץ\F8lFR'vioiP, qO\oĩhJLxbi`41E.iDpbfF:m~z,cF\EzbEd3I/c cd>ƘŋcIe2Wf&Y\\|fH b}kLrUL #LN͒2WGWC`kf޸+PTHR/ze'?+GoXvק}H}J}9q)3JeaD:d\AS)35> :.aR0M( Ct]#!Z ]@ ^UXf%=M{k۴[MgncP>RQ(,!fBK+U`:rY(XAF0U\zRHjwn끌gգ(B* 4UQI&Y#LC EAݨJxEdpTL0,Làx(BA54t]C4Dt&:6fa|MUBѠl ,TEB3 B&czz% q= rLE*d26aPuKЧXG.v0 PX ᩢǣN.ŗVZ'^IbZLm0'YbѵN}OiTg>kA96l &)eSr_,lqٗvQT~t&&VιB:eJ| fƞc2kbc]y+Цq痿F a.Yn\c"kYnzq f& *ʽZI>I|O"Z[&/ҍT>1kbe7Z!id4U0M4Cu<CP^auf6aDJL"B,bl| Ch^̎!VJ&b XVl&MV=nFQl ɢi*j ]55E"T۱iud9vaXLMMR.WH$ E }a8 KL,~061IZN "O<IX`sz^MqZCY'g |tz.Jzկ͹4NRҳ}ܞ=bWNH&+(כ %(a̢(^m45.HJ(BWU|vqe%s]lCg> %jb 3"%Ba Ri^\3$IHj|D.eޟ8_> b6|D%B:xl4ya8XxFs¶GO|![8T&tm*; +V?|{CWi4۸n2NgOi6[iڝab#@,={ƘCH.l^DEWL6q:-,]G(23dj&)oocyd2Q,-m4/A|ߏ w+v_SJ|ϣ,}ٶC"~]{o7x{(3{ć[ VBCAﶛt!Row3{gzPzztX]ᾂ =C?I9v<#⑷{!]:6^$iYx{|1k8a2„6%Q[-NUJ ȕWQ,B\/]0 ˶9Y~xwiv>H~uF/dv,CUǓ8]3: =yy?~uE\Gqlze qw{~Qxq頩G\H4D <&t{h*" CE% \~_Q@|$Agb?EhHOJ a:؎Rc|\6 =NL& R ( aiu2N}}= Aǥ]͟!d\HsOױ%&oqaxoDQ&Q5P:AqUbч} nqkĤ4#؍O>Th:%Sic8ɏ9v6ҩ"(o:=4NBDS_EׯG0WL7?ȮyxT[]~&D(BAzm響01_}q)t_SFLO:Ȁ@ AQI%,аmb! [۱3P(I:)Ya]͠ϓL$b`$IVV\N0GD_:KK[,$?/_T }L IDATag)FDJ)yo)X#rP$*{DdM>Y ((g}ޓ]a 6t13@ٔJy>,̚*;dRօ4QgLPȲ]>:R)JMS1TA$RT2iFLZ0 i t]!GЂu4A\`~wIeL2ٌE 3s36d1 {5wyXZuAA3W,eةILbD08 d\e6iBic&膱md\D2Dd2ed2itMjlPubHqk9T"t|&P5꺎8v'Ԉd&xT;aH2i111JW(Dlո 'rPxK1U`iOookVv: }iڭ&jNE*;d)omIqͳ{TP*ftxDtjM  ++kۯȊ|qrF` ^^0 |?ftИhEАQDբnh4ZdRB7iFvPuuJzvhIҩ$J4z=\CQ|?]LCCQۦy#~wBxivV+o_?O9 <u=;ݩw֗Y?ݾk/${>_uw(d}e ?|!ɽ͕6WEkl G P-sɋg8վ?x3߈]gqO(~01hڻ1.A|ueN =[@*cE|f&YZ\$/АA 꼓Q.{&a3:et(+c /ZX^Q37Z 鷣$DfpgI|w^f[N$C'}M9ͣs)@PP$2}YQ)K׷Ǽ @ Gxw" %hFCF]Ou;SM\U8owUUB0 8D Eh1%?ŗ5t3v~AVE|XN*샶 yx@ (A]H?COD&k4٬i#‰I V*+hh6V=Udb4*; vfNc}_\ڛq̣P$=A7 U[!tFs~h0DUAAʉ|qqa&a}Qnd20P>a:\xll|Chī:/E_A$2ADk:_£{>7YF|-8plkї@\+qbs<?o cYą6= 'V c86]Ӑ =8(;%Cr,Co|/#C𼀯|ZgmmǏZ[q} vqz*ZL2@FryULLdy<i"b~oz~h_ڛs*D3P`LQqt QIAq>g=qD2*M<^a/{sFpVy^_}zW4 EhJ%LJiJ187[ƥ:o`Afl~{ 081kwQcpj">˛rl{ʠ,_ZN2ضϖI|K#a;mJyJpi])aYv}@awD} aW`/7xEe' A(@pWp}1a}|qA4x~;"De4ZB]m (O~j\)@0WcO{A02;*D u Ϗ >^O?'5{[̎6RCSjIta66+Nm \.D Lqi07nb(J78vLz㳳Nd>,`2-`8u08&ffO>壹1wvh4#靟2QY:p.WnΓ%:Tur$nG6;brW2onѳc96Vb ^Y>}밾U۷)%b᷷y[|ůX~zXF3{#&s& ϞbmˋeBEf/x_߰Ydu(d<Ə"45r\6PTMCUk_W\N!Q)翛4i}7P ʙҶ e+C3;k׃ *o}w=+q1_xk/>>0%<\ɓ^ gl,.>F?!Sb:3b1iyRgD*q* }j)+2I ?Y CB౺ n<{VLMN> 4=<~#[;cF UWJTAA$[?JTw<}#KjD0⾡g#^-/m2j2No[5wHRF'ڍ*TհaMuO$:( َ\':'ѱ:: >~`h7` &I" pE!{@W/=ϣ{ߣ~uQU8tF(Ld"AaLn=|?ؙ* qi>ZfjXyx}RH"!BtZj\@.ATd$QBQ^ob&dD"P:2vAVqAPjhI,z qI3RF ^uHC (܄aHEyq.%VF>?"K뺎<~`yy!8lKI)z*կCu,B5!P5l;f<%jW?.+2 u(z'^zI EQPa ?ڡsAr?1y2 l~|P林Axy\6~W?ʩ FksD)v\snk{b(VotY[?f ᵺ!yzs8uScR逢=mǝh?wKWߣ(=.$DQe/1Iw8 ]^C"n'h:tu\5#0dlrv}x3 Mx( ,3=QBtl [4mc\zvID5* LtgfgrbKר6 >"S_Fygs>f*"G 33ԫ5[#_f&X,!CzF4>F\[V=`0m;{A¢k;(BcfzmJ<;B"jw?(lp\le>A-"l xGӍuވt3&B*A˲E[UU'/ȈFd9:BPUgӳm4²,PR#Na nݺE=gd!ǶMD"8FsXdtZ-|?" 2d!PU 0b f B(؎faԱMQMdRcmms"0tTB~@:d MձqP$TUBߥ^yGk((D2ƩF)+M23;D!hZpl@?w0!aj0Msx5!1 KvwEQ iڑPn`AܟTVY|_>37]qD"1} >Įi*0MLuެ;+=|v9)5Zr.o,N? N8EMomgo&G̗u\5 ໿͕O~K4zkIV8}J2/6Vڨw..1h4xՙy*yEVzZYJ')z};}n3 5~353Å&q;mqvY_p#8i7`,K(hLNNÇKTޔgQi5CӲ(G鴛,/?"]A%>lTB"TUݬs׿f2Q AC90b}}YS pj5)*LLN*!q%rUՐ۶l`q@xƐ') pbb a@.7"{}쁅$+a "!/ҽ*!+^ }IFݢ?4-IcM\A#xn3P$U׹{SmnGclf0t0t:-uﱸ&\.u^= w=0  F3³(%ybPŐ\;&9]EsT+|0?OG7FjV3U"E@]T7 bYnC3X$I,vPٰ$iElTB2rDԊ1AH.Ib1V@ IDATs\\z"j-ν9,a$m雃\5QFn՘٨+i <ɉ"*^dCPThe IddY&I$a eM͋ Do3_pyUCcT=nPr榫(< }Ibli-ީeVqxMDV$"&E1iFp(-bgƮiPd v{a@++Qm!x"u,1>^Q.- !m8.׮]Kkbldyuva8 @x*S$ /IJMH0X^^Fâ(qm8<f ,;S.ؖEGta Q20++ D "3_HQ*Qz}02!YJ?0L8'o?~fi.\0\Ӵ! ^E"3PWnw螎ᢙuzΕ+WX[[4MJt]>#LDe qa2 wR+oRlF2EôރKԟohN=ޢ`Q#vUff kahvI[3YY= sQA u.I$O`;/k'f { c(*?n5嗨I~[nPĊ$f!{Zu76X`q~!Xw_ÜvminE7$_\ U|/.Rw7]( <=;fRgHkk10o?rp6 aكG< g1==ܻwҗLJkz4q[ǂmL0(k:BvK( R!5Ȋ$%RUUp5~{ JDwχmUUoAyc.B۶eyXn3NF%,z~ܞѻ2B"Wx7~dF?//;ޓL'&uJ5MvB@0?_N0 LtCH(8iqۿY10kj *i sTW"k5(rn3=.GM߆Zڕ*2,{3wVEqs/I3YJ&jY$ 0BQ$TUc%ᱞA,lGG3V({.<7L4F⨠(ΓCQa;qE446 Ðy?OO|k[={~OX!0xds%/I&/C)aZoy I09Y2$$S,^#X$I!}+iOʹ~sx/}&~ 5}M4=" \ZDD*JGwlfg] t]3CZIMuKR?912K;$)8wIXM7EU4M%0HIzIC,K?⤖x7XaIs͛ns '9}r[_ֻ:,ݺQ;o2)|qqs/P(ٕߌy" vF !+ȄAlbi;еX˛7_ t] (Ya<\wwkzAXPfZI)5: $qPT}&AmTݠZBfpP*lSsN?SPh@32sGn+bI(HXbLuJckNC<4"@UsH@LsZ/ C]7(bZ[CZ9/9u4U6\jJ$"tRYT|>\סѨ R$TU"H7b, IT Ȳ>]"X-MsyEr9nܸjM NĄqH>,I64 $f5=ia( 2w n5LT¶mX$,;e(rl>2R̹*".vp Ac3Ka>lz(@Yo0x MM͛|;U_bu/`*rxh!I_9u< ̑RPW#!)w-9djs LU tC-`Jo> eWd[[Jt|?Sg-Biȡx^2s ̔G^5]GLOSMq"΀S1 ً&nݡ:5Tم9Y_diFVUfX*r˫8C[G|n޺A6|U& z``Y) fkvk.ocvTڽG vPant$&LZ# ZL C#bB$!!˶ d|xw.5*OgM$kzhbQ Gޥ|Mql MSVB IH"!&RQ,)}A $)F ]%#L0-&''k,h1 ;Rv̰G _.@< 8{vN6:f_7cwtk,_/ ς'H풛L7G>KRH}mY%Pnws, W/%9/R'Xp DqI6˵- ؜7678{r*k}w 0D6""dbߢ… ܾ} ._̏~!;W5Md o8RE:7o&"֖!+۷Ȯcqω5yh) GQI9٪G) t>iJK$㶯}=EޓeIm6dBuwn&<~/}0?W,iꎽc1̓YFݽC}u ˶B|"K $#bG|Үy.`uܼ~"E˕/EwW,D/ R-dkУM^y0Sjbo;zzzc@xܾ pbufpG'Jq8zS{.kIݙZE;!^hĨ6w?)}VWeS'BLkꆋ Sf EVcҚ!pE7zX6rwǶXY^uczʘ$FA:fRx\HcH\ץ\u!KKy Nʕ+QJv#Jª"B:3 $CIO@BV(K\xk׮q9??qbI~>2Ȟɱw&}~Ŏ8FVB) yDaGlAN6i֘ |c\o[{,MYL3v9O0r;^|0HySsG۶v=`HϾo;kzFӮǠduRݵ'ƫm}r;La-;l;HG۶^#0}FG Ð0N^k> ,a9*Bid-#Zv1|>ـߧ>us%}s?6Zsf:a211AVc`\~˲0&9\.G_$ӳk<\̛Oq# U}D(ϯ T,Y`aU!oEl>TR!;H"c\iZ)X>d.84QY8D^G5tu#ZYV1&s, yDzUjE66q`/'LX]`fn! sb~uЌAbHvCT!IiZM j m T&'tXx( \]\>O>O$!P,$:~ ySE KR"1J4 qh4LMM"m@*b(RP~,n*6w?0@gmD:Q/kLfaW%(#'R.*m hF;u."-ɄasU̩h\V6 2!W;yyZȲZLK>=@pGG sSn4=jX$IXjxQ@{h" TMu-t]#.k!![;Vg/uk>x=<6;J,ǜ>1tm7Uw}KW e-?ǀngRe6 NQS(NilmnUvBBTkxc*e&J:cdG~Vٮ%m$1ˎSX\$ |@.F.Ocs/UIMG&y.,j9 Fu$vAg>'ϜX/bԦ(Ll $zoy)@eۨ:I+O^P3>:Z?*ePQNIL}s܋YYzi%)}׆+NCMddr'zB #D8-<KOx$9Zt XA^qe\_\#:>Pc[&[H:fYv㎋H SInVXbX }( 1M"LFm0tG$<ǥgZF EUØ@bbBŶ-\~&Av 0ysCb)Ʊ] "C(s0FV%dEF P1ُm LzG}&F21ΘG?cEI" l̇" uCNHfSFt2oR2h:v8Se?q䃚/prae(BsD#b8 GQ8F27?ڷPd8$%/-R9/܏M 5ǹ27>$2h.g{V IDAT8NRIGp3ɡ"0QIQՄwLVTEfi1LT>C!8MUUY~蜮I|gDfdXA?gfeCH`2uwZ?F2wo!fQ!Ğyc{lTv"&|vBnXID즟&J^~jPlKO-]:4CmYAeY[ =Jj %A!\I,kPTʥI5,[>uR:nesc4]6V1M ! \ǡAYQ8qtg9O CF篢(Cm+0fPi6L pq'Y< Fɟ((C'N`'1c=h;Ruu-S'~Μ=G؝uniB5w2dɼuVFVz?lHj{G<_բ'j,/*|=Ϯ;h XTFgzzW_5w?N#\}kv`p>,Ԗ} Gy8!>-P9k<^YǶX|v;/?" |'yF}/NZtڭ}w]=dH/EpeA!|beY躎mۏ*;$177Dž q~Ӌ^t" y.1??Of5as _jBryfټ~l&'^hLM<5Y[YN碄gܹ3'N6reIˎ<\e@prf"CS$0Q[|p<1@(I/խO3t Ezn`:S0,^ SI6HNVBA6^XD-8VNƩR!mΜ=Cy0 dr**pEי,,A']D1Ru;E7i<Ѯ~ @KxS6_CulAtrF"}ԉ*ID\wɄEIƹ8q:F$}GiZG~F92/\6$kdX9G1M >A2"oa0??O.öap+P[05Ijs R Dzb&!/r/qwqqq8(lkC9U*o\űM G1LLs\gn"G#IܿdA%:-SӸr+e: `"0{cAqجw_>}@\VWQ($N/(<|PR7:\0^B,I %%6u2?3ͽ_cGc2ry,,,"3L1x4Rj8Gxb-/g$h3L-UTJe] T H'lˤɆMe?H@)j"Z\SL&\DLv=axO ) $iR bdhϢj}O^VqILgYa Jk/2oh zHIiAh^:4RMQ'〽Qq }\P5_|:Asl|W֑eU>DJgůwRc?<9ӟ=!8<K9pB UuQÈ._&|4U=V5ڰ=t|v򎬥'͵eZ |/jHe%Q sl7}UUN/ç,n|hn߸EhڃDGTHQ:L^cFQo <{JudE1a'&v:EtM= #_65kى+٪oI$)?{% K j!vV'=?~Iј"gQ +*"m7YYwj^%Ο:B=v<&&+X٬!AqSڤ7xqÄ37>3@3Kt:ܺu) I/ecTU5%_fY rTI'lx뺩1 |[./vC'F< |!{O\}[}?{? )`(G$gÀ Pq4u}$v؆  qç.t;6%yھ*`pI5I=4 |@n_%!r݉IX 4q5kG/ p'`;/ ccok&ܛ%;1*oDA@GSdRu MEV 0 2BE6>'Y *6h C45b, dI´mdEPaLFs{ME3gVoew|ׯsE`PQ|q2Ym7~f X~t]0n)j$%5/&^7,Gq;dӀ$5> IIdݍ^Igυ/ęoQ_{f\CevYYYZvIpMy,2=ayei$siڨqenAA.#)iZI}K $+|j$F-Coo@ r3gYu]|?`n4i:'0Hm"ys$__o-B\oɹ|}޹6hB!އhgz.JžV ٷas=)NyDB>G?+3gL8{+M.>JhCUO37SPP_dUc" 35ܹ;F@W9ub.qn"0w03=[or{;@DH1 bD=A:6911!<0= 큀:|씝;HbE#d8YGsue)9|a}}5'M/:'5h f YGG.% GG`"fA?DC\Dz~@~t86,=Ie'(j` @LsmTM# |*{bg z0$re3ey2,U3c̀asN 3,E|ߧRpu螺fB%ma ߱u^Y*Vg4ڙC!ppʊDq0m)B߆XZZҥK}4qt]'Az;򯒂@'F(W֓י<'&s4Vf}ڸ!jlσ?sAP Yyv"l 膞^@²ll5dcʬ.?EGT-h56O/b{tP89xHBЮo2]fJ)Jյ5& Twmw10=:fA ]br;t]CSұOx>MT^z]8&w?,Lt5սvLq^@c%SCtxw2N殴8=$uxoĩI3p죌QE'ٹe.Ȉew56z=^v1;l8j~NG( [֧"*j 0;yilq{y[2'l>|o:ĈxFMqMB 3 $0>ꓤ맟=>|]b!fK\f`ܺ5Fn׶8(f7NB}5m{/dcsׯ1Q*t6>ڭ(έxÕ\l2Un(OL>WW?cۑ>A~p; Z6*s7W$D9Htm~s0P,lWnɲ"17aĵ6"!˿:N&1A:`yG=˨E8|e/fB=,I;Ht qA$f6X8kE& 3a $&QpE]$- @=L{^v|n 0 ׯ S8GifQ#=f;"{ՌeǍF0SEQ~s@#,$+LO"&G|^OHjl5{+;^%M.y]U/&&i$5~j(7*;Q;l7"er:-dt[-$Enb (zZEql8U !|wMa bP1i5M{P*sEZ+SLQt#d"$(K(b6f9=8SI9KRE3` fMam۔e|4X"+'t]Buw/^D$\Q80:y6z1f鮻Ie<# yjR!x@PPD|8Ap]\_|j툖—7p{ٵSHRjvA3~bE|\ …a6ϟ]-B@mnI.Kd߸gN! t~wBlws{s_"/c]$Ecc}VWVz'nyϜVFkÙZ_]|3e[X\:MXja;9bhP~Ϙ9y|cݽtmՕe$\|jEq(>Dx895݇w YX/3$7 I>33oR*1{=2W|F3?%T^W)R,=<[9FI>ٴn58wC$(2^ MAb,!)#I1[ujuy6~Q(( MBy   *hXPMqQ UGC$jC=\.y F $ma_&Pg`[ǔJ%,eܻwK. 'aGM4f}0R(f P!͢~Ypݻq$4,}Fq|zu}MUU,BUesTn& lj$i|5H $]ӱi4An4 |EV鄞cl51 =Ygv$9sϟH]Y !bx5 š9{h{$3@5ZWwԙ=|/"2+*Kuw=ʐH$s/؄a@ݦ,.ZJ& q5DdA:[u_D!ihqm )!bUԞZE,,,}J%>jW_}w}>|Ot*?Ϲqg|G\|_iOSZ(smmM0<@4mXlje4ejj^{h͛Z<4RJ>#fggz渔E܆CGo~/fCe&&h;-MlV4릹#Ifڙ4(JE S46X(np/L$vq$-U;{Q|:լmf e}RGo޸AgGʲt{Ǔ>zHB=Z-E_z[,eÀl iJ8mIrBVPiBRmᖧi5KZ~H1.!lG MXBԧ*w6v^?Oh?)Ifet=yb>=$;zs{ɓcvKRح߫?w- HtY섐"+6^e`Lj"Zc r )#8I@= IDAT  MmG I7o  5?`gkN$n`;N*YP Y7&%I~X(rO /LWKx`/YlÛ>,][oI{ 2ai\|$Ixt]yeqJ)66I'’I#ݘ$qlE'P&J4V'1ƀ^!.:)[ePT&EBOfwKR4f52I/[$|w.R8Y:nURouO=.}=v T*!kgr5 @,>kG$Ir@ǣX?CSpYJh/G;$w{kl?Olm=8 Y]/@!z>WV7u?oq:M:m?6E0N56ݬ7x.n{=rb#~:c5*g%ң O&:+x߯0a?"س=/^!q Mkk'ӓ8 *v1/C(??,#vv FiZ$lmm#RL  [Vl.:71)JT߄!6T˙vuufAg}Dɶ }~ |QPi_jÐ?E|??O:HiPV6 q9k\"5)Xhlۥ{(U H93$TdRq@AiLzN+K7Hm~hj5$aee^$yTpxMƙ*'&|=MkMZR*RrUmwȜycu]xYhfF!'wL>sRHߧ65 qKS2T DZ tDv ) e;XJ"MB*?]Xj2vB@l,1JV.G8 p $+ ^[,UG(*_B2;SCYK|Gۛ\p qFk!uTԦ6moNs Gxr-66IdW,ooM~3"ߧX*v70qV~OH!qSr(i[IJu m Z;= aNr9> ez['T0;%%J XC`;8ژ\Be ,Ʊm8?ssVRtNc{ NV+()vȤmY 0( X*S,8NZNXl=Y!l^{8Y8 ='Zkl98.Pp|lp3 ͑P<~+<qFtC5qsLP@&A1v:8h#@(\.hMa)*"p@jN T$XXA0(DP߸w^xA@b~~R SBC_a`X|uoRP*F$Kzwy-JҨ~tq`3V_j}^[K|*侴â~v |R,~eU6VCgk?Ncze}$rF{:]nnk(#L^?NZsnQ/fc[(BJg?Ҳ3ěj\wI?SRveV`Fr )*.1*Hi7c;mrRk 8kI,r "? )~ HI,_H4)UX}Y|?I>³5_7 !+\hx!KwK5lBZ.]DF\t pr@(m,SLv!N2@eYI)pr20'Z&w9^yspW&1и.Kl8jkIX}HEIʥRuޏ%ΓB!(Uj\{Es@Xfqq&H4ӳsLJ0BV;!J '"lDum8T*4b FP SfIId![5ReF 2FE`Eck;=XeeQԤqRRV&jL6NӔl2c]J?hMPP`x,G ZdJ0I65E$Y]jI Zq\z׮[oyTU#(hqL {Ԏƣ@9 zZۥX,󐱷P(߼Ï~eYaH(Jqn=-̝|aBsɈI>J/6q5M`mv %h4wXXԧڛ(4ܦ';4ԫܹGE%ހO;X63 I`eJvMR*|ÇOhG{q 1:͝%&JJWW,/±-ܧ[MD D6L" X ;[ Jz8Gqn^ZR ??ߓ+;> !ƍN$jP }ݡ<-I)BG!actz>jRH8˲FBeF)VCيj1Y-[(Q)Je)Q'&Ff,51LD-sN `vԦ*$I!3hr=<8[(P(WV+"^R1b*a'RH\xYBog02_" C(тTQI5J*,;=Z#Ee̗f6dGbnooSL4Z.jvM~ާ_KJ13;Dž\&:KELuiZxހ8Jx #,̵+/ L9<RI22"eM٠t2$[r8;gx|o|;C*;uաXZLAͳw/lӉol͓ql<~wޟƐ/d.Z>=||.KcΟЉvQ pg*{!|Igt[" It 6{X:j%1cG]boP*H~Riq)jBo@xĉFJkS2Q4|}'ȽB?%J,\,{FvKhLhdu&$~ku4vvv3NQA1)N-leE!^oЧ㺅 H)l8JF$!' !ru<2!I W^-:,$|6_ s{ۥZN K%Ujضoyc|84VLڽ(C?ݬIę@P(!<!$m}80x#Mw Shk$#G!@8)Gsq]Sk ¨.p\Z3 ($I­[h\~}$QR,Ipl&Irq~3>}"xl'N;u?ڶv!-Lz05X qҶfI7~X@UewOHp(; $R #{!,϶=dqx@i"dF埦$јFiFio֤ev+:E1 }tsa4 Hi75F'OiWˢ(dkc ]T6a.i D'DC()hzNt k#.af.7\*k5NP+WInՄ:ۛs w{<붹 *2^/Kl~ JAHMh"{i7= 1@kL㸒8IFbC‘-/#u?,BÚq 8>i³mJ)H%Qڳ 1e=zD^cjjn;E׻, mm QPTJ8?ͭ;/_{Kse>蓑^B7>;¥\r>~ Gٜy|t&թioiti;)R+17U~wZ=LfD(VA@TBW/r n  L%o\_~NS~pkvkH0-y+|oP<e1'xʧ`}2=rA!}K`w1aDϪaF4jfª֘̈́zamqM)F3XZZb0"bޣ+9/3U킔,,]f*Fx٪:7>Mi5^}?( <xܹsr=-^Xb,k-ee2G}vz}K){,]DQ$#G7n봸r]ڝQ6 \Pt2NL ~PD! 7o= ׮,!c;4MT*,W_.T볈8DX K%fU>7osA·b||5 & )1O!|Zb<q\83B8 G/q v(Q]đe$*Ӫ ) R%0iNSLf̝&ZIG8vq'jzKl;cL5ܘ(s>3vϤSf2پ4D,&#=cX_W3f8̨FQ9jgs`{9aj jvz$;\~\nj$@x:~硄gλ3}~8sZG='-ɝ~B_t-&vJaף̠#JzunJ=vD:I}(H$s6NS5tocZh\k7soWkCx$B*yA@e6ׯ.3;3I# #Z!xLMO#Ï wA/#w9 S{ :%LGxxCy>J\~G_~_}c[ PBi~@Z$gnMɖ^v{G/FGgˎ[~Ӥv:\|݌CWN1Vsslooh ʺS4Z;$:en~0i;RTE,JHaHkĩ$J"R \@$DQH$n/(Ô4{Oq޾6n@Osb~@xݺwCYO+AHE,!c;4۟'Έڭ;IF &'ү׍l3i2R0:_ _u uI٥CIAo}DY4|ƣ0!x_fx!Iv]mLJTٍ"S=ݶIo0Opnae( i~!&XMh! C o%ZǸMG(eE+AȬQwGt>|ZIm= +bb)JYKEla^EZUHVnRB`4YO$ ډ2,m4!IbvM^DZU͌ڝD'%%wy  0S8J.J)ffAR⅋XD*EX"L"e9a4kh08]R¥˗in v8C^n133s\z$"8gta0lml=}eo 9F`?EJ'd.p9V{z? 'OY&~Ce? I9ʹ c4 0dnn^xhs0=#Q*{6.hǛWy!ˇN0I~K 럩Mk}!M5w4Mue#[t In8'IBjk'/ |&#:L}<>Io\8i'9:mu9kO :BJ0ЩAI!π¢^\* <q N`"4Ow,PR5lY@;Zr4J<BRTMi4r6ŮoJ3`mZv k)eQV!TXCĬ IDATR\)!e 5]C* 4IMh')), +R.y*E$caR*RpٌԦT' zmx i0j= uLF=Gtm{qSN*,Ȁ0Fr8^<~K.Q(,D@}&^·Y]cx3恝VT˘*4hW͐=BS1p+|yVҥxq*3\G?>vGp RW^VqeHio@m\\JVW%̥KW-OѻAӣP֏DE M^}:vnrʵ%+&I-ݼƩ/_l~8p즋װDBQ0AD}+[߾k 5i\{ lŸc%^~[غ'\XN"-$Qb Wf:&,R='=Yo*:E1t:8F3wIӌ<\I*%{DS%kx:s{jM#LPJEjҌE!FAىANl+;( Y[[RJ8($oX +e 4Z) :0>W):qFa6#r4%A(eS)sF397^U~o |3IS}3tmt)K,ͱĽwѩ&2!۶'eQp?xpxT4,'d8~Όa&l;# Ðb8絽[c~4$gG9<-Q>gY;;AVBPI!`|(diInRuW#,,K ǭD[R0>; +(7&ٙ*3;;ÃMtJnanv5ۥR-,./]۟lq"nj"$q$?\qaicy /B1e$Iq .m:6;E>wKa*~n@gYJC.p" Ӭ{->O` [4 Ze Wۇwort~Ԍ1X!foŤ&ۄ'qDV*tsoW|GJq*8ߥxQ1I~wTƁ0eto?0lf曛ƖcNB-R2 i0@RaJ)b"y? b|$:`TBq'1%(Mx2Ry9k}2&Yp착0Ea(5tAilo8iwڣk V=$p ii5i5v Aդ?{Rw"P.ǽ{ RV{` H3f#Z=/&4CA]{_~FV1|pefG]6ַQBS%."u[($#ڽ$;SE/nAT߿C82T/hM)@ FOvoGQ,'11?iuO4ˍGc>=A11%l!y=ReJdgR)2t-!rٛ3f RTfC@M4|"wQ$r qtr+wN{oA5֙8n$aQq\) 32MTcM{=Ru;؅2rI.umDQ+$4i-0vIt"F[i:J-JB$E7&E R2KDdCC{}! r6pnyR]~7~.e913b9d4)sI()pH>sޞ٭{?/C_;La-:գ:ჽi7?dNvn bs\E'1n;7.Dooglnnӏ?iM'mN^god{dZޠݻYݻwn~|- k|3wJ'pl=z26I9ljN\JL֓:g8x,:=)'_~u]]YU@BJJJ2GQ@\Zv鶻4[ )z:m%(2˗/"0aT0=57q=SN4s[w:htEe'=:ETREBԤXvFF>VAP% s3l=&I4R,:JƐD'(e13;$n'f5e 8SaӪu`l.IX>aKf0XN,ȣDeRR#oPIp?)͸0=8Q zұn̎μ,=Ds\nbǵ ˇv:9\Hf$3ZF^}d-dNՃsP( EP6QX$]4Js !)DqXQSć:@ܳ_ FŢKZT-uˌzfV!bqllK! S[bv6,D4 :-B1q`[<>M~P<5>Qqى$Y1!siq X TKlғDax"@(X| ejFQ"*K }?aFfl$M pl$I>(]qS RDZc+NSthQXW7rPx|@Ja{쀑v`VcvV c/Y1Ib;`$~Q'z<:F[o1t?FǠqqqjef:sq礕cr)w^dǢL nc=hQϱ߹o'(Dсw~lLR淾cj˸*:DO>1toj.s:[zM,0f}PD K[;ԧgY}B@aa*pdia;OΌ+op "̗ȕ n|}=Z{TUv0-<~M믽x2[Qǯ9qw.RhIjtv;2Wi@Wyg2H%u $!PVf+nbDT 3g HtBFUJ68j4O"r0}t0a7TmڶeѭTfIۦV:3G'q 80@Z"-)T*STE"&1RmtJL(e2k6(nW^N݁G$zHc~zSJeNz,\Be^%@AI0̵BqeBLs0bp{xDa&8|OO>?i>wXq=8f8cDp;RR$)j(Ѿ5~J9 cM@h|*Rl\˱JQ[ZY9YȘ=Ї$<5E\ +( C();vyxdiq6%~0==Mb7^}U\KYZXd-_z>,R#@lx 3ll-UU^;qyja4r(\[JU /N؂ >ZŦ̣$$)\\iHCl#jl1UgRTYsytvWc$y, u=i%43vPMR(L*hހ`@He4 YT."ƀ%~/Ȥ=;۴Ӊ)Xܳ3臲C'9TQD٤jg|* bN2ux|lj|aʨmT]A瀍5/]2aفQ>Ors]{u |\J&Ѡ=*Am X\/o88XI-i=ZÖ0}~d?0|vܦP,YN&jSHd`#:YXjuj8~wN8x*fKu y>^Ǐ]e{|Iau*0MD'1*&+HG:EplIG'ɏJ9gc4o}3Y8m p8(IP-O\iau) - wRqqqm[|~ CؖM$X+Dc6BhweS#ܘlTAISRIӓsM d֘o[X.c,6QgD&cTJ!k- x2)%@DDqe۔E|## q3zeDQ۱=(dm)%vIgqqMR摧4%R, -٥"*LcLBjB(uBa Z˱i4<~ʀ@NjP siI{uǀ:)Bxܱ^3Bi=ô}5R ˲m;^T*4ܼyckkk2AJM ,7c#W*lRYil89T{&J4I!HR%1leL;p8/e65~R2520,)ro&IqL43r'ٹf(SRQ= -HO)ƖtdCɼ?thveH92b k;>,Ec瞯bɏ/eYGNf:ϳL=?}=!#sr=9ID<7z?soƇ`<nXtQ4M]WqtǮqSҼ~#:Σ]7>ijFC2aff7qt rQ_:Kل me9L5$ך,ʩ>8'SY[l)ka:铦)a>V?eqjpRqp:WI ۿJbˍ`"m9udp 9 jY̘eOCs޾–{'\fƘl~(/əq'9227~t<$';c<ᘔ'}j /o4},7#U~U:=y: '9O_S[pPR`\vL`m;n`̓ur Y&M5IRa;wH;/7X-A-=>.~ސ%!5$Qи1bΈC]!((G7Ia{iǧe!=vcN_8p, qI,#tV9Y#D=GCrp%wdsֵWx\ ﳱCej]F* xdre|ߣŅ lom2U bҠʣLJTjuf#^Yhcz odz4lR*`9Jf<6xfƧ$o_KSb}t>ȷ^z>/kL$ZܺP;[kُ$Y^p=r* KK !_4\i e@h:kϬ\c_|w}9`v,##2"2#Ef9};j{?#}ƽO>?;.J8DDĩU4fuoɓ'D kpx0zQ(Br ʭzCR>Oꨓ;RG3cEZ^Ħ/ri$Wfφ( +{ρDHZqh=lSXh w;RCIFS*p4y[(W`{lv,.̳v(Ti)BPi6QU(J zvX %Cv\jՊŰ"LIJ*TkUF!Ԥ8)a Z80=SUv{uk #Eg,Zs }8╓Ir"9nT*UFU*#gXḷtUHGItQ&7*q,0Mrpj$FN"ӥ.Y d*LJ2kR):E_V!qH}z4f()e5`g7VVnm?nᄹ[4UnZ^ѽɳco-cr͝.[tG6rI*~]֟q7EY77amsҺ/|Jƒ&'uj ߠlq =wB!r{O֙[l[v6;:k./>?CEYrsuƒ/ w=(=?Gwo$fuq 󘟟O1|iERE/O/8^ԡ=ZN9>Nrkgiie#~5'8WVIdTG IDAT t8`=,;1yfcҢ~?L|S3;7G6ad nŰX^^QZ PUy)@(*jUzjn*S2YZVxC'4H(*c{BZlҊ"̒!PT 4QQmۄZLeʏȄΕ4}a+D>zN!IIa{.alJ28$@vCQ>Z(rHЈGb@ ^jRPF@aQGPe_gzZr;.j;&~ls tzf{Z=ۧb- TFk7޼k^'/Xgt>7XإŰ5X,.-鍈z۵&d2bg[o"T6מPZp@RmAAgq{yըߥ2 twX2Nfk%Q ֶhU˸g$kIGO8ky}E K,uZCvww6ZDО y~?cxR j*g9_qK W?W7:Hub#IJRxDW}9ju8 H$3ȋ@ VXk;F7 AVzA$ 3cXEĄQUPkl岲BjQTTRZiđ~rp2c:b~pi Ir&bHB:{>GcSRo%SMuNq,*<12mT 1Ig Ԧ d50x1,J9@V,nYs֛.׳!~g#$ULFCӳq]0pS–Ip0블+e&/w1>A,ٽ{a﹌"2D<>ӟ~p0j2 h4GȚ O?~ן>e1t{?CMI2p=ǦR9,G?f]S̭}SDf}(X[ߤaQo~~Y|I*t_i_%GzK2="'NA9{]\F74~a^(LP_p%H`wh8NoK$8Gkz:6Q*t( Aјc>k.38f4i>$8IP0QUef jdUW*֟ZM<ףٜ=+'̸,Ue |ty_i+h ^Ҟ[\2pnYӄ;iRyN d?I TUk@:ڥiօgkbq)}^"c4;:~WH t̜|'( sS;̮]`8tCabOVCߡ럎M$!00:rAoJq'o_iֳl$shcO׳vD9V?22x`cx&&>zΝ;X%CӰ'cNJ+$I?EpPgT²B'Sv2X2@u\S9*eM#cr[_YƭیGcڤ5|TM[Dΐ."ի@:2Vl$df O0k=Yh0r!K"d{Ho_^:ns vvr;GKܾډ2zE<} @Ѧnih%MŒ>3'T5:gXzV6gi˫`^7ךab "hjLʁiUIB8ZB3-|Ϧ>lldB$4g y(N(W|WRI*$1n榜Apw;{2 ģZQvp?E{In"@8唗J0r8NW%1N#BӨժ$3te:H$;*BxnL`y"_C@(Y?hYsr _hkj[e { uj7Tdvi&s9 ͢UVx>\_f#޸{Ͽx;Ĩ"M[Y96.q<)ʖD)e?-KaM@/ ^9suM%&iID$4E MS(&㢪 ~Ԑ:ni QTZ.aC" ~ Bh*bAGq[3"BM2J1=% &r_%@X.s@ꅝK _!9"Ҳg31i4,EFnŠA$gL奛(zp\-[,Mܼ7&eMjW^y&"TTK*Yaiufn%tzX2͙yBgssZf0vXm17?O4szCPTM߷Q߹3ss3lcڭ6/a);8~Y`D«Uge ^P_5n,αJt?NFTDՠZ2z?3ۻ;23b~nP$g͐w s>N 2iM7XIJ/qe}}(N(, CALs/r7o2vޥޘaiquFc0,+5(I($cJf)KWUi5!qh4Nw/8T͒ؓ{YaLÛQiYjhy㺽ʳL.8J.6IS>gaZijv2Pf@pċ u5~*ndx|S\o{x wvhT-j33t:DQbUS=^ %M>—OyݧRPk$xgeڵ[;[ coŸglOXx죏赫S2ad8s %,PeejD-B6~ɨj1#=~9˨*<7awg&3s fgwz:NgΘL?uq|Kfj'kܾ`#tl&Q Xƭ7yt;7Ww &}TT곌{?Rqۨz(xl|泖 aHjX /\<IuΠr~@Y̻.R_q抒$ VrBLxa{o l guey$qx& 4F Ax0r@$3~RV"p2")FaH$$IL`eyz ]K%lo Le'j,./aQ*aUyDs͍|G "{z1 K4gjQBRV-1Uaw2"*jmS\B0!1R)OM lm?^k]]K$O,zFuMkGQ A0@ |=W"RAHoT&>L;``<3ۧ\m{{(`0 m?~L#<!ϜOyg8%FGh2ĝ }9G./ t_v6;2Gypz}zݴLUH!?9x+yH\QT%unWu /TD(&W83P;cxyWc(E34lô*hGtJex.n`UʴZ3lnXb0 ŅʖŐnDZJ\h1cQT'\X`繦IYb8p8dҲ$"AdyAd8vDZ RD1C;CtàV3AQ'VqF R0 ,Ue1Ln((L~Mu_ ă 8^]zH4ͼ"\*LlO!"y ۫l#JgHBoF:V*/(j*U"qQ/#Xc&akLN:ӊBu^9˦u@^]r"<> yt 2QDqv)[e ]ew{.0Xlaz.biP$JP42pb }Fap0 MMU]w/9~B$x]&clμuTd: '#8!bvw  \"ZYʢJ쪥R^0BA$LQ c[.Ӛ#yZC2'ywOTU} H?$C]]eiŹLF5iha88 _qBGg1DyUNjS«`=D  ?$;9K"󳃌0O[9sf-H YSD 8!7Lcv6QT%:aL&<|e c<ŒԝLp^@(L2A^eJ)(.lqM0P]Oi}߿/jE"HzhqQR4D}.J(]sP֕V4z4M˙ABzݮun?Mpv"Aq jJΥ*"Nf }V!_f."wsӯTPy q ]}Q[*>m[$ AfB@rqaA^NE3U u©D)y]lV\ ?Tq",8NPHzPA6DdF3(SFGNE@R^«E0Qk(9tL΢7*% vݮuymE}q͓N2"+Txt?!|??z:_ph%4UIK@ UUR@35"Ri)TA M {Hx9 3kJ_RU5JV 0plX}㚪j-( Ea d0 Kj{i`zY5w c:ֿk|ȍY^*eC!eaţ/)I,PV !DN8"YH`]P'#yԤts$|s un_&}bfN%Jj0})Z{|q-" t, .U ^"3b*U}8B+Y$&f,3{0N8`%;&ϸ:KK$qik5(Du{lnm% 2>FqT4 ]'إRĕ l]JƝ۷ Yئ֘ayq8`~~RrERRU]Ex CTMu@I B$yMEz)j =;;G`x$05sť8&B`h*Z&QU2B0&#iA0hW 7ٕcWL<#LE4zҁc>f]vݾX+-4nI2"#k ?2z,#j pN^cnM2Y9dA@G̶ڴ J^gX(JPpseDTda&V0JH#ɐMvύwR57-T ib:QVY^Hs8UP6KϷLUU(ivDG!l`s.rPhfA?L t]%c4-$[[{%b8t u(B,!-BBH*B\Gb}NE:^D a:ǹh0 ^vݾ.TEe#Pf>%"{:+>?g E:R̿=MZ6 ]y_vmOpk&F%±C (U, MUU+5C330w84P@Tzx 3{nǪT)[PVUH +Z0B TԶV-#H_V4Mz=FcUZ>~DHHbC*5!eQը+ȟ0(WU H@t*2QG1pP25qSU q* <5Q1p3ڢv\i!(Q}FY:Mt/cjp*TnנjZT*\^IR^^sPJB!.v۷oEE"A%;V;&yN~ݾs0fNz=D Y׹uMO倄t-gJk?cx$8{:gɉڅf)zr yk.TS]_BǙ NAB{nӷ \f~ri -dS-p.MU.N*')0qRq!P48$s zD 4-\g>(΄͍ TqIx.(`j0q=ϥ\q UI* @ n QBj e&L`yu㱰ih&(k 6g}cgO',ܤըa:O?:&w]:]}1EZrFM̽ű/tTus℔tJAG$IBEh1i]k@x ǿ8G!fȴ8]Pdkie2m#VNAPi2LP!|~ 1*.Fu ^W (ti0I/P bR8/<2O?` ΄( 3RBDIB9騊 ɼ"C#I8,Yۈ8dgo F~ IDATL\akk+ng᠗{!2:x8^~+#9fgɞ)JTcq$h`Yf@1rJ\tWͼ@_v sk%su9if*Y϶IqkmkB7v5z3(<x2,%m(%p4l8=?uF$)aȋ E$EQn=wMq<٫\A)hMwd4"bDvpJ-"<8%NC=[|4MX08L HbH d+ ZY"E]nfd]_ğ0mzsE"!R9[nf.Z3|ȝ8N|ϝ˾AaW.34T> /[ÚI`Ymsm:iAp { L;7XF/x:9WE\ m̩T3t..D!eYNatPzD Ri 4zhe%HZNfMKlR/NKazޔ8aS*c $L)ST B0̔u90ZMN_W׀z~>=eY祤(t^0(&?& + 0'2t󹾾2y˂(ѯZ՞cb %C*YxODB\2Ghi;mkf`AJ*5!cZ6AV\.*8.I:^Q̚QcCқR%z0OƸx)Wܹsak X{T5ZY*Vߛ0j5*2qNUKkwug`A9pRgM4E%JD"0u( S_h1I%>%(]QJStslg3(Sp`* ǿfa4(ka* ۿFӴ$/jU eXεǏooFc~# uz~cΝ;wдE\TI:ARz"n?}pǏsϺipggt8!Ҁ}]~W=㤾9)e?Q:W}N??GdnN!`˴C(Wj꺞2 {~Ruc*L2Ӓʼ:Yg\*yA=n+,NH۞I& qh!=Mnڙ12]wNfgW*9{s\*V {2ƶ'B*uvvV*(*jgi!q>Ph4L&&N818h{El'ͫw]|E ,D؞GGIDax<:gqHnSÐ5#cןah:ADQ')3tatM'PE8!N|E':A},ERI>SFIqU#efnnFm3 [[[躎O//|Or(@-$)?8Nh4__s q聼(_/J EZ>$7`O^kT"00 j~?gQm4 ӟHEi4"}0E}?UU1M9,4sʹ4ֈCE|SjFQ\4sAl6iیc\O>Ad$}A>oy [[[8ç~ٜSt8ȺNZt}{MeH'_8 cq]>`*JT954F>&I>g̩JvM\f0PVs08Oot]77N.4e!Ip=ֈ>u)Jy_y>e1V ÐO?*}Q&HJQҦեE466oQ.Flllp-&R)wH3yFl~ m|;gq4] 8:r~]x!yq*LvRII3̜tܝ^??ӧg690daaC/D5EA$GKK-铆}~a()ۦiĄѮ( F8 T*e(N([1333h4>Q#C?dZ^#Mi2"!Zy1@WD"S 0sS_Ҡ+sC\@Z->:Nѐ>LKјJ,ޓyܺu ]8 ÇA\TSZl)n7҈'IfN#tfgg@jxwM؅aHET*ְmj_+mv! <%j6ܺu UUve, 0g2*333ythqݻwsN9Js.Q] d1 Cm;7ƋNdR.y v<}4%WMӘl2B>;;_|1/0 t:yƍCNZE}ޞJ vs'2 8i4Z-fff 93 #amy[0{eYw.,,|>SF lVrH$Aj|{> t:ql6sGp8Gd`>.vQuf8$?~xbD%u QEa"vGl6I$qGָ}vg)}eB}GAԽ5jQ1 7o~d:a,..SFA21u7o?1S4 x1I|:rmwJ%V:\7e \] J!D(hcO04e4T24#jRܹuaCVT[TSà*VB.qI!jd%R Q'>Q"րaK02n3ӨDcq\0ҘaqizihJFDO-e`P cUpsuZx2FlV-̽+478fs}![Q Id: l\Qu_b!짒/zweN]I`ną,c^u;^W\rc-h4뱿G/tmvmwK~^Dʨimf8Lzܼy˲//X__Zb60{"TD&~U;ݾqv !rgV*HQVcww7…aHܹsY>Sr RTt$%QxAYmWH}lll8N~*siH:rGhA1oV/sT*嵔xkeio}n˿_*򈡌Jut]Dz,ɣ[[[?E4{S|:s>ww9=b8n)H`RtxHr]$?f0>$"[Fy}}=ooh4ѣGy`0ȣȒX'c,IqGoݻwÇyd2!"ZVp_OYotxq-2:. t]g0΁0 tEn޼g}Fɣd r92j(*D1/?gYSa?~__GGZ.:"6V 4vy ^ֹ}q'ӺLӱ}gqaN)UeR7qO":x뗥(_?MzE ֑B!{8ԫXLx4Bi`:**I,E!t@UԔCR?L=Q(8 њ@Q,Q1j.&O~HŲP4eTAynJ"!Rf8]Q{N)Qxe $Qf'Uq,ȂqCҋRdz&Ov51U n@ϊQ)%&DOZ9F0^V~n`E2K2fa&f5x׾.EzWV{FM#*#6LnzwaiiԻw8&c@=i?/yܽ{ViERE}tGݭb&/S|4MY]]HS. Al4 TE}ƍ=)h*?I;wU󵱱1P6QJVkFǼ`7"֊hz*Tu]a&/BQ^hZx7@GB~)ŽtZv͝;wzSշ8< `?-eYEcU wwwi4X/\ݼy0xׯ_RN`*Y=__!}{A`ar5}]:ɊF?m4|ߦT*Jamm-0,"j[K)A.nYVK BnlooGG|/~"m)NՆj}{[Y__lfbyFw֝:O*Ji d&3E^OZg HG!NH!n7;$EJu:t"d1avDɸ\4A޻yO]AQ9(1Q M+GAFHqz4&,m& Z$IÀ( 3,DF?<zt*5'"h:A`m)I/]$Y om=~O{D7="vww-RhWEdj8 K& zsQ(xAH׹>Hdyy]ǡT*嚈/JGTAz K(_K_{{{Ž*R:mG>^y YSunu*DQĝ;w׼t݁'>KYexm#/˼5 G}OE>*n~Q(-:jUǏY]]-pK1u~r]VE*y;]LJ?bjS?;7&:Q.)yI5O\eyy‘`Y \<44μK1֞7σ,4ʳ.g96azpRplߧ ^y[oLU;j/EʿN766IR*~O)oV’$)MEǭݿwe~Tjt` /|o}[lnnd3 8=$@?֭[ɟ ovQj FZ=M\e(zAEO?Y8T*h4jF=SK_ zGq"j5k/;í[<7o_0,NJRDZgQ,iΠ_ h@WOB`&ЌB]p\Dof ϛԾڹqbZYWo GU"M1L 6n|J˨_*"K=|lg9A~10MlB)mYq|T_G keZ"AJ4сS)PiXA,0mŞE&9b -:NUC}ZVaH)Y:THuC /eY|ϧ2TJdZ(^=y1bӯ v]"Mqee`-2Pniv>zZF&FXVklTU>я(=Q{ @ [VG94TGNo|"ʱ:A ra`${ntx饗{.jnU^3g*R#opxxXDxW+Ez<Gz^8|gggZF,HzdLU$Iԧ>śoQ,//, TǵmǡDN Ncqoͧ>r]*ER]_iq=n5.("4 J)qRfz_e|:5ڿߧ&(0x)Eىuؼ~L)H>vH%!y]l xͷICH$cEvbLWp7}de':  MV3`KSkǹqeZO:kVk<>>|7n\c4[+y44k_TWj.~qud##!Ajg?)qI#o~z`s2{NERag{NuV>[[[ٛCs6"{63Na0lz!FVuMƬj]W:HPikBӭ[o HuXrI'QTwZI{'g?css`;p[vRuC?N=JTT.t:?l6~۷_5/_ܽ{w>r1=ʦ}su饲;,7?ȝ;wԧ>UG?W~Wx<3Nڣsl9jU(PkE $K5ƴ?:I!N?6927Zܾ>s(J8apPɸ5c(ts9\ʯ:JIDrBTj ܼq:퀔RbJ㭇gaUjo@yűmdq,r-0DYTkUJ%FcV5h1HףŠZ_ŗ^:<&1KIշY@㲰9A\wY,;B"E@JatEɀ \N"9.vXjmL GrZ9 Ð@L't:E*Q#:Ft?ER2 0TJQ'h_ MS~ꫯ"ݽ9vt:(QU|ӟƲ,zEݒH|ЬmGy;;;E@1Oޫ*/+++n]T*U{"m!SRwu~ӟr=* N0TZ$.IjQv*U$Q>pk*etar0"lWnUٶ]D}ߧh qmܻw-~`Zo]8eYVT9Cqj7 ױYY٠R)(ʊ=צPTlE¼@c`o|kll\3-ZQ̳ٶCۡRB(bg{}" 8?&{D,1 ,TS]mpZV'jvE4P'7э[EHEREIRUqssJrDܺu~ET\ACR"j|/"sz 8> )4M?>@:8)u0>?>ȝ^9( 777vY΂@4Q^Tp0#::upP^6Q)(8Q/Pϩީ@kdY0MO|EZ_'AJ~̯JA8F!c븮ˋ/X)!tixJA2"7D2u@7\ӢGll[2i]QME}8RJ;RHPN"7iPUzI$H^\\к+J~@Duc[ܼys Qha8MP*NE7*7nܠDh$5^?i֣#=FJӁ$3q `0 Uƻj/gP`h5tV~_ȋ(0wgTHU9JU@TNM2>tT^7uAnݺU)"™&=VCQS TVD<< ީN3i B5O@4[XET)չ'1&gG6apQO:4Rzq_sP\:f bER8$677 ¤mX^{&%M~Wpms԰08{osZ^Q;]OyG鑽W#x7[1 v9<<O5T5;Ìz퐞:~݈eS,b}@öSS/ew{83rvs}/ue9E 1xoY߉u>Q"4BmX8؟wLH[" TFihw2` ѕa$ QӅT:JԅgYfetft9݃{]lkk=PO8t.*B8x=X9JұayCz(!m}yM(Noѱl$$f3t 6eZEqEo5k_00yB2! ;{92$_,[H@8썜V ?ꨨNp,' GG1J^z;mGz^e!O|*W)ZEh3\ky// Ap&Ψۓu@h4IE> hcIKb lL {ӆ/SbEfAH4j! ?RK^u0LsX&9O9+ي$}&G&c8&;aRVID'>&vH4`eH)v3Vȕ\ۢtPA8 HVqv}Z+KKeVVC1kU*U,4 LLBi@%qAF,"<騴XR'[t|,$M)y.iX;MK̯ 1'@@6qG,޵(M¾NGlwmr$Q)4hA ZVE&WA0 x^npQdPtx\_ _E`B@CafГjG9 xȱBr iJ߈cD6DK`=O>k~LZF4 TBY!"D~LW0r08w;dD#YV~,;P&v 2 eƞ0uxHHb1!gwyL.{A.$=z>Jmiiw}jU (l!RI#p2GȔvWP2+>$IV:pg]FQ)iWp(詡|W\Ev@52 HLSv]< <6:H:Yu@i +@k8՛̝f,@(<#83x/>~>ܣb1$:9 r-=wȚSEKBh.rMQc傣ӥ@LGBG?m&c)z*rAvQƲP3w䨾زzp3"]=\CxV2b!ى1'=4D%P"#y?ۧ|7 yd)t9(8iPW 2 #\Zĥ=EŶ$Q8(e44g b$'0$3E&3av&r,~?axZFRJL2 jND1i !%լ^y/39^4L>}ߧRecR\+ӜWkcZ(ݠׅɓ$ljBbHK(LX'\?t꼹 B aM鑆(J-c2SuV$'y#M%D/zyEauP}~E M Cb"zj9㻕YA\K0LƌY8׆QmΎ9r "ca!ADQDR# 0sӂj"x:38Y VVֹeXIl($"){{{t>ZŅ*%!QH1z9r:ىoh]vbVO&ANp9huv?޽,,)yi5vq^Yjwfcw?^_ {Vbed,i RmZ9ݽ20-WI␝1~pqn&$G}ֲl߸E8HiP$nrj2 Įgxh0%) 2I0"XNо|s6g49VUPyƱ6Rڤha:-a2z~~r=m8bR罩k~ҘRе4T<5,lOiiV)J8O"5q< 0bNx6ߜrTIsw9nkG1gi*J4<|R 8fMuSO*s^?-;ܥ2lk7n!>N +뤑O7 5ڭ&~iIW^dI ZF}|z T9 ;E O4M1LZN]0+WX]_gZ\,$MR($3zTfqy$v\mnܸs7x!x i}ldiq^EJ%0%t]FQ9k-,,p;Z$|R)){+eDb$H O0m\5kT]ʥ ¨EH:jȢF邴D/xKSIq8KR;Sהdx3&V=?O˖Fm˼DC`&jykQz3TjNQF0)|u9 98S`<&1ȸPnb5O[4'#:;^Cx<}4nFAhcq^FrퟂT `0mvZ{=~2f$AR8R1qE" CRYF{va@1ɢcEZH >I"evqlrX$QLY=$"4( WqD <E<i%D^pm(rlfX8Y͓.@QHS& v ;됊 (AH^}<LbVR[IaSk]mgXY__R&w6kņՓ9)eLshfH$:VW_㊭ru}=ai BdN,3f V{액U [ D)J6jͱԋ]'ɀ*a6`Pa|3i4dҞKQsppe9J%!Og&Ch4FCH DJ( L)wd ZN)Snu)I:eOE M6D?̯Hbt |Od(FB>i!QgKÔRuz~'* !"M! H)UJ tZL&N%~GI%XEǰldI g8ib($am,D^{;ݓȖ$1;{[״{rjUy,!?]C,9hHc dR !d!TE^˳ GH|}?UiZDqʣG[olmRDTG=I4R*OcB҅aH$Is^Ȍ(*Gd@qnHf{?fs%̜nYڑXʉ+gyͩEDm^ ^u>Op֭#!hΦCxi'K=vteΛ bs^cO;O{eL<:2$zɅL3_Qc$5|^ePBriQT9X~Wx=aNzWQʫymQ쓊tXWUO`?-p (+wR4%cYM $,+)ꄐv d!RcwJɤ'육WYe We|$PLh{kj 2*T 9y8c&!%iX3 C9w0H#%Q|n:bReYfth:ffIe. cxjY M2a{%;%|S RɏX&TKqHHWq,RL`YWayezI>A{fJDhq(=:z}ݹWF(5IQ"eJբ%JK`&,,,Hv%D (0Y"SiXiYqDZVhÐT !,D1Mu=.Y *KiK!"e[_E4kl$)&` Sf`gBV٬yO2Uv $)꽤C紆t$8ZR.{oʩtIEx&EzM @"{smzJ6`)ɨXz¬qN R\m'&7 (7_SLP8)iCp(R0kj $rrJtrҹu]TL gM=8 O2z/4ϗJv"Hp2Xz'KU`Q0 (I\LcwvJeNId88 }n42z8"3ى> #nH!%Ck0lviF %a R !v8`Z$QdO8<qL-[ڵlpmsa 6o[*WX][`5i뛛~'1qc+gBj̣GHZmۅ>[VGhmyym[ضظ}) m=qF9/'O84+ֳ^cgS҇Q/3TFfpҖK21@J9!D g%fat]wHH8q8t-+"FQv`Y1kܺu##,>7wP8̜ktYcOO3@|"!^O.;YDP)|.=|89P8"! [s㭭bvzbrֵk0j> Y*H 0D:* IkÐP({%:?/i:;\סni:DaH]Bf՞#&zM/,ԯ ?S(˘M'I-Nܩt,"& IDATR:,TYa0FKL@V78 ;1H<'Kfl4ab[BsڭAzTUa<7۲p]H('(ǨekUeXAEx^ZKftfZ{:]q-ETU,6E#$!gt_E@f58p۶Y]]sm~ꫯGE+P5( Z}\Td&qi֚u)iM~l w4i=/bJ)$TQsE +B%ϕgɀym'L`)= N}}']j&?ӯiH,*/er ^|En߾GWY[HdDz* l[i@zz6OPhO02OENg7-OeVr(~7j#Ձ `,t3pĶڔUzQ.e*Q [\riyx, @ȯ[yc{oITkUӄ(p\˶Hӄ8Ii:ecw1st]d~T҇_a[&rGin8t:)+mv-6Jt$C3NJŲC*Km> )ykT`cc/| O>o&.>dgg:~!4QіIߦaݯNwS: sn=sV2YInhQx%=ˀpCe!#R:#`aT6<ϯ(@@Zڵkܺu7nsϱIR!ct:J(Kr|={?50i㘈FZd矸rkOu6\1wÜ)] 2vRp"nnG(Kcl(",WT]`umZWd'0!\ U~9RLӢZꬭiej X ҄NAAR\O粴 AT*qh},a0 i61-:xK}a8X_htuqI:RE@` HiW拷ci7'ͣi@GRFQlmmtp7YXq-6vFAߧnt}0 laOd 1ʠg3س=5|bF<(dgy~R> ,\Bj5j,..SשVJ% ӦqBH%lj=>J.Rdb8YiO8TfZGPm>9˭38ik[Oj(&CXGU+laeejărAFJUL $$"=#H8d ǵ(hZ JRyqQ)KqSxΠ9nI:8B*(FGHc^O\^ӔTJD J. nafaHA/M$9`QHm0M(g`Rx޽B^)!v(IJ$diq[>8& gFje8u&n;8u[ x t1>Ib!Ӏ@'8Ӕ3hœXUG6#:f: E$+ T@qN0$^\" bq<_4L4!4M\(Ls84c V'T2E󖦰;$ +0xHe41+ $05 fFQ+~A; #\jG sKs$`@P˲V8Nc!tM~L"ҋgwvϼnG7xmҊz\}eok o#$L3ҟJP^jn64 (q0, 'cYVV^c%3E{yEGpE)fo&}7)3kv)ÙÀĬ#杚" V˕nV A\6W`DQt{p pի2%PioB]fN J[ZA4YfX( ilV6^Xț[а{s$YD:NY dD  Ⱥlt`kDs7@WUU7"jY ~c<¬̿d!LZT&i rmѕ=\_/7f %ur@x|oP@UUJ!`|mC47͠\.v;ڔ  NQm. 8e/Y]^22f*? OPy pC!&`~P0t<{ 1 G2\plCF0FLz6 S]2 ` T&Yg8߲,}PJ^FU!/(n$bL8p(@xd'x :.2`f )@F-4Gp*d;`I-| 0fW/r& u@b؄N,x|>eI%TFItskz&tÂm9  yx̣QҵUNNh,bZ A)HU* PS`* 97m]ס;OUաQ?^60} Y&Ua۟-`5eIuQY;n[@,"T'܀x&yXc?7(a?*Q'1OS_ׇ[A$ &5Phxoh:[o(<( (Y{`f2kh#Z;D!Q?}ڋa^nr/!(t~_!= AyT pՑ&NI^`S 8HERP!MUP9F2Cp9-¤O~}<ބR7LGE%,;|ڠ'c̵xCfU -‡c6& TQ!+ `D $A l_]7QVx DYR!"TEBwW]7 px *i1㞑5t^ i'|BH%PY>E(@쨢yO{O(GCF4Icpa6#{^! ve/8aRf j&zu*|KV-)  .qsfauQ\^0J[G-(g/IxMCcEJŹ{ٳMY[QPQJN/NF)[M.#_6@K.YH!ލ 8,zyY il~$2zh`mmm244p|ъ0$ ܓB 1zTb8*;w!9]X18Iz G}I!iA{Rʒo0J冇2APaݻ]"xRTg+Jk4(Jh4$ zPR}~dx˅\^`灯<ǐJ+J8N5J$b{{ CZ};,4"{+ FA)JCƁ$}>.C5qoɚ'ҟoWy0LǾgu +o?ο^z=q=AAc5x5u W#fTe4*H5aRA۷4MȲ 4 ZRN4 ;`%4Ms_Fw`w|2vܬDDATnwZvrr#(%|rpA!B7YᒻǕ_YYix!VVVk\ĺn hC*-S1!(t_j.eY5 496H-<>@W* 'cqg܇Pt`` `XՒ WA tplx kYů#A~"o88k>찪- @J( ]2m۶KW_^`KSJ穪"TZ,$(* kY eY ȃPJ'm֞0.Pߝ;`mܳ(I;n^OygoTBVљ&puG?~3,-a&,˂.h`0EWQETBe $I(J899At+ 8RkẐ?HKӫe fϿ߃,)VlC|or닋u&lBtȊ IqAȳ|ymˆa,..nð(J4U@j0iw ) 5H>Zm4qrx X+>TH28D 9W+,CUԦx1DQDw^ "rP .Hsx @;0(aBs=Gn A࠯R#q ٘VJ)gzBm8Vt8à0Sy(O4g:4փ4&g* SM'Sao%NxR_ pq0CIU!+c0M~-DY(xm0pGAyPPz~  7턡r LWpFIqk<}yB/F@_dK2S?N窉#碿jgDqAas!Lͺ*)pǿ?1 RAQ3kI 1xH$nwh?/w[u.p ]oq3`>0%˵1MQ ["N~ 2"(rjXAB$'S|{7es}VUA'0t_}nܼDx apсF)2 {+ Oē̌A[*Oӯm IDATȀ `2 ޼7;g5h!fϻtZΨa [b1DPЇ ⼿[ĂBI`^)sʍCs08wGG]DiW#[ .W0ȀY{ er/#֣vjW_}f?Oxӟ9={UUQ.0JZv+QBF $In(.A'w op pTj x{2ڝL˂iX@ TBy APiyN$X۸77a=P 0M+eY7\44PX(4i+ ӭ2]cz,# Mg K{?=ܼy%oUV2 p,B@A{Y0OAB=l ߠw)o$Jdh@\*c 6/ <<҉MEw ;1ҷʑl0 ,(m(Vi,(ItNe\~??__ɓ'/?;;;W'J2%X{7; VvKcwLjaiC ^m(@7 v(V fjsZ6H0#+u) ah2'= R ? |L|נ{ AAF$$>6 ?d'C0|aHWSXm&P8AAQ^NP?i!d<~IA}лL}pO^?=ނ"`|_x\r<5H.ދ EѲ,nNSޠC`QŻヒ'?ch~ T,j8I֠{Z.'w&)/OK11Lxta&DItQd iBܻz@vnSpi`l?rl 6akT2WfC膁̀o@/|/8$1x$T9`}@)`{'&\q ,KzƬN"DЃ8}Ӧhg`XTO& `pz(h4$ rR +++hpvvVM\nBUUr' !Um'Rq8 $}G>BEޱYdoCVTeB7'+%\RInPjU۴k}$$I ^|:&r "֖ DSU (IIǕ3۸qƠME[G>K䜊l)A턜@z,A?t;8뜈aC%!*A8KZ1<ɷgw` qcV°\ܴۗ8+yG*Ih &4()X5H)u]aX(wmvw[ SNhNA!x%іa`dCV/Js:jQIi;( *nFf ~ 4M[o^xqd^a4J5_ :)h7چXeNiÔ$ y. i`Z^ZUEkE#,&/`0vic iT朕p/\F3mRH!@K2$YConw:|v:ǃBAaT3Λr"(`_5kxCr*Or|\B @8ד4MXz P!iګ9M of^Q'r~B )dBi2FQ)S2h '''k7J, c /I`c alp<ϫ:Wg )a.,60oE;e9M;;v_/ChKQ罨MomMy?~NP|軟#|ߠn7wPVqA^YO\Ġc;$ 3P_CNXO  s/1 9 GL *2,(Ms5\'WOО^y;}x߿j.XCVE E4p3J5Uưy,Tvյe<}(|<.F PXEg hܣf%J?GeRRZu?FCw٧={T~r^.#Jgqקw;ҡ6]/!}.5>DwRԨyI3@<KA- "ŏ5O5 ZBÓiL1ljCul={~=syzN (Bt:Ԏ(z> CBWH!SJO Rc8;kW%mmͷkAA4~8N o^4 QBLBn rIynZ5ȋS;y, cln>+ڶC0T6Li_*JWEulӂmZA@YQAm "Ѵ$Ȋ ۶EBT*ؔ`6ãCWDo{ IV>S|嗸/RŪD:~aɴ  ո2OztWX¹샼xtex/x'[4x À,u=f:vAæ,`j aLsN'M,,^!b8N|F?hE$Y*!B( Ȋ ۦ$ R ˲<9W_g0_yj5c#-pHj`p~uI+QELWqg\qB:0 (>c{(EBضݝ csrm[{_V{Z\*w~ض=_M)RؖKAZbJK;w8yG]O:,38 "`R 4._s @F>o5(h޽4uSFC,L1GEމP4 [CāYeؖv}洡蛯a[&t#zzS1- nk eQhUkʒzNNN`ZkNNN׮͛@,` 0x`,@Xx ܣ p9dDaT(JԿgVњ7IHis Wmې$i(_th6O!cVdc77 e{4M빿.4އ Ln Tc5O b!(Ϸm%Hn߾w@_cﻵ?5Ph\꿬ܴB:ٜ۳IpNcJLReŪ`' IDAT1KTܨ珒(!Q q{ΰfAR!nQy˰):&(dE l>4YVܹsz{0 uܽsw\mY{8RxkcwGœ'qtt4v놎>y睡2\޹2+?-p]x mWV7IqTx 8З#J{ ⵣ8ƵebRTfԹi¤ޟٶ TU;UdUŋw^6VWjBVDr沤(X߸^d ƿZb 'N5VB̢:d!S#| $ᥗ^{DQD{c OOO'cuuw+:,UW^F<;h2&a@[NGw\"f|~iH⤞@\@1E-4l6}Jq||  z_iYP n%#}<}ޅaݣ:o Zch4UFg,:9Y)%V˖$ _^{w۷q}@׵M?KXYYHYet^tׂ0~-yU^&ݫ:C8 ^8ay__Ș DD&X(&G"F'~ۓS_gms3wݻIڵxͷpttv39^/QoBU*,k:E.Rx1I4p\NL95d4INa4Yߴ@~4X(L%q~+W REV($$IoW^ye&Iݿ`[ZgQ bg{@Z^ 9೶z@$2:b&eyOM:Y%\|ۼζmX˲19{YH! (@ kR^|X mݝ,Qy!,`EeHQQ^°G)uSJڜ666&eZggF |ibºppL2:#o (f>)脨%cy xؒ(ڇD^$x `Nh]rt D~ ~67oʥ[<qq<ǣq43rAJM2>|~fEeeHC5bRv" ZB&p'BΒLÀ(\\΅ߏ {fa̷B{ًdmC-p},..~z=ѣoP.7X&;?קU&d3$ꟼƗpae[Ӹ?wp9QBC7}J׮]CZT@aڛmz/2.K`ooawq˲`-Bo+++ (JZ]]Ûou11>~'/>L,>ΜuE$/C !+@a ( 8̨/lc񼀯4yT%I!-( :@Ӵ\ly 1Ce<{ f^{{{x!dYv70|<RȼZmBj.IpWohD]'gm@,``trPp&ALC^/Ni6O7pQ'(ހ)uX^*˲rEQJiP%v *2Jܼ<4Ms=yyGBTUu%A1m_E|/y Jef_OKH;aq#=~I0I>]IcE}aa Q u|P״:wI+tdE?UU(Pe^4BDQtȔJ%,ZFA 2DQ,˨T*T*. $ eEh]]]ҒĸKY__ǻヌ^_=e@0 |7u~  Y/hC(M0`2ʳ 'i[BYomFr19r#(=.<0F|F{e&1~A_olQPԈggMl=}qtt#B7tj,d`%G3{~{R)eLq$m0M<kض :9𚆒C+~Rׂ}OOOVFoa/fi[{ o޼Y?#B|UP @XH!"R^@R0bVif`,f899iPTU-A¬_D 0}$>\O"@/ W^Vu=ܰ#l=y9@¶-t]Zg(.Y$U b;>>Ɠ'qxx߃eYXYYA\ܾ4GրjP8m"",rA}7?~yC1eYJh/ëqVqRa4Mlmman z [EQ:~B9(sB =OJ%֠Y`88R,Dy#;mHZ6duQz}Ґ̴xAϺ)P3XF-H5bSgg,t:,, Jgh_6ǽWR8A47a{O@s IX[[i,AXaڋd>UDyޝ 0 `aa ?i=[&S.Zt]wCJqiT}̽~7oO~ƛ_~~kn )dRj~A}2z=`ggGnx?/dvFI*Qy>d璺" QNߟ>GF+lۂXZ^kw %j+?裍% ߏ]>yr Ēx2EEQt@۶q]Efggg.4M뙛\y(OE7G4aaaaZ[D@]o4rV//k{ѕ>>@o{>(/RkY/`.nl /ƵkװPGZ(^GzQO&#AzOYu:!VVWynkX\\DTx ۶$y;wċ>& c'J%׮_GyJY ''{A\r,knllضţ\0WQvU4t=jk&IAa`/UUq jGR 0: "t]/aRg1 ^XkNcyqEQ\p9a,6AV,.-aeunvPZ!Y0$P T*jX^Y2j: 994\u]᡼7n??@Z'|ۤiO<*onbueKXXp֡4֗˜$ai YV\ B& qڃ8 fjERm,.-W^Shd??o1@$g ۊZ Ni~%YFR2&q>:[NOOZ4΂i&tMi0-ӵX*Ó( WV IΚM˶^(W*# ܾq(jH)mСwpU j[]]uvÐ_Ypd]4# ]e4Ʃ:G•U|!2>ol6S`?<8W_=D5,XYYE@YV ) Āh\4R t~ɫB$^o@T!ظ}!E1}P3kF[\"ҨVw!mVڵ j ӴP7m(/`|ultMi:y|ijP/3 )8Ji~p'K+yڶ^c3 íi}B'q̲g}Qh߄mOqzzi[mYggM([O%,--auq kջw(\zO9yr~Gy~ӲiZ\.R`qqy߅9**qZ IDATLR6[p7kIwګ\(*(t/8aUڹ'M%ȲQ"3 F1N b7nނH=*A%ݗ; }dJD9~%Ϡi ʶm{=lzx9j$~~o,(c8?1onڵcslk`tp&0e 'P⻐ (T .;oK ^]@W})dYvJs# / wB.A'x*6 aiNgOPb7zU-p5 EuYEuvCCj jظeJeJ*D\DZ.B/ro0Ĥʯ߫൒sv Q\_U=wҮJUؠUB$c F&|0  XBB !ZvW09wLOt]U=}9v֍u1SLJ%xKXu===`94-HD0{,$)i!WYm|>~ ]y GS)TSE$&'&07n7‘MU)ffcaj>54%*}Uٳ3B˞TݧI 5Ӑ:-ފ@S䭌CIqQx&$P,k L@qihT˓~~$qpr^)@pEBzQ + 6l$@Dk~6&H;`G^> Xͯبzߗ s(29A!133 #`y/(BXJx @'[oK(W}1{vFA.n.-apէub(Qe0_ ʪ<~?Ba T=,&'%0$j%m_jSNjS[C``"Zj&JϲQª]V/jBnsQiOlv2SKYF`^g^{٬~y81At 4n7(+ JA</jA HA3̖wjCm~՛Q˛ ,FڱbjJsKtMM (R+]\wKbS'Y'B ¬)^'̉#녋ttXB^.42"J%$)XpHA`Y?{/~?T]DGG'(_&o`Fj'?ya=py9 tuv!/z>Euuwan~^"bbz!tk~_rёrzwQgggОJ-|z+*>FH$82'\MP\3ia# Wij@ުgy~bvwRb~%.Aik}5JCnzYOD܊&"Ht[aM(w# oñG159)PS9 thQ'ҮY,E ϵEO n݊$S57;:>~0Ch%P FF@Q~n- Z/X,X,~|^oZ}677T^(ߤ T|>tttb֭8}4esy$I`Pw@..g%::0T꿑]n7z{T1e]cŒh1QD0:A!oʟ)!E~3M)4r3Q&vi f11ܗZKHiR 5_`ۯ Pǎ ~6ܯ loVlv (e 6<:7;V7Ɠ)U%$<.RA#BEi>H%8dG]XeJzcqaCzVjZ Izi2"  VLCi@`4fEaph@Or( A򣻧G*Q)Xf)t >~ߟ>XwOg>߰O~n (Lc!#t/A#a#.!h]\Ĵw }u ӳ3^aT*ax".44"(:::N#NcK$eYd kOijYߨ7`;3} EEg$%<5j g_W(FzmVjVr-p0m q΀VS.v0xщ˷o bјtJ[EWwn7`lN<}_c@y#~> ~5kzi-P(yx B;0=3˅bT'E,C$5 Lh2GzZYYkg^Ŗ>%׏Rf@$P(E蔄y4EjynUA4{̃B#<٨PF̙#7A()44v΃XKio 0VWj@he2JZo/]ѕJ/sg+6/32?E$mpŕWrzR 5,nyZ3MM3dY+j z a'ydKQn'x<5*Ty}Jfa=,,eYP%Dy"%k6ZD$T{͔DhJ[x "Ν?bʪ kҏ~ȣͭHX%7K9D_^oZ9\$x@Ā$@aJM'aJH'?׵z Zf "7`݈b79z ڙn7O&q :zVAwO.b;.r.,VY/EmuT.gp=Huʂ9> L&16:O##] !ԻffcU; 4S^":.,,`qq>FT8VWV,vm-oF#0e9#[꘰*([5)Ṅ=&*/fȕ>܉՜zxN-fǍ[87sQ"µ8N:Quk~CjNjXϽh 8sV,g0>>TB \{|ۤ?}KűGz7 rxc H7:wU _ _<ٙi@ڍFIT#_WxyMӈع:wT[m>3zǏoxn}뱲ã?'$Hfy?G^0TzzJ /YK}fgv^s-n~> ?2VWWs?oP/ ?||8Į{7QP&='8.; ۅ+o~seQFԮ@`0$QjlXKX (p\`jP  EAV'Oqr{"b ~DFx 9+ mi(# Rz*iLuY@PufH[3&5#7w&T JJFS0ۯD"َ3gN3g03#!I=_;dRù_)7ux腊yg?+Ǐ㾏\ ;z`CC"O~# KO"с={hƗ?wɉqLNԉD:@WK7tPL:~3A[<4 yX*,Rd`Zm8=VƷq۷R?IHRCHpE6tWVa"*q"*PG`WUx ]%\ χ1<16:@["<0o ٞ?8xi<( wn\cxljW㑇ٳg_{/}E ~b\ ^:|X ^lx>LNcO\f2iO!ޖx ܏~ߑH$я} x~cճg`yy .Gλۅ=u<8,y)7T_xp_CƛnQ)5pp>o}]ӧNG?xΟÁg~[oQ= mTK >"O>Ç^/JOa%C4=#߿Ij^iLZ0 9>5#flwYH_J@ffض5 Ԙ`i>? ᑝyVFX![e ?*T__zZuկS#_W#W![mG$IJ?PgE *8kp166^?AغwްCC[ Ax-f$rՈFV"N|އ}}O| ^xCwWwp~oqu#bhV{85u= =x[&iP7!\;|y= w#B0nw^~Zc{[k!QV{YsN~Mo)w=ꮸ>?7+?rEw݃{n@(B(=7eSٗi{ޅ.( ox[yg/Gvصg/B0߽wxo{]+=q7:::AQn7V 8}wލxo{"3u5VPKK(A| ].iSбRTBZ , ٓ&CR4LcZ7CUQ҃ѫ_<)|X]]^=;5"H[yz v. `|| M=>B֭ꊚ4jkZ˷B~Ffl4- aKCxqkv#J!hΝ9 ØKϣT*ZpkRh󡯯o|poG"ק&'ϪOj7"woZٹ9lꪚ_y̴n0)BRwOoyȮr94tŕ;LM^gWwJz7 n((;n(wvkϟ(d AQ|evAczx<صg/~}>ՍQO`<&q+سw_'ʁJRV*.14 X%혞S'p=yN(CWV0˷%ƫO]+I@{őIct.|?:rtz}".IS,DC۶t/A U>}X"wCZ>ĎmǍH[]v)x#| v\(ʘyL&17; Ai\Vxo#:::1:2, Ƴ`~nB "iܿ_m%#G YrsG7^K4X>U{c97U<Ȥ3MӘƳ9ݘF@5]cC#!C/<<`5Ք_SZT9kgNY:x _|Aח^|O>8`k ,~S54-Lkó7YѪ 7kv f'Fotr|zd;$091ёac!| (f108dq~ ۞½~/GW_h4}7ތ1)u(z8y?oov ^'yɥ#W,]7܈q<4|໶{-p^CCp-I&ωo|]g>ogN<5O!{ͷǏ"J/ ,-. 6n Q,r dT;(QB)tt3gXl+Fb1D"P~?Ks@.kx`ԄzBc<S C(QK=A"aqa]CCaIJ!PZV6,,FsJJ$P2щ Lazz ( }/={ߏg#/!$yuw-bj; wG?yn\}nfyS%2/U|i 33S۲E ^/*(z۳L8'' E1?7΁.F10Џx,) O-RwpzDCE+3$ KAj]H4^;mԨI1!VXWj:Ϫ9 tE0,qܮΝX(ԩ(z /ڽǶ$׈FCE_*0mAeF$֐١ar\{zUm+5p̉Ch4ybbbc#E.$w@h08W=G^>g~v"v'F+C0>kc8ܳG~_whUzrjL˗+4'4_x;F0,FQ,!Dъ2:H f:wp-Mp)?Fa~EByoI9^󢷷YBAlٲEW8;(TyUj"0Fz~XB} C02 Ra @P@0Ys+ǑL#N#˩ >}:aPL9=ړfLiy{$՚6tw !X/ F米CC&rtk[nseL$I" &'N#]BX6JELLay9Y  !с`0TDJ^b8ԋ484˛fٵg8ϼz g^=Us_gW~uZ@!Ixˁt K@)lGz>ٹY~c$*bχ4<*Սl6[c2J/jQJ˅N;WkkDxS ?lލJwߌ9|~ R+R#`0C{dҘC&"KK( QXB \8n>$ |TV=v5;u4͔o'd= ?)WDqW[oԳj @h_)GzH&@@MADT,bxdƖB(hr9q]AӋx-B'hT8x%񚂸NN::;$z#7(4sh|& FmtLF&N-r!BlLt9d2res @4, < -@Ό&iAG &NyeWˮp|Ln=N:T( "]T7O-@60[# d2EV0 L&P8 T%I󫘝Urk |U+C_sV>@{Gr+9)2" ~7-fr[4A`&P=z5} bU` w8$D z#j].i}yG]oLK_Beee `xnEI 8Z&韏NQhK$?@P(`ue . pe 4 +1](NjT )B!mS'lw.'jYTf_`s|S!4Ryvi T@%h$*D]G('%d2 Wd+_*Lf>Rz1qHt =p8'h@ ?wJ~of?fibɩpZ_Mݿ s\p\( HݠiU`yyKKfX@%  $!EVX  en[B8A4E @H:#kTwvm|w=0(%E~ a|x$mf^&W?77^%(ʔ/f5AiF184(1%oÖ>## )vӃd0OBT2iR tMGDzʁ_d?EHhEB+ژ 58 !PASp~K}Fǰу´ i@JA"=!wbBҕ\N RU E&0`h< uż^>L! rRu9eoiހөrNwYb^ 3A,C<?ை B0($qAi.xbSR(CLݍD"ih~- " V#r`<@Ӵ!(5@ڃ>V>ͤ!4Z|j$ҨhNfHЛM n[ m^9)(Dsye\ ϕK|^/q Z>$z=~=AKC>ʯלn|ZB#NG> ,//cY$P0p$p(Tv%$awKiߐrvUT#316>zz{5Yx[&f*r ݃p8l%5 menVVV <(Z<B[[J"rVr9KE`0$IшЯ,E1 mFj>2Y ADȯi0e%^23Z}36P>jYe7`j-`ZRWQ[+J+]̀n=YcgE$MF$'deӁOx9a2}Ê~xe2ԫ0Ctq.XELO'EdS+jaZfDP $.C,ptBfOqjx9{&ޒZ=JɌ(ס͝A;J}cI@J*N.r4HZjLr2TBFzvo՟ϯUA^NXOzu%tڤ!^llJ7li[>2t &6k|5fm'Je+5tZZ`t|3iivL7'bϷ;C$~h䥲C7{M'#zdhрsk0y@_3=o{q3Q$͔j:ο]7ws% S?'t SQAu8$IFU"|=L an|6o]僨7? $hgUmj]{`^eFcPxslLbwWgivNԬ|v\NDR'&jg>izk c~Gzˬlfkt. V7GqkT> m0  vIl[ 'YiX 4\>tEA}`_lxmNv@5ڵ8j`ߞ""oT'ߞlYG˒p4@=-\-&KٲDRjYDDDDDR`ϰwHض.ANd%Pb-{ۼo+_0lSۜ{ؼu4h>=6q芔yQ;7S3K:>9OD־nϲ$_x/kؤ`i;[T[Pm#?(AQRDh k}.mD) R0͒<@L0nsNvV09$2o{+YG4q*Lb+%|ڻZb[+pjMQ;0 zg7tVbj OgJNROFuH~wGZZ1o˚| f˱IҲw,~G~QF8=R^n[T9@V[%ȉT;B)A$ǬB˾LG]%Rx=oi]S8 >Qj38ֺ$\Z [bjKZ"""""۸9-3k"S_O´lJL]ivm+ӵ,C=s `(x \R aHd(~@bozLߘ=|o 2_YX:Z% (}xQ%b)Kl]"0)KKZ"?(9`nvCV(ZeoOͅp. ?k-K-EߑEDDDD1qox@6sxM/QR$\[NM(v[ 'r(;ͅ . E ǮX-u@,U"""""aRw>Z \/ٲtjE۲9;`3khݮ-K 8V=hY"/EߑEDDDD Oy7osSx _ GXg'$eӎZ\DGyDDDDDDDDDp{&d`M$ """""""""gN1D 0WLODDD2$#DDDDDy-bT!r)TdKn0Q QkHH1og\OpŘE)EJ: B=*""""raQ&G{iosL8`&d_!{Y>i1af"|;LXM̷* gz&A@'@`_\iK/OM.mf]{-]7ai93"Ccj).Ɨe[\QTe(io̯3* S?3Ӄ/'ѫiD3/ 'E.[9- )vFAǠ( Yύ@Qnaqly5¡q.8}4:+ 8?43W6pg>?\Bi|*=6폽cq.')ñ#ΉmPYcW/Y?0sǭ'* wbh'9"'Ҁ[">S5>Ǵq "aP3ymj='`́#UچQR`JAXگrX<*aj ^_j<ƕ-?a}㉚?@t;jF輺ǎOxQ"UT uC; 2ОѮS^{m̿i?A^=G1v.F gȃ&ar?}Y95'kAXn!*xR~'Yj_.?S?W|Y?oʧWODD/fA{_:ۿ#w{Sn=z ;s7@#=X)$IPhUe)E`6](7En x5M1( ˊiSd@QD%o(uٻpLJv''T@oi\>_"QpW ˆgl^>Of -HԦVxAE+< 'c_EQb}Ni(Pv+ NIre;eh6hHB .8嗮di좳l nJ^g:4nxRڷ#5*!agF)}98S.$ٳfkH?'K;$tk?_g(>$}* \&퐰#㤚z})sT/KEӷ` WW<^`{!oZgJ[/ -_g8;ِ,dQ='dŐKL-|_^J`,"#sۊ"J\?Wfdkyn24Ľh+ze*.ϤeW [Ve{=wCa1DR u"i|\\T/v_g9(A8|?jmoT~՞T/E.V~xA`o{IKB~-~eZؽ; PE>&?8ĻrYQ$jlYsY%.Pz6ZW秺~Q+?ecE+3XbD((?$e0y(}f|W+Zٛjcsi\X>-^J? i2o((l>,֮ۧu;9=jVGݙ|p,v@I?*j)y!p))/"'5MHcւKV2?ٷv|ˮ$4F4BwȲd,l:X'T]-c\l>s7JЉ9~P!s;9,Xm_oC1Y+Bf[Q&?Lt@8`ZccR:A|.\k@@O^Kqj`Ϻy9:EhvTpJB.mm?p[ÙJDF(BuBQ_\o~u+2¯>NEQ7~.*T턅1aD}h^`ahQ=~VZcPb0x|f6h&_l[kYFW :8HAyP+, BXSOvsz(~ m 4́W71]ˠ爺8:z"קk i+n"Sl[c@q?/*Ƥ/8|\~:!2` .k@;|2 _H Nay% OTa i(.ӆ@tyT4o~h1g|w77 ?o G%䯦MH-fNϱlY}揫 ;fʨ@~1diu.wb^J,_U-o yJQ N=&Ðś(ꡃ1G4뉈-Gp[IVGSj|{'Gѫq,] bQe9 3\^>]z6>DDELZӣc`R~Zjc}Yl.ݬws/E*\z.V  i=}qrW.rI:OaYQ|T~s(B+ J3\1$yiB 6kVbx.(tr_TF a&VҸ XI_+Ck-(s1A聹/,[aj_؛p`?q:`7-윺W@c_ͷ #:t 을91V3"-b0ܺbÏ&e*WIonQI Gx)J?_Ncp}]\W\Q|jrQǐ}~F zcYGc {HݲͥԹB:ާ+y4 \tT|mЪaac p+Jo5B8oo93JvrzF_?wme> -_ZˏjT?㳮cۏݒݯ.s/a]P. ӘțI{<6 #jWkl4;孃 ^yp!K0'(.ɻ;cSD&oWRAӏ&\%!߻PX-ZD]J[ gDj!u/'ۇj=م_[ѱ,Z{D;$(ca03qʏ>F{)6C4c8bm\^jӄcW GWn(>}ԯ kf#ŦsɅUˢlYSxj1x'xX1P#CVbEn5ۿ_ë;.b ^H"A$qʃ'!_5 6` ece8v7ʃX14B1 >D8gKB \3F8ooO竿 IDATSmwຒlgK?cS1买 ˏ?|oj6͉m IM?c\8/cQmd +'kUm’Шdow o{ O^|Wn=۱svl||R~S_m盞gn_za37TurDnq#.1'0 :C`OoPD?gA5ƨr;UOMݫ苷*UAZWc/,L|jzⵞ>k [8\ ǹGn L4ojgg/|;|pk}:-Dztn9AQ%J<?N F' ӿwOKwOn]~d7>Ťv`Q|p13MnZl-к3KBGd-s!bf?ޟfm}FWTNjC{I;:n]m 2#f,2 !;1+%%G>d݃ K6f*Wv> Waof蒷 zG&9tvU}܋sQQ?=G)l;6ޅ5o~.TGFq91/'g=H-Kopg܎ W'g@@/T}&[lu\lQ PQP't'@rr,^JUĤϜ7H%,{m TP?{G[u]OQB; Kz CS+-gK0;i)"{ʧXneVfs1-ğ:rgq%pAV?OT߽w;b5 U"P=LHnçHN8?X[̽`6V66O*~u@"V`PpkC<-9p&TB}VR?~Q2<Ğĺ%7)JmGjԯVη~Q-?"HP;zlN'dGn9jwo>z!ǯ'""ڿn1gsP%ClzlЛF1Ny~膦#J(g |Rr ޫ7KObX5p[,aw/Sm/}-Y"q/q|~q~fFj,QЧ8|} Ρ 遢1+?V)0gBtD<͇ Yy#+hkv!;,/?[=' rri8 Aq’Qݯ֝̊rAEojW^9 :n5\t +X>|: 80+%4i^Y̨|u`;bD7M轊~2|rMKm/-Eyo ;5BVG}:x|1l%@ŤZGe0=߆d]Ȕʷ;*/@^ە哸=_~-c~U98y @]wxWhkfcʂ1"k۰_W?W%TvAh>?(cL~ 7_N@Q9#w>X[!>k6> =5#8>ڡ;:K<ZvB\Ń9ða{wDCg1Wpx2\2Sbp5?f:S`J/1xmx v?g-Q| 8 \ca#Wvq~C^p`^G; ǦMEaG?7XWbMu\4/ 8^cSQ;qop(Yb/ xvugˁ|{(G}:-1i%PFo/av"6yGƨ= v'4Xש)(hU/zr- pG; oBU6[JR|;˧;ac} ?1K.74I>Q`s۱~]JF߿n Č]# )X1PBvj?n}/E4(`0%_:UBNT5FN%Ьc ~!kW=vwQKUs aw{Go^\A+ӲI]Xykety'w -ﱽ?j˷SůыnC[ tv}G}-siq ??>>o ljqGO&/)W6a-ngr >Mz:c V~oQ99|ۈ<߯)+*hAlUZ_}IF@5n?(- C}ni&vv1="UvYM}Y4w1u\N3=J~kd÷ĝyeCAds,nË{%M172Y6@gJ5~k5%%+,%ۗ,dCg"a(&:Vǡ".c NNjwxV%âgWJ<˾gmm(>Q:p-0(eyc((1 R D_2cQX _ _bM*dax#II)G"""""""""҂c™I@DDDDDDDDDDqp`(>Q}"""""""""" DDDDDDDDDDD2e '""""""""""@8ODDDDDDDDDDp`(>Q}"""""""""" DDDDDDDDDDD2e '""""""""""@8ODD&\P~vZ L """bLC5>Ǵq "aPSنB]>"a(d0Q LZ! ݂_AK'jjZbز?p$"aựv{zr瓰fEs1u8'|Q42 5%MQzm/lz~`SEI q |8x؉EY\(H!FE<0J;6K|0xjlڲS>Fz+[~)x{l 6]ӿP=Jkw!4"aG7`׵%ݪEeqF4P$Gby9}S RWӖj.4b?̀mups2.~zԟ<~#Z )ZP8xEAܭ8MԧQoոTsI/1B<;,ܛEu}Qzi_#+~(-,n Յx>rW5xw'`(EĚFgx`c6=o4^ ];iz?~J? {?hjYKVi>__, NJ%.h({Gg:cePG.(P˘cUM#ouoCQ-/@޷1fi%!Iو{``#6|A;Cvdql^tZKi߲l͒>-A'g8'bɆ YqA1K;$tk?_g(>$ޗ%GVKFq K!rRE'NK-G%`tqt}RMot'.ޒBSrPWYA(n|gKh$nK:2A'>EEEl&KWȦEeŴ)2{Qy(yb$(\U].|#CJ3EXR9rpt]Hg&א*~Nr.m U%˥wI#lz z/)^u)SO|ůL 7XV~_Z^sD -9:q/J8 r>[wTpy84l1 :sx)A/KAܼ RwQ4UR'Y :4(ui:D)Qt R~1QEmY'[IEU>_|2"rW.+sR3KF(__'uΕwmE%.Bϟ+s猓Ue)E`6](7En Zڧd E)}_L{7H'~YfV|)ky <Ȋ(Eٶi:vp~oi(H|UJbF_ܥmQh%EESq(\D|uǥ\>%Iu\n SQN%^,+ \&퐰#Z"34xԞ*m68Z̗6~:6e|!okn,;KK繎TU(InVA-o6g)3h[Vקk) Y,Ư>,eÁrp*!dEk3A䟱Hk9 &{g@t^wd~b,R{V?7hLl>s7JЉ9~P!s; \=d\ud%_mɮ{'4xG@{FiKgy`RzQt__@/fOYd}E/QIz*,YҢW|@\'vkPQ?[;I?åp;D*(%_IOr#_ET/\z:2X_EQ$zsE\V?[\VD ^ 'CzI/Iĕ9=t@n|~` i3EM-林h_(E;%;Mll;)ZĹWi=\l?{- ltk)|i4H6j+X!}eX7/_ \,D.+xv0=z(~ m 4́W7ٟur6-vf 8b0do&z`Qz"bVԯϭHm28>^5_KXoD{)4y @>\uϟ%ý@5)q#2/leP&. Kz|75|u/}|<1 G?bidyz$M郷;j#g=:EYiA!1{Y⦹|$uquparG,[U/&@C?˼ѿAuT!~N>>|I"d+ xdE{.#=0]se#4֯be!Oi9M[˿gkFhvܿ5hzuӌS cҗ{>.?`t | ܗ*QBCt g 2rØ=_Vn\ <{6ǣH*)%HZ;z65OFlD1]O'ݴ).u/(,ʼUsgq? ~S?[ MmQ[9|O𨎱 )y{ *u?|R(%:m=g:- (z8֫(Fxm>?%wZZ‡ۖgcJ9Jey?~5w=k9J$YC]Gu.w*d +4i_蠏?eGUP͡4S?+$yO݄ډRT7udH&iV}b/Ǒ=&7!ƥnhuuP*ȏuq˿z^ 8~'u(e|꿤W(8cq$j0%o.eQ`:Yҵ z!"7Z!a>RAHoSrpMVGo:hV4PQFM䗣ʨ$3 E{ʦWRcmX[6Y!=V–)΄Iģt[鈄Efuv}^oΕ϶+]/A!pde"a'KH! ;$"B$R<::2b^ajjęw'XQ Q{HIg3 E{ƈ9$zrmin,tZflk8_*j+'NIC?%{ bYVɌ SpC˾f{ȁ)5fdu&*ɟ:+M/[лe~|e'GdwY/Z #A4-$yΔZ_æ@e&۾Jeݳ$SNixl8vma\湯 9!9;I9F_ ~ t^Fs@VKzfiNjL7JŒiWnk&7E}$ Iʏ\^xM#EIY%kqg(yP%Ɍda7]EGZ/ B: IDATp.'#N+(GWAgg쟟hZ~|+#?RDQQ{_Ì}Vm\RQ-KD 'kzdE/̬e>Cg+;SicvIsK<-'ZOg)-U(XRju-"d޻0}?3 7{XkP5_VI-xeI*giq:?J\bpe|S#蠗E vRYrIՍ<pJ΋)MJ%NV#HŖzQ,_nʼ#}ArOKrl?ɢ3`ی}ٷ!CUtB WJ$DLO2اdYT KBlUb"V3M \]y$3t>.6}+,:;v/ުTk}_pj3Ы__B]ܑM '&}Dto$~\òOZ-h78 ݂sAt2 5ߒsOf+C܉ ٬M0SX5m&tDyOGMiF>3ȕÀgnX:O~duʃs7aعg;y Fxd)J=ܺ~`etGYYs?#=vή E{R UO\c19C #΍C~?ڈ' },w D\Nuw %iWn"o"E}; ҬNΟn) 6\oG}<CƟůmG/>DG,mGMYy`¹8dO"W{/6T$]qq$y/du;깻Hמ$-[0#sBE.5^~r{jd~7fϞ_75OI**̱5'<^o,qKi͘{i)q˅r}VZ8a-D R" 3VuYP[edd^St$w+!vY"\ G*&tQ*:]R;WC<6qIWر6!ZPoǗt!/ghtE$tĄ>ɓlBl O~ÏvqE]dRI P]˂!`$"N3axq{ qH0q@4!1yT>6"j)s'\][ tHϖ'tIߝN#$T]|p7󙺈D%]cInl 8&V:-[' Z".p#:ldTצf߀^?RŻ(h8b nldL dqI1W<~ ǃKC~_=1]<$> èۣ YY'M%qd}% UdIeE|g<3BHz0)$`_FE eݹ$=oP.e1aHM7f=1BH<ufˁ#bħW,%R3<ӽeFhzؖN /B3|m&De&㠥 Y^G2p2n3 V"U_?Eptg΄{Ԕ u Xv?:6)MHպGw??ƌO3Oң;O%,Ӟc dTi>IFY1@D͹B2?M_Rb' Wʏ#/1}G] רOQФϽ$qdt*$];8)k^6e2k//[3) ħl\a| #ZVz@<KUJ|[>g%%j5&jH3F5e3IEnw̚^Mگ5Uol8!uƲ}ȉ> Z pR`^NP>BH㓞aXFJhT(Us#\%O`z_%&j|ͣϖ\ҡ:q{+[9 -6sۃþ^ /\ɧbק+l9D~_PZ`Y=;̭#P{QZ[@iA!Iԑ„$6ʠ0@aUZR'k/oX)VѼUEl{ DmpҖ_}яZcOtu*baLW'K|$+쟶^DT֥(OVae/SsJTgSu #ƵQsjF HHӦ$nqnAS~<"йob\♘c.@e VT>II|_QAoȳ$T [0$ˮFogEXcf#%j箯ǘenR/\?Û_֟I㏴φ~?rʦ;\Ē3Xe!Wx@>~[$]|^c_p>'.LRSNL&J;B%(J.\ XC*zdr;)$FJ$(J+=>_^4\C`UY5{t2 ޻u/ڃyY[$5J TcG$-=xtng)5MH6}Kg$Icä/mt)Opvh@JRɫ#RtҬ$H}ۤc~~!I*g)iT4ig.~k5P2FPZM(y_Μ;*m\V2ɴwFߝon/j|P:5Ij(=eΕv<#I.O 4}Frm'HBݥ^:F_X R?TRjbzJRL0AҀ ~?O% ټQ˽Ojŏ?V:I |'I(J.J&wJe|%U ק7N|vK:fTA+5%fyޑEQ҅CO_uu| (=ѦX%]Gƈˀ5-ZӃ$QJ*!R6'D8iuSҪB$EhS]vY=TTF&/OY!bs|QOW\(WKrP|`3ʬE*)/ڶFZb4d仡(1.>A[J$~I㏴F~L?OKHWƧ>\~xԽYߘ}*-y"JI&zpno$_EƘ /| қ՘o!Ҿ) &-ʼn$J+KUX>'QDQ'EVT*Ρ}p}WO=)cOiNR~NjGݯhjWQ _;Ŭ #uZ; BFFFFFFFFFFFFFFFFF&g"r} Aicˣ ԗL3y9.#####0)BR=>_{N^]FFFFFFFFFFCs²errb_FF&hXaw_lH9'KEȉ},źa(a˩ka?:4]#B8ܷ,/LҨxsbG>:䓣?Y?dd.~Ţd~`8(E~lK>s99|XpQUp갚REG0k7^ZnA]VA*/Vf|o-4[MjZMUQ |~Uh]){z:Ar*lf7X+0J+;ڲ#=#VtŴcia⻖_лqzSgڸA#%$٨EY@?/ztH=ޤHK\=k]UsjMD{{l9q*%8?#߻oj ;쇿>yut瓾z@?|/r&?27-⫿}mB/IU9pc|TU:8w;m[T$N!ǟcDha6SW7)2h=q%Ϥh,FnPހl=7.cd _썻9[flfZsƬ?oGTy5#[kW~3R0}ɤC?3>h=ygTS \{Ӡ44W,t7ԮXva҅7VtW z,*uDmT6ɱԔSɒ7+Ӵ\9&sl<^:wsk[IT̬(Pa6ͬ2+y滋mOf̩1t.C˟ _NcZF)ih67}ha,WjY5VIMh;(}f2+7XePj>{5=ډF68 QcrhCQv/4&oR\V+Jr>n=`ɴkQ 1 ڏMQg)+X5j~[~:#~@ye+nHovJ'C۱]!~ck<ӿOuS2<]P*FqOjnTk0?33dE_Hy;_8㣏3">M|TqI1: jLQL}D"cǺztZ uIO ;w}$"Bw)X l[w%#W^H-$sS儞KB>l9Ԕs+?ç Z~\ 8ͱmhU V:y-Gb^Ty-wXGc>1nf/DS<=>6I)Ƞ?X{m[r(\R g ~x`RsDIfX(3m4/ON]睯m?s#=@?N3໮vD.ḷ_4M&팢jWH /9,>3)׳˛R!U-r ,<1XŌ\IWgBvQx8wK%k*':,{ؑ}g}OzQỽ80slĎCؽ{jotg?)iNL(bb!1[lN:N SТ:UY@=sg 8kZ'7xDSMN1F?/ՔkCԉZ/!SB%9C6trʚ0*&p9>!":GyƵs.87/81z,kKX2Rrz~}1ƿ:>r?w1-Wn!8[ON6A܇' o*;8鹱(w$)eb#Eo$'^ gsdaQgNdS\81_Xр9o9<ɠDž#6_$m,x5ZST|ȵ'Zʤ+vqԛ|5*c?ZGl(tI^IAp4Ta4խ:U41{J_$\kZT5Hݙ33^]jal؄zNkq("-rKXzjprl@>*) =0mGF_?O|//' Z:R3frCiY}7~ g>66sh[͍F|(ZAYȾ% C‰K%\4l~Ɓ~/w¡ɬD=s &qKd_.,3GIԀ6h%5 FFMhX9 9/E jq=gZs~&XPJ֡+3|x(;vjR(1()P>wv;bN|fY+#ӧ~%]ܨx$~Շ3P>,k czu*TFlG>d~\-g{o'A%+jw*xJh,PSnlHR5 >K p0™GZe= %u+Q(.VƬe>0qi7m:ϧ2TMk8yїѫU֯ |Oil7+^ DgY1~iaHoawXE:ECM݌O[.ѷ7@֬DZMSJXhUߒ@_Y?~d(<}8ocWz$dK;ҙ)u\`ۗ4HlOr>dL|GB!04w+9cZbȑl$P&}c +H\eoZ[)S0*p3^|"?M:=Tj s WHBIP#)g* 6G(6LX0-R]<%V;*Y;^ Xu> bp;I[]VH\űh3uj2Uaڨɏ1{+W9y78MUoXsDbe̎j=5ڦt#uGrv "i?j$pk7K2R4Vh$bE{j@P'$"ZQ}݌эv\Li i[{p\8 yJ4>1fT7֖6 IDATivu: { ftmGzi׋Y5AHd z< gQmC93vطp$t>Xz 'wwip#S} #qhbئ$pt !VS jMQSD-0D%tm&kpg \NO^{џ/=477`G%tljE>l,O.x!R0}G>o֞n,`] J0j3)x 0ꨝԷ*#տ.{P˺SfTuD~H[{pp;iֈzKNחtJ@ FGp~$O#&!wb-qQfl}H|>˷Ą%3lR ?mU∌IzYDxg%H1"aDcS > RkpVP zZ))OEɻ"׉D+yCǷ v39۞+ .DK a,He{h<`FJdz>U9DDޡp%4VEd gε3$)N ;C}([?M*$ExuuwK⛚p̺3U2~J '<ҽ }!&Ő$`A:f `۲7Bc7Ѓ}fA#0-leufE/'"i-%c[}PPELxY5)ՃqwDI^^ђ̹. ܄f9N #6,}uq$F /Mq <ԽZ:cwRq쩼(wfܙ{8e#GWmLo6&e"Krʤ*1dqhʮL\<1[Dj^iRH7RIF#Ǫؚ ު4N@eAsS:*en$5J^ܝs"ȼK? ;fv&lLԠl_J zܤ$.ø .l'޾~;$C_Ίb#H (A}?a~tlRu??o947sU*Z>ci'Itk2e<8֏,V"E&s7(9`KAlwk˒jL)T6]>+sߚuOQK5j|ޮWx,_^MJ B I[s 5U Nz-Aa*/^P{usU@A!ڋ%Pv9lgFͩ]5K#Q#1.%,>dW @y;%ªP5͇,7cfܵx/n#Xy &?8}u?-*noa FR╬.އ;Z0+5Fҭj:X.l7u} (H"QKGr wM)0-њ>Ms} Mگ5Uol8!oM]K@iA!Iԑ$Go]^AaO˘ x&&jLT)W>r߷T._ŧ΀ѧ;! [&QTV X}Ϫhs+'i/,Bwj׍y,ҏ],i޿5%T]99HP@ ~+x(LUI>kYK#Ї& 1`Ck x-A/āe[Z C??p= n dcv{Ac"@$bDw\W#ljhtZg |ۧ%n%f׮D_vnatFeNR1!a//b<7ܤH_~7lt#(Q1Q+EߘߴO{{7T ǽSsc׏"?.vXX:Pʽ?Xpe9D_?s|^gD׊ ! ~'qʘ;i,'ʶQǝ#K4$ŕ4Y"9]I"~, BiCEJ wLXL̥F/ vSpH"f.sa,fס ƅKH{yZ1bXکw*l}rbو'Db Nmdyzj+%DTF"!8dgF!%g婉UV?!L֜ڃ=F57)À5 jk+̘!$ty2 h.s蟔{.%!?׈w@,XjpvP~{}ol{gl"[=?:MkF>O{?eo''?g^#9'|߭8g./Cvf95n &bR&pk83C쟙h{8N_ ~mkv:“~g?0Gru~s9=oGgbάǠM4wVqV.6)D'#U-eg<>:Ao.h1'ɰU(s,~0_i j1qnڄ}s!$y|98 TG{W?Sn&hNƢ޿O0 ؛!\O9K 1؋#Cme̘ɹ 8t/3F_F?'6sy> ]ד^2kO?^,V> O9o`蓌?^(I=rnidV}AeG3>e͸Y8>@%썟snMGcB/A ׼h0;8^/7:|Քw2'B} ^H n2BE_Wgms9|EM[Xg!M0edr6"|s# r\"########[sya8"_$ho*UF Hϸ/_A|.Naߖ22222222222222222y9/H7gy|""mȯ] L!/_FFFFCq:ϟe_ˆW9~ɩ9 Ğ!Ÿ5s:{=4Erg9l`D7m[iDu7LBq|A⹹E!jIxi6W{s;:[<Ũ/*LpB/nk?G([Өϔq( C|:k;M3՚iqty ꚴ1cVw:`ViLm=?(O9|6k"Q[~AZ#"+f _3G41O#Ԣe)XS)fNblr/_LCe^\c7f%,>XNfv(%NK(pzTM(w2FeTmZ93XrZEjD=~%$PC5Dqi?ȅɎŘ9 $v;Fʒ_Us)K5 Dz@i?קOכ]`dD ?-SF>>טq8ȜA g_Qcbh?Z ?%?g∉>[e5\ lWg[濸=eKM-(f]0~]YpLq.s)JvS k68 sf[^Ѭ +3p?=~D҈ X!D88=( TZkq1\Z#!>t| b=[SX'tIՈR$tj-j<4J@3׹z rIWὃ^;쵉!q(fw39p|^8QX`a@X=Nni۫=FP"t;=]|l|}ׯL亘YU *g[b|](_r.C*T7_i}q>u*̦If0|w lٽ>h涊Kd;cl)Yb!J񺻂sщYlپ=^7!Σ2xi%-*~pF/%Tu/2F6GUT("r~}H TԨ`W%}:<'般|9_|U:]P`Gx<@J%)֯Vr'=+TL]LAjwrS.)\ǜ$@*[ kU1z{|:UsZx9WOylh{e>\ldXvLρ :!/K kKl[]L2t΋WQho V`ȱZ<#9%P{Q˞td-?Z|<͉8|ON`UPAۻ8m1=2ӾeǢ1Y=< 11SOכbyk(>eв\RimG)'.՟=ХKUΖ[]Le}oXya؁9浟5K׎ Qm$˖Ᏽx H 7aY236_f@ץԁn 8=O1b .GHff8+|^]Bԟc^?e>n-wXGc>1nfF_7ʎ"Nzn8$ }%xuX)؞oY? HK5|w^}XpLnyhK)_4Y_%0;oxI+~0?$ˏଠDԐC 6uJ"N R +p?:~^B8EӎΜzl/);}cb:wkmjl&ijhauO/Sn8}}~H8SnlHR5 >K p0šsSt7_KWTҘ!(!eT æ%ktEZvȍMxh^Dm&4לso̬R8r_բJGΜ aڱ+wץ3SBй::6-/iZU SEvYP9 LQѣn}˻r/xǽRA rJ{ O`#J:hak!9Zwc(zZgNWtuszUA1M5%?)KJ!^KVrzQ\6Y˼H̦WVY(=BWĬDwxĊ^B?(ӿ0["6ua؞a=JψċJ^& 9ZIS_s>X Xi$5 6(`G-U4; P+)#2 iS]s1WVS}iZaq%TEP޸MOzUT g؀ynRmoOi SuH".< K)5{֧JR|ɴq/#M'׊.$?a&4Rv#1jal؄zNaȚ8iJ [3ш9~#-fU(sZ_fq|183shaWd-LNTQ%xzq|2vL鉏xH+~}S%kzG~ A$Lk Xj@p$yθR?2y ylN"یd@>ov\OxYR?'62/"I: <͏kt*j@o A(:sݯ)j HxLIJWTZIfwΙ4-.Z/{9PT1G4Rbn\7VNZ?awU"O2fG5ƞqmSҺ#l9;}YshW-} p;ABÊprw&X |_0N. AG277`G%tljE2v첿:dNѮH!" aj艏b*Ƶ$ʔ?4Kk}3-A;r-=¹p+$7?TX1^g%[ҧU>0DEQnZwDPR* $KDuz )LAY= *]Ѭ}6HZ֖!hl8\~ C݇x?B¡ta>/o8}l?83*}Z0&jnjspJsNi@%@",-RM/> P" Fs?ZQz\oI;~<ϧu޳3.,pNsdF֢u:88XT( fpQ݇oU!)[r܆{f̭֝(pZA@)3X)%n_8Cu(_K#`S%7YpnЇ?FK *Sg?RlSԢwK@J$ј{;݁cC iq?C2i߿ 7cII/ˢ^BP)(M̜Ӱ0mH՛.>,*S }xOseZ  *^AU+%e(yW:lѥOSi儥Ƀ݋DfDaR(؞.mWX(ޠ$gƈH̺ #Q׽8.Mc<'?e*U*HѽJ֒Xb.qƽPFG/ڨbU $ԯX1> {—os7 tqaH$ aZ V"'GIh\~G'$%!@cym6eTZ>%FrB"6gGP (PPR!B ɩ}<4);cI[$(!tjSu ЛWh#¹\ |.89w$2%b'VQ{F*FNih--wk71ٹqb%7$|߯ s|9y9f:EC~DžL.슉$qN ',QٴP\*zn&*HdvkÝP.&WI,W4ɹ+},aP!4>ɎԆN-R p1%$aD#$41Ԁ,?L>-)a[#lz&z0-Ivnػ 7"LgCS^d{ϓ*i7ƀ}'Go!^k?Q|P;V&Sarclv$flgl@ Ns# p}:pr)@v_]USG^??3M3hyIT\د€3 jMҼ7${6ٳ)kZ~Q|Z?`,P>@>:&_M-x(HdpW^e)i|Ƀ_7qJ [fΐ|:^a_ӧMWLp#0@|st_1ݫ2VV_3-zKӦK]8kml]sIqq4iM>hѤCWr-)OlJ>(;5Gw^w"dߟ{EBIv-ݙw|x鎏+!2^(sk@V}šGncEc?x Lыk+t+C\ DRB2(&\gg),[&@EsdG0c8B6]k1r Z}}H*fg?Ox9Нڏ*܉*3g2m}ꖫxX4PI'9tb4nOFoFQ>?叆wv쁸 [ =p:Q.eyߓ?)hήrF~d~4@ή-%Bv7Q'#Eg;dႷ߃ 92G~߰|C/.\8΁Ca$X?eg1`4^c&MnF_ԉi3Ső)[j& %O1yUt0$sHco dϖS!":g|10-@ $F,kBj's7mcLakⓡ[S_m?w2;tHuYUB!B!$]<B!B!B}y vxxrRN1@6hCcX[A9?jQR'˂?R˪w(nziO4>2?\i2_D",<5]-Z;3AW''̌K)fxxƚ t:O;P]kQ]Ix3J{,vٚ)alDw?tnO|$OI;4 NlGG̚tT}58J2Q8–~ɬ<^Fjv01IwD UM4,Q\8qaIOp-/g;Z&%>DJjT?e?/[P79|"tjA}c}ElpM~wyݷm4Kj?2ߦC!rq֍yt*IrsiYߢYƼ6p3y]lk?Ā>J4q4c$g~/dBg[S>_ܮ$*s=2aIy9R@|BLvዯж4:K&H9?UkQVyu&N||d$qyJjy)ςsj3X$ fJƀ矷iI}v[׭kplӲ!Wᅼ˙$qwPz'%^*f Mp3iǍWS~ƻ]%iڬؽw6* )3lRT{Ryjh +:w+p序sC.El2+f/0-.dhVoesmt ٱZze.T˨9l 0h;+&ZV}]͊;[%)6s>Qa ?m7p-Spj>_'":+܈3Umwd4a@n8gQ"Hfa(d Ns=;o;~Ȗk/kdqƒ}fyZ7~?>h*lBBN-7i:w\?V jvFvYPoٺx?2s~Lsqf<֕8G,.{f{CeI|d4'61Q|u4V)S],FG~MBsiKN{w~K=Ny'0WgZmtzeU 0½rKc;{f_fE< q9ks$'E!Fw, X;y$xyCY<< K(Gޯ_5 9-[^)bgG0MŲ!C;X. >435HU5$"&^L&nX8z_WIo"F*55¾-\׏ѳ.M]b;0~Iغ 7OGdTyVZm@թN.kVk [Ws`޷[光|=BFZ2fuӶtd-gLƃO:aݻ{?\-םAT&j>{͊ =EaS%bc*o``nZ)!,YGb{T6G?2?Bǩ'1s:n^L%Oj`]J]%x[m p*՜w[;g _8X"_//`7KV, =i4?HKq68MeK Rx&I<7X;'6omQ\ohzG&ݳ8]ˌ~%2<?RdY[5oz6Gʚh?>81+|9שTw(ds19$W#8w)'.}s7m#ɜgごNǗ:ʑ2>M"Xt@s 13]YC#ʩ)|m73fi8Frg|PT]ͿZz,O˜ TmvA8IAWcN1cIK5ɜ/h$?1{(:U1PF -0R}׏%*؉^Awv/0oL[I[Am9FŇIӴvBƘIC4wG/*,a6lT;C'zJ|{/%v.y%4SFI+S 33 D,ؾF F1g4o,!xt) ŃrLÐgD |c'm}b~;#`n.meƒķ$Nϸ{34o~ۧ`^r`>[n<॑ZF[RPXt4͆xmNgW;^blD)@%őL&@8?wTcJ9?Rdՙ^{P#r%]eY|d4}K$.lZDž]0+aJx,^F-mx=b!%قBnls[x3ߋ&E[=qwVysijNs@%`DKQTu4 3;\<$TR$^ `_{K \1uaX$? IDATTuJS:Jq-~{{R-9mR랔BB:N1D֏Bq6]4w 7ŕd .m֩@n; 7.d_yEg &7wmZop2`}S gG w,( !%2QǙұ+ ,@U*:_a\MTxW)㰚GOgFCPҎrbhx ;|1GK)xtTa6q m^]y8e%̯?O{^!D_4!? n81|*b0C˙9\Is/;SsaYH4)7#'˞ecs= l[iXʇ2w|>Ϳ:gc~@H#Gְ+E7Kq~ N%fa|NJw9*>ABrgqp:sAQ=@h(^{ƥ޵eH1 {+׌gtU>Lq7P!.'W ,@Ht?J|p\AlTS|uj\Mt4 $*.Wia5ֈئsGw&(;D^}ߩHEtF5썀=c@ SħX^t0؃W%xk.xѺspOG\uk'^2jGyw#`¥H5H/KX=~zTI[o@s|&*`rkI`Wmw:Q7e8z'CB$NvY?f6ç+f %>K w4-Q׈s-Mw^Shj88LͽOvG?2?Ba28d!uO㧗3Ię3cgl_ ^n8R/Ϊ)~D~Q71aM DJ؛)T0Yv`!u$4ȀWࠁ/7/fK 5>lmf5ΌـR}5o{\|uj݋%nhbMeDj:\ heiVU6r:qďYZW;>l|d0lkEZ~89{PIr}O(Tn6]N3>C(\7Ҽܕ> 0Js۵o+3.rS2%:O#>#6|b.[ ]@.NAJ~x4Dn㑟zv-Siՠ g[dt-Lhw52bJQnJݍ˫J)MPW^?s`N]to sd O2=E0lK$%d-:`Yf ט lwW8u"a?ʤak80Z<-Z?L~?× !'ٵGvq+^cja}&0߱F ޿d,w$\^˧l_;EMGK&FD#/S|9[QIaWKͤS EI\ۇn㎓ՃW2bb-FXAPbIlZ:~v?≝?dоPټ&>37n82?:Q.ey_MaȞ|9mH9ºƱf,bQ|\~vBy=6?+Glp-4$Wqx{fװL5쇋1Kgɗ S'~x&~K祹0NGz>;ջ`[s,et~mO(T8XV;QSr@cs^-qX}C QcaVXx!RĻ숓 (Ho.F NM ?& !B!6&s2mS.DrOc_[²AUl!B!O=I?%$\ѣ* F{y ZG* +ibXut=_c~y3/WtCL-n)bt=fvs:tS9g>Yg@s:~-e@5xvfqPU vcjėΝs,]ewE[ Iu0NquhzgU)5 ؁E+B۳X{xux ?anuu=)s~ IMc!Z{qo?kHas淒K~)BQRg S,wņEB_gWn>}y vxxp|Sa vYឥa]m+Mf].GH ?r %hB!B`Uqnɧ ꯨ| gr*ftb۟U]rsv(~W3&ߊ7rCS wkHx2rχod8Й 3kyjZY4|T:5ߪPwkè# ԯ-$-FIZЯqs:,5khh5k9NЃ*%|'s{xȩm9k__i&;1/+Vt5Тq=w9*gXc'9Ӧbz/?ϸ`iŽٿr0 7+u'ԋ\ Ϋ>=C;y%,6N~_E]9(}\a띘z=a䄙x~Ёmz*.q=w4Y<17Ǚ5W ŮRW~0#me;Sޢ3"91Uvf!ʱ`dB!B!r>To u'J?*erR F*]߫)lP87T uG/P Q^mukX*Ս_Fv<i mF/7hLF}u.+YZxW{ʶ{Eo.;|ѡ4R#.Q%72b/[R3 3:+Yx7IbQBV_Hy"ӻ.b(C\ڏcl.To4u@Enu\kű]]:5Kј}D+#y\Lz8VN6Q|u4V qL) !B!Y#Yqq]1 vEpdyC]^Fӽ{ww!#WP>)v`*ҸDžsع[_g6G#"{\Qk/*cwzœK^q5p/"ϕ|fW<&[M:bO6MeE`9v:1Z}„^\>3q#s3Ѻi[~2El|NbS=|? ?4pտ"V*99'1s:n^Lϳj5uC~Pvس{?6LY.1\O։ dLv1set6]NFŝ;e9W7jó}PQ +7mŲ淕W1cq5iB {{6ah~^xlXqivaS|6w|[_ozjO3}q  83O]sZ_Ne|B4,Q$hNqW$ !B!ijY<3=ֻޒ1mtWg\DcWuBl ?}8qz&~6;(|qݻ5:d_6pPA?eN/ޞ}GTsNᛃ/9x ƿ 4oY(ƀՇ{}Lyyl>iR/I\f|[seb$%]8nA{.ɦ?&" ƴlܲ[ֱzk䱘qOc) O)\Z7˴~N16Mg[W$ ~ QܚBr5nchEvؕmC /pȝ W-ˑ~]w#d8{#~ EP 5_N}dUn|>7QyFi;=W$R}M<~\*!B!i3R $=}Օ?RG>u rq6펤xqc9EF=*4. $b9 ܐWy:3* Nd/bS"T7Os)gogoԣg<ͤkG ~ Z @.݄ģ!7lܲu</o3&J~#< Ce}+?[ܳϱpfr1 #F0^|2 Szs {3/&=Kj X,)$&=\9|,XtaSrh,v[?};4D̜?s2uS$iLr\?I#A/}OW Bɋg#pz A16hw]n}ME.?-ŸQB3?z/sxvw7&\TY(_w)%qd4}K6\us.ctq؀ghiFs,M/v-迏\İfV_1bӜ5 &3܋RY2~h'2凜i֧%%4Ly}xrmZDoFJ40qNsWz)p ?y?`\J8fpؙ h!;ٳ/KX=O7!uO㧗3Ię3cg++kiEzA&}ʉ+vGLWy-gB!B!ăǿ"}r|~ohր9|zi-&soI#X;y;r7S sC ZW~WIX]j+hU>/)u'oT=P ]Wz`UlɳuPQUSmWq:J{KP` ?t]WS[?fQ# +o(]ՉTl6qggz5M%Tw[=)uIyڵ{8 PSSjYP ڭ6.6,|ǘ菕joP <8*s5uvu((@ػ\޷rf+W{*SZ[iY}+{v+w4i̻ZU_/٨S;cZpw~1G(fC)RH"E)R"͉@EwONlx7K@G /;k{St.ggPkKS7/w>M,J~m]dv~#R 5%PE}MMz5dHyp1RX&+tϺ):.S+RfYOYɥ*|D-\ŶARH"E)RH"}EZi>+My {.uLm&nRw1gS?{/23'Su$R/Ƃ[bv|RHy)gsT"rG)RH"E)RHNw\X>4bџԻN'O̫ <%a+;Kf07uz:b !x֘Kk< e|id!B!x0MVl[2J{+n벨 ~bMg4m[_e/} ۱޽/B!B!SVrxGSL G#_n'RNgZx`5 5R?B!B!Bq?)]5)r/-.w{z߾hڕN1`}7+X/:>~ynfw ;Mm{*}kf/mT.?-dgPW3Ӻ3 !B!B!NiwgX_ \xތ>ov$^2*95Y l^{}9uRz3Ƒ'0>Cg`41 aB!B!B+rj>3moM@G !~3@vz TŎ3-˜7uxY`8$?׆Kp(ȟK΍%O]Ξ72od[J_; n`P,gqߏ9t_֏}v+֥"]Fas`AY1'r]}4ǪAynȎ=xYnN$bOeQT}>̯M˯R~߸=?/ydB!B!xHia.;|ѡ4R#.Q%7M ڏcl.To4u@Er~Ź PcRBuj4ߗ,hw]0F?&H|9o57>g kQˈqc|3EڶBы SQ_fK4% :oj>yt{ߑWB1ZjJiԨ֨բSE[EUQ{bb^8?KBj|M} ^hzʮQ!#s5m?I$D"H$D"H$%h}ШU-L?hY)q!Q`8gװ!WtkqL Qgزqi#j0`/tKס۸eVBs8zLjH 'zK?d/=G""h d,^Tmޚ '&!axj}[w]3"γr^ O"H$D"H$D"y,h]"vd=̝Xܬp-yA]|pg qomMuM]`+U;γ0B2n>A!퀉X\d|@~<@IA%}~ oC+H$D"H$D"Hr;RK0&VTYQ@|b~:l{;Ns3„g8pcc K>ye#]p!L|_y?nPZDB7e]PNE"pBAɹlʯս:ncpInI$D"H$D"H$/O.hѴ8֧.S 8*5]hܫ9%tyAnLR{0 h\KzӲq.,)̑5Uy{38,8GZSS p-\^ݞZp?6GSTX<-=Y/ž}kmӕzRbjNK$D"H$D"H$  H0MCO"lɬ۸?5$l&Xnz@껱Q$Y/-݇B iCc0-bcyX::(%dÄd4.j 8]_?[{qpKo`y!j==Vsvq<D )D"H$D"H$D",Hqm;wo+p7&W"H$D"H$D"Hl"u¹ix~Iw]2[$D"H$D"H$D,ǠSx)$pH@3;D"H$D"H$D"yV.l p2)H$D"H$D"H$6:aY/^E裐?MD"H$D"H$D"Ds}5=9X/=G$ҩ*c6ŞG O}* [͝=onO"H$D"(?t3{&VIfD"H$قTۉ7׀i7 L8̐FS$N x$GhX0W0:צss%m &wTK;u.M`oX0!:Hrź:,-ٹDzDFD5 Cac۪C/e`oh,5nڭG70{kxkMڭVv'лN^%NleGUVMj2mX*▣ޮj)c9a^uq佄f\ut䷆](o#~Bos| \?}wf&t{J;X~|_UuN )޴X:,xs*zb 5i|۳,mܣ=%%ɟg@>*|{`?S:?rS=%!xŻ{0O-U_'8[wLhmCi5k?spnDZ]S :qUBoWh0aY;ܥc"DUnv.DsۗH4۷Fmʹ[ٱ{W,>}ڌ,icB@KqxOwM\ˁ?+FҬ6s2@O~ H^2qkq/){j^"* LJ^E}I*ڡS4,(C.9Do) hov+d s )FRgڭ+²ƧH;UZ'ϟq&?%h9Pv RҝIYia$eRHJJ FKj>^3v`O8LL}A4-S"k7xi˟,m_Os,w2!ZW|}9@>1壸Ve^)PX3vIIIdy0Zr|vOZٚ_ڞ>y|?ޟ-b=Z:׼S秆-bÎg0ID"Hu,࿡>p#`ȉ<UPW̔~GEX W)J8EүI>noy|,}ݍ]_B@Gj2~x*R! K^+U#hLX4-WC 4^~`1_v]D )*m[@~'1~u*To#?IK$˝-{CzѲVi :?</Ρ[7hfﬠW7W1'Zc>}ڎo z:TL h?|3"\q/K"ɜq>EƍRr362.G,֮A-߲0b?# 48X"a{yTex6N[DžD)g!_ÆdYfn4 ×].P0 <:\1(Yڼ5-OLBqZw]3"γr^ /tK[=$ZydђųYNY`8xW*#0Fz=.]+\R Z490ţp~YOBwMJxq[xY:7͇n@3!,&ޫ(b =̱8z$`yt.9 >@$X׬ \JÑQ3zJd,/sJ >lb:`!a״?;pzʙ?TW~*P6ǵ;Uo_oAԍ/=|w>vΜX ;wR>'/mg|4rqz$[;IW h}ШU-L?D"H$6Y1_mm tjp-`"p.F\3E/~e ~8sֹCΌluOt:s}Kr,g.k@^u-OdnTʤ]h-Hx8=if!rlؔkP!=~q 骘8̘Xfc 4yߣK{ Wq!9WśA46C?aY^m li ,O#[W!l!ѐri;{"M?RU.Tk޼1A gJ8ZW4E"q֚g>oӴi>}BU^Mcodmʨ|᧸VWk_q֕ʒtsw9^>L٣-I+KY|<)wvտ۳~{y{GAr\e,PtZ@ŵ{ӗ̝R/H$I6"X8]dgZ0#Р{dwny)7ęefNk_>NP S@^):#2\H𦬿Շ P'* =X d!F(kyrͣm `߇&5Q;M:ϼv{׈N>Ï4zPUkb]!ۖDB`9Db 2(m bΡ=d?)7o5ܾ su,s)O@GFT07k^_bϥ'nϿeKq>N%i[Sک#p51 %܋ "['|ɬ {?'OVg}뺗_GKhh8¿ks/]ސ9MKG.V뷌_1x?pI*$D"Ω̂A`MV)evr" Ys܅ƽSQA7?,/-ɋڃgC h* :8X]6vղ}aN {"Nh*~ԙ^:ѻ!KvrӒ\}tũ-?طSRl|;oLpDs>,gǨ%|; Ѡ֔:\ WqWpE'+|V>x{ y Z}R:Xbx1BeP@q@׽W1nSb[{2:5be?Z4U_h}>Q*$D"Ft2 2ya 3\3BHgy0aNȱqE]i1ɖ[0"c`/cx dej|8.g_R~5ܱitL-KoY=Vsv1slNMinD͑hmݹ?Wk Cl%$d}p2ۿ$Aq}Kg4ؗXj}JQw=Xٻ?]Ƶ4J0y}MCD./E gH}>6> 4ӇfKO._>ñwILK5cȨ#R~_.$ŕkIӗf{'HEұ's>AoзҶG'7,9||א,O{T6߷z z tݛA8Wd$o[7{oٽa4Kɐa[0Uef=#MDŽb/GC IDATc#9r$}%-bʼKWE +akf ` ?Jh4hO[ێI-J2?c) rI_j[(ϝ|iS3Fncm2<5^dvq̺q\xLr"H$yG@Ig47A|.dAdAda}K(2?^IdAd!I.@~)E(7P+vdI$D"n/w")O"H$$+Qdd-Buw+ @31D"H$D"H$DbHo%&zw%G@!yeI$D"H$D"H$;!+RM(0 hsV 8_\H$D"H$D"H$9GWuJ\de/R(c,`e}>g^Iq!(?t3{&VIV ZjzԔ^­j~}а`kEKK$9:Y!d-t[{oť|Rz֗D"y8fTPEfK62 B@p=uܭK?Lhf2mb;!a]:qA3MLLPBzy]!IJ]W0:MZt=ASth`P|/VCそZО 촒-+ԙU4ͭkgF h;NOt=AuTkGVWzOV};gd|h8/X."=̊/bܨ;y/aW1ucuأ&t}2!?]~{k9[ER>)_υnaʑM"H$9@W Px,bk4{C$BʉX ƻ16J<}N4Pwg8Ʒ.9Hqv|ֶufD5YZw| g7+k["/XLz\Q G8Ƃ#v]LAA/#WO E$􂋳l`do4Qu%(MlmdX3::ԒY#,=Sµ_;Pbu*V'b{^5?8k[сY6墈0e[S?ysP]&+r͔ c3\,&WXѷpwCB_)/ȧkoD#M"H$? ՘9?v;| |)\}f\а`-kVJr؝?"syu4եt5}?QpawjZqHϘi7!a;_zP%WxFs4m bb=~|T6j#<2veqɣJFcXU}vhmCϏAhB: `n~g] i^%4Qf!/p(Hkݽl$m{ĕ'M`h6ʞ^vW:t ر{+4/[Owvvm{d -獞Zj|?lg|#3 ',} J+h[C>7?If0; 𬣐^}Wt4EO4= #wp?K#)@C(uToǝzMQC?TO4Tx=hȟP_i˫<]T;If#))顝L׶>M xnߑϬgS,6~}+[cӀOzk"!972sIɮWp؃_'4 K-d #ٍ#vJÿ1'/ GKqx몃cC;57s-Ns~vIZ֗D"yшFXnV#lE5^v Jͤ*z`"Kgu5Ox~``5;˅/ngKJ:#_Pa<\P:ejM #*|2sIƫ%" GG$C<u-tcm~.wu{(WFYyՌKO aj4}ʵ<y-ćr}3V4懑(%^}W4s,ЖP͡T^/?*ѷtȫ&+(\O\PtR|فΟ.4X&#.S'rp =iZ 4üK)?jFf<;?mN:oи",oVIbnގiV }H2G_Aw&v|it5@|sZ`NsQ5KC;\K<v5] ,%~=pd}-T?^RF6~hd&D/b3Y7LdI[>< r.~2}BK7_$hd/.ȶE}bz"gs=sp_~d7;7dD+o}UZCuU z3[kQ3\NCҹW ~|l!#9E}T~%c3I&./ɘNxR@cpŠ$gjִl>1 L?vMyY~pppJ8nǤ?(u-kO'@[FExn-D/`ȥӢQ+l*Kaf<7~a{p~lօg"|}8ޕ>*z*`wu-E**()̍;@2\hAGʗ僤o]_cьHwb)3%oGS{4 q!Ҝ ӞF.ZϙDtc#km{dq-Ĥ3;-(4?|4ZZPBh )}? a KxIo %J Yl!2H̘KkH~S6`0"n~;P:A\ hߛ\Ӽx?f<'0U7Uj/Y"x3xbz"gc=O/{},E!3 3w&*kêYW֦[ g JdN:uQs/Ay8t5sx|g_[w]3"γr^ Oʗ[szʙ?[/_??9:c1 ^E)HF!N?=~})H$0jK7Z:j =+Y4pUn" @0ը?j@kz)jѮCUg{ߴ3@5>{NπP~U:{Xj͂ [[ig=:E}lBTh|I3:)(BBdR`N(%9d3:_=PnlNSwRd!$"h)OǽIo:u͇ڽ'sz,G$$Fq'1;Rn9[J}q'_>2sɩU٧ ݜ.hSt 6%iufUͩQF 4iOL/048Q;I [~܈zAw+_Lܽx'6i#M'ǥlŃIƙԥ}L"I`v7tP oY8R3.:ޘ w 51^cFK>zx@q3s,D& sB~:O7[tqA َ  $Q N #Yfj|W KVcsv1{lmloZ6] e\exU\HΊ5B@: Iȴqw$wG8cW?Tھg":ų6n=n~iLCkGt>)\>_XH$g"=ͯ=snvr U;$M9}u\߽ˏ\bQUOswK؎JSP0FF,YKy.$xST$|+뛹8>l Z/ayxUtz>&<ǁ 96 :\&x.G>.ƃ3tȡɲ!c'Ýai2 BO~Y\9V b WCNŁ;#>rRYAg$|Y961T̀4}ZD3Z?u|IfƺYсHX Ҵ/WQbv@V~@i G~pc,^ AOˋ\^dFPn u-8H1 ΍1q^ѓ/"I`zR穠$Z0a(oR yPFzWl_Zme{)iL AAFshv8fbߡ$ow*?q>9.Vƕ1q^bLEU{!7t d!t{#Υͱ'ת͘,uZw WC~/bOtT_z|1{ۿ^~>vH$'dDUӎs^9$Ts!1ci/}Kn+0\6AuS+X9V+g+KUOLS9uAnAȒܴv{2~ǤV:/nmc8 1(XN{[_oգ8凵Vs*^'A욼L%)X xwW1nSb65[zrKqヂsf 5bzD]֏R/H2Z?z.?d,&I<2ޖ|"ϡ.4,D5Vh9ck@}Qz܀aOWPY83>נnS+jMo7tkJ%@4)y%=dK$ي3N_>ir䙠RCl0D"Hr~2~[gc\I$m\֤=AQDWۣ|O]6;/Eak} MyL@#) lYLuzz?gTOJ{fT iaU'+E[Eƈ,ZpHͤDJׇۘ&uKuB+1IH}D"H$IUSb9U?|^Q-KLBe!JrR(H$D"H$$*0h}uќHz IΌI{> AHp.@H$D"H$D"hjٌTN_\VD"|͠WKŞeYA(1\/Ԕ=/6_ίд*­jC"4,XJ' :CEhe^ Cmamu9Id`n{&VN9j}r ( @! @҉ ʁmGg@ -I X bS A$g:5kidUwֶ^kdH?Hr>LZ}ak._d /#a?v[/}8̑3]A=-Hoz.jOlI,۵O=pS>C~m.*t=ASth`P|9 cٽ+*J 'p u7HT upm]5Z;gsP(jmPw;Pw CꎡW";ſ#Pu/Ψ;&X ]8J$܇t#y%ccg yy0^AJk@a4( 6]16>cR䏴ni"8g>q8_2NϾy;38P=4:su+ g5SFvCBhRrjtFZƙa45( P\d!"pfu58xJhl%7$1s|X)_]uf'z Ӷ#b}9R9[mlEłѢ 1aXQɃi!ѓ 7't4>:]tF3a;-$HV7Z(5TO} io_@4 )|*hmo{BZ($_pjNG -ą9>Bd)@ë-$ "8NMt7-*h͂fB bSLTA > {fMph (~`jZCfҟzr؝ѿ?"W`~XpKǷ1l2$RL׶>M糤t+dTShwk`ʌq>ɧdW, FfN'[O!q؃_zF! 7gS{""y[W5t\!K+Q ~s _Yw_4&++fYl E:dMK6joW}`2ڜʵ%vuG{q9#(uE_бHNףWuQ GfG0%{2n0}q;}Fَ\?d=u)磬1i$H$N"t0ѰA<*K #:מ(N=G7E gEo-t/*t 4ڊ?zv!|(ԋ{Cа`z|[)Χ ΕН|8R "tj/6O.Fԝ!jDD:|Vx;^+ E`@Mz+Rl NJݻ /֌Ez)&ZM\_x*i w+#V|`!F!E).<*B O> eNQgNzPS'zZDz4B#(==s\D)z4]/Di;۷=>D/4E/"ܝ_?h2@#8 zͩ:Q2B BqF*(^4⮈rwQ?T/[G(6X/R}E4B/쬈}}~(c8Q DĠŷwq3<\Dq} %syyU-, ?{UےMJSi HQ4QQn+`ATPTR B @@KBBzvG&Ιs o罹3sgoތjdV{ecr85'tbO[w[/w_QP37ew7_ُҪH5oΤ*JPʪF襯f>¾yXyejΪ[-j53{|d[wUJ>!YuPY$Id{cyS =-~+֞#FI'`MX2vĂ6vG錣nrtjrlD&YׇQ_,y$v~/=E@`C@#ejih ~p;/plbURaS~J;²KIiЁ]Dd&GS?.9~:'ʚVTL!|E>%j}鹴/Z,;Qi΁h?z ̀<;cl{9|zfmԸ=Utp0Ua;SeK[o_˭fT._Jt]3ߎ,}㫓I>X{ يB'%.%k?z=CG3q*̧~H?ޢUpλWqLHˈHJ['dE;y?`WQObS㹐υSȨ;7דs1xXś&wծ\Y?B^mG7L]=3ޡVXleψ* PRK}]rhǾOIM<'/_L$td#Ѕ'\#:3mZi;rd~Or~G0}]G:w%E%<3%Ǒ}dMHV7 ]o:?(X;~6N]5 IZ;1|"_AOk+,xmg\ؗ)3}z`nWwGŹЙDAʿm}3|l IWoK#>|`(v+K9ճ8^F-ۗM̘wԟ3xC'3츤n!˵@լC d+p!})kQ$lt,;~eDh9n*)j^OՉ_L`DH=-ԊˑOs᳾<()L7~gVC`Tp"1]çp,O kf ? 0xhltww'HHħcΙ+RvL7z (cx;`'-:+!캆_i&P =[wͦ_^&"vz`FՑ~;C*iL;LgrГ ê G/8{Z0JSX{dw5T糪*Y/^ݹiW;D…%JNT-)CW ݁K%:?_#3?@z֏ eUXt\Z`V+:ZSfxfD>g >>.;Rrg_⫪ٯG1k]6-_i?Lb\KK 5Q;^,s.yVYĽ:C%ޟ yQlw|?7 jg3CF.f\4͐ sٟHˎu)jͽ-Txr/g2[N]yۀYkaZ?`(ژPbq=})yB(N[_OAvGT 3.LBxiH@)Rh~TR銣m x 5.I&FJ(btD= )ޕRwPfgLxM56q8=&aE~0S̤^#/[v` ~(D >Pa QEU#|4*/ fWfF T55ό+ecuԸgV,%]2R6gukt[Rk:Nx*V93&O\ѿI˜ ߓ&*mRVld3|n%w]~gaͽIo>Rg0$Z `1Sr) {[@`44WˍP7Y |x"/o~uDO_#>iX3c'Iׅ͔ߣ ]^nmJc'_iGE7 S`zX5r(_;ff&7fLFZ5O_pW =&\|dfHYE2O>?b$Sۗka2~kxS9>?\MW a/xiq|x xRk_-t`?N-aؘ|>y1_ a!l964зFL6Ņ56]=aNEw }vMWXEFƁ9^0DVF*G{#ap0ѡQԢH;7gæ쑽m2qCkũyjnfS!g%6\QC臐#kvθVv@;[sRtpf^{ *؈suu31R= xz6E;6d]Tplc7}j{z;U0ʹ韹J*Ydã5:$le{6hl)K'͛c|m͐a艧,[_PQtVu8Pwxw@ a1n60߸v#yތěVXa#ٚT0gt4lۃry'G >*-fK7؇NFhoj:Y {<=/rdu"]3ƙy{HD6bYB/gpdzop^;sM0} ϔq߳*2W+n6hxTnˇCG9?3*#_4/ax BFN$J*xZECdDUY5n u!I$I$VS}^{_iّjJʜ零ťjz|^~I?H$fI(V<  \Rqk`cNAAF_NkqtEóv^ 3.0_ ? +V<AAAA$&\xAAAAA!{0݊+9 5| 1QDNH gz4}G["J5`3M[,O:υAt%U uxz耩CgDDy>c_oBA ƃ{OqcCe?BzӺc<"FAyQO9߾!۱]wd:j@˩~WF? VsV06il DƅtbR!?Rm_YYUIo`W7e,WƝz! ӰdF0KI?I֖fxI=% N!|Inג2&Kx<G:}F?1`[k?B~紏7{|"_aԖK`m$Sm? 0ؿ0nːy눎bd_RB'fŠpvDc{A< yjR֭H4uY1M檕}_,<{ԬOu~f8<ˑ8}o-aG4|2_+@l "; 6b13];g 0F?3d'&D x8_A_i p/eNwxiTyʹLˏgh9.s|x}^@P3&i7Dv\ lzg޿3ǙhKJקf?gλ&0CŲ?>|v돍rW;wN>+gB,JVfmp~xF"6o%Y.^S'9b&zNq{%> Kۉ5,hAw$h$۴?ՏZ͏QgII]˙4y)a|rIxOomϼCV#B/~ ]͊1)҉CW.|ޗ?:lV[ME 놹+,1c,Ӄy;Byҭ%?ϟU+Y<%^# E1?Etjf~ޑJnyc_;';aޘ=Qڽuж1? 5p u\ Yӳgux} ס^i~EHL2ao&z2hћGEq`1RE}ԛR^1bȣiK~ۼ5<Ϫ? ˺+ WՃm?&Q|JGL˚vq4Z< n6}dc_zhZcʹL%?őP@uRst|>W~%fBKflVQF:>7ҨVleG6t?t;ZY2N\% :\kyT?_e}`J(zƪWvm 9Tt#戉Z}Cx㉢y  0lK`ٰs;7NO}̜>pd?8/i!& yC\ͿwwpT?7V1ULXRtDw~D>gъ`@{DŽwyp?i=4>k+I0W?#MZc׭6Sc{/hbg`=9G*ѵ/LmӉaְҡ3ҝo?JP'3)<[.uZ|BTA}ƕc_;/ͰP>g֡f<3x I< IDATRugA^*qtTBcÊQ2+0E>q[5yTZ <2hOg\;tN5',S 38Yæve㗒ҠxZi:9`C@#ejih ~p;/plbUX9p)SYvl+o_i9 ` lBǙKg: Q3>S($mҹ(8U7ڏOs$\̙wΥO.i Y T82K''ٱW1/qƝvEPpz3NF銊KIPXf#r!olZW*`=~PΖNr/,Z:I?uCSPX g|<<5jՑܹPj.쇜pKj7JI;-"' (¿LXGsFO?T2SJOѴ|\-'9 ?5OboT$ct@%`'X9cAO0}b{z86ڂq{P;?.`v>?h˖8?>9ZfT._Jt]3?  {E^B'%.%u=CG33W$<(QC縭Eϰx}l$te5 If?-&K}V[u+Y6If+ƮnWW`ԟӉ0VԱu5h*ڗ΅7O5^hf~_:G3 4a΅~D6vhT`x3dj .rox|xfj1Ј&@W8nAJ@Bi}mf4`RUmN3{z"1S0A+ZZ"Sp8WLaNsa{2qf 97;FԬ#_Sܞ~nvݞt47 HcwR} ߂;?|"3h~y?lq9(/O.T IT@{:VvJng @;I<ߖG[Q|`(v+K9ճ8^Nr' bƼ;n1[`tj{k? TiE$s p [! w{b˿1q+`)gF $g1m,wD+qdH/@HL){"ʕ*]3ɦH|( 6m:]YceͬG>Lg+|k3}9D`tDU w VSXkh:fг5h60YxKi WH!δstCFwMln9IaUo=-\JhQ]) =K4Tʫ*YKC;W;AzP'8., 'Wr2΃ |Ty= Vg쇛^)}ҶցW2O_ - C_6VbKؒ.rbj 8ZD>w >>.;})?=!`~QCmbA ZMDZD|kWXxŒ`{.)o|Mph <>š|7˗C2w(>ӾapP:Ogʸ`Y x+vfs10 YΎf橡I'ߏ"|g%ώ]efsڗ>b!);#1CV_87&hhtJ"I|])7v8 ^F^$uƵʾgK5#kX̀UF䜫Ri)ر!뢂cx+ W392;m \:<.:t<=s!"zq?W4߆ljC*Pp!@AAAǗS`݃;̅A!![\ORr̜89^AA?~&qyiL^xq4  3䳋|(    3HL [     BB bZ"n#:f:ɋ4}G["jaOAAAA +lVҬ~ Mh=o$:&zsq*<6Ds?ӄL 1&hꙭza?x9/ftuQ3yvkZ3-7?Ɠ!k)o$?s}wꅌ&fkLîw.%N`o_ΐr<LN_1R,xez?Da;h_SyzcR.QM~x]    +$_@EBÙ>Aֽޟ]RLGYл)5`#<u}b>9"h]6$f6b|(     c$_(Hu'(~8=b)CJ|SsxRzfmԸ=Uݮ5<2hOgdeMa/KENGoa_ NOvТ<47YZVϖE?׿:'ʚVTLqwܾ [ƮrXu;>q4['    B>GBEĕiH5iwMXZX(IԶ8R݊3gXUdro1c A{X0GIW.xpy]]Iץ3I`=R:}_whS­ gH2oKo+O7Muy~2QmAAAA #Ѫ)X8ξīSʎ€-o¯3-KÐ|ɻG%ڍbT^H 3`p2=SV3+XB`͒p2~9y&= K/?Mq5SJ}JGl]:Z7wԾ⵨ys6q:]a3bp w'    BA;Rn*: k4~&Iwe8Dz0ޠ;uK@3G%:MFQ)&\\̸.6Լ51d6Ғ_ejI}nj_v̽b_3bv1b6iztOqٗ 4^m.3ǽ2^nڸwcpzn7Siٱ.EMWeOLF>OAAAA &BĞSXǚS8 q8_1nrv|857O My+GV'eZ8#Jh8D/=WO*0vmLgܖr~fTF,1KOem¶f0FEz-SCxoi{p׬ )}q&; CvNV&qzF8i os`a;hKh> ㋑TNm_ǯ?V|'    ټppOSY^\4f8$*     d+AAAAAA(@H`_AAAAA E@vAAAA$&\     P J :1@z,dvQfW;>…{}XۈNb–<я>]IĨDF8ү;YoȒ{ 5| 1QDNH CAeA{ pck;u)M=8}%{E`ut$?w!{m~:U3.r8r,h:8]'qn <ͷmQ ;T!3oFc<71hC/ۈb[$^|~'j1.\Gk7CWVoR1՟ T ysGhp4>;JNOS;řy[P\=5~Za}fօV+ƶQE ׯK7ՊmTlKwʭTk)i[P U_\ 5[mN7$IBA$IF`߽OnUʨFWI r۪9t7j@ߔ-Nt]WoTA+sS-K[ɷzk6~oUꕺ>J R TyC5E=YDˇߩ~^I-~0UiT5*|[ [>I[I-=W&BEtE=J]|!U|΁(1GoV^w~:Lި6*iTzo56ש9ֿzp9[Ĭ4rkTOCa^]U*n6(:{f.rު]RӘYWlS+޹#9?h:Fm TR[F:6Iw6S? F<$:`pRNMNd 0 wDm_IX2vĂbR IDAT6vG錣pT}3ZqQ)*8:o*ӱas(yuwI㘺=PI'8wG47ʡKٟ βckEU?yaܨkGE܏g?1KI &6^(O )bR-.X ՋnSR|,*[ZaLSnԏ|kӡv2\T|$Oі-)oKu| 38Yæve㗒Ҡx1 g/$D`BdF.ƙ ̒̚H+lS.7X:Q?sE_HtI|nָoMA|I@iW7捬?wϜ$I{v *˹cM7w>|sȸ_/k3לoKsϰxd^e`%füw0Ǩ')9w:tr4S,^|T-Zu{5Qtzwܓ!]M$(#7ž׽X{BݼqU)\LaGv\HOJsܴeptJfLq>m? ϰC0Ijxk bƼ38:!Mf%gv.$][rncRtѣ(%NۮeʹX2~Z:_[&K}]~`c߇EUOω΅Λś#v+0zxck L(݆BٱY(tf|VA&.;wGq.t&Q!oб/`@[ _!pҕ 5 IZ[4H;Gz;ҏonsx4AWoǗ/˝iV#Lܫ XJsdmJr?Ci PA!Jt2"?{I3lnXN"&h 駶 X\ 'aԿHzi~i O剩'Q^9w*oaF4ޣؒp՛hYZ~g8ՀJYsz⵨yes6q:]A^ΈQOp2'|J_߆oyffv| 9GV?6ߎMKf EaeX: h1l>?YȳgpɠJܡ;\i0{('^D); &Í)~ 3-Q?׵n.)o|Mph ${ǭo.HnT~$g1̿yDU w NV%_| %GIQf*;j֯?7wkד9sކ_bp->?g ܵ. c„O)oL }JGl;G^7#psx\r'}w \8S1wNv.O$FGTcM2(q"} PxArPi7j'O`Y̚?TSг9|B0qL7^?눹1`ُ+3. Grķ38RLq\4y/֦ӠW6yVcZXVOu|/nc^_6*IsٟHˎu)jͽ-Txr/g2??~y_VJj8` U2WA}{R+S؝zI''a (l(BӁ٫vՌ]̸ h!yQġC wMz4 sۨ\Y(׼k臇ggᆪfKTBOEH/R"DPQ)D?Q@Q "(M@ @Z@B^wwc7ZvI|s$;m{;3wuȮEjG77C&>oۑf0T22RtǢƟT?DSϾB[?#{ y)m+9~ǡP.TqU0o˯?L܆9y?dtV#Yן7G0Y>;צA>ONqЧ?DEDӈg_ܿnw?wLܵdaOUgUT}r4==7tǝ56,Gm=muF7Zm[Fxj^?q~I|;?v~Nϻ9:sEF֙_`?8Oת>zQW!BwB\8O{/CkQN]焠k'98~&rso67g17(ڄ/Vƣ|q R\Hb۸a|?lsx6W8͙=Ć6ջ;rqsD ey ZGoqs~Y`*Z̎]yڇR}E2C7=AMݮ=x}ݚ}};]K\M'8O:Mc߰ҧ,_;v&cq >476}:Ҍ3atxپc5s,2eW%{Ό= HS$~Sw3ufʏ[ވ=Wyf xw\0#,Xg?/xk2 Lj œLEX6Ln2' 6#ONg,ց#N-FdŒ3t X?Ⱥ鿻q>CXGpȿ~^e]&6I={EN>WFo҈ eφyMss߿OO?R6_ ̜ L Gٸ?ۏhsYn/TtWܢ,шבhtZ#1b4bB6|,B!"oAǠ+==g6KqMOm{{KjnG)I ۪}ɷPMa߾[ B]Ar)=D[9f,Hwȷ 2 2A슖󞴢@g>MżB!'"K^’܆gҩ^YW(E"RߗW`ވS B!w&@}`_--9>W\k_x]N!DAlBcIJ˷YrZ7\*nT6|9&\U!?#0cp`}|, J1)B!B!BH'@^<7?f`' PP_ !B!B!(U`Uu |-uih}r!+J*u4G~I:%&RمB!B!cyؿ|[ ; 8baGх5;B@j^ˋG_۲(QE z9i̴ *Tj/*zݰutSNdWBƭ߄=,B!B!6݋aغ 7`p\7>?K/"U5B9t/ LjMdYX6Xb6E\Y" p410*]^[Q }=KT/|=_!VB!B!T/lAk쟻?w^lsfܪ˝Ov"+kv` XxZiOZ4lEڒUS#Fi5hV$;|63TOrZT5XS]徼 T6a&mn-xDmOZ7M47pk}[ O:lߵ}?[vlf7;mĘY{u%oeAdAdAdApc[&~ӷlwݽn6?`4q|lsOSb_6;Hf_7@Ludf1آ89r~uxчr:7j3仹 OM DzL.Rnֆ2q,ZOMO%|Xԋ_yzVC )NnkbI:}h1%8o$Bu4>}:t.:|:k0ϼh bbaŢ0`!B!B!rWA@=fOvǾOdSퟱOWud O_[ '2WҾtIzu3M!YùHO'sB>k% A x3KÜGll2ư?xi I)9RHI#XIGJ‰3Q*.% B!B!pt^}iw |,U`kޭZ!B!B!p!`,?4( DI!B!B!rup;B!B!ΐp!,B!B!B!  !B!B!~@71Q瓵7~ͭ1n$xn"ӫAQ!BQ0H`P1Q{f aQQʊS>JX;p:Pq"B7;aElc) ~ .,_!C}k.}2_/^a0Rn~%H8Z^jJFNkv| tH PCz(ՠ-/Ym7a<TVFo{o5ϝ&; 6Ėk*`o(KϠmc㎥|v+Jꝛ~?ǰU*]~qAB!.ErO1z'5 H$ '0orU֍~6B:y%&yGzvt4G׬EWOW^7~}Y%iOQPbgFqB7b2H*ޤ?I%}P^ ̓-frD= _y}ܜ-/<'jqxjUPJFhcf(#n A?htkT0_gϰ`2Q5;sbGsZ14jC]~ I%nrgI>~}QLw:KbTAy:n9_-a@yjb!/B!C|? `T?0٧;@+X_/c0Va8J|Fvo[Qg*J^uHwɎak$5c@[QL3?OָyH{J,o |hŨ͡ 耷?.H&YdeeaVAfeƬ^7a&++{\7cG ٱ ]*]:9KukY@ygΌT;뷰/"}X8js7*xaڵbM )\^ *kz?bEu8Q#% 4HܯrmRVG*RBG T-ePc~0uϯ|ul_h-k]=1 P[O `=57a\BmvHqy}1ՠoc~>MlB':u%Ҹx$+r"1(΢݉W3ų6/L^ưP"bYG|[F>͛gͦX؆<<5]j]ӱmw)%mᡄܴ ?.?{w,\9V8Jη9f `(lgqt.lGSδϷNr~ \ϚORx/fgӖ5Zam3|C V|՚SA21gL%eNo+TmVvkhXwؕg1Y*+ނ#",'U]/?SLX ^)]},Q:Z"%B~o '_ *W[p~+Xl7ZAR&-gɻ=YL)5eZ; q|YtUQ3:[Œx֤KiPӗ*9u,Af^i٤̵:Z2Dm9H Ls|xҞ=YpsӐO|¾#fCP6* wiHbth' nۚ$ Q& -JtBFWu_Ppɾ{uSʖfV 6@%%FZXJVJH U=̊fkzWU$3uT,feH Pug,lfB ߚفҷ&ub8[y8m a, O؃ƕуѢeܯ+y])~=62mS6x9Z_Mxk6H]Qj7y:y wN Pm*4-oضty^ʣGt՗兆 icBamgʫ,|,6s4h}x(-__''?(![MlAv9P2s{)"6G($Sx 7%[:6FC]s~f=IrdZ/Uн,:uP3w>Uwf6Z G6xӇҗ`֌˂-S'i2UܨJЃs@t{lESA^AA)T'WG\N?V5txZU5 %kS5R:JjZa #vC IDAToA(ju)ZРP Obgs"kyݵyueүY"&eO-4=~m{~ݓ h)9q ӬZϵpI'Llm7 N%Г:a {t Y"͙i c TTŰJМsosO]sNOfZ6VǕ@Nj?0 7^Tw0])ޒTBHȫƻ>=꧲zJNkXbBu:P~x9LY%1t?d]Iu|!+ |=ݲ%Y#p˾Cg`une#p%_$K_HixZz5%b2!+=?s~7[?mL06#fe~%fy=[W|G7sE?:cBY3#0g^iqQyysn.mTXj4=v-I1'rb4ywOֹ"n_3[eڷʢJǀO9 a\##D3(;0ijob?}V!M3Rm=\͜YCSVB|©I^HT(ZWVH{o?Vz޴u $k WJ!FCn%6Ut8ʙVt FFejG)5G'Z8 f LE JSAJۘOp&MŨ13*?dд5|y3S#F7o\6ě<ݾ:QZn|0gDX\NBsӒY<~(ǃc|8+>?qϸA]wҪ);Dy?eF ;ۛR_#9vW@4͊uXScIҼ6+Vc~RϚtd!:luCgv./_X_qw#oo2}?0II!D ڧ˲s_99qzx I­8FtɅЁG4+HH_ڼ^Z,ɀk~ENr>@͑ xOε)lF֙_LܵdaOUgUTřoۑf0T22RNq{HFwpOD.tj0tZ^ު+FQ_=z{B q1(Ms"=K㗶'9OF%WGB({qP*7&nÿt\~ V{ʸRm\Gh’B;;Q; 0bPAdA3h f &:8dy=\퐔ae5]MYO[jbӲ:X4vZػjvANu>3R)epG3 4PD +1W6p nh,iIx/.T6nO>s[~w$ksSdNoy+@ 8&l+;~lMb1H[]b)We]H&5 =}}2~1#~#[wԔ;5@s>j=3*ѲX51K"s:W5g`Jo;0YNl:[>._u26a2m|XG5@)FWcѝ5u7S'mq;E#rtL5e#>Yg E ZoM=@3WIMBJIv/,/-e?G%+Bwѷ^hjM7ϳ?fYrߢdL&gyy~xiepYa*f6.O!ʭ?}!_* r&g/@-xa'O~'gIP_!0S>㧄BvcEuϕ p;ǾB8jy]Y8+Y"B_ |T5]vַ7 !@lwˍA}#uȣ <,B!w[f!Ąw v-{Fqv#]܇BB!>e9%BAbR"B!B<@g%+BBB!B!ΐp! /B!B!B!  !B!B!B!B!BDB!B!B!D"}!B!B!B!B!BQH`_!B!B!(@$/B!B!B B!B!B!  !B!B!B!B!BDB!B!B!D"}!B!B!W!e'aI鼨%nv#v1^%j!B!:%&If!B8$BPq"B %,bOaepQD}hT^(5O>N^r<ֳ6ĖkFՐdn"Bl>Y1\kh<@tdۛ^P8M80 gGVfjٝ3CiWXU7@)!*z6b֏ٻH;_7h^S%ErElaJSWЕK!h$uLwЉ~,`:t91hw3zKE7蚸:>sڞU|փ>t&~::|졒JcĆV/%ҷ˦2Uq[}qP>w{|SJ`|rW(k r| "B7:[~Ν_q;DkmNDn{x>Ļ6drvo~q.}2~;OkFWB! dA!bgcVt to3|t|13/6΃OuyW1znJJ8#afQ:O`uJ [ΰ:vf_=Kr-Tw挥Ŧ3lbTiԆ {\Z0n"xUL9xr-C^nũu*ߏ+1Z7_;n_rmw~lGߙ'$?EQЫ7ͩXL0R7O+8ynYwԡͣ.rB!ٷJUl}˸zJ6mYϚ:QBg;Iw" oa_D(aֱp3~NVG߿CR;Tg%>)7V/Y3IlڲC(s>} BIL8Hh揩m 䋦n7>gǂ.W|A;^?yRf>q:D#>Fz:}m#]3t% 5x#]gb%#̓jR.9WqSOAٍbnyt[o`UV;:U2۲'`eY2=UWth(W9m$.eP<֪#}% pܒlG5N|XO&eTÃj- _lG zQsߨIf&Xʦ)cEO"*[Y1Lmn5` fSJT%(MhU K)V I9TY-I~cd#Q(NMyRXrX^e_0Fu-ϷSd<8뼨ӹ [;mӔσʼn l2~?w~M)َ!]-,WvJ_аu붣ؕL;_&QcpXߚr#|*zRX:ţ+EkҢ|&Nqݾ>ֹа! }LhQ|76ͧz拘G]7n; iӝ9?pB ~؇?L'#U6Vich>uy9FBB!N^KVP(n:ЕmKf,0=f*Қs'r_$)V Knķ~r+Z*iPz,#$t;|MkϻO_‘M)!%9?5jb*ϣUٻ# ﷞gCDE#`Dמ%90?0oaPii 5̩)f :* : 2Ni$3z $_$69Bʩy dd89.o|Eh $u#i1}^}yri2~̐}$EɾP4 ^N,uj#$wޞĒyDGWm'< x Vnu]]qĮ}?mOpar)L395`Z/Uн|E~{w~o\xŁ><2iTXU*IKbN%h%㎞#˷ 5g|%V_*{~1_ꃛNB-R+9a !`aJt@%;1Gϩs \:r Jމ6sUN,umI Xs0f\B!p_h)-Q`),^I&ZaR EsXUJywQ S }֚OR dpy:=N+Iq"}6/;7'2}o(KiGt-eœ x纼k~|<&I;VQ퍏2X~@iSU\9]=~gV56Bj<ˆcqw˸Ǫ㕟.};L߭t};).q|ZOpyp^i$$gEw͡[_ze|垿JA?'2g~<5&oeşPAm=WflhF>h@iɠLyk6YDx o+T'7&IVfd8^ȣ8M{пIMJXs4zӯǓ}zx)IO\]v)G)I~B2q&sLVY>C}vy;b ٮ{SHz5B+gZ*anM?toҒ!*|,(xAyR1# b5"I@ ~.V d )G *l&LJc$?|W'UIK`'ɖX{[fwoZw^bbxaѻhJ8+B^[pzVcc|!^S瓗:N03*?dд5}xfI'&r7:+ UA=ֻP3SԜȟW)'ȌX„yE7Z IDATw?|,ϽVlݠO'gFcƆ| J 3`d錠oozn*/e 'X/Daٿ/wyx%lJ"O-fO?߽QzIr"΀N$%9L+^wb`oWmA}PлRT-datw!o et}uXyM@D1qqq[}SFJ-w)RCe6p-Uޯ4Pg时QPIByT0b*Q=,m+/jjc};o\&::V.Mtt,I|Ҿy44}nFoۑf0T22R;̋D$A3$)b7ZUp\U!Ir~a%F&"~ JF(>0=p %L1GWlw"rFdŒ|1$'"tWYHc߰OYn gf82}f|?n5{hD.|\(L_՜Q+y'+3 d0, W[=>Av8ݚwi2^+i;1tR~ܼc9&8y %nX#70*#~hzi.8ŗn1g.K7#2iO̻cPI\g RI*֎ BQ#hɜ'::9b9ܷ?#Xs2R9an% @u?:rߠXh[ k/Wj>t8r@6] SKgktg.w^؞t ½ZgF>F8"VMa̒K:omOKAi?Wb/2jXA_AF4' @fو(?CCkV}[SNu$`^)$]ؑ{B!DaH3eQ0J{KǑ'B!n.WM Y}-B!Da&1B@>jqJB!&rDl(A~!BՙA;cIJ˷yq2$WB!B!'1a)DOH`_!B!B :!B!B!B!&|oukĵ ޵*)7! *}buK^˖E2'uR }!D!!MBܗVO7*|q!gk:;wɾR^TUK>V5EUUV[. "ڷXb {| Hro=Tsygwf3gبtjovq2 =oXy7‹P{(KGYzZNQ}'>rVZQ,mTp"uSO;Wfp"R~V[cþ0}V3kp Q|Zܨ7e7Q!hYLӿo^T3?ce2( G#?'*#ө/JbĒ '6VNxn č ot/t`ʭDDyp > $g0OcŠ$2ل {>LTtmi:QDFOX߾-ujo~]AMb=~o%>C>i[?~f3(qZ<IHO!#gкx爍PM_g:GOwZԉe xO6O3nD"IYD*}yF,!S38bաv%+)Dq%zO=#Q VtT /7nssi[UKL9©?7sɘNTD@Gqf*:4^}.]EctxV]XbV*,h)Lv4?þ[,Dˮpȃ(~ƱhW L?.LԉMֵC_ѸbJ;ObTnakz8Q5h AeYjxƷ+`} 'C5~Vo~;>'Xԃ&x+hyzĤξhm/H%fm2riEv_)GSۜa0=b<2pRr~ulD""D8:S\ʬ6=IV̮ż/:K>.Y1K{UnU*' C/@}R t ّ@xpUpܹ^5 I< NYxm߹Ɠ!gwJpݷTCY~%*Q곐aDCY0MWٺ*߮mYx }wY*p, %6VOCWʗm3!)s# ;+Vy]ևq(}6[BZ7s7H۫,C~ȎU߻-wdښ!J<حA4Ӕ>KcHK!6&tf9ğM(ydG*Uo8pLX޺+ ,܁ U+"*abRVjenoވ: l }pjIJiy=lQwE9 b`Ӽ\ ?uS(X R. "7o+.;w.N ?#'\B,^ ϋ j_9j' P@s5 ΗU._7_3*)wTB{]kU2vZ*4JMOBtQM``PJ<ƌsI8=!iE2;;Ӷ0NU@=kX6ߙ?Ɨf67AEwEtex*fRtuZD*TؐN#r&6QwŽ,94I9=Wא--a7WޠƳ^MEI5#H$ed`_"Hr:</osɉ:?/f] GL/^lAAZ*)()Rn w7 ` d<T gCsC}0tLyLO ?՛2h:˗aa-׷&pŪ8};EhSުomUZS\رE灃1բA$}{.m{1l5j 5^/eύZvK4W|`炽?j'5EܑJMp2I_ Q)'ʼ]9ftܟOqcZKsYMI` uxW.؎?A\t KeBSfE/\IQ;$?l{%8Ջj-vânַPs=ͦi1^1#{L'G22П:-ƋׇɕXqǺx|UCE)P!zg-Z [U+~7@Ctb>YPq嵂w659+}Lp4C̿\{cݽ8|-`g6d>h 6[~57 soS<.Fޫ0%^$p%r?cmTS艓HlBNGQ(ե7Oad3OOniD"oU H$9H67n<6 ɷ1IJ./Z[Cv Hq|}k$A`r!OwuE5Ԭ`"lR-ͺS5v-]"V]nl} rGQcˍ H)[~p[*N'{gYI\JR80k noD ǿi-_vx]W Oxm1Ne8~:'QS8e#S~w|U!mb51"#(}Էlp', u,q۪I8J^_OVyqSr) 71ժȕzԯU nGf۬gn<-nr9~;Pl_΢&#YƷ `6}+$V7/8 tTzMA/V߯q'೙*d;V^ϭ~^ w $0i)tĭwhuV9z$kz=L_5;GW i~{[ tZ<]S>*4ht_3?zv Ո@50LLU z+vXߖ γڂtUn:q)DMt`Oֹb.lׯxሇS>%S< njא߂~y%#H$ud`_"Hrz~#ɐOAS~AO{LFD$fѪ&{c">Nt3,=dW ?9n O0̯*fWܒ!Lp*@1#?V%Z0ȓRQy~KIJwri'蟲2/,Ӣ_.Yl/W$cբ(>ؔRyVU 4G?A|RYsG|zEjb4)w:8oy;L\-B<;==OSr^3edt:wAw-Ě{ Yh_1o?*b~5f1F({Lda;c\5~^|󚏶UAgg)TѠ=f↍"|S':O%Qh+^w#ߒ~xwO0.,~,|^?0V>1+`%{Z-LQ8vrd)+G"H$(D"iųo ܽygr!-Nr[gy麢,p#ze}=w Du""P6dOMAWs .}ETM;{_h[y|Q' Ppk(_bC6T\ }⣹keH1%lWƌ9&o jFqs݈p e1cؖLSMR=*a̩C }#73/;EѤۼp'|hܺ yu8qrh/j (niѪ}gt;uC}6yIj7 ᨀƵEbYs؅&}[PQA'+-s&Mp6ٗ:U=rb'IxV}+_5]t~?|:2y?n7+{n$c;Tռt8kI=XO7*Z|\߸(D!9B1WEFoe!_>҆Z@k4i^w M(0&Ɠd2oCMO݉S nV{; UeZYxiF*{7;sє3oDd~}$D"wK$3X:rbIRQOĆ^c٠ܴbNJb->q$>]/79MG茂[<#(8>QnRO 3vQ|{|V LU?tu=v?h˞>+fWm"C3hfn>R;<}:=NcK;i>HDnF/GwO$}p-_~ zkF-30zѥgg~\ub sKYyo&іSR_8N~v\qdB1l`;~{> w}d5Vo,9Xˇ?yca4fGšq%=h2jj L˘ܻ{WI)lƳ~F)ҞأY6Ea~ύ.kg˯{*^܃݃G3v˭\i#H$\0ϓU H$DbW>AQԤcˊHh0= a Y%LWw0wN IDATD" 甿D"H$ID?D nl6wW(U UM7Oԯ];nܿFOhZk BM-Ά._7/4 TU[PP< BU/K_۶$O KEo:b➪ 580b|m\I :1E njq5$v)\s{C+ۋ|6}i6T'ҋ3"C҈_EYzrNVb#\EYecb*b#D^+g7}K- Z|7Olf?VYzܯ+SN?˺E>TOc9[ ;XŤbOT<2]ͪx}Ƌ?1G+c[A$hXsY}+Ŵ|4gK b17x\t/}sbʭ""*\D\#f}(j|6h_hsh +VZ(S>/K\Ztq."#֋?йkpGlY5Y|XM(Dj01UZt݅ nק٪K[/\?U[_m!38T,nA5Cg0? 0ߌ Ѯ"ʒ3~ӊH"EsDbep_/`N'ԁs扝,1g6qSU%V6GLpW *T9Pc!'0qWU8U`"("O=h>=};DzѰ"mETm[|]A#_Vs~Bgo\ED"_sX֣u p+BgvŹߚPWT\D/֊]DMTl*z(/ JtlUGj`_/H*,"xxBD72}EWEA//Q42L,y7|߂XM4^*\Z8?gŽC1l{XeȧWS={v[LHDo6> WۋC,o}y1d~Ƣs{EiAt AWWF+j4i[gY?ӷ?_vyj~+-o S8=v~FgX~^9_)RDbNtIcR`?"?LP׉V^i:g[CUzndfkUjhw@(uJmEqQBUUqz;A TDo[~Ɖs*ԓ#Ey;X 5o.ϋZ!u-]"rE;E3=B]K ,BG+GbQZ}vJ#\Dm,{{h>Tx 4iPW|1O/Xq=g?yO6=|hd}"6&WRL"w ݳ]΁Ł+;B&Vś j gS?pn@qO}#E?1쐿D"ƚx*TD]D;L Ɖ![Şc"tbtx Ĭ !""*\ڷFLڃ5yj?EdfOq`K/w-m6I,NvJOlqX7`Rafkj1f#WnDȊb-bWrXsjbܾbnKT("Vvص)EJ|P\ʐ/'@9ߣ\-Ѥ 101/%/^/O3K6?U[!jz'kŁy~W[H 'G~.fm+" j{k,~j:}N *l5{VeyĶp"?+İ;o]Sqm' ((N4zh[Zh:S/Q}`^4hWD:dNT,q]Dў:x^j㦈u,h9]'tWQa^Ԫpn:E8ie@N)Rd`_gL"P4ίcY`_–O@l_KHLL#ݹTV . 'M W՘cy'R¶q6Cl: K}@ǟƕ}4w %_C4rjԯ=}MWEtOŊ 4b-g\PdH>\R& ~)MqDΞB/W= |ԁ{ip&aU}誼]qbv$$BO> FĞ9,p% HP[[fRZwmG>ڻ,bPcqx!+jS=H|?fkX;7]+<4'g eȯ6}KQJ{weP[3[ '5fugi tv1„.,O7 E4yt2ͣs*7NP ,_ @`*0o)B[MQaM]QON#iR:M9烲e_owE9 b`Ӽ\ X17~ӏ.vp~S[-Żү`5ʛ >q%y|<9s`2/ా* jn} :?>2ٴIWvv/)\ߍ?{ԥbծt`x*V_z>,ώ[zF4鿞3)&?-'#m nPQY߂G p0^ekъ 8ߟ8{ 4`#[ Sc8lb`{wL#<5ύlbUַ*aC 0pJh]1_WP/ET;X;ĭ:jHiBs &.H$d`?'pt0An.x­&`,PUVGL3^NV|: k9)ܸXk~sP@(s$m41s Ab5 N֕/WtMdĊ˨Zt$}{.m{1l5j FQwI~; %ѫy>s^cMֵU8q-/Xm}ϨbNf,ܾgW+ovK3R}>S FTC4' -'9/ngIgZe~^3_Y^X7Jd?kP7\2 NВr<3.`Q8xÀH:H6H o cWEd4[Y1O=p]] .7a*Úe \^+KqGpj_kT/vM\'D">2v6L@>Ĺi׍mH4Gqp2)u˜`u;mVoKf4 c=P o{6L5OOn/M9'sɖcp+k5 scNJekĿ7L/|;)p|ۯh4Mϛ4Fִ0gP4^rB֮g7}](1.rd<%vaupZ|ujZEɨ\M~g?p~Fv9Å{w|IGs=݁Y7.bJ~K~\z#qZvngW&^gƮkq^+l^&Gg7CY~ B4;NNea|%* gbGBFu+L=?\ܪ֥HB/$ c"v 1/5 _J{Ԃ"|@zɈwCTm53\P2{uDFFsr56KLjN~˗+ʡo c`&:"H0&}VEpfw^dZ+8BQ4OqV!F(]zoWܒLVSQ1oo7DUt4TDf/h<4Bc"g&S *h4lG-eHT*O7ã \N~myjbo]ᆯ}o}upѻK-n?KƊmXOxwO0&4zMyj5ފJO^6:.ek_^챱ٔ_jQl3~VI4kM(0T ;hweG-dC"H$G ,-pHu+: @{ %1ӆ@b.݇n)Pl_;} |bԜR@ۙegcg2f#V̧pj;QOLX2h,'pF ,ce>߾bec20Pk6ofcb9e? hX, w?YnRSDEo&uCI2I7+6%_!*6?z1Qa)b_EZyу}bJ!:Vx<^}U@Ռ*_w zח\I[FT\ eaG׶08B (P NY z)ZvzEvg?X-ť4{TSƋsA~0vvzR{DL(hU>8xSq_tXnU۫5?|v*fkE9=m$a(oV gamAqG]z 7͙49&RjG& .;&AY|֟)8imJ X>F5/Zm"5Cyi'-y΅sYO_ ;3y ԣ=W/#XHrd~^3_w9s&eP@qHi _2.W}ũ$oسcS[YtȗZ2MݚUEŧ(FAr ܖG~b_^u ,r/{$\ ? 0ʑHQ/_"H$K|# |u2N!c D`=J$D"M</RԤ-_]9;H$D"J IDATH$-$$Sy|¼}ϑV8<&%5]"H$D"H$D"X F| llWVwPOd ؗH$D"H$D"H$ /0 p=~N:L**S % g=Ȯqv.H$71z6v#2j!mD"-DPc!rK- Gi2IOY:s{tѤʿK#r~ O"Hl&M󀪘|#0ÀxGlZXȯ6Ystq‰Xϟ!FVċ}Ǟ0" 1~eti4;N侕LRW"=Y}d ԧ&ǯ͏l_^P&f,L[HC/dvs_ i7NOYzZNQ׍ Ͷ@ӽ:D#?'*#өPy 2*J]Qon"BW 2K~^!É K,D7JbĒ '6VNxn~2/e:0fV"‰ob>܍\CnPxi RҬ=ށ Z_݌Yp&k 'w6% LauJUc Y> |jQ,Apz=wj>k58PG|KA~h Ʊ>d+{Qv5Ĭ !DDsh{ Ỳװ/*,5%~BOYٜvd&iGGP iSafv[͈*L슴ddb$glyH}oGr)-jz͛"DvVNI!Uo]awl4~XoJz{V ;Z+ⵞ=(r`&+K;O}Or`^}9 l_9VL7bp>37%2j:;P=zk9\u4H(uZGO~qU@Mgi9CO/x=E{hE,.& ho#2]%xAi>"=ЧmlYv|15yb6Ʃ*gAUN:{A lS{ّrxZ;Y@HA)J)^#(TQ J/ % =` 3 J I8̣dvNw9suݢ&?=Sn!\fL?AڝyX6Iv5fK,9\%\  7tGƐ~p%t)w\]hv\PqeoP]n0QMxלvAZ:5?<0- Ż3TsЗiD.m>FZHO{`_>P*< 3Q#@Hq]9"!αbL?ZmDg>dQ󾉫=#-N;ЪH^ CSg&ѹ~S_8 [zhIHl%Aw.hŀWrWp~Υ_;?%)۞M^lF ~#9-g@ԫמ7r)Gl9֍_^A,1cR[<%5mK}5¦3:C tT-w ٳ\%9yo/ccle䂦}:f+4j:>BLٹBëֽ|)3;9G{Я+ U3{F8Β~$Ƚ/-fXt~c 10]nՙAsΑi2~[Pki׌z w fO؇׏Tη W s?9ܔhO BJD+_@v m~noXmE'~7* !˙(osD&xnARb$]uY6b2HVKӤ[/z>-b;j/GCezZа(yc֔gx`Q\M0qu6*neZIzI`TJ%L n -VfDvUTGIO?83'-r_gİ0+_~feVVyj9buwȲX=xbGt:BRD̩qKpyx IAϟ>SATAqqޅW,{8}MML78q4:m\Jaq9/ MsYo8Mx4G|iC,,e:vMLί\ƓI6kfu߷bK#y<O@k\3mC*XnTIg=m{qN1H^Ӗa~m:fʤ yr;]l=wN迍5م,;͞5T?5xcR;g~0c[*`5#Zy~Sٞ;'TI4[E-n%ٚ Y )Y'dh\YdBf3UI{T"/I-A#∆m$o߲Y4^TlqXM#rFr% [5 e\ c`"o ?+cp`+'/x- DjԵjd*Brqb޾ض ~}PYнgYXLjO <.(N@e- @u`knهFйE-ӝ@JLd[vӄj2c20cRe#srYzG-f&"P3p3z2Rdѧ)eb$Wpߝ`{;~:ys"3J`냘|k0+VLa> +5#-qpNl:2I\7I+f,F\mz[[+ލ.lbРs+Dƛn$ϦJ6aWZb柌a1Fdф,BP&d웜h/AݿWϖg`۹|g;|K60'"N$f7?o"z{`L"Y_ ok7&5ZAA$7񇬣H=< 错*q,QyߝhެϚ+SWY Jn; R-#VCqQAԔluKCsPt`eh`O[[Mų" p#nDg|AuwC|93iq޾4n $h4=k|l]zgڞ}ڥ&k]8e~l:ׁFhK`0X8W9&IZ#eW/'8MmȚ;T/jUqA:C6"W ~WwT}n>Ahv1Cgq$J%f }6(O42$?9Ub4RmG*kA*>WmѨ,#I6O"xev8/0T=>|{XV?rXS:.l ghqxgֳtv L5r׷U0ONXˀsoo?SS6Y,\| dN!QsCp3 T })5͌r_Fԙ}%N5l?fwA0゜7}4B#7Q!^|QԂM1jXq~tr>'RpT9X2W=Ac-4?*"ޖ-pYA~"Ȯiۥ.S.tэjw C;Rz3hո=/ n Ngc^x=V͑|ُ/"DO^4m6+,P$ I:tPy?kUàӀ/RJ2 }d_rVwB?4?fϜ \?&rRCɭϷf_L`7)-tA~4ηPꑜjhq:Neh5}pj`.2Zݭy1 k{'OIF }TOw5T YϜcU._{׊oPdKPʁҷOU~SbdYK]%\@rY"JRre[3'DVIiEN^f ?^ۋZ:@b:wlMJ1؝g?:?ml_I_;RUc$}>{^9=jX+w:~? 90<_>5iĢ1IN_)v| >cF٤7 , ݟ̯"&ffҸw oAx4ePxЉ뿞Y4+گ bڿҢ+E#V '+4\b҈ib_8xK8iN^q69F%a犉~gm%h6-{oj5Z84XV@zS_8 8Ncw|LtÐWZ'++to!q?FaSm:Ҹ~|#PGd\jg׎{hOj2rWGd L[SNCOyiy̏5 nnLNJSϙMxcrSw3oNL׸b(72f|hݣcHJL(2moџPIl56Ej ݔOռ xtJ#")$nϻ߽$_ͻo暹wuks_]s>a&>'~prT,wn]Gˌ%lt_sN N=̨ up1oOMfʹG|ˆu&nRh7E#F% ~T#lJ`=^]FW (dqqLGLwf1߈BO%JLAJzo+%1U#Znҹ3ÅoL8ЮR5#[w RRFBv -A32&h=GBBG~m/O64gier(~}s$ヘ>e 83j6K?bKBէ|?@ g@? \6a n4ɺY`EC8!pgm C(هc=m|m޳5IyZ鵖D[w!m^8CPN-}P | hzu|eˊ"U いsVuA*=f&\ts)LHf{"`/"+^.-N&"@ P-ASjz$˴)`9j71HWcO+xZ g5W͢|AD|d @ @ [1,@ @ @ X pf5I@ @PU S{h ܋&L;#4l>b^[2w=[9x>?rȷ"6^|tQQڧB6"8/Wm@X̣(B9BOnwZQF+F>U^Q<_O {I*4@OzV왷~T裣t=>KVnt\BhXgThr;k ᗗ*fMh3g?a{Ӛ~+(%\{x IDATeuҟY9cMegUaC.[#a!`ټԭ&m]+OO1K8cQAoGB j4]#jI*ԣԖ6Bƣb|:BO{Fs\ |A_V}Tk>3m،z?NI1] '!amHa7}ʗN\^}j2eFqK/vZo(}Ď׍ljJQb_'ƥc$;Re~Y=[TR@lJDl[="Ꭿ,Kҹe Wf;+?U%>-k[MťoH^1{?1T<[^K_v |g,$X޿~A FDYB=_ݠ ?o*u ,Ip;yE7~KzS 5"()`/8v}|D7N[჋Y'e}Tifz-JEyW:sr$ZZ@PN+S¿DF0E=Fцؓ%SMNt38wHóD)V\= iIʅ uF23olkk˺}3]ɦtbeOʟ)Nm9Bk:8^$V]7V[oIilo^v:&6 {`Է9BhV|ғ^f~֯:݋wkVغ\Mqy02LL*VK( 5f6|\&qQ®Vb"#ǯJ+Џ\Nq?}&0Z|=)"z_qj,nuT{[ONU)tgvL1}OO$5B4γUC1/IPC=4nNef-הaTzmoщ8? `sTrF0Bh^6FwɎ;Fµ| aQmgg~ǧ}D D`_PWxz"54lAv$/Ջ}ݜw\hԏ6D3(t 9vEKA~ 7O^ߺD<PL@cHxK8or)e fLJ , ^voY͞s[skSxG35gIk!Qs5U2q@]ߎܧ~AOŞݑ h~$K/gs͠y15a 4u,7^Z̰v6b~aD<ݪ3#S _n՘? #"roR9+8|vj.ccBLٹBëV _Q3qf+4q7JM-^IȖWlzDDIINP-=1&-H5Y7\OʱF62rAdȃ{;7v;3uQ6!5lcעT5cJfʡ&~cb>dָF6ܿi׻)3;9GabNF,ޟm_k'cW3KgyuU4⤣|ߥ8+O8#>i„wpdӾ˶gdw|8>3/ldCL^h^ zc?s(N$d9VG˺ḣl0Y#jW9/6~?\ӷ.ôVD|1ҸS^5##0yL51QNmY9[[7~ښzDnjIw/ZoKoz\gNتO "η}0$,g{y4F#2s#삯N`QW RjitEUЧr u$=$0LGRYЏU(QD)t$j4lQfO7}R_gİ0+_~fe]20ss:O`d}˞aq;Kt&6~Fo?wK'Z5.ƙ=\L0Ebѷg)ӱ#U X?/x?8:gL(ג2X^81-ί\ƓI6kfu߷;f}֮o<<} +uqt-4 gپ4٪X)ݜ1˾a@T~YY+cp`+'/x- Djug?-<ݩlCmOӿlm~l=3'l'((J:2h\u &2 -IPMh&3& 3&UF;2'|T[ki)E>rԌ$24Č^,<7_QG3F&5̶ pfsAVGI-DB*G>SI2Ka&;OnKnuDy1Gcٮ^v,a; |&ΛCq.+p&b/,+AqzgnKV]-nM)T]:dJHT 𼭎)m}?;yS7\mޙGk~rJZ|ª%;S­]7s.WH=>Gr;+UŅvۀ bo nG_y|f4;Ę8=B\>)1$jny(n$zO>E{/2Gi52BX#fףaE[?^5G@m`,J/֯QC) +wla)?SBJS1-Kz8СK^6qh0Fen}l52禘eEc%b{Y_~qh8\G2#;[> ;>Zkif4d<cƤӐ1e'*CB徯xu }N9r'k.F"~K!4$Lٗ^ٍjzj^MmrsV+5hUErSy}^L_ "tb.f52β@~ZX^ {9\2Ь?/uA5O-UgnF}؊`-~<ߥ*Χ [$YA 4?mKkiRZjw^URE<5Jwr]9%nQI=~z_p<Ѱ%\ۢ _иJ 4աO뉳5:`lwgNo8Jj*hm``mlޏɥi9n!8θA)D뜟򵦿C|OyD79J(ށ K6='DVbDRu;i]G})RWBQ\/iKtQ5\<ۏē!m_qsZX&uD倻qoW $w8%ݩD,8OVi\u乬ƪ\(Q w,W*4\ِ?b۩fg ;^B5"HT7gY;޺ ?Z5.K\75KҨHnx(MoLn~ oOQQF|iKcooՇC{^"xy͛3H7\·]'Uɳ1/<~AO.[OXYA~"Ȯiۥ.fb2DZq~o PE-OZ]_3vz$xځuN!6VH9vi5|֏M>s6}}X4z:~3氱W2ɉ+{.u ƮX}!u;~# xDZildfG b2qzBu(&&?Nڃ2_Ge `Q DعbYF[ =:M^6ۧZ_T7X7&JSc)e̦i1˫gy'lzqVf?`̳mK]ZW7Ws\\/S)] H) vo1o ߘpzE] 0j$FrZ ~kys$t*$1q׻11̓tyͲ >f؇LweioDO`NЈc&Zr!E9"Szj y}^ ~ `LՈ;;P: Zʑ)fnY[}տH9̩7i 'k\_1?-_bX}8g9q* Oue_ѿz7W20EoetO9[%ǺWAbޙј=dz#Fbe|{ p0A|Tri䯚ɢ t!)2!GCPjX?ҷJ:)//C_:&_8S[KYlĽQH1'}4ңq`gX9+Hxp=aFy{n5Z#GZ?k*ӆ~ G&qC8!qC8l8ih-IqQ/Cԟ=A @|d0Q@ @ yPxeAȟ@ԟ](]d @ @ [1x@ @ @ @ @ !-~}$ C @ & p{y[ @[rµB$DQ@ KD`_`##r:L?KVnt\BhXgT* dsa[QVg:*а~ybh3g?a{1SA Wm U0nFvkgFS44__97`BMQ[)b߅ng>TFoɰ>G|=ޕ(e0tttRWlNuxX};DgkXS =@ D`_`3j58w&$>[88hAn@sSt⒞?P_x-ST6 [xȶlLF3&m k7/^Fv1JN ML-@h\gUs֌_Y s<;ޯ~lP#p֑J HMS;hjiwmF&/0B&~5}O~Ru Ό^Yӯʰ9>{zqf14:DZ\M4JCF'uV)_X1IJW=_\j:*/VK7q.4)AAKRez=8g8Ȯ_&ѵݰj&SaGt˾DOASXceڇ;+4Cױr^B ž3I9%P6E< qUrgG[bO$p2S!=V#=1o +T$HCep ~l$3aN|, }5z\Wv/S+RʖӵllO*ZدbNkSÔy7m*wmd?C}.Ӓ4j^̂ <ٷeU5 đM}W8~#/#']~<Ħym*Ƃ݂Q߮pX;XIOg{!C!x[ꄻw/[Y6_bkBrz4\L$313Xy,(7d䏛Ykd,8>9 R})bߑ' oX}ɘA|d=H6rtq[\l?Xo%\7;v߾E h7{9p:CoQ blػ=?K|TJa YV!S:KTNO:..BZ>N{x ]$ n}B! iĿF(tyBנz: pz#GQfCm *w/qi=ݲl5TpjveQh7CO2e]m}$}`)Nίf+\7z?Xu5?ɵ>]!eÜa4psn.f31SAgS-αbL?ZmDg>dQS&BG-]jNq]QR-͓."/Q&1_%ڶ˳ Wyf''e =+Tc{ٽe!ThVz9)<ݣٮ'.4|S_)4,jp_UB>zeZu&'OκX:K={vGZ4.OwU, }6 hԈ'psGױ哴W%L9/zT5a &C,{kQ*ƚ1O%3AX1o=hFyvk-?52%Be̞QF63W]Y'uĎLlkb}R[zcL[zQS[H)Gɬqy#loIi{5;׀M5򗦣ns^^U({Fv.-oV7//8ri_nI>ݿΘvͨ| bG6_2-9}HvШm6귭 J IC_ڟU1hz3UۊNWY>nUB3P&wLί\ƓI6kfujp eI^h_}Z:Z)7 _QG҃N ^tT/!ejw[Ii]`^$Χo0ψaa`Wˬme q7L\em]>e K-^%x!5{0L9S5Aƹz^Z\0ˎ8*ӫ5?ׂFs%/rjtEܙlP`ɥ}?\Ў 1F+lfzP7xWWI\Nv]g~[@ %(B&a_'k4o3|2I/Dε .ZIJC/ydD?[΍<;5i=}[o"zUƄ()m 'C##9N0T5kHVGm*uxgdʣn_'K*zfT2ɸzw0WqRYAԔl%}KCsPt}i}f=۟RMfݗK@*I{+SWY J~5TPSAvdS3oihNy/+rYzG-f&"/\Y]^\n:w\ RV}PPMfLF3fL^'Yo "%-4?zg71z +aHLs1ՋZU\Nǡo "OFR{9 '@F? nkfp(QJa4YA*>WG- QYF`Ry|f4;Ę8~Bg/\Y1?Ja%V1 kpq9.f9%D ?̀SY/ɧH6[?oNe1}_##*Ջ0bv=*Z?S@jc XѯŞ}ɽ 8W5.ω :K NCj'hd~ZOߖ+WpC&F@^8b3쵪(w}wr9Yz-j2d5M1~+)k OP3+(_G1F#! 4QlOO )MtKT[l\ a L%tO7R7{ZI4#} > 3hz-vt^8xJHYm;/uMmȚz>lr~[H8˂)l@ (xJ zu&zBDz0_Öp?R@ӆwdpEN|uR5<~';qH}z%P4)X;D"E xDܳ]c{;I.R\KN{̋ib_V r աO뉳5:`lwgNo8J ȥi9n!8θAl."OYϜ?k`mlޏo#ՇcJM oӬ=f3< ݒM*A:iRGi(X@>l *"JGATD TA PB1 ( BBz;ߏ$d7yg|0w̹3眙9w 5({ ]S; Ņ#=F/Rݿs.݊&Q8ŷ\3Q߶!5 jaW)OP"_ !yAft0攝ܢA׿XO9~(;*f.9&P8w.j~qU@qn̓t˯g'3?%pl9Oݬ?|k7r1 ~gv5}@cʅ A)z;w;'\M}kUKKhhfE-HS} 9 @ISo$'9hI:_p &-0fڏ/g-T7)4}SW<Sgj%k7%&Fx|1d\T`[jr|'Qh&O`AT4Ң8,J@~D" b_"H$D"/aט[5/- .H=MHY#H$e.D"H$DRкrOXte]:OWFh**Ԫ'Y*D"L@U%D"H$DRjyDˣ/hp0MVS}Z4hs>/H$2/rb肧4?LxĄ=TxyBK{ZLXGя6c<#.OxG#}":hʛ$ Ȏ7Lzk-;ܦx?ߌ6ȖF6q.hd3]X΀&iq+Ă2]\1 1isvיNczj_6a }~cq$֜]t >ց֊mR GO/:h߶Oָ9~%Y_%?oԔ+^=$ hVȟIА7JsƏ~3 7Tl/kBܛ~ˈ}bszWWq/J~WotgW!$>} a~ K ow#OK/D"/"1=eܲٻaL 2}^Gp`[OjW`ɰ1[5OG_1ora =Pǯ:K`0z;Gg,O;|RABx0E>,pΚؓĿ #bi`/C DV*: #Y :͗0h_p!]`=qW' `e0o?|o\F\ OqZNxte7[3Ыv ? vn##x 3~8w{࢐|G=γna)gtS<<&{gQȟ_'oǍ_I;(c? 7zb`-LmłB[~#bck=wؾ;.e.ng؇JlkTjL Wٲ*d$Dq*`-?#Jz^͟u%j"g%5n&$}5)z?wrP/PW?g2Oy-V,|@K|0G۱y8γݹEKְ9@ź4U`)Z*q8_ Nw8o>g>su{zPeE:-Δ( w|GOA usu4ctY'=KZՁs7pZV闵%D")~ï}PU<Ӽwa-KZKT5nEi}A7kLFi5QpMkog]"UV~{]jqAG'0gE]Fxz yn|[@Yl{Hz .Bl+i6_Ot4b֑?ӑK`p*?Nm}HĶbTx4s4j Ža㢑<59>ցcKD(b#V"X ?S?z+f{iޜf]#$kشpx{wJ1;QX ]w\[&? ɣ֗R**Ts[O+9Bءe z5+#m5*4ȯThk0?*_O'g~y[ ef0u- @=6{y+F |c:w!YQ񢉝ٽF X/먡?ȖIfbh77zZھ!#4]šbsāeSf^#zL4y߽'C-4'8e_cG:*}]1zѪ5Oku}/H$I9O*(/T@Cݚ0 T\Fٞ>\3ćbIP9 -aWI2 L!*M}>Hc߯>UV~ NN>ۥ&43|ҎF߾%E!_ŝ?$kW6ғҳ,Y贷1W$-=Fd;RsI{S tZ@[Ȉ IROC%\f6t<>33u ;Ɉw-ol~ <;"}5}-55|ܟS‹쥞gD"H$e/GēXwnCnh>0'\'Q8GlP*tcƜ0M6q-1YJ K/_Kpα&~g8AY-bgNd|RO 1]JΟk7) 0Mu[mߔ)EUM`\x?ǐfH3Bysspl1zBx۠wvŽy JqO}JXF!7?_YG`J$Dl.ma *%7Sf.=^\c{*Xjx 2q$\ZbD;XGOl`D7-0.Kv,?_D"H$IG$L2$L2$LdXL/t,_Me$L26IطTYD"H$h"WZ Vr8,_oDRh>UP6D"H$D"H$Db 2&\J$D"H$D"H$DR}D"H$D"H$D"H2@wp`n+eeH$D/ڷ{8p4$xH$A#y`yh? Ԟ^J^%}gPh:]Oyzv~N4<2/gJxDWâg>_Pö[X,XNP[k]5zL2u=GWc8OlbL]}Vfz5ҹ|lf/D"m+}0 x>=K7@̯ʯ:>줣VEkVpͼ9Jtp,v;k]̤U议G3xw /?W~-/LxD(^5`uゃG2]ߢVDe)Gܽt$пjb-GqݿgLw? c_ʾp6Fio}yk~'$"{s4vV3Swͧ;7 NE(]BcCo}}7}te]~Dbii&"P'L1cDc?%ENU ,}%ӷ fY-%=-&,`Bq(̾܏[ :q=5/` 7r@6]T 0aGMg`neW˻R_Fdфrq:S:Q92A妣t6r0Њ$ .HMMct7N.S~3o djŏvX4#Ϝ_t hη,7旓gSgt@FGt`_5}.8bqDKWRO%&ddS7CCf*mNaȸ\nёƪRϑ_ta9Yɣ5+iWL&|@+2&.;`ʯN==F)5^5UCH|O/I$}Ei.Iʭ|%d`x3'1;3;=C93{#g =936=~ȴp541m ~ӹful$#ÈQVw fP¦ D,+H?rA\ Mc@o\ o]O?7|{U+9cOcŻUeH懔> kTxӇ5JW2A^+ f$opph7sA[п?=22cY#sr7؍o|ȪxRƲETd_0]֌. ?-~?,=_aƓ~fpZ"jADmbʫg*_#iw1;W8/'Th0vXNn^{Tkך׍^ctl6{o#L=M |O:m>nYQ8JwԘeUgM@r#?zn=~зoXi_ٯ)#l3K6_sçBlZIs/ߎG@3\Nk:^ٸOm<\О8,]qq/#C5qexqwؾW7kO~ _uidvfo#W͖DZ&kp$;jAB:(U4y]-}`MYgZj5PКqḠ$fn/*ħ(٨ U _ RY?-O5 &k8 YTai&u\Y`(ߨd:T0h!)Ub V=ΛŻ B5S󬙸\++oc77* /\IP<+oXr䧿Vt#UN.6kپ}m ~}Tf/Si{20 :8q=+r=*x6P h@#h.zՁAE#sCAjęCȎ+)|dGWOP?kd_n|[@Y}>s쩣"=_&PA",ߡntHGN86`["xbWs9@ʾs&X<>2G~>MjIo>+gO4VRauu0.`dh!c|7=x67E rٌ^u}p>t5y~{3T <cb_fd(#[&UoPrh]U2U&mn]cly뾹&٪ #knfDuTv+~$RpMF .sh!R%zq b8%su^#zL4y|g6Zib;&O4q6&&Khi5yPgM|5ڦFtK2r}%*If):^ţO!i]F gUh=k*$ AI'IueR}jC)h voYOYltOCkc߯>2G5oѮ[K#EZ*xDAwkImb#K\T*(L ;M}a$pAl@(?[>cqh][hݰL-MHPa~Aϲ}/Vd{7+׿RK~?,=_?#~Tt?RaU+N4ݳ%RNsIڔM-MXi*vFMsߜ~>)p1+ţ" gch=;ҫ|3TNׇs-8曫 6v=߽I7zuhLk׌G\Uh.*˃˞si6ט/Gql"\\.bSG%' AXy*WT*7sTc9c0vԷ+oyE -oȄ.$G<]VU"ρI/,0VAzmAARFlip@@ H"0& Rޡ( WkpfU kҤ* T5j .d@63f_ v`AGzzߙh\^VAR|f[`<SAgU:Q+/|y_BU? Gpin,R{HK_ Vt}VR3Q%OWU)@߫|k'_,- `8ih0AOxo܊ܐA·X*/. XδwG@TGǕ܍DTUe&և>h3t 2{~}ǼߨKcFlbw'.lppJڿu"##]?n?Y+u~'^;y}* eaY dR@lX/`Όs##g}K(TTm '-#R M[CClcZ|10knTN45Xr!d_˟X%Vk'U@i[qJE7^j*$p%Δ]VqSKߙ9w.Εp&8sv~ZRv^xJf:C :Ys\*UwGyZmٰ\`;wi $ھO^̊RjJJ~ŭ>f''sf`?FR4%ǒj.zʷ޿塵V/P&3&AkDm# h𨤠-h.ZMSQ %W tS tڜYd- XFIzd{[ اx{hrP>6!DlFе(VYE {O1&#ȌOE{}@' %W4=F ajǂ, :4wfsma}oemlj`֊RCUu̅s%>yWϢ[?V>[>Q[>_aT@˱OؗaI~h,?}61,9:9Sh"rJn̘7>x[."3?Q%F4̭d`x'~g8A('cٸ*D 2g=}~zq̈́%n/%8J!R&,3#zM- (HLWpN汯gT^V`|gX|a4GQr>=woѡ0%Ԣ=1,WeUvDZ`Qbk|DEpU "˜|጗.J蓎60#РcRWUNꢅ83`#ԂW>7AzT(fT3R1#j8Qx)}ME{LG!YoS|oc^cPe)KoE lb2 )t[Ok\\cF:wTڗs駃$H7S`-tҬʡ߭1V퓗}WֶOXBd֍)>>E:p3$S#wQ)7Sj2ifiFT|u?]^;2.[3xD\%EւAOzeѫ87ϓ醃ub'7-{yRNnGԶSUWw~9Χ{ѾEۂ_K#ϼԎJ:xϐcVWf7ۆ:4A]<BRg?YM_?Yy,Op:œnSQ}- |mI2@ZG%!c ^ylc_נGqe֘m!m(R[IWoy_++4KY/8*S )˝ƕ$|^ ( uz($?Zky%Wܵ }{-U= "Q9V Ǭ` IDAT 6]#LSLD\Bp [ Ũ\PefCqS}@!/"_ *g֩ܜfJ~z@J\ugVK*a_QzS͐}}_Y$B~a~_#2_\[m河O9(IR rCLCj1DlŻ?_|l,o΁#;Cp<ܼ*>(t_nX"z$^_';>Ѣ#բ|$&տ!c,M=F\oN1A阢3O Kß۫ 瀚t#O!XߞwXs]lq:1sNi,5/G'HZt}n l+wڽ)9fw6jM߇%Ƕ0ewc PG-'^KZ9|ޭ#v%2@fWQ:7 >W6gֱ`Lr72RzC&B--PQ ߤM^`LĞ`E C= Lȁ_260\K ZMⷴS f"V\G=F9:kFS[=D Z2?_YG`J$DZm)WڱVih4L#``~ RO Ygu -)\oZ^H-J(fӾ՛fE=h*I,>i~ "֪ %Hk$`:gZ\HWX\ID,5~8~'?I&dI&d{7w9!L;5=݅r?|+[J$3I/:?EP/ڵu$LE}ﴏ H$D")(8_-G4.WZPSpH$DRqYD"H$ej,|@M<,+F")瘣|.G u'*7dH$DR֐& D"H$D"H$Db 2&\[H$D"H$D"H$DR}D"H$D")sy-=gz 5+%yhm D"H$ؗH$KRe=_Ml x>=K7@N[;8Jx6~=5%xF_|h~$Pnd۝ϺF XP#XTҖ*k=ShlNl+tod~b8IҜ^[ON>1~m ^kb-GqݿgL+ dƾ,귂h̡PO,cdp6Ff^˝D oR~D"H$DRdt':#yjAs56 Vq:~ձ7zb`-Lmn9Ж_oHD(Xq?,s]_y qП/v7p;+>)q9M ;Gcҟ]NO-Vk*5elY 28CKfb}1z66*ǒ~ 7@¯$c.p[ߔa$#+Qß^X&+s;gwxr@꽙~/i<wmՓ;qL۰!_m+ũ!|=ᡄGypdᕭG1glXǯ;wyZ=V $,"𰝬1\|P/ӳ?xSH$DRn}D")n yn|[@Y}旎=uX =uD)O68ݲu߬y{05t"sG|1ZuxiJƭ=2ں"CD"H 2/H$ŌF5 aAS?R_9b Ovdzo.槟6=šw4~wARbV?{g^>ϹkUZ;R{jVjROUtSVVQT)j =Ъ%vdg~KĒ{# <<33y;gΜT@$u xա[.isl!s׮?.j)dv i5h#:GcaƏo6ǟ?CBZfuy?qߎsJfo%$li|3r;W?̕lO,-20WQҡ7-T.%䣽`,Q^fʷW9BZ+vzL}|Gg-ӎ;Ni,Jl+JT~K:qiGq0dzݗhP5pn g5-&'1ׁYAϐokQʸ_ xJY<Hl&1tNjLZʔi}ze>'o` 4ݍ^$^%FB0By2}XzYgû7:a >%qKF b}CcHz*Xί|_v$Q_W ī7_4&iw%D" V<DRdb |:kum '+ء&Of}WOJ|J \iF! 06O= ~ |t8Wfh7/"l7cu_qHG?H kk;Q?n^i2^$12K&@C1AƼ1T.B>F!]謠+īW?9qˤzTJqfn4-:EAQ-Z嶏[Νeө S1TMj2pt&}tD-z^hl߱:/u磹>gC-6a + 7kHF5S(T/Ztm{\κӁ4u .U3 xKԋ[Xt(7F^:S5 |5ZQ\sp#{B; nND_$U][;#&*`-,'D"H r)H$f+-: nw {FC5-z$LRQHT'n+yv}j x1iv4#y >MЉ8闉\9&'!T bVƨq.nVj(Lz?ϱy#]$yb)36aL.L#!.&O u>t(ХV`J=C`ϩ)$ߢDgv/㽷qG%h2~lm3}-gjGـ~|4WӤL{{N~9z bbs52mͧ?3L(#m`&e~kcG1cgɗ콥J&lJ炝L-pyOefb(g6Ⳑ5Ƒx,ON2b Sg# ;zx%H$D񢁐] H$D"H eBp:OK]Y^_w5a’%D"䄌 䛈D"H$D"kd * eO#37.î_"H$Fn#H$D"H$0jŨϧP gH$D"y] V<D"H$D"H$dL H$D"H$D"H$1B%#5? q) qi@8Q Q\>8H$EĮJ&HhKM(fgIc*Pc=-ZK-$ҏO`?OTta SBFI%Re͔3*zgπRpiOq8~u4.4廵fI=1~IUQ3op:l)G)RQDV>W9Qgҿʩ)q)0#V{z, rׇśND}il5 h;w<@S0}+Z3E::ۛ w~IO[ *ZcBBAT67zϻ9_}Jr \&Db2ә|IXv-Edf jlGgJşX:r c̳~|1$λSә y ׈M@#xjF;ql$;)>zY}Tni?JGXw:Y@b$S &vn*ldbZ8mҨW.zWo{=YWΥ+S0!,,^H՛8o4z&=˥i[ד!Pѥe~3 Y=Xc9dwQk[뵛2]|k.e]5lA+7[k= 0gY'C>L5F1{c~K)ʵլ*ĜCgxG Ekh yESgIL}`?=b뷤OsX쓶V`ʼ3{ ͤr.`8ƏcU?\~3*ɑnحߞ 0֌{ f.v6Y7W)۹=G#+t|96оԭU9G8bKkG?3~&v[ŸzJ ov.6g{;o坌Q:/S3TjKR; L̤HvM#Eb ] d&^ؖ%?=_vM;$~Yǚ/[y/3iɺ23w󦬟VnLr0w\r??76V2sU_lxJ;TW)w{2eKz`ۡ 7S{'.DE 1α~-TTOAZu? 6㭔zr>I맡,A):`v_hl j4X o7^ UF4GOl_Qp7u uGh=UO$#ו$~\7f {9:?y|??? 3ٷw>?á\9Y])uۿ{9_1y_y򯊸=Oײm-JCٶsgu5?_~|v|ؗ,zuU Džr*M5O ֍Ue~}vb+@_~@qՐQFƟgJo|^Wm>"f IDAT`:5 $ĭ`H<ݼ}gc{1⑽hVu:>IyqWp7Z'f>4T'b .nut'xJނ3[D>V.x J~o5jzr[3[Y5k0A>r\ܨʳ[";x!#É3%xa47_~r-+Sx[#yΟ}ˏgsɆΕu RUy1x| ~?Īw+Ҩ{ޣoNKA n"ߩݯ-ewdXÈ;[h4?Mni}h\.ۏsž}QO(!t[Ƃә++|DcP!?n3!,8$kԎ$_O<ۨqq }[*t-Ljo-z[GW~`KN1O$N8yvhDQ,**ѹ¹LEDQQȋPK~xY1s'V;=PzʶW[P~_~bxgis zm9~o .P~V޵ *Zmflfif{}+sLc"YKͶ(=PG9Ž&BX^IGn'ᮕf6->OR?֧C%8Ǵ>/Э}oM}>mcw~nwdo~舍f391ϗZzhYBSXWC ſz ӭՅðuĪ grc%2/J.#J/ӯ_?Ǡn%iӻWym) ֬7]B;XEuyq5gϪؕxGjfާ,(RcVRS5u|ƙgXZRu+hӾ9~.T"1',^1C:)]('0Bǯ];;4į!F^$"0dž|E|O|GуV d (ɛl,٩r%gc9z4?ϔgRpVygpX3QF|?Il~m5N6pu*?bX]^ĕ煾7hpԉ >/uGLå]޿~8^NsjZ+:pb5J:`ѝz;y y4l\sdQQs6?L@DyN^ hIY d+4;=KڜWgp1~ ϢKL>^s #61cT2HV}hХڔGp~i \?Ix[7WSّY?N?\Hs\,I8FArߜOo=*HrhW=o|;|ye#}ÁiN %`/zJ9VנR_o*m8Ӯ̜<ۖ],v_Wr27vTԟpj饑ēr?w?Ǵ/W L['A}ykpUF{vsv3&E贎=ָROǍSW=³fKGq{{4C:eNhՌ$2WNC ZEJzG~ŻCzYF9cIx~6%\&YQ7mĬ"]`1(l{h(]UNu4'eAY@m% pVio/ɧf/IǃXMS)IsS>Jq-'ʶZYfTقdA`jk˩so?q}W>\cxwȿ[cEog~/50D0 \l>n ypX~^>I%~~t + 6cr$s&2IW5n[~5hP3ɰy"(Mo4/q/nb08OBq~xK/=s׺]%IU*M!}֒G K1@/$[S]R~O^ch BOr  1IYv.8A^CaCi'dy$?\?IL^P^ęţ9aSU:~Ylx}sTN^K O}N.BT I|`\밸W&+?9LmW^Ɯ79X-˱f+ɻ>&}}s>Ze;"aIJ"(驅x ` MZCWfv oOH&! 2.Gl~|[Rƅ-f_;Hp8^:&  !K_65.n^.e8EѼ;#O:#6K'8Kn(G#0P$\ؐe?:=A~ԻBfD^n̶+GԎ_g)t\=Kykuث~wIiNU\!VA{B\>H,SPThs?IKAwiot\|J~ui~^'{Ck_euY ߞP=#kW9_ۈN*N)yдg ʹ1աkR&*0n1bBԋ[Xt(7F^:S;#&*`-\x7p|aH*:+UON6$\&գ2Ugf=p$p""5FSyhҍ!9( %lpczhmݱSR{wjjQ<)H+ā[сVg5\=V=,Slkx*t6M{ێ3uﯬNԫ菇ęI),u腫?5{=UF<k:+3KsYV_.Ǝk8w瘪&rT⥀Q|o/9y6 *(.6)b*C#Ks-%}#AD۶qm <.mw- , -YpB@g7( :(dD$9JR~OR?~|/fϵ =7¼'77?ȜG^~{IAQ?ֿy.#K. y (Oɲ xQ H_V' 8 Sv[(E2[ؿEf1Ma?>͐]xNlɄ7?ǑŨy_O3>g#Y tpz\FMmbZ3c'|J9o="kVí^NP&lg!k#)4.Ym8_OphW:Eal~:~Egm6b ."GPPMK`0 7ThjiV@Pk[D7qצqnϼ3vn>8Q|h6-ƽQWa&jD|DA<˧zo&؆2ΐ~~??ovj;Џ@%j߳!T bQh{5q"N8R^0<ɰ3]ƀgacXx "!i6`/}㊚|}?dcQ33L(#m`ޯCs֒#KVYu  &r ֜IġKӆ~|zIٽZ|xpEM~0n+771S=Cfчg/q`(5rDꇛ {]q]~ M^ڛx}3s>aAkdxg99yD̖$R qۭag3~H>eSҢ-Ed[]i9cB3TPS=̐Į߱G5_K ZH|~VlJ炝L-pyOEg}Oy߮R{T9={9 ھ>D_. $U7mQL2$L2$Ul0Ik[v}"QShN9 h,R?uek`?y4s$"Ӌ~΢켨ԯRܢpHD"H / Tc r8=lF` $xAӲW%D"܉T+F}>Π_`/EvDRı\NF RRpe8~O$B]?pm`Db {V;,+fzD"H$D"H$D" DXҩ5hrr k Q{J)XD"H$D"H$D"HnG#ql}^mrؿ35?@Eźzǁ ԗH$01R ,֥oʮDE/Gq0F"GЖ0~QΒEEL=stqD"H$:|!AR`PY3(0Yhޥw>1RQKiz+'*:er| 0GO,{B?46_A)8k kb~ڡ{ ~|^AfDGud6-r;pTWy jxD~*ue? VVL{ZY ZVl!2:v34֋Wfr#XZi*AɔF΅"˟&.Ŵe1dg۾-{|ÿHk^j)#\wߦy巼#G{_va'%گ-I~DXŜ)E\OĆLp\"H$e) t]U{0 T@Cb;ow?7 %4ĢebPEqrDiZQp)/qdh"mIE4M9XQFpvGԈykb;EVQ-B[7V>"=!Jr-%QbˁG:^n&JabBDBEiO]b:.ED|D hD7zѴG\NeQg^hO{{zѦBC( xxksŹ""jhᖛzQ~"wЬ(+J i}bК绮QZuYw)n >l&RgYBhЊ2+ŦDyBn+flY+6GmS99ʗLbšGqEْFǻA>~yM?O5-EDEO0xU[/hw|jGQETd%گq5 o_-XLڱO,}c"?ELU&LңX+(^hr?xzN|2$L2=)?ge>=78c'oKGCwbwm"U~6kNыFԈDE<_Љcנ{zybx{)lhPQO~Aq`Vc "~=.ſ[|ƳhQuEFYy]>WDՉzaR8v駃Ak@nƚ;0s+> ; B{~3j='5]"o2l#tk`?|paX,⛽)9˗ەK kƽ-&/X,%v6J {""aぁA~>u˾i5#DT&}shȍb񤞢JKX;9ƌ%bMb׾Ub\=3 Wle6]Zri /B}lA`\(Ք#GoT=IJoFC ~Y'|Bxb¹;#?EK{6|xPq`~+vS|ֈ"#{ŶEZOkKk5s6Qğ.jo{"j}sZQM0hDݑ:z^o+CUFD9z<['wm|DӉzeVT{Q'}*sFf[eh5D#|\rq]ݭw^/ӋvjEOiDwS~ꗁ}dI&χEXw8@ ‹ )@.s:eqq3@(Z ÂͬB*yERRKzjbw[l7y hKj .~Dõ"ʘ9,i>FW}\sfTѝb"? FAiJ}H? Sp;^[Gf ~:wjVOoV+jlegj`|5<] IDAT(?CEW_=:p#z]8T3SЕN\fֈggw h+_KA n"ߩݯ-2N;2xI,{iE49gqo?YP@ϳ_Ne>/իG6Qw FA7Hc#{Ѭf=>1uF3}ȓwlt`Atz- cLЕo>ɱtݐPwg LEDQQȋPj_D\+CCִ %] صT[p&k8}˔l)lηcSqBvGgKcs9>?6TY5 =U|UGX3ĿBKWꢥ& 5cJW2D;&b˟%D"q P6H+Mw tۥ'q^_@/01xq HvBg]OV6gSۉa +PUXX}Q<AW(S]pS8箥VX\SP*7T@Z%w/-D䤠L%~IGǙz:MRܹ;Cc&[v5ǕbFeKH񶉗gT8QUEi(*6=0HK Jȵ~$o6C;pf1w#$n46Ή&"ABRYgO^0_˞з1 :1sq0a5[m1.V]xa}{;S+r< 0_ЁQ;wy,i,ٸ(C:)]('0Bǯ];;į!F^$"0dž|E|딽c>A|09y݂6%ʟg\TI>sddoB9!(i]!zAgT9vB*#0UߤqU(]Qp!T "Azw RMBrRi jXEpW@&\XgREPA%@# !%9),\n?H$$Y5_*#@-pgS dZ`:Ppm[ĂEZb Xx^ }o7rEV#0 rL0fQ>6'tP ;t97Ab=u)[ևD(lAfbqUr OÓgb582ry-^~|("Yo5U{g3i`Fbsb? l;L&d܀*1S m{N)3zbZ>M #(2S1Ɂ99tÂ~<^[*9??=оN=6}<? lՒK#IK'6cmgu%' 󹯃=pt52ݪE贎0иROǍSWQGJ"ͷJz ?}Z7jI(ö+l# be̵Sqwɠ(\dƕ[mͻ|D0)~DHqrBIO"ty/! G4h=]m/g3*c|sLr/ گwGgiZfNh;GП D|v5k;O>N~oXf.&zkJLP~+.V+5wM<մUAY@mt pVݴ/m2k[#U5 o(f,ߪX=s' V4LO<=D_f3'eɯw~D"HRXw;9AXwCq'k[@ qװD.nu45v%<58Tj]CF g]2+B[ͧ lBEs?P4+L$gXWYCT[GKT YUT¿Rv%\VITus !#xx6 cgqC%{gmôS.-*6s nQdM% 27sf, b[YlAP}Z-Ua}r~l̓H$;\v&;~}Y̳3xv`mh7s^N=@,a-sU) 4)r1vX9.J 0phPO$&,:gjn38A: c{_]%bʵ PtY+n!8KP2@XYh|h6f_5=Ș7f`c)6\_,\s6dQ\̌ɴ7jbԹPr)\"?>5“nPɶSR{wjjQ<)H+~iO~RPć +Z=Ecŵ [f_ɚre[3h РU1ElߴGD?shЮ{=tT]h/ry3l(JG͡"0[LU2h'p.uG&e[8b}p) c"3y<>t uCG,Noӷ~O[Q௏F2d4;V2ڗEUd_3axLAk &csp|ɧPƍXyz"a\ o})qf½C663|x]@Jl:K~EYo l8҉qT/,m<هd| r4w)%kc΅OJz)hߍG .- tYI נA:,Ah]o<%Tw\ w20YXԴ^7`  >gπ],K),-b #Xݭ<ޔg+?;ʂ6PTԓ=kH5hРA /[|ί:P主^4#B4heXBep `ԺF 4YG(z[`SX\vKlxxܲ-"?;zj-Xs @d B8';cmğQ[ZkX | gЕ`cѳ6s5hРAta;844hР!=8cڎ:y ,,d0ӬF_ 8aq $}>+Oo7 !`; XN%,I5,v PK| ,F/?/pUF} 9m({+e' ՀlmА-5z'g69ko0>n]j^Ɉx7_eRɦCM꽽1ޢ7-.iHbC/-::5cHP 2D1,1\fE2ۀc*,NWf0 *` #ahPKP0CWo/@sa4d Q|:ޝxu8+~:E8:|n3{sD::KẹI$l]ʤyҳF8b8Vng5ƌ'($UӍـS̻wq\)nȲChߤ5]3;EK綔@pOa|B ?Uas]Lf. g|Gj)l&4$sE^3P;x~h m^_DhX"gU|3;?arz~1w8 >|57b`f";bGC5uͥC䭹 6gg3gF]l{];o݋94se_wV"A,Y7mD6ϛMٴBMh+jWD }zy$fk/Sktz{_`[/pBC)(Sǎۦ;ْЊe x67:Us4(KaC85_mN1gRuB7ţ EUΌnSxc*GrIn;S1'͑St˫_ sADa8_*ވFY( 1Wp^0j6Jwa} 85! e3՚htNr tlǏ.a#90qaߍb:41 נ^{l^ $Dra*<;7Td[m3\3S>%|48cU?/=/KZxو6q__Ξ;ʾuT49ss2o[}8t|ث?2[l=#}9f(Sn4V:h淓{S! O*duj#&{gvK9_Qgkj z{}8ȦyC*OZh2MOgЦC\;'""h=ZUkJ4隉JtIOTGqk*|H ?xeDwD<kh?P÷["87^[Жiƒ1ek^iڞA.8:CO[ycUs?{et@ĚV!AQg5\TzI6H}ohq}Uxcr3Ns7D IDATKzW/cts,G&.t9=y{ڋY;Yb(J 3C!݃)nYA!xT+r"I4d~m2}Jxg:mrPu\)> N@*V/}fOZ]W|F i_>I&$j;y\J|_z]Yx|Cr|$\cfO~:GO峬ls~ˀF3-I #86KHܧUIi? ;iͯz~U5(!*㙝_q2wL\Na+ l=ˆ3J.q!aP}jbNgTWݙ:G HܾZ/Z}v(>;K3h7EkzPvQDGxac^K{%t~ku\pR5>PH"-K ̄%?Sٹ,)6vFDg/ M#HAS0ۉǫ|9Z$AI6ۯd'Kj[WH8dBLIE'J~B,OeJ|6\Ä%!,.ѐ l8KyK}&&|b.H<]JHY &BqMf@'Dq~ # kL#($I(^Z&nvq~BN@пD$#`Lۛ2'Ir{}>TwOT-VsV׮<^+ύZXh8~!3cܐٜOCRp#~exRP(^(/eD*D nYi,c|FnRH`fIz]ѧ((Z+Y+o>g~~)DbBULz\]Lt`xH (ꪃ03` 16)?Ra2 hDsSR|/k`3,Vs?ڟo$Ng mِhD)o+ -I7S?@Q(HO"}VBL_ (z*]˟ 4G:}j6=c$K#(S\j[sF퓣 2^0v\%uӣ;_>Yd>\jȮnn*gskx$bJ37W=\f߶$P$B)<=Q@2)=!}vEt(2 pilTY5%41P< Nuk90oiwChY\Po4F9@/:~Tg H}ʄk*3@b\*PHWz,[E1Si=x>O5g0]MHߙhpJ10] j~Xmkj_ǣ`a<mxJp 1;Qm c(oҡA]||c$I/'N7SC¾lFwwo~ J~@Сc.HaK톣{~Ĵ2[~>FX&Ol̀M(, 8TpCb7:y5& =k1=>O*p3H{բ0 N|>Y},9kb)S7tklݲ=>e\h&⢍_m ?xo-fب_0$s91 u 5'wFLG6*"^H| xƶ)syZt^Kzo+x愞Tq%jѾS5\ED[N}'_9F()PCŰ.ǃ9.OCSE=(XCd?dd"5f@)_MmBQB_El!d\SGZX=xS]"s@žӾP 4hА ox}{AټHiG#ҹ=Xr.I-qЕl7?b0qa79VNF W3oK#>|b(}1+Gnp3*HI 0xG/FƵ%pH juSپZ6(xdxk G?}\X'2I'ѲrũoS}h0NX:jp.JhV[>!w8u05 ]AIFݻbB_[e|h&$7 Fx2ߜ :E.S{L?ʹwRmMNgmψ>r'V7ea{:1;#Nqڟo>mEI{s>ɜDt%c76~Dlxcg=s{FqEgڳLCNh"%( !lĵ~+O,33B)爷Ș?пzgc񘂶3m/6mf j&qߓ$Jy/jȍ]^vE,ɇ,/zFaqpl#r/j?7'㙷g" qA8[Bd7 z_;1 ©䴻2NTROD3roufb"89&&NyO(:`ewK)$ :6߃.sbG*(? ̜Z$`-)D=T ;e6Jg!v=+AVgS`b{%QN!*;@= R4hРAC(/P>s@YCBKZҒ%-HO)vZhIKZzS^/zTJߖc./~—zIhIKZza|-~>Ս{NcPmvjРA pؔF_N\B*ن LxzMAMנ4hРA=0DN3Pnѐf7 zOEu_0,g_fHu~uk`+>QKZҒ4BYwrrZe%-iIa汯%-iIKr x=zW}Ojt_P,%MK$ggPO/H.ۈTOz̕!`P+XogXeDnĔw{:|%QQ.흒~8/1֩˗JeC%/y2ҏ tw=| _z)?7pĀVs8AS X>>eFH_|=3A߀HQ@.'X/Y^n(9|-Vªȹ|a2&(ߍI+T/nkpQ߁w/^/˶bn>cjG|?fN GW_-aq o?ZRLlMq9xSj4 LG>^aU% YiMb~ٔ+}D)-Q"ߊGԄ݉ZSDf%7Jz}> iw}#{ ~rvP-WLmdt3uzk5Ȟ_e Jqy Z`d[F-2됳8Iu"}t#goFbzl@ǩ^_]I߻c(u>yֽ ZõwuA31q>lCþ1EU_Vg}$9=ȶi2JsM25sYe,P?~H i[>}# f,b?+G¥s[JJ קw0L**Je OZu|<*܏jRU>;?a<,_;cL>I$%6:ڼЮә=D>{ѐEf{NoC]50|9lec{MFm"ZMs~SYwgQȥ?g5e 4hРACCN˼V,uꤺ$y˓뮭g=?[S ՕV-^^_iPj&w:q-zUl߷C70NjO{^:'b5cbYn4V:h齩*%gce ӓKZ z-3:;;&z5h칣[7NE죇2WsC!4w"\nV3¥c M .#\Y)s"FB9+`n ǯfNN fyikڏJl䪎A+P65j\&Tgw:yE :SM0Orn ₂q)^Fȱ J|w]q>=-=f_ k=?G9pCP~xur|_٠<ڊT qW'OI\UḰY+Ц^LB\SK9 աS3'"Dή%^=q IDAT"T~S;ߑE -z2_]IԩCV[c揭f17^[Жiƒ1ek^iڞA.β?R{Ju,YR3mmgqq~gax'??m۶N~~Z6c*S:T ҌuTɩQؗ37U*φ;54֬4Zm3kY}<}?ޡ#QcOJ]Z֛&ss}h+|cbDt/Xv PbDílLhy3o{zJ8H!Ƴfv3r򄞦`bpcL3ġV$ 4s+<˻(U'#ӥū(`pY_}yϝIQNSoS[R(Uu3MHex}g405˛nI 2)OQ@$IuV՜Kߢ[ |}b3N~բ{h c,"ڶ?{* f;Nߧj?xӴ{Ciz6Ìm6e6x j_>|쒟V];Qb.Ӆj[ ȡR.T L=9"VsEvn:OctЗKœ['bo22 ~(P Q +\ٮ`- (Yx=eM^M~]BA6^bn1r1pd(8e~uśҮm2+Xx,!qQgP3?ӫ9a/ u/~9 4hȔgNgCq2wL՝Sߜ#FV߿C,w ?s53v g>^>>jաvE?; ua|7wkܺݫ>vk?}smOsb~psۗ:v ?Li2M~ "Dp'̔hy g| yGY(z6Oo<3h)wB F8p%g#eͯgim נrgO_.i쀉{DH& f\Dc):XBs)$tNផzvG;*uiVN̦eT^Zew+cDr)$N6ڏ{))q Q*vϾAR &*Z|9þ QIn٬ H:G:B8)ay|;֤´-ןI3zAM_͌Y} W@VWd9]r*M|n/хm}F7QT? BIEPQ182I<_S)`W>Z-^Czflx3-3SdXw/Q~VP5WDJ2 Iօ@Y«%#scDtlpqCfs"\\>]yzV+'p9{0?Yeg6E`zD|#ɡI2NCQxpwws|/ZePV1>#!)DbBUL/WWp7v&.J?~{OM{դ]>xϳ~E@EEgwyQQDHB=es34iJU)?@xfh0L₷7̀CaOQg2O~/=yS@|/k`3,Vs~5Sz12z%>˿?}[|Z~~ ?ŌT.e\xл)!xEe%ܑy).pz헣 2^0v\%J =3om0aqt'!kfm P+, L#Qdݒ+cJB:/_7qlP:#E}+eTb`BfvL,*戇D*ut!L$<j>5?3?戇DЀ:3ܼcѠA 1<mp[]"'`2oǬ/8ߪ Ê3޼9'UusZT WTTV6q;#\pùpCOڵXTMZxf"ƞ)0Fg6mpͳPPJDXk}qp-=5Q ٦%4AH! PDݪ2dBA@xmH!"t, 싓Mp |7#agql[Xk = xhn"]>ͼQ4^=1HP b!9|s0<$vatw7VOC%s[oYmB D<@WDbCGdb%Iz;jS Gg/ie|\_s\)Nu($P{oRQ;NTh; ]9餺AN^DDEvf<>b& ё:pqrd7~ώKal@>w77$P}  4dy}&7 m!ɥ<ɬrL>:яI12y{&RȠt#*1]G*|>B?4śLdu|OP*Q̜\yxޑ+{HإVlQE]{kUkt*-E[Z-jk@"F$""6)2dɺGXW$qs}møp$Ēn 3q'q#2b8~ʳS+=PߗZyL/!t Ár|GLyX @qk-1Gso|B>[xk6>vc1~9Ʌ"rE|1S!Kޯ?mp[箫kLZt&AVo@oino}tMShpڇ.M+7>$c|4ₖT_hE[H8R{L '@wʹ1dc7]?5xM'$R͹}^ʗ#>ŭv6#yazuc3}V"xNlGIFE5vF*V y~7Itk{?Eig=$[{o岹w+ϜǗ#S0I,7 Gm* ooܮ-PfOͼ)9_Ma[c[YeD")He2u()#WtWL #uJ~G)RH"E,O{וo ::H i?ы Xb 9;Ŷ YR<)}U!ABԪi,'D"H$DRzyv՟מ;ұ0'yfPԄ0B&y~ L}N>(H$M%Ң(gxH$D"H$Ҽn5c||֗gؚ*Y㽥X *N`%$~֖Ҷ]a©L)DyH"yrQ"Q/SD"H$D"H$D".hdH$D"H$D"H$DRp}D"H$>i+{NVD"w1mN %"r݊)w!B9/JrK_mP>B5P~&/S$Ƌ$yn%DرL/װ/2Mn<4O0}tz:~a7-쮥L=qNZFDdvAtl1[C3uɡHL^aD_ Iaj #"2 lOo$_0"ΣC6$m}=3 ׄbewc_ÈA};\^E}NuYbGqh=߿I혰ȟ0""oUmU9?]!5螑P@Ϸ{VCS~A&~fݾ_@z^/#}d=-R ҾBm_ó>$'K$cǎ2J05aE{bVV:ܦ=E{ZZ8#f:6~ ldX#?iދyR .З5PfÒKLHN4{-$t t2pǴP8V~oޯ}d|сZU6YPS.s`Lޝrӽ_E:e8qiӸ%}l'9ϥ>KzK_:c濇o$ZϤɬn"FG0T&7iG]nf1R0췘>?g:Wnԭדd۹lzeƻ=Z&|A(IOccW ]{a~*KD{zd\̿I?wH*H$ǽoJ6΄<'߮Kff<ŠPBJt< pmؙ֚Yr$&ͣ*JNBl$#㖘l$N$5n$&u)zzbsS|w-{T Y.`cF ڕ5PqWCMkĈuZHoO :ET\w/# JQ߶0>g+#w,-Կ^(z5Kp(H9'PGCOڔȔwq$2S;]0§YL;s7Ye?|~dC3%3O?jR= I #*'V*4P+6ዦ8?J\ӔqwR#ݽOlEL@)\Rc`\ڳƬrz{۟_փ/0fqv>%;7WڭbWxsjuLck|+pi>M?F_X5l?@Dd0dZ֧ȅYkwfD7G|"ErsXMNF)aɧ(S%Z|[Jduu1x)3 Jho T1ӷNm|}[g?gSPvDY4v/I,=C|85ir3IO關cpS|gb[PNKKve xY1/o:na'ݘjo8?h<|絓[{?|9cZj?-CGK&4ch7&2PJ QF5g f*h%[t#4q3kZ<]3{SJx#FGh7H:AK"*ladr;kK c#mMT.k}.~edQprϊB#[igP LlĖ&\qU52u޾+*W?@Ac:ʱh\_Dx^ɪe+?O]OZ&.}U?Q%!l9eUS\IK\"IW8쀗<#Gg$?EUal=_C+o}?=)kSfn8FNk>{Ztu9*0EǓxjEYAS9Xbiٴ`#) P>c9Kkm?,jm~r_ U\pn *N*N N~+*//H gP[c7DAJ $@e 9쁢W_dMf̕5X"F@9A, }wcZIJctYETT~+gf1D`(p'b͜d@&쵀_PPI}"s`W-?#3j4Q`~u*J1,Ž\ 1zc~x>E׮#:F55xb,&o0_:G?&2*ߦ+DUy,D[ƣlWW^OΤ} g[ն֠ErmjSq S^Hcco":ߌSLƥ,]NjxRZb8ϕ[tn\KFu;z |t[s%>slBE̘ffLVyyx>:" kklf~s=qќ-Q7ޟ~)T) +Q۸HםAM^Y XĔq8C٘~8o &oh7&\%Y_7"-[A;~,PtZ@kxߦ\s-$ Z8ܲ_SWVo㪙 GGH},o}mx Kc̹~-.s홒{j`PA$[RM7VAw+2ffȺ UF0(]YEǷt}{l[MXoFKz@3UR?sǜsZsqwҫ7&=dur~2TP@) ^͸1CIo{cGel(Ftni qָѨFr'/LR*=x֤69ҏHޝӖJ[o]2xvOzy׸pjsI~eWJ52]_ZI؟ 9&o nFf|ՌQ?{fUߜxDPY f;$QWE*nWX8RҰ)~K韘+*p~xN?گL7񻴄fL*hm2 G]A/t_ש`"/ɽx wzEUCYe3 N踎;!#ta|Kq3Dᄷ.bE'!يIH?=Cu:oj9[j_1ԏ)l크್bi:};إOM 4ncgM8g+6Qh7sQx7'ފ{@SqojX4Y3>߲Ͽ0񯹭_IAG"H7)Y5orŅջ}6Tfl+Zq.pH^CQWPƞ{UA:Z S~wz[U%lJl:({Nũ:@e/WRpwĪh̫CQ'N.4$׏r2ŋV]ŮWE{8W3-z=6z w։ ',F_`C]^Ξto0NMTJ=/_*mݼ ~eԛM4buT-3n\7Mѧ~ ^KbW.o4B_˷-#ށ :w?<;57X~؛7wXmW٪I&e~,UrUlk"ZЖP#tds ^l@qRF!=\%GrB Y_ԹCz*{f̧iYAw+1Z?VbDK|j R%>-2+4Y8(SyB-5NGF"@qKwETt8>ߢVP s[$ yb_"HΝbʧ;5B_gboEkLZt&A@]N*{/)`F-9}.rhΕ?ft7l<ch-PP)nEoư!1e\>p qAK*Qp/c`OoLn`HЦbϰ~p}'QdYO?>9^_ U0B~}_H|WSa VA[j<ˢ135n$'^7 Vp۹$ѭ 8o-オsFZb8ahn~:EjH|`C~0.\8#ޙ+gO(Gdq&Ggq3w3ofDLGIe#|ͶtL[sF.$ufTz`1Lޝ [5֍Yy9qf%NHl'cnxiѧؿ Xe>i9O|o~AK`om !ZUЪb"WhH{#^:PDA3:#t%5T0 CLg}9Aq:z(h@gHP fFFW$ |S(0Ldɒ}NǪDW0N bX>oM=3?9F l:FǐxW(m$n| {y;# +I2TK:-oͿ_mzH$O!E)RHFߜbۇՄ)Rdym݄"˗oE?)y% hމǤ銤 H$DRQrhDsdʑH$ Q1cGSٝ/W^<r'r$]y ( NݫIa@D"Hq}i?MkKi[PӮoT&N=%DIŦk7[LoD+Pq%~3C0<D6$_ D"H$D"H$dL _#H$D"H$D"H$IB%D"H$@I[;>vyC6c:繷 ]WوD"HAd`Р;QUQ3np.h ldNTQ{$͟6`t q;yqE<k%5t^4IqS!SgSm*d/ۿsE_")WkFD&~| 'Yi_hKl %"2~lsJ V6N5HwwęJU{2{<ޠ[ 8di=UuFw؎YPl;&,'$2Fwzr?no$jw|ҿI$D"H$O[6AzMY2W|Wt8=0X U$,^(.̔g!7 .q*T5CTRh/"^+x?L![SBUUpS6զTU1_}#F UU(~)R ؉l/xz!AbQBD??(GQA=QpurU:{Śտm"pχ }[\4TTs/&l셫b@ 9?nA+lljޥPMZ6Ʃxy/ѻuK,!Hƣ^<]VJ+E)R&""}Ů-b焍[QDVrBmiѡx>KūXW8Y_JE),PI\Ilp~JVp7T 3ݣAE]\a"hN}a-/kXM|&""ņCD-g%[`?Xl~,yhTTs;0_4|{ Eec#|ھ#ߒż5ϋ!$|l"E)Rd`#rRHHD F6ԻGCc&|Eh|sdSGKGz5ۻac%?|Нq0NJܮ՘2s%H uHy8"8ƴzxxU??[o,c_x(2 V.$5OSkGEhbKsc^L:u#jO1(ƳҼ%mFm%!w7oɋM)2;>fbbC1nr-YWV4r$9.pZN9FX&KʔeOqJkm)ҿ`ϳ*KK@F%xxahפ-otOƓ_^;ۼ7r/9M/fMWИNrl/WC'^k8p Ֆ% [# V5S[)7RPnfmg^gQc+_q(K$1($nЍ.-ʢOMCq yuKȹ%ܺ+ޙǯg<_8%P|3qfpEZ7<ߟ3St~4M ۟߻.ޠNbt]-bcaT_˭%3/U.PvM 6Ҡ o(C_qوH9TEGlCmcEk#uvL"'ٶ8N2vFOg\3Ko+H$7*(<$[;GYH)ކ~B"+-4h4w7c՗{p./宇篒.SipH!.%:n=D2Xѕ멏fDRQӓH6sؽ,R%-t/xb]ŬIǷS=s߇!8)\\ֲ^Hf3?y"#kz= (oKjhr? :턚 - 5ΐգ;=0Wtk\z`Yzgf~ m=ߞ4|q_^ NSyUiMrε.ڒ^][پk+YA]vBTlLJ7l&_gw.mc0o ::SCǍs]ӊWΠ߉ťcH$D ű<5JgmI a'5CyG |"T)/-+ƿ m)r&iNۯ/[K<_"ɇӜI)JYO[Dp%/6rUeDi|.S rOP>3,1[_'䀧8:Cԭ jkZʗ{ҿ=]3.TiV:lҔ9d=߿n\&!$_hC[gJp8bo\>sq2M(>e#iE1*Ih{1FLgQL]_|J"H$3 t}Ys./~"2w/◹#rWf)?3Pc+qkf{ 3Ƴ9ʿ4/DRfk5H=7:2 ws5>Pѫiv3Kziӽ~i[x4աS'| `oc @y[_q6 }愫8Ur1ywaGT"YVE{+BhJ>燏C r)TwдJI\ :l=kU?rz!%|Iz -O0P/GSX~؛7wXmWYsg}0ͽ(vF#u M#H֥ggl M"lVZc˥U@XU!]f`2DZktQճ^#H$D"'qzPUU8oDʶ_vh.V'/8".q*B6U&*T5DVRc9:Έ*Tux阩6UB ,+0ߩ"j~Sj9)R W\+G#w =1mI//O5c] a""lX2xAC]EAbÛezm&⭟EHd8 V]T^%DVGDbە}*ObҴ]wE:Oc;=TV_Vlp 8-0F-گe]D&!" 65ޠ"82LDDvƋEoSub0yH^)挨#RbȆ`łDDdᢁ[WDņ-bESŻ36Ur|(=@q$2LY/#⹷Eh~o[}IgH,E)R$B.i! *H$D"H$D"H$V c…*D"H$D"H$D"H 2/H$D"H$D"H$IB%D"H$D"H$D")@ IDATD"H$D"H$D"H$ؗH$D"H$'tE[\%D"Hmd``ǜ0""o/Ac#ec`:{>BumqbEa7b^SLXͧ+5 #"|?LY_[-fKphtpߏmNɬ+3u,et9?>řJU{2{<ޠ[ 8dԪ:;OdlQRG(PFD~v ;W׾㷇:vҿI "4|g5@W6fB|&z7Wo`dGVWf뎮gT;+S% dkH$D"H*vNz-n'5NlL{>RxE_VeL'ӊbEj3B~_E& ߪlDeVv'Dw 6bAHXԳ<ϺOq5bzJO$EME5b^z(t s ޾h)Ʊ~])KoA ?(l#l:[>ǼvwJm""to'[_/{_h+\O|w/g1KVx!Wq·/bY-&{z15 =kS ~:uA%|D_)zaAb:V $ͻdžD"H$I@ +R4jMƩ#1b^4^/O"x `g4c^L:u#jO12CGh7s=QTwk*#q `煳7v՘cop4L {M>_tIߖ-R74g?*+kk1yt[=JЁJp5gT~FQ`dGHܿ}y8=˃ǟD"H$I7*(8P!3{Â?䏶#28jQ$P~EZɋWDjJ6g_>]̡#"<l$A}ɁXr(ɗ9ge.?wvtZʶ(z*`Th->5 YW "fZa&5d9ū1($nЍ.-ʢOMCq yuK[2έyzv?7fH EA? pcIoi}R.ny?gR xV(k^QFgO 'MtHIEњmz^/3䧨* wh_+=)kSfn4૘o9P0\ȲL7^)m]WVf؟ !,"՗hD"H$~qo}7~~?BOl(Ftni q:\]KZ mIz/íuրo`"l zJƍkşFۅ.'F O#3j4Q`Z 5:(V9ʌc{-Qʱ*~$҅ eV7?~\ڽ/O_ڟeGj<1lYLFatzk w'xDx<(bAo?Z{D.ǛnG)c1:x⨵8RhZd/brϫl)]m]NDg=aBhvI`Ŝ`W,BP&f79c?6_u?@ྏKV83hwqeѐō4w@FAM,8Z{N ŵ1{2jT/g[ն֠EJFaLחH$D?|N 9@{p0_cIhҶ"=U_ E87V5T%Gכn\&!$?ǚBw*"M`r:мa>P H$+8.fɮ#H1Z֛/˼ʾICkۨ`E;͙T)r< ^%V?ϺO.CB֫+*p~xN?.Kz 1ߌ!Q8 f@XQGH6[?Y'"vO#̠~GlػKlu~XHH8:CJ$ _ cKI2.l*Qɳ&_ CkW0oΈT_'bbΤCƥ "4mYY\a0-dPnN$Yk{=b:xKK~ZBq3Ac!$!WDR5]t\7_"H$IA>IO`'`2p̠>_ 9Ihh8zQS+J뜋3p$p:2k]zv WIqHb0޼9U\RhӾV$-ۉ>j/ر\9$k/RC*%q1EW(r>?2ͯRJpdm ۊG3+$ 59]S'f}$'r{v(x×#ĪZ~w{wA7OXȗ1y谱cghkPMֿMZD"H$ ̇dv='Ԟ@xN3A,}{믪?~ۀmct I;xwqz s7ʅ?>T^号Fb;qs> H>_pΤ[. d9kΐ>[n}tM5&QK-: f;-o#f.tq*~Bg)2g@Y2~ko֦??pN3 CrħҮqfpv`ōƯpג>7X7v>g(b}4kVΟ,6e+w^i]o3oO)dpvD~ب\<;'ZzD[vփHZ. mҿ=K|RV.!ȱQ;S)D$9雬o4xuAZ?-YRH!!CDzJG|("(+r)I'\DtcRIu ̙yٙgfw>2^Tny6:~g,##vosǂ?-0B!9!QP~RNSW- t%l5GǬ?HB!B=IgQfZwFn"%Bd/.Q<}yؠ UozeA}!B! )/gGdP_!"=(|qB!B!Bᔌ ˛(7,&Aë !B!B!S2&\3s{J;+A}!B!Dcp._\B!D&#;/&e9 ;Ěl)=npt+wk/^iN&S!&Iw|DuuĸNCY2^iҗ^×m㺌ONOb'&.gK^ɨ޹w RN|o;\E؇[5-? Ysd-z.1 wC!B f(Pǿ!E[j(O)˕=nğa1P|sZU.VLUh9ZT˞-Q7"vBL)IV@vT~%ZgLT**$BU&5m;UWnE^όW{;;~j Ur.j5q~Ϗ}6~:&\\QI~]jjHGPaZsdUxg* .E)R"ȆAn liǤI-F)x4RS]Ȫ*fU?UZ {y~?G=:E̶TQjaVM;5jkUtYY,[ղ{i2nfVYYbjjg&xtU&/⮪5^kRIA/:wtL׫G*oWT?XVaK7u[(+1uj7ՏtUk7vnW5񸯎Ny~^Yh_3kEk.Q;,fePf V|4sQ͍jϜv# K"E|3o \46JO 'bUB u_ϫs!,&Ȕ {y~?.ݿL+IҞ|;W[_Sg+A;צ !eZenZ`[FvIe\Q? !BI邼{Ki~jFzK<њbҒQto[c-ToL_K &G3ز5~E|l= P9v ^&s,Qz1_xT4|tFn64] <)[.JE0L?gkG| df3`#W3Q?䷂Xe)0yoiT[HőlnrUNs?3\?J8CRPNazt7 BXkǏ0d^̖-\@ !"OJπz/K^ĥAlfKArÓ|3"Yڭ$r~a?/zFCsy^ߒ;T.CBzxk9}-"eRJPT|(J?m#3(NZ+ݷNn997YoSc٬1 eqR7K9%u|]iVR'W])+.BHnЂJA;D~K?f~0W_~ٺs3[wnf×])f5e\^׌}Ml6׏s,{Bǧ 6IB!/yf`tKfE/s )g,I=nو/abzh^83޼uMC/ou>=-PfXv}5E̙]g]6N鳤 \ND۷3Y3"霙 X6Ҧ??K~X0b(&ΤOOE=Av1Юy JoOgOz|һZ=m/[(l8.+oBaGJ?o/ޒ[!B2wf̗K6Qws4*fRFt%f.Υ5UglgteğL&㦇8l6nnF Z^tޙ`w C@(/\~x qHB@{xPt <}8mգ71g(]5rn:^uhZΝ3'~+/RE GC)r%-Tv;#tTm<`׉})حfl=4\uYSMIM?=`hztx>^z5g=k<~!BQ ȯyKߋgu5joYYoTƶPuc&GeiG(%mhů6֬,]U]NKԺa!jYYlW+>쥪y>PKg_"G;wc+7} IjEqJ WMR㺌R}jVV./[f,Gfۿ$?gU g7|'+")_܊ϋkZE #B zV?^YHjqzG)tRǟTVvThfݫ*wo2EE~C$i&l߯'W>nͻѦGi"?fuM\Z-U oxue%W!BRH"EŊٱlB"@qSGH)ţ_-R1j{ ` IDATYOB^_R1UGW/;^sS5'lT=T SFZ6ܪ"ר{_UѱfelU* `[ծfe5{U>ue,հ`CTM\ABd~6f g%-l޷P}iijܿV;R;J6DlW{1}pEj:{PE|GME3_FӨ}lP1fe٢M饪{ŗa~AԺƨ-S""ǫZ:꾹QN #E)R~[_4N;2t;*w*goСnc:at5KeҬv?5z1n. so!Һsl=\ڠedTV}UPB!(S㎿C'j`@}}NiG>xCo}C*pw(lһYBDk*IK"VF{ҽmEPE1r~a?/gM}T>(ór'^z&ܼ2">b6bztws9HłR}{*p>]xG2lMhD7}c?;SgFf~NٷI~˫S.ƙW5.$7x/|NZҩi}m&as5sx"A~XzGp]ʿ)_@y~:pZpgAnT8ZGפ!B)ێ`S`90 NcTOqO'I鬣Pr|Ű7V9^ h/btsh~3@Q~Cٺ-I OUPZf"hnd=nğE~fii.c㋖] 7S|?̨,vn+Hp;.~L9og4j3Iݘ:/?~gs|ͶK[^ůlPRXQXI0|;oqJWǧ3~%ZId )` ^ZU$0fUh=_1M3pVB!(rk`7}X ޻_r|:>cZt1AB4/:^> co_y l3.!D!b;YqFPH)8cLR/u%R܌][>.؎|Gj7/q]ySxE#cΧMR^nsfV.ObJ.~ \LJRw7[+ tО)ƺx$Z,)wt2߇3P0BO}~J(`G!Bv%@WycrNuW7cZt;zym8poa@UtZ:vu ! _nsu=Gb+uaDw_bV\dSuF/̆O[c"֗Z'Y{(e⯙Y{؋;a兗kpyۏOra5 UhgZ쥪y>PKg_"G;wcg2Fɏ}UT}ߟVXKU.Xpc6ݾ-?R=kW{\*sWoQVAL5n jjw[Td.kV}jONkU}nwWRcԮVME|Xy?5/UOպMjjɂw؏6˻ͅB|_]:J[Bi WV^@|Ç`c~H"EG/ov z'c=؟h+E9ic)c8 \ow0G\\~Fʉ}!B!xDXϻF{?7=IgQfZwFn"LB!Ľ)@n='ic€ewZۯw }6OaXKgas?xy.!B!yj-d[$[|/gGdP_!l.wdt.e?ym&u%vWX K?84|;ynFw;[WnB!B2:maRf9ՁV(__L|} osJF+;ɩB!B!2/o'd`_!B!B .B!B1RuL8v:}K+{'o&rFc<iB!D"B<3k6.3X{/X3U|Js+L&S!&Iw}*vbpǚeꙌj{9|Wo>~OB! !DY-C kiLU$=nğ%zLGY4:4kG;xS>P$ɏZMϤX( C{2j.ٴdrV?wH~B!yII"%Fjj~K17UߛU̪~.6Ca:~(~?԰Y+Ԧ[UdVw(]@S5*:֬,j=Te3nfVYYbjjg&xtU&/ǷO]فj5,ؐ7US#nP릷P>}<~:&\\Q³v']U97.H ZV{Qr}ǫS+ZK pa1+KlZ7k݉/xjkV-jٔ^6*uWکT>Pڮ"g4V.N"E)RL|2FgOJƵiBHg1iX6/j7S7ë`?g_ޢ}Hcy]B!zJ@!r8њbҒQto[c-ToL_K٘b[+`TeE|l= P9v ^&s,Qz1_xT4|30Sdٚ<"6oE2wէ΀\Dl$ x..N8oL[J"lqZNt c{ 9t)u'Iwj{$ǜ%ުHx֟ſ^y<}Ps.|8J۝MB!( BlI7HRnxri=C O[d=nğMt>>jm[Rf㗸޳8uN_KuHp;.~L9oc֧LysҚwV?߇? Fr } ]4+̆o#JVG~& ~|:i+4*&|e ^O/1~DgB=1b hq5N__t6oǢLB!(}! +s,n3$|^_ώ_(ƽ0qHHۃ#e֛){^ @:B&)/OE93+'lM?~g2$S,S1rvUg'6wd1??S&.(@VOKV4 Ά -=S>uH:YS<74)H/pCyZ=\:.BQyB䴄_nsu=Gb+uaDw_bV\dSuF/̆O[(%mğCg*h6q7=a1'ps3fȦ!kfkBy\#Ǔ\`;Gwʗ!su,RE GC)r|g%jw':`9lg2 Г~z@ѲL-|t{Yh~ ӭ̝g[f_e֩nDKw2]!B@~[^<T{crx7*oS59Ҭ,K;*G/m%)~Էfe,4W:-RUPt懫fe9]t@/y<Pߍ$VQ}Z/ھ]KU.XpcV#1ߨ WӼGՇ7(Y~AԊ%ڗw`akbԼk.R~2+K!25cD壡мT>U"6% Uc?ڠLwWnT?n^Z1C}4BXyt)RH"E#Q7 B!B!B8#c|Q!B!B!xB!B!B}!B!B!1"B!B!B!cDB!cp._\B!D&B<3k6.4|CGيu5c92^i{~Kl=ϗ.vo2obtwC'ӯ3$uJ̣/A/3$uE*L;1qA8cXbmLF5F+(1/_[?WyvM KǏ`Y˨*ƻKc<B!CI"%?-*fXdq7Y?J-SJr~a?/g\4]׭ 2[f^i{Ԇת+O7rs3*77Y?7"vBL)IV@vT~%ZgLT*:C7U&5m;UWnE^όW{j Ur.j5ɥm$c~_䷼ߨ WvT~y_WZrplt7TYFU1ީz1<$K"EǾ@B}:3]Lo|Mu.Ϧ[ְ|M7>l.k ɷKj&D4Y+شs+kxd()^Kte+Ae4'KL7VzooeOГ9۷3bGWMmϗ.p=&WGF@bD1DL$bUNNdChp%9Ls}Պ#n`d~N_o+~ f;?~ҕr޵ycv>j_W3,>tŀbY=ݩ3*):~<'B)Bt-V`+Ğ0Pڱ8bBPmL9_ǟ8;Y1RGCԪێdџɠ+Ao]Ȁ M'ū(N_60j3qV1M;Z5Y,AyZt2f p:*yPQāG>.ݿL+IҞ|;W[_Sg+A;צ !eZenZ`[FvIe\v !BI!Dk*IK"VF{ҽmEPE1r~a?/g- 2ɤѫT&ObP6@ş+֣{lαDE(|}Sф"<ӍzMW$)OʖK)(}$fj?[>ZͿh_Ƙ$ 4O9% x..N8o;OФ@z,d'p3#r"?E#AW υƱu sדФ;=]_>Qmj_2я/Ð{1[c'r-Bs>)] 9˖t$'g(ErH[7H|^_Ϫdڶ=GsgL^D4?Swr%{[kW .Uz@Q괜dqnY7(AywHG_}\tl{vTHΩ9tdzTמrn Nfif(1uf_ߗ/-į+מ35J;O\)FpErT E]}V&[3,֝ٺs3J1/5f kb-rαt| B7,$ !"}! +s,_ƺR X8 {y~?[DJ t:>p%+oxi)th2/b7(oR8"q*%M%]r%޾=X$!Κ8I̬\IJ!6Y|o#FŤ]ՙ ~(b'hѮ=;R5oAz#s-lWOtOzw]y+ ge T=SrU*7.y{9w !"ߐ}!i 8{F WˆĬŹױ^ \/m%G1q34z4@EnOR=O/΄.#kfkBy\#Ǔ\`;Gw$ÃkIiN' ֿ9@骡saCr97\Y|Zl=WŘ?VaߥH"Ec_DIe IDAT}!B!(C~eug+r#Bd/.B!B!/gm2/Bt`s]!B!B!+dLB!B!B!#2/B!B!B=f,1zlsr~VK:|izj2qmDG9zdclRt~!b5c9/ǵ1P?cѫ]?kfՋe޴KlS˔Uۉ5c9/4:Vcoˑٴh^C^{LjnJE g7|'+");pIOe#p"-bMb\T2ܗ|Щk6qGЫF0IO;1qA8cXbmLF5νٕ=1ah쑏/y*~/>®ia͓ܷ~_vd  TгmWT=~F9Jl&]!/BA_3[g־Ә֫I8ο'84>P- 4l$).rp–?WghڊǕS11!tE_Cvt>eӝl'ܞrk\LuHm^:!ɴi@h{*zt%fҩ}g1w6E'ǨyD_ޭqֿζ_W?geUyw^?dҴmOr|s)zҥZMϤX( C{2j.ٴ߳+{2r</K_WFc܃ȋ G^߼n_gE+q;K!DN_?A>}j>_G~-)˅Ye(PJqz} :];KSq"Jqbn{bO\<{ F.(m૵q]5,_=L\9&Ǎrŗ"5SZfsr]@SFX3V߃.HXվlKME{(Of`έDFU;vr8 +aܜm<"ke&rOlBw<`ljW3Q)]KwChp%9Ls}TK7nz |2S?{!)߻%*~w ~ x=oE쏆95W#g3cwx]:B?4~f]Ӡ3ҦF}d !ӼZiΎol6Ao>x4}3 4 t'!_F 0 m˗FZQ쾍 2<'gT=5h?HMt#x#^48H:3f' 9hq= <3VۿE5j\#]ib+}O[OQƻq! ЕԨ}S&@ϸ}G! BNŪq8W;BYM)gYQ&Ey(^Gpom$xb$f<ecIL:&R}4ӝԷc꛴ބQt)߅a(]:J4";XPBRt_f{$nopoK~̱`s׶S ]qtj{575' {> OY4@Wӧߺ P훘OWk4tl\_n@&So3WF肶`Zyۑ,3 y7ywP1-4iģ$E]8K]r 4MSSO r%)_og%wZp%)~--#'F?y,a@[O=pM7dy/)ڛЂVחiOs ܦFm&*iG47]j! O=FΟM3k9l]>+A;צ !eoߣ:gcTζg#jB*?K%rwF{aK*[/MR9vα\y)lB$+W*h 4}Qqh ɋlPmRHH4(3Hu'nt (=ABqtJ ?P ܨGR[6.}C? f}B Szjs?7w·JElDNa݈v/tP!xSl¶% '27apJeˈ-SL|ڗa!DAo.BN$mhԹ'VĘx U.gf)6o\] -Y!?E{0_<( &G3ivVʅkMFF9K3(n:<+wg+[? l~]Rh fOqG?Tkۯ_s4H=OP?W;m*xDkGٲ[nqN8XQoOE}coU^<_}w*#f8l?ͱ+VA-T4˾6|{r-8'[^: cZ4)St& L?gkG| W~ON_CO:1Ǘ>ݨ6pcRRbR1Jo~~/%8NA%]x“l\,?;9>81n\\ q umx.4-Хԭl&ݩ홻c8yc3!*Nqr|ktcj+n!VTGF*ƥgD#rWpfkutS$$@%He ;gunU><$/y%~ͯ4j 3db?a8{J$sl~vL?d}H%;)q7֥Iy9ZLJ;r } ]4+'&_Y|7/ηsބWҴ/7?\?\ZZujhVt9Ԡ$Q>&O+gVMGSWn: (s{: ՆZ|hPn"SزQeU(FdSgĻbeM;6#:=Gi 7[,q%!< i>HPٳk`P.?ҾG! Bp;Y +( )g6s&)g ō$ IKK|[ w| %ӚD1S.s&]W܌]+`LΛplI++ # Q޿<ݘnrb*~qcyʛ2 hxc?L|(tL3\/1/*t>v=xm~4Y%%f.w;qjZpLP)ΙYp?gPڴ9|=Ju8=;Xe};3X_ F*FoTd*tʶ ߿;Vߢo;{c=3ϧ7.}J|Ih{>NLajM B%A%xߥ5skq [wfE;ʭ8p+G=QJ`3/ 4t`oGRn +hiFlB"_ˬ5g s>>)' OCKDŔ) LE.XTCf3^!DA!B mhT̀{.K̊]K{"mi{\9%I!Egt{F0mfT`@o4YfR'˗rMeec@;7;re/[ĮWljԨQC͟-UU5jT-DbEAEc$ٹH̒MH|?soy_kJ?ˉ%dbx+q.ͫm+!l%\x&⍪w |+OrH~ѣ8 7p&^1$\iL(}9y3sheu?b.Tp:VuJj2Q kUWiWR8)Q D`|uR ~lH Xa檋گmvWpM{./ z%߬_@lؗK3AhGPU!o;-ɩIiA,ODZP(J!E5)1BکA+]x^~G"Hr rǾD"dʝf$fxv{ؤWm,\6q:jљO \嵴@sA_ $[88L7aIx"8e2nqÀ%q$s c|{n$2lۮbO~ o{HĚO/|ZT-әG a68y3P\ XGcw)8H~kg6oW!˾zg]1n_s" b}cǧ#Vp;G,q83 na(|c-S:I?'>S7qǧ G/O|}3W7mb^$h)ToȒ_=c"B Dw(~ojQ)_ׅul βz\1+jӾj9ܵ`LDeLQW%ArZF~km-?kn_C,f}bǿEٸk/H ܎e1/(GDe~=oYF#bd? +DZGI} 9[3fs $ry <5/cQeƇrt> `cG1SIo8$2O" Sq⺗H +  AgXz$DKhH4q \Y`DCG#-B:(;JG| ТL1&cmsz69LdAMA*P''$2qs p%v-]DHH$=Q/du?eoDWD!ok),+l})ݑ +wB詽&U]2{nֹX{,6(c[J.OtY %2ffB ;ȞZ-$ڿT ` _v/*G[VKiZ]YNzᜫOV})>eLLߏ3=>r$ K$I@QsU#Pb=3k!NMGb2mDGGFv0BV:j7~T2 [E$\)b8ǯѺas^^^8=hGxk!QMaV[Ҿ%:Pеb4LՒ[qh4>x `µ{QZ]jUKj=Yz՜U a$UCӲjM|LbiLR0վu%;sZFϥkTo2r0 YxtZ9?* 40|ӅpۢnO)ٳuTW|뷠Ѕ2#Y Wv m*7/#E/i G@"Hz^]91J!|!jo49BZ Q-܊SsM4ث៕X?e់RN d_e|0 Nϲp/GEq)?T(S<棱}(anp]n]fgtm[RѶφ j[.6z-ާ/˯Rl$%^2뻮H}{^dC4 oǍ1TV/uתΝb~/樓lqVc@iG7MdS@ ׌u? BûG,ȼUp F_uSdN-;.VNJGpl:b+ށq2,ÞGD&_U:q>&[# IDATo1$,CVle7qH~k(G}1/q;:sF /E˯2_i>@Kq:N? iI){=dQih2WGPkks󵎖hڣ?kiiꩻc5x;B:.aFo)8|ҮzwnG 28WBhXN>9d@ʯ/fpۅv/`;ˆr~d}+m9ʎSXn5w`ӂrS2?vx o;u[k?k8|:oDҪk_+їxgkyNUtFˌMK;}а#y <5loD%$;9Z2r"쒎jobx|ꓝk)X`dGF.k<<aF61UZGN.2&FSs"%3CZ rөUOf'ݻjĺmZ!5++)*W~ۿ?rzլAժ9a3-O׏fV_*MN(ֶ Z& ZM>) kLZ}XgNyvHd`_"H58cPxP}:5+>1 &ۊF x]MAIy =t2s"Puԛ>o%( ML6S/#chkld߅Cfn@tq ?33,eK??ʠwuĬ&L8xԣmy]~sJdod1q_~Ssa%?EJPw35~4yDst8USxӭ,Z\ 'gnxV/'A\<k2-҄%'Mwj ?L~`G6˗#'sW_q;^%r(֠Jm@{W ^k@FޟY[b/z|.p7p߂RQ`{48j-xWߐDCbJj Qh)AfA\ ?p{O>3DP~Q*[Ȳ_lڥ]M}{oyϿ[~Fs+ bE\h '&-m#"[o!n'*;O?KO!S>oDq t ;P^V? G=F,O[S7~\_nI(Fy1 l@MG?kX~nm)%9?zlh6h[\3"3F-D"<,ɱ$ ;]|xuD y$Œl"`NFv.H<#A]uT/n!hX'=eb1=OL__Z}*/aubo#WfolB~[L_6ߺSgN]?9+oJuRI=d:j}ɎۄOMpa/cr#ZUIo~0Kg &q@i8R0;n>`Z|(wm *r@|j3xx 3S]F^.q!{+d܈_WqѥajϲLomYEJFR8`%=El}kcvx{$0)إ֓Nr]4E5x9Zp*crbo1r{;;a><>=$A~ a`]ܰ7pvP`Nj ̘ffL zν(n¼p3`l]f=NE|r&_ N~3qE}>\*Ļ%ϣ jUZY¾xM=sSE@MO?~+ @2vؕD;c,;W_M~^_BhXjӐ֞o{Ό1߈c Nj>YmI+*H$,^GO*pJQj!%<9L 6YJ jaL *g![ Pڇ|6a![C dL=37o|3,blYLV"+[z c&WU׿MQrA|*FwyjjP c9dF%p>Ŀӝ3_C6}GK<LZ.xC~Oq7{)!4y)y[2ef7ˆЦ^Skwc{RAnOʗSh!]DbѪ6|u D]E1oj(H1=/Q(H 3G~$0 pxh]AI2Ϳ(m >Wٷt1ѭ5͛JMR F mˈ>͜њ:܋s vpJ$ƨB~+cXrчRu~j_Ğa͗[Z-?'&. פvH47Cjn5R!55w$gN_ZqJ"29c3z3þ%KqD"bΰzG ɍ=jg(ǰvufG_6V,|LNh *pgcGuPnfGT *Zc!2{޾?aRaNŻZ2T he\;'S۾YgcΜI|u"]C:qpg??[+["Q|ݲD"dʝf$fxS+^~uU?\mL_uբ3 n1x*8^PU=ZN}htί6ϝ]0wI(ܽo<-]f\\ bt`-#?X5snﶖơ4MjR>ŏAPlf ,%3zJ)f._o~nl_`}F d±s 2&ڠki^f<h5|0) [qp7 K?ߓE)fΖȇ)\^1>3ϑb}ȥݱt5".棉?;eƇrt> @+[m?kXczDJ$a[I#jt/Y{濿8?}mųڟjֿ3})ߚ2eX:/ 3?Ͽ2þ%˃I&dI&d3kY%a'!L;ieЋu(6F/|_C(9~UXb^)wv/?9]m9,u)CfGSPt[uXlVZe?=+Ϝcߒ\G"H$$ǢX1>%SŵnA&v_$E*G"RJ\tCGzy<+_wDļhSڷ$yRD"H$9¯2j4ك%) G2HTD򲣅2c+$˷s(˭ON_nh?ج})^R?~jF{Ҿ%"U+Gh$D"H$D"H$dL8 H$D"H$D"H$$!D"H$OC[KLbΪԮD"U}~~ӭ+heHj3y^.V=|mp֊R{_;SPFrSS>Gsy6?%/;HH$s]́BOl姏O>Ļ:Z/az] Ei=&-Z]hka5UT{B3Vm`X)uޟ !!Zаֽ]4mB9 `Z] AuF!4x*u2O&j?{0e'B=6|~о\ %2ffB ;ȞZ-l_}ۨ<;2aNB=u3ޤ$k߉z_z=_HeFoˌIΖIr% GUt:^|}GԪP7 ".N!`gT5'ɾD"d95Q0/c:ӻRmo;tT,f(#&[Mtj ^!<[ARc/UKjuU'Kzɐ%VL0e|=%a^?{ot#Qw-ց^edϭ,+:?y*3T O˪53ݦ1K}%?* 40|Ӆpۢ ڷJw紌K5d>`'5vnY{|]k1y "Y| YxsO"du}8熷g%E*["yO-}D"u{Evļ_8t+DQQ[ۊAX-nŀ)¹C&UΌ z0IIL5\p7tm Z|'-rM9#z0n<(tm[RѶφ }9_/dLFtd鴌*?"yKq(H87P[]6oQM>d+5hx5y0짍 !4t7+LG3(8W{v?Fu~CNLZa^ beQAyZ>=wJּR;u6/|L )w#8뷊߂cI~CYʦo㚑c׹S,RuoR8u/WJ~{GY{{pUAGʽ! _çC8yM]/ql:b֟4qLJ@*_AjtXgZ*Fz|{k1Bt=jvgruzZ~GZ  &i?MK7tAO iUtzUKzڧlOŠ|](iJtDṜɔ۟\^_/gohalӟꮊjE>=xm]ŏqt=^ ;gwXOޖ9EV~6-@-7u˼$+@[طGr mz޾ٗ]LLȈ>/ixG~?GbFOḻ~&,QdXяJx,+\f_v=`辥ѧ- _f:=KU&5#ă{Յ?5j>,`WqWTחٟsf-֡ݤhƽ/lftovUbmPll ۧ AtjPBl*O+옡ɷ?)eCۡjҮa[~rJf `bDf T9}ӫf VmF .=E;w@Y̞t~؟M+ѽgZ{(ץk8|j]3d<ś#7r%NR蕫ݝNz2; LUV<h>+"=M5ܲd}Ѿt%xq?;hٟ^#Y`G6E 5Q]~xa }zbncos6jM9 Q;~f%\*H$,vg J2qjBf%'&!`d}~[QUhϺZ)()>zs _oPwOʤ4ӥ5ր?&37m 8d iu$`tQ[䷕o ?%ާ48n˻S&ڷ p.0(V*ƭ:dz͜OnfOײ%%,=׌c@EGEѪU~9F 1!Yp8ر,^R\KСs~N-{)ٿ%dZ!,^Se##Z>]iOebT鵍;S?$s+'Ꮳ8?RL IDATg˘T\l?F~;@s Yv6# ,&ޣeJ 746.`K`D5?r]Ӟt݊|J^ E .$xŸiCfK`('p)I1.Fq!/K~L1+AC)\.7O ):'ٟ/}}bm6".uv U>%|D?ycIJ5~p5X_Dq t ;P9؏ng/m&-q?oSk`O??\L\^ɘO}M\\6ۄ }p~ncLqzw< Z|8h1}ha%鷒t.c]Ns;?[6FbAtiXھ,#f[3}XVkRYW~r{C0}.nd)}1_y8zڟ?ęp/{Քtj&b: q>Kra!ĩ0C ]RO"Uxjj34l>XWbW RDM~^_BhXjꣻe}oj۟ν(n¼p3`l]f=NŪ*^WʾNt CbAݒRyc]fno_S|pgl6};.q!hݝqO?|J: BBTB5s%l?R܂N@"Hx7

_\=3TJ&cQ~[QSUѩa[O˟}osW妃f@!'ęL\ &F@Z("f~~ݛĊx:j pt@PQXv` 䐦9-c_%A ]†e\IIg~ըՇ7Y@/Ym(k@殺*su)]?nfLڥ: ΆGvv3rk"Moxѣ3<_MO}|" yYA+&J3Wx*Tj PceFv3QGIxC!C!M~Vߟ{[W?Lw|fuē%]S5ftOizWޏ 7Na*MYʹ}}k 瓭GcoE܋##`QHbGݳۗ&wK!W-Dn$_Y_3g,_'<ѯ?LY=~Jr rǾD"d5 gX#jRC} ƉU^a(ǰvufG_6V,|LNh *pgGKA: PxP@t[z(.h߱>劸I3y;EѤ{OoMTvѠ8sjCvO&XmTq?9ajhP_~to .Ԡ&wign6tW{ܳ KE÷š o83ge/:-z4@z?6ز(>e\;'QS>I q3/PnoRגsf6oys Ehٹ&t8e׊h/Onߩys6q?\Ha)T㫞z|[S=`J'l")ި~WgzWU~:53HG>iMSŊBrdhlq@jKrn|s=zF{%5BqGO8Ջ [+8@SHL56{5U6|Gw\:UUTgs^4L]-7ٽ&:%9}_a}ZXtp3Fs?[/z띆)8;>Ϛ|Vw^`|u9&2˯{-ùY:~Jr rǾD"dʝf$fx~;ܽeqxlҥ6ę:|Egc"8Up]Tjki7HppHk7;5~΄)ؑqØ>SٷęG a6kÙ7i< YՀ|4v7B]Sls\>)uؓ5|w4>ʷr +}Js4gLeS$=r/K3Bġ%|4h+X<|^簹KqwInhI|61Z/x5ym0bV'Y,p9$XczDJ$a[3jOǿڕeȲm{cdL3לHQ>33߄û:|)Ap7 َ}589&AtN,nT0&X,_՟Mw.#,\=-t&j|`cG1SIo8$T؟Z⃙9şyq|~tT*[pIԹ+ أWV.'A=`E?šRݱt5".棉Ĩ_Y/E j 6CqYYVP9̽ZƿW3gK}lÔD.DHy l?H$ !L2$L2)(:,6+-R2$d_U/._$t'C&[xoalKg^Jɔ$ H$D"y(8U;gB$ n\m2SD~~NO"칛ctByw]A/"#H#*D"H$VdhO_5KH$U#Y.D"~QQ,IX8GH &D"H$D"H$Dȫx$D"H$D"H$D"AD"H$D"8fW|D"H$ˍ K$]́BOl姏Oh|ݪM !<;=yJwdʝzj/fIU´k$4,#FתOMl})w2h˘ś !4 {fhw8cv/_[ޅz8gr"H$D"d);'Q]ĶE|vb~a{!y._v_tspQѱO"$thbqAZ⣭DŽW5 ;>xabUhXЪjN?U =W4T-E)W;aRP!ި*\{?X7m >_C,^+gL2$L2eQH$2/L2YMŴ#Abq@qb9E;6%>SC|uX%3;Qa6q|w~=&έ'IJb9}E bBM`QbOő[(mP0)%GCDhX8x`],/SS=tXJ7CVli,\3?o9\E_ o}~bj]h[đE^źK|s%boh ]Am~h..?)eCۡjҮa[<KQ,=_=zvxm6Q!z14x4/W͚h6c;y KۜCws{|ӴQk>-OMﱃԠ5T~)VɷY=k]3d<ś#7r%iPG҉2 phŊ?{~J0Wd/#|Rƛ,}=UܕoƐ&}@ȜyD"H$ OJH$I;Z3%8wSy\0h>.?+[9Y| =1=_a16i nI: u;QQ}`Gtn!&gZ˼E"H$' $$k$ǒ,p?vɃK%z}XVkRYm}Ti3(SDygJqOW(A}t{ۇg{ϩ9i!L4K:l.}Ռd[和J::L;LyMm_gN旷>ht^yKO:NO@_jv|T{]b;tpKS&̼鷚*eJa [}~z_^FWf2c~ sEE~_l:6LpQ/ SN(P8}( =QO\"&\8A)iJK{>@:|;S bs################(Ry˶j׶ʋȍu>4Mz7S߼A;Ǟ?9udDZfM}c[좦T~qtKf_ZPm_~7fx=9-b`m ;,У}-~)>gc-o)wŏAodڿVO5k/uuvs;Q4uO+Nְ?:ǑSLJ͓/pWq8t]O2zݬG{wq q8KH*^0]~WkG[xAW['~n {n_vI//|wF]/v#|r+Y[tţte.ϳ?{4?Ymp6{H?mu9 oT2>&ͷU.;_Ubs|V~}~|/B-6H*nzTOhsѥǴsJR;o:^ͧԫ_/GD]κ_|KoL|P7Z|/[;n_|)_jʜ3A @O<:?s? В.^vQGy)]~X;?.F;ʓgjޖ6|7?*v[ە5vҞZiWlZTj3AP~gG/n)Qxg2*O-OWNGێRIFͿw;&[ɰ}tϘ?՚>q}ͧ\痽@Jv f꓃̮&=.0o.swsi浡L3cUtKn3#KW/E6󊹥Oy~eګٱn3n5O3 (H9/+Zvu1{}4{5/|}JtՁ IDAT3fט:OաoǬF2*e1󎹨kw'Xj5Ov{]cwiTl*[55E))0ma9Ʃ?3^78 55M9Fe?r8ϜJ`3qf&I5\!]}o_u(qN4m%SwqOe=?qc#sul|?Sj%.h]Dc1Ǭڪij's˛|fr6?{8Y5(R2en2ڮj/=Q←31111111111+і:^/ MlgZm2e'gWMMUq69AP=K?\5AͩN9v|tov#cGY򢦼>CMyV&Զ(zٰJ˗-ѻ6{o>x.{r?yf|nd"5nGwk$m^YK$]x>LݴAGkTӥ}v皶`T]?Kl)JUQ\}^lVkHf& hI$o'Z+i`ʿlIi{N4yqfkN?*)0"X-tVOiʕZcO71!Qh.锶f:m\%uE-vέ$Dʿ0W\jWZI[\,9NlgEE_;,( thwvIҦ.iwwM٬e}osU*NmU*i- SK|_Ng;?)6w݃v;npͪnR5сԋϐڿMUtNl9qXEE%~pNj^AUc:~GIGZq'Hwnfmˑs3"9X~zC}SޫOs;VN-ҎkAkW51O0]}ͼ3kRŀz᡺g]C=z v7}6UnRߓkg4nZ:-\'c~j~:m'U=Xvu5x=R/NxXoQzrE=uk愁\WlѪ%+$I/`[-|l>Y_X-qp=Pm_NGo^}9@?WRO䟇3GiVus7hҗ_a@2j}1:=yiWdϪݜ>l:7wyCL*5on?vs@]9f}VE!zl+jsaf?g(3lHӶ8e?{&2?ƴN|Ogzhy}n f'=Ŗ?<};bɔ|8/4KsMg7fW)wҞ8[njڞ8fGQfoe[8ǘW8q&Sۥ?4^_3Lh濎c3ʔt8I3Myl/Gf^_8᳏뫏}?L%͏;ZVڏ>?]G/-6hz>[|$^̛_۩fؤfVw)^j,_~ϻ|6sW;q1S>u|=W{c)w b~ns&-#Wݯvn #Ą }<4בO [_k V͏/ԑeҚ7FrIۢ WhK/u{O_K/o:. Cڮx%&|IGI!i9y4fĄ oNΔtv޽"og I~;$mVII|;b7:VEv̰ ~(IJDCF*cA{4l bI%iJ';WZ @ & 5#7҃FZa$cz\ ҽ߮4d#H'FHH=tg 4CnH5>T7FZe[Ԋ0Ro#-Tgi qsH4Rkr |؟' R gKv-otV'5FrKTFN>_c+TJn#U']w99@NiG<?dS Kg}--rv?$%&5c4RF:H5IFꑲmF3@#.M*iP.hL4H[ 9z#9@͌4ޗ{$hI$t$9@#`kS>ú%uveF'ͲCF(MPm#!gh0Ӎ/2 tgJ5#5'whpfF ;Y#5%g;P0R)@A}6 @A|C< =yH^yn#w>gH}}}2sHib咖KZ)i=~X4ȷvc).!yL97BΝAt`=~X4ȷvnMOQ< yBcʹ :V)arI$T-ió'-i_3ݦwϖKnM I6/I:.i2IJc]m҈mt)1S<=C66IHZf8V{$-߼Lv6>0yU3I}%RG%}k4u8!@Ðm,i N%I뵕$:cMtJxģ,Fu^ Dzs Er>i5&M^ye&~ (yո48^4L>lyz];A%J:, io'ii ׽Wy#l Nm3sٖx4X"K ?u3n:$/He>~e} 7l/ 4 f(#7gp%~ι~H0m6D_pv4#iۓ}Aӕ I~ym$Mc$ΑvEgjA yz^R@ۖWH+m4Bұv~2?yՅJr$Hܼhvު 'P^N|ɔWaӑy衶JG< [Jf-:LǼ=dOFAˣ%VIߺh/⾌5t'urRr <^>H5*o{ݟ y"\?h IyuIyR?1bᕮ nt $̵NssU\/1S$Oٿ9Vwlacf}vB7Ipn^e{1Y udʗLy6'~MJG< [Jf-:LǜZp2c.ڋ0Ǻ/#F'DA>7 @9ދG$f q3 sH^S6ehOʓi6ڿ[l:@&] x%oHRo|.qꘟ3J9ͱZIW^fgLu\L-[žWe;1׵# lMGu.(e Nm3sٖx[cnY(=0yY)4[黣u^?}1)MA/toKmC`e._ $bw\Dι~HPr\E*.Uf;_c|T27*I]S=~G-l"$_򺏣rY6zUf-:d˕~]rU,Cu`?h S 9w4Fyϴ\ >hٹ-:۹h>>|a.>@loG]đDsjrcF#>oKE.q&?5~[1t󣖧dWs t38m`?e\Imf.s 7v^yP2&/I*?!n/2K Mˈ+J?rw Q-;huد(^.>@GyC:D8&b#sk#$Uc_mZL5Ҷtj}~%OmWrz&ŶrI}n{W^*v_̰ߠG!>r;(m;VA\tڿ?;gm`?e\Imf.stLsy1=ne`?h^j^M!7"S$ p5K<waGp{4w]3|*K]!\|tu6?݋=OG x툒L_>f&zI*,n W<KE.LosյW{pq(}y'5 k"HB(-Wuo˶ҽD/ 9i:Zo^vP_9M& qCԅ2ԓ[ Mrs閇.a{4w]Y֙d9/Ƈ\| @݊# s/fԀNۅ߶+J۠r]} z_&\Iפ]Y,\3<=7;K_aAle~!.}~-NT묓^Lw4A//V}q9l:U[unUr:yr'[$%HW:~2yr|HtT.&HPO}A-;]ؑÞ׹h仙wJuŇa/>y@BkF&+P.Q\WS}3],{EyUOζ<;4t(Dv3rk!r-LqX:XHbu3競; my\>l"׈=-ˁ3EW `!/2Il\nR}nlwl?: 2}6ٶE`?q9VDK%m;qgI`/Ϊow/~GS1]Q e4wC:};EI$]Iv,QRbImrr@ai)w%a~\4?8_ʩ\?u6;+xXTsc a=}RK;,$˩wi_'iS-{rQ4@Mױ1J<%_w6<=Rl2;Z&Zj;͑di4VHG2L/; u}*3&4U>7>S)_6mk%=-[t-\i:Tl}oՖҤmFv!!h{]Oo?%ݦm~ZqK%ʹJM׀ n%kom̰Mu٫3㷭 T^ΫLԥCq^e$=qٮvo}^rz\/Xmߓ®uSQ.,۾mcS=#͒A iILK$ Or2f~_w_l=$+L ^Syu%칌 x;^9aۭdq| ͮn ߴ2.)KI:nWsl:OSEX!7f}rv<@n05kvJ$7^9r߆4rOMGnTҡv>ː%u4ήϼ Li=>ʡ.4}^i}EDY/q(1oJ#iϺ\2LSwT]_7Ioj{vXSG[uT 6*o{jǹO]}(Rr7r@Eu=8VIcyn*e~4\"*_&&yfҶ!>ʡ.46r_% ޵rvN\Ro9[A8uW4Haϥut;v^,4a۫i/|O]:xn]Iv;X4NDžALRmǘn<9:eݰ$~뎟`lFi%jM!WS\Z`srR u,}bUs_tն}\D r$?q;m{g`e+ tų")=m&q;$e~}&&>C]W?YbLEJg{suW<~TWžK~lyY=[Ӵm<;u:';P;;<öԥ\݇._9`=zQfgs܎ J`?XJnܷ%*vݱ!IDATT%M m+lTx&+'v1;Jd~vOr2r BG,rA8uTWžKt;WؿHXn\np鍣*勑tAۧLeݙjm;ifr*K]\ôq}ԥ\܇.g7OW/L~S]~ޟic+ۍA_T|i+iI}MҬtΐA7.6KYd~!2 S_mR7OZInJ!e<zFgI_s NuT>gzW?W}K:uyt8'co`]gbuRL֥Cq\ɿQR }ErRnArGq P .7%'ijr/7.@JMU.r|Fv4^+$/2HzԮ󭤇=!>$=(ui.G&sY<{te~!H\[Js T@kq/HoAq9jmk$ֹ83:dY̐f:,ԥCq\fqAڤuMy!rG P?(`)vreDn`/rgkOFIENDB`glances-2.11.1/docs/_static/gpu.png000066400000000000000000000074311315472316100170770ustar00rootroot00000000000000PNG  IHDR8a~ͦsBITOtEXtSoftwareShutterc IDATxgXT){ U+h&`KW ֘1PA161" R AP> ј4g^{+~I+U "ʞnJw`Q^ {15_P_t&wS@{J4Xzx:IZBള[sKs}Ni㧻'_1I٬bʐIdW:Vw#$W!bӕiD;?yXI#|/dٿȹT1"n3: hY¡oO6OXr ٗNC 4nI^e'Пp>M")4w?P(ovB{:Dv (mk~YyDD )괖!#1"bmn-Ք0|}~ (K ݖwy#"> %j!)d(-˺qNFJc bS‘_KqKmxo"`'n_yi{w }/Z"Jǁ%XEY-U'G)Fҫ~R~+xemࠠ#^4 =(NuD,zW˽n]/Gʄ;qmΏJ-H)aU&$4#Agn0ڶ4@x#Ҵ/h/ntTe_{FK3|-C|kx0ۈȐS w".Nnr?~-I4O;Z(FD6n~G8*/:yrzNl0E]eSt̵ڔߠV1>߭W/b)"nY}J@cG'x\ H!eH-J3@ZZ6Ji]qSz65K` NOЖ3}4bؖo\5ۍ-PZ[#4^)^VyзuzS_]s`{{VmeA@qC+3ψKJ҈{Hif %eOjL S7̯T(5aZ-)yJ!VL Lgh~4)~~c6Y]hR5hovQ_OK yy..j6>#5z^,1"b{N'tO!b߮YgX\湉ڪsѰXxbDlmrLmjvD,gg@ĽHO TQcJ"XТ!~]~xgͫjuMɡkaQFLZ{^ 3.NP%e4 Y,"bCm9=D/*EDV=JY h/w يkc_6r[&LXC Poߖhn%Ǟ+ein =gˍtI1¹[* >~Od+{Dl;2FJN6ϾqA uv0" o;wG.Y^1#X־aÂ)n?v.6İӗ<u+:>u /}x L&>|~";hġQwcp3+T[r#ffZfv\tǣf;g[ht\FvZfgطԔ,\L ߲_֎P z- =4F 5yk\;ڱ]YU4 yjBRo4. )Â〸S_Bib#o7s&M򌆮E˴ u8wiaޝzc Zon6c S:m)R`VOjuSaKܗmut/ WrAXR⢼J4թ!px^#+/KBl1e2K'X(JCOhziY zɞ?FBZBz=S&rRo)5'G߿|< ߜrY״uP!P3I*kJVˋiC- @@3\kcy7 EZi~֪_p=3*[0>U[y`~N/2z@]di696„d7ָ0'?3JT'HEnؚφ;:tu{|Q4Rr/5iusa[Xi% >a7 cj &N$$ uKBvm3o">- e'kOm{?ږjtfOy7]PYw, L)S4vIYaE3~ߝ=h -~cN|X?ʁAf PDڊ;?d N3^ylV(S%-DUIm3RKpjM RBۄ m*Q"&X5gz&cocU՞xmK%K e͟C,Jل|)[x&@=շ&W @ ,#9KSQ{z{bmk[*" TQܟKM VĶzX:#QXfE{ ?4xCkIENDB`glances-2.11.1/docs/_static/grafana.png000066400000000000000000004774471315472316100177250ustar00rootroot00000000000000PNG  IHDR pHYs  tIME "J IDATxuU97 ؠKDA@T ^PAENQFRab;o9~w9ܙ9; lpVDFF&&&WjBB*ΎK.o?v@EY#,r]ӝN+V b׭];668βs-˒DB]{( 0c/z TSR@D [(Z1oet8|i5q)iz][B`4"^)PlTF$t22Đ8uH5&97,!L6ępfOEd 9,P|k^HQPtj0*%I+M!Jfcr w%eMu4 TP(*ΛcN%Guzwܹ}%/N:5R$Qt{3f02?G 뤏 aiYKeB#[J),ӴKZiZ1eixs)>?- ^≽>_}ÿaW-+`e]%GMՠ*đo(Np"e_ߟ+?iڪUE ADRSy+H^ʊ2MS3s˙DFFeA9K4nѼ:4M39f5[/Q~#_[\u/fOlxy54Rbtx={իg7˕}=I|ڝ%)ͺ;'+`Fz䞈-{%1a|Ɲ96]DmYKؓwgVI7mGMivͣK-{ 24%E\a$M3}ߎ=%UIKJR;G-TJ5; 0{"Ŏ%[6z8I%$m;Mݱqːű-zQ؜!=LEuE\aș:bh^cs0-#^{I{o֦2Qco2QlcYHb)M]a`DD>:ztͫv Υ%0 JY%,E}uzh{~z& Aj޲0d~=;%\[e'K1,Njvxטa]t޳Wߋ.֥Sw}N|Lhm ӳO MNs 37,Ea~??`hq7sgM; 4Ynۗ4Ag-ƾ#ӦLИV:BɈ>uo*2iT^Jˊn=|` Q@D 3d{ \YV}D:aHVVXhTdԦNI"nK")-Q98iqo >{ ~'+34ʲZ&Տ~yMaG_'-[lafzc{0G[W\ ]dONa b#VM7iڴiF1RB*=GLĔ6 :a:c%$qcOW: [=SnL*C@+~LTsu3)6.ө,v?gY+ۺm2Dw]?ws{a̙yψ 9o~w}_H}k%I> ~;.j+3}R5^̏;{dh1Y>vziKGLcQb[WKkԭ(iw mq7ONˮqjIv")X^Ce}??o4.6pui$6J s褻pY[&sC #5.Ea$e {j3,[>{GaRIVkǂE/)Kl߸c%2_e"3I4?"y+cS;qAFO?^_S;ɀ+op",$%'x䡇|sRyq?-4.69`ʭwC5\Ox_ZxDLEl޹5VB 2nRكCx~7MyLJuOCr.+j,a5tɈL1~|bPCڇOݩ)ծL,z|ٲdgn扮Z7 җ.Buqd@+U&7'uVzSF.3LغuPSj&;~yzg+WٟFnxOY֪_SNkAVC[#l/'!ig/o4y§"F)2{O%Η)9OKtw*v2:vOKZem\Y"},{۬z~9wj]w'?e*'"ս6*Ҽ{]m-*J 8*b(#GEd7)ܭLJ,7?}Z3$:k s)7'%bҗ? ջK&Ȩ}`ˡx>󆢪-{w6{UrZDjN-XzK6X H[}i'k'- Q>Xȧ0b^S/]x ˹zqZF׏x(?}OM]}ُq%k]9%j8+\'7%WVޚxAh\fUiRYZ84E. ׹7_+i{٫ؿ߮4rPkDG[۔Ps%ϗ lck^Sx! ;WczMcǚD+LIj(U{l.BV/eѲmڦnh15v3|h=sE{v{y3Dm7/P8k_ɦOIgH_ Od^vݺFj2X>uj~S/g?0~gt #5%…iML4ipp"*C\{MBa1k;kHJ-4)TJ&6.jYCl_Fę9VujWKlTIK~__j\"n[T]c3R ]1)cvY/f ٱrˇ/i|*sVuk~cS+w]7/UOtږݰaƕmS5GMg̦<Ş ¯FZ-$"iJûg\yUN>0<ϦWȨ$":\9ꆪ-]o喽9{2Q7^T[|%0"n)I*'=/Ǖ7.we#.Z|[?C'GgLf.ƵzƪUJSK?j`?,|*H8;%#G|OqMfIvS>^&a1f\:{'𢡄W<ai'ҵQ ҼKx]& QX>c'Gb¼5fSE%s#FvH1bW~~ٷ\d|ԖWy$PIRJt4Md03po_~1_4#"+.^s>y-)3^xLS>zrܹwl()NW!BBL&-bZL}d_߻|w*JR*!eF}t[IkZ*+)ժnqB5glͿCp[fE)Z]wڝ EW),+ ׄGp*)7舏P9XȸRf >l4[_yS~r}㟻I*i&n땽7IR[6u?]tÅeT,{'߯)!d>>Wo՟|Ynm ?NXQ]oQð!Y'Eś}潹U?s{EocyÅuS 8n^Q,_ag"^1r?0q}$TǞ~gfn6[Μ Ӯ5Z >;#TƌsnSi/!q9cWYNgS?YH)qΙJH"1 zaI #6.gSI1NR-l!ڎ#ue)rFێRTl^-^ؽSʥ\}@Z[+{x5]j Zœ,ܕ~+Cr #" Tx]uO(ֲzW]c[r-lڪS';n~YZſp%I_?8/,j ߿}z:M+LJJhh\ng- skgB#+n|yJ',5N}&'O [qTחWk9UV87v8wYQ.T(~Lm~AY*|p-Flv,)غyVo׆zޛ|ӥځo%u$wC/bOZ;zxg~Fxvw~E5S?ݛ3\:+NvmM,ǝ_ o|fY-}Ò+{~[2N~EĘ QddD?tno~*@c_7p"!5Gk5vçLޭK 60MU/~8kD9k޹CJrҷΈpn0y$%d|a1 y+~Xsdf6Mm iP>iTd2/{yPWE{ҒSl[fL,R 槯ήu12r˝W7 wn\¸/_%j޼ʵk3qLO~X牛{*LѨ뽏M>o_xm@/rHYキ1 A1~&1G=:6ax >Wi^N~yQVў [r۳n.t_0$7'Pf?`;vNyY3ׯu;YMmjmQNXnwywIӗg9g1ix%9~E[%&ÛkA䨅dxugnwh(*}rna$-0-!%\Uu[uM lvI0 !HQUUFT*6r[}naBWՃ5U"UJa%$c\4A,;;/$qT &Ƿ/@t/"II3 Nq_)~ĤjEוʳBu_6{U2趣jGOf\mV Z2S8i~CYu0KQ' IDATcf6 8#O@4g**  @PR9GF%w^TPQApve@R_Pj8zSUWUu8q(2l6?_bnf'RJԓ6o >djxU`DG$.BGzv8PP AX&LMS_!z-^jsh M&,7*j#uz׆tL;]opKdF9WvD5?V͎CgΚ٬?57D*\ XAuz{;Ffq=^_e'!xc2^pz GNLXv=FUjv{>Q3q}ò, 3JI[Ͻޚ=0y媊<,q=)^nn T65fwCUVlDcv{o' H\S|Ͱڃ.ءC:fEc{CzŻẅ́IJ[7>*4C.;nJ6}xFlM;g<}n73Q2'gnOl7q؆aoOxL;MJHϽyq_nkUM1; 4N\|9['})򞉣$̀"f2ӤK"=0yָ2@z g*8`ڝSc;]ӂ[ݔ'K3*a>z-wꐔpQD3uۀ"㖉eXcW1는Ly+!wc^f;ÚM{/W/,>n]ũWw=F;z{c|EhlL QьaNU̘|&We2*JB 4lsS/,Is~ڔ5K>uk =1q3Zia~j',uڽ>\̔B־}k|M+ng_"'ٽ3jH +E3}5mFk]Q;3-3/~EUueֻo^_Lrճ޺ +66kG?:k${3o}sSf:ܙWۣ.P+|?_w?ȯtM LJqE4UTU=¹j\-~c||u\LkۅO~S܋ C{ ֻO)ٿ&HtA}lTeSFwKG@ȢSʛW]lQF/Nd_&[HxXK]^[R=,2".L_iq)YHdS%#gxtS7} qvW|>K4:l`)ydBùiΨBwF3g[Ej)w0h;I~˨ИHgI^^@VGwG9 B"-/)sKbw "[XTD UR IxK<q=*&ʮ EFE4n%%e;Cկ8~̬v4{af0^W.w滪]#yʋ=^p0&4Eރ@Q~nÊF*s8>W^*yIOYP>Vx+e1,_EP%y-Ң PP(~:Pg\-TD~Qm嗄f}YaiW6֢ݪ?3BZ_poߛ1Dnry J@ 8X1W bD\tgop)ywuHu1&HKK4]JWPP>RBdw.** REEE["""JKKTaaaVl{& #d60Ӿ'/JEDa[V8EQsLD6-vLᡡ֏ |eUveYaU4MSOժUzA V[lF-vr~L*ULLL~~> 0.1Vg?=0G"u|{D3w˩zkX%`mjSUqSHRdWN2JjNI¬(`% G¢T%u_F hj8ݿɊ<"Ӑ)9j#4Us2O+M'")Lj?5r6)r9@SRmd+1F!TP54G\q* Qxql"|*IuT^N%ځU#Iu pfh6dD%ҶjFPZg;  T?MeTIQit26q\LVj9r/p_|J1~VFjG,|y  $TN1n'`+ߖ\[QX"IT3)~ T%WZ- SHM/#pY OIѥe-dgʸBeYr/2J w~*MBB;?*I$hLˋ;0 PmdM3Ʃp't D!|J rr7Z]qT@@8R{su],2>TӕO%)M.$OQ'|6+JB@E@#1[J9LXڐnԩi~MD')HmS G c Mj6陧 ;XWt̗[oPg> mmϏ5;GZ ϡ :j;MRt4,`ނUm5F$k .Ź"#ƄiiiBӾGV<FT[}>_P R%$$!Tqqq0\@قᡡ֏ |eUveY\4MQ 0.߁L1\UHqDlۧ(JPul6[JJiZ1B[0`k^o~~~樨` aaa',+Ut]WO,˪lqj,p[:uFWBb9Q^n.UMI-]n)Pmdܡ)*~9īg+T 3cTu^*Ku9ZY` A[-k쯂ph:K۠ )8tBE;HQyRS5j }5(/rK/*L|0sk9ӽ)[9'}֛$L=pZ9 clŜq6bLUOybP'-|] C:Z9剱SV9p75NHIIXsf'i<|/OAO\T8>q7%4" W.ơSs$rnlTP6Ӌ6B"UU)13/#'<_wMdWdF[[z}h.iN`}P,w%Dr!4NKwhwf޹+t]d&H+fvfJk?F@8Vo=3[|גtYIqm:G.dUe߷H )2DcåDgH_P5J ${tJQ2ʪp%q**r7:T{푂;J2OΟ;sP"fQz8 #W.fjrFSDsEqs+:x刑yj4] IDATWIYA{!~ߟ;U\MWW:J7mwUNӗ>ص!A^/TQ 5p2y*ӨF H qc g\3WN~(0=qFFM#G so[^Ɣ;7UUz@t`>.#`RChﮆ a X8|.;$:*jEM{=Z"$^)ug4XDH_3RBIcIX.|:[XIC(w>Q='+Su@߅ mHrӯhbr'J797 -aXs$O¡pq 0Gb LH@G߂j Y R.Q錁6Cמд(/{;igMkڙV:[{}Eo]:oJYK?~Or+tC$Jn@`L+(+o9# { i굫ge)z“Lflt@At -c瓤31j>?:-5L*T:3A-pW0F'Ix핸\3bK|4/V>:M}HpU9>4w`h-Ŷ?A1 l[ĵ(x0y-JLǿtՕZ0r Uw>Rxd,Ekj1W[*kC-XB $(*#g\ }|Ox22׳G!y b}GYҭpԕ/,$O춑+洟A4Y g 46$ 0\g4Fx%b雴6e9(';?Yp ^xs0~NB:b7`>݈`ݘg]J7-wb)>,@x#&S29^@>@;\n{1W`RQ4C.A*z0_hv.|wpx2}7DWȶql=Mȹ~M*x;iEYri肋TRbO UJMѡp=ܘz7 3Rb^~.%bfBABQϼ} E}IS4V/X#䬓%w0=`d\ыWvZc8Q[do jsS}3i)prANo| W\!vXX^tu^FVI".!<|XHˑѾMMڞuh+UӈQ/’;f5֋R4]t>]+*;:ȳGCxoMXvI~qSH&qGdzݵ1ɥ9yI[TrIccc=Oתy.%Besڍ>;WVeSOh=L#ӴϚrvsH뱆i8G|L"}@}dSg]xB^KL 755! A|@t"3 `.^kᲢ_ҮBTVVMlm =k#fr<%P n=̦(_-VGMXg+6ZBs+%N.Aʫ`0T)8)kKmm43WXs{kQU9>~_gHGsl)K`f"R!7Rʡ*!OgMMuߝ3J eD=O(ߘ4iQQQC9ΡFPM&i^*\UdybQ` gO`ZzcX?9ZVKqw)R} 1.lxx`kƀkf2.U?&0J65 sYo&m}˧l\Cær_p* H캴e>HBںkcfNWSSsjUR N̮ǁNIQc8]{-oE}[yR.8uZYc 94qWR{#S$\|/|3/QfS׸t n_o4r٥'t(_$B-FUIe9*%O۝֐oi >DUB{%}V*^ 5,~rq|1+Zxo@$ fݼ9Č7J?E{U7q7H!OZ!,@B(=ψD.ebJA1Ari'[ -(CmUPt{P0( 3Q܂O(~0C~ƌȹ&su3t ?) P.T;K PspjgP Йr5 Ţ8]Shrhhx W|o~k}?%|M Ӷ#%Qtу[(TK>e"aj}\~RT:!Iѣ˶a"*.^$OH a 0"#9ÂũY5Ck9+ߗ㺟ܹW v~_.݂ k`>e1.G7~7f}SAT*hYt P' "YaX?eb]ȾT .Ks+f0f}U{1D≮o梏D%Sa\ؚļ v Qи^ŷqKuEɊa}:h^:DD0zI಼_$y%'^AQ1, CNxrL5$Y3>L^bfqVbH9>Vfl^&BbajwIVM<Ыc6S?BџCJ.5~>vwx ZK<4~ KwH "[ʸr(cOڔc,{:yø6+) 1B~SLٷzƆA .4"J_4HTw?o⳧A/10\w?EHEKG鮧(㛤!P2u0Ebo`ωͿE[E@R(*Ļ߅q0c,t"IPq'7+F\&(@͓y!4b:G?CkYḰH?=,~~'DzG/Œ/w f\K֢j7\˝WTPAJ^oKi]Kčȹ~1a=D kՎeB΃8Bf(, T#6b߳Й)F|&bAٶ5׀5gmJ BBBAsT5`{' J>t:]/ϒn6(:=ѩI6:V׷!" b趶SuO=\;DAU\=ڼR1QCtEsrQdddGk354.24 :> g+Z+?"##ۇZ"Jxxj!^'L-KDQ@scj_j7Mow0n% 7r7ǓPdbPLbQwnB䱒Ԅa&|.l-&(z%,|҄5PЇZۯ]an'"GȺc}uPKS0AY f *b B:[{QU5{;G^12mzA;CKuʦBDS/`[=mPB[mH[CñR"4 Y>M E"111k@c0(:Sf)Xh0 4ΨUla 6|\ |Jx$rq-4&4Vye[=U ݃Ma)Ioڃ ͋?G<#ڥZ/@[s6 Euo`=7l0K CB;Dc {&DtvvH2-rUU`4bt)ٳg[m6k2mT2;0b&l#s_O1-x t#*$aΧ0a-}GGvῐv r O*T^Hg.?%o7>)wb7zXb0bۈ{55:t9ӼI^ŏBMdgpjB?ke9 KN'"lH~̺)SsƤ#"I9g# "%ؗ(~x`u A!9 oyJF^~( EGU\e[+2>n/nl,CTGpFSDS͐Z4Y@I蘘kš 1'}Ěp6chJ(zXa u 2碏 *& K>:[.|UCj`o撋ًVTč8VbYk^ 9&`6#.V\*[g`PPURD$f|>ˮsۙ1jER6l= 5*5HMh~kt+"Gpᇔf7\IT)q,T[ #so>@D5\!uC$TzE"}=28 Rv#tzHy0N(:])nii)@[ }ō y^uѵsYjY`9JζnH~U{iG^45c(AJ۫hZ!~7=_8<{EK?9bT}& dПvPg,):>n(i j8`o%6mJZ'3EKR=(NwSs4FQRMEgw#D T4'm|F/AD2jg>zR&#"Pz ]\(쯱2!} ?t=TR1n%eA5rLUL3Øk75y1cރ[JšW訽BvYƣb' {Ʈʌ{_(A&'/Lxr_h`j3m\{#gӘ%0Ejϩ,1,G̢wODdïsBzp,O]0b&&EǛFn8 'Y7!$(t`첢2l|)BU8^Go 2j-ͥDJ_7:[9aƭ°,mV|yw([ʸ& g ZJ S:Ӗ!e I3kFQ:& 4a( g |wPjt+ykqPgn ] +HʡïѠ6dLzL9ha{@f@D,BY+6WIMdi=CBv!5={ՊnDupXuv%n,2`k@FDFFbůѧBUgF(}\:n5Vq`fקG1'AFY۫h yH5L\-eH̦I1 {dnj>L `)8s ތ\~*n웑0;EP&c: ça (,G[(stF  /?yJ>:Dd-1q-.-KݕCP%'"6JMs+R&cL4cGέTDM`SurnԻ`DSC1nT!kIsR;womUbȸL*T,~8apͷD!APAc4k8 ~o|=tPWy*@0=OljfPέ` ~fu(cq=GaCYI4\,Q4/P2"e FC[M 7PsBCBGR^QWvT2*h#"i? [@ `0zowe&fIARLRf&j eg &|E16|..KBB7ch8UUyHL\K#fJ탠a/0q-2qnr4A4ajOM~Ign \2#j$6 mJ?f|U{CSs4l ݙ${s<iJ{pH+˶TB7C WϯIPU=&߁]O񑷹j7ġYT .j2v/j?sԐŴ{Y" > v#y2MZ)pwp~T!u.T$.}{8rnA271Qvl*V#. ]M\|ڽϠ#.Is1r6X7/},Nc m>Rvߕ_A6/YN ɓ1f Rga5p4%܅c@)&OKnk(r8T#{rOrzjG>J_)zcs eߌh9ֲ.Xd.7l%84K]"""Vq^ OSDa?͝!t5$GzUX򅣉ǩH:;0a e,p$ƘaQ|Ua5{C ED(\[JL[E))h1K8J@ j. FPA X*P(DD yxt[R$q[:jْO7',춒P XyMh.FsɕBP!;@9}3GNd2Qs';kd9|Gј%(#22+D2X0j.2GG uwj52!}|[M)cuh9WZH kP! &8 _'uHeitE_ylƭD֓E$ҏ_EGKQ W;R mׅ%uSVn[2[ n'knI s4Ư/'̓=aQWCS1_\C`T^gļt u s·2A/{BvqԀ!"SBLK=O~`d,Y!gPMacWeu\Q8,D",WK"3(wab8Q^9tFB1G`?Q nh^}>LQPtWlam@Nnk2BatO(q"^'[ ]&f#vXky@Q' TX"j$^5t*u}A#yb)D^l] dx:O; "+w9+~ Wv^E\1,Z%/ѲG"&zF!Q#*2Wؗ#A\AFP%pAcf.´ËDv Z˸j/Fps1CJB%AB!W,ʑ߱%r7""^-sv?ԇ~nAh|n2Gc]؍ 2<="Tj--e4~ F/BBA1:ӱ1]EšgpVBPhs2G#)%5e݃Hg_h#D.R,aS 1:r5 ܦCo?qqPG8|N Z(@NsEP0A#p1w=l)@ZzK~cEO'5删v? 4/Ďf1&L L|tS!s9Z31|h󊷟.[״cP|UR lq{,;hç ۣkK$MBt*N FPtl#A\d@(l}/D{V$Eo2 ;hW/\MXx<1~Bc=W;{YCLZ˻YщcrϠhtMlW`%LC[M}-ه|pSh7Qg;H;aG#_*v^g!\\S4ՎwZ> aҏe (tZ沷| (P8[h39^s4KpQ"\̍X1+&|M%QMQ`T7"}^GYteyPT7 u@{%"N?NVɨ9_ {)A?#]U? ]dWl9&w>!\ҟ#b8:h*ȿ,^}(H~q`  @CU+:դC>Ta\$&`@r>)0b:cWK$+ևW#x$ypBaD74kZ.CpAZyﳀ#0D{٠IZ"a8 4?d)^'oʈHDG1xV w;*p8 ?(vK}(!N=.FY Ff} PTÎ'OL#H 1iT-HB9yj9"&/D.x;Q)4{T:2!,Ƀp4] M*s_5OB(psc:,6SˉL45n-èHUǡWPbGk^M-&1ƻ{W rdH#g'%?Cq-h8 ft6,5sI7e[uչ]g0D' !F_]):w6ePFS Z[vE4Bb( H W:3=I?aeR\' T9+A>' .yJ,:NLmn+u(#O l6Л=p4 0?;Y5)ƚ?^*ADʉ}_h&r\HLI9:vۨT؇&o@G'g:}s%tF3VVme/bL1J'}\BQcُ EYԹFjTW@I 3*Q`sЮSݻck Wl |(U{"Hg8"!5.Лbn*bZeaCnl!V.ߡ:yZx\4-*]%27G:U5e3|n:3pQ#WQTD1j*dCA5p'DՊ/23Cy~0E({`|vs3Bw|.4ƾU`5 A "+_{EJMGh,N1Jq:C:PWVdfv7BPL@04* kJGX?fSH3 /Cѡ a`=cDU" E M- :#gG`i>߫3_'|pXd^d, h- =RͤIЙ@$ n:y &~.'`TiFx! ŀT|.+4'^nS 6~A hPi\JaЙ 5=8 7.n;I Uw"RDp6"m! ^yN 7Zz1EDxRא1BL\K  Gᶡ?y0k^ǝ-pۑME!b'z8Z+z佨N3 "^ {l\Y# E NeE "HPDX>ʊ(yKW~ #ga Aͨ kͩ+H̝m5aD ^)TGsM12iOuh#al "]2;PM\!0"&&LP qkbC9p5w5$!(@{ 74Y*#!h 1"9~>',> ~8yRjl09 ӿp4ވRh^h>@gF8TYJ:cp;B) @٧C0t$Aq5H;gA;!Cb`Rpj^$kP]21"ï_ұ[KCQ 6V 75s4"fZ#r8Q ![D?Pz G3$I9,3 7AjWkGf>dĉa` Db;+ )+?" ./*A~DDI w;\rDTRnEefRI`AW+oy#S8: ͠qRqͷh݂<C`QvK`ADjz:Dh8,k1 7|%d%W@fAADA jAqYЊЛQcqw|3}gtXv6Sg3쓚 aKSŤۡR3қA]^?/: jv!"AvDAq5`7G'%Ӊ@2 IDATs ޺zo'on/S`!+Dr ;[eQ7A UEJPDA h>H_wٻSNپɦB7]M) "ػ^"( "JS/\ z{ϖeCXaݝsHL[7} | UQsiH9{:f@ܵKcgҘc1ƈ9E{NjZ1!> U` ĎAǿ.DwgpʌsN/}eZUPOV?m\sVkwt#_90zT~L1 A0Shh`{0M$N8ʒ"ʉMTYҨS$/T?PʒbN8R$7I]lMuX&K)S%IF RQAݥR$1Mv*Efر$IbU%/VeYQ16[xA HuoRɒj!N0BLu)ؽ{zJ.HrTHu +4xA ]l7.,)TTS\T1ſ-UŜ(pHS]Lb$Ri xioR$1ʋE˥1̋u߯1IrK.,<{DUv*#/pȽs3/rX(H=]w.s3Ia$)dVdݚ3:3E_:fPp3SewcUU0m,GQMEgUd7TVm8( M0%$|HVͲ_5Θ,&3÷?|ћ k+>rKN_-ZUc#f5CZͧn7p+f< fkw$Nm Wz`t2<^*S\ח,{k ^h7cR>Am3WU?EKlMSB y5k?]3_~bb`,Y#!"6o7_2}澶f7|*E wъ*.䛋ta̦ӟ[5_ 3ƄίL]KEh[/&>b1&!s^`7;K!=9LC u.S㕏OHǪdUƣKV|0)rʰ9M]B42I|$:sT$[zm+aZǏ[\6"<K 9;!UIӽUsl QCqmITegNg0")č8}ӖDJz~=vkq=vgDTC,>Fg8t'gOѳ=[Ftvܛ;*I⾩6q'YtJuS<4}&푉1iG$pl~#ܼ]M%qVGRI]o~ow\RmRlR:k:{#UːqM#)Ϳ/2&M^vKBti.F}^fzɣ_÷ 2zAS?{ BcGʖ)k/jޝÍA>1}hAV=~{Ǭ3:Xe=+=&$ߺ鱆m1\:>yt|)bAgϜv_H }wZ 7%ӂ9/;wj'rTs.cQ斑ޒq{N{,>GI3vpԁ)7Ob==)E)7h(3NWt4}FiCM!̉$`:qK:OO)5MHD2jۺc٘ji!1pbԏw tq6o zd Z|ctu/h2pFI )֊9&mHw28j3Ə!f}|Ob­}{蜘<:eqq|۾"x-[0cكqlf{h8VQO|{? &uc'j<fM'n`꽃#</cۆrm)93H3hzwT8;d9T~U%{Ϻ0Ŋ{دe6  O>J};sNرR}o7kYb ֗?^9_4Usz=gYnG2U=}l:!Z⣽n"Лٵm.Lk#]z W,YnSNMV1qު o<<:0yh<<~ݰ𬓦$fg{Rw_u`_)YVnkݱ'߿=˭p#_?^&j}xŖOol%g,R8.~wMr}>=g0'y✚ilC%仐ѐ0gg( /X}gUxJys5G.hley'T9~!яڂKÚأ>L7)$U[]eOhj,EX|8"-B)+ASGJ#S<qh}":C ⦬|eڎ2X(qa.nC06c}9W]u6jբϞ,Z80) #QKQ_}zDM{up|S/(V%;R+sGS{,^y|ұ]\TdÁ?qiV~R|rϱek}eͨO~(s~߬u#n9AMݧ>YӠy&6S$aW'@Fm}vZO?"O9*Ol!U.j<7 7orr ۏ3 b؇'iۛF=jWVW=_&SC7,5m_9$:m}o~U`ۍ™3.Z]|te揟FصYSGHԉ*73|S7s|~ztwߴ/zb{VYRj:涰ʎ=:XS2zxhLXà^ayO,gskw?>vyQWG0;aa%}iEoQcWf~Rl-!a`gGq?)]7駷o}tɔU 4581ŚW ݰɳw@K>2mokΎښzId$GEsƾLȗ;ʈȩ2i6#b wh2[jt+FČ4]EIé ziwm= OGшI]%2cHrv"y27RQR*!vnZx׌q_l Ó]R/oOho%e ٺvj|R2Bn yIԶu%fo{tD@UIIzŒɟ9Fjcn\&9k3-?1:.114Co|`VObt$mۼu޹,ɱ7H8<}Nbt~w[NBZҍNyk#ccj+&HA~ *q;xb{_oiTS(F&9wr/}aoXԹ|eV/JeO &|xUf|w?ݲN3NHUnr?~c~ԐP]C:]jZ:||X\,>_ۺ#Ħ'D:ϖj6X;bҏn76C-0!4yx\`s-t0r˚5/6b#"-) $҂zV._\`)Rvm\cfA uFXu 2cĬUj~Kwzw}?GPf6p>Aa>$09Iϩh d=:QԦ_cuAc&DDGr:-1AɉƢsȓbk.;_PtlU|g.a?8[v d"=Y*UWW;"7to[YT!XĂ֭`΍}+DI O>ݓ압k,j_/zw{?ޘ=7cK}} 8}H-"-URrJkYuz69`N>Bm79,7,=^),Qc{jFH9s!M``TE<}ql4XF>,'}wE&鐆rص4[xeM&a؄a>əX=j= f:wiFߨi a|KQMO=:iFmȐh_jTvMHlTa(8]*2(41U91:v'[O 65 ZDRDPH|Y: J H;u/<Ҫ3^q養ˆmn<\lYCm ɪ 4R5 Ep``cNmgN'zِDHh@15ǩoIG&'Yb=hgC[٪1F/w':5.Qvpv1 |LG>4/s'plØȥ \]m o\jGaKM-˭G)ɼHV~Tj ńgk3D 5alsqiΕu, g֭Jg#專<.N#udH&'vՙC U玞(DicAɭ"E'* }A.ŜUTbLKwqIڼc򔴮wcZXKOȫRE ETy66Ε9{ Qdro}#m:Ѱ𲳹.[5[W6εBSbkӥuG)PJ2x&ٞ?޿M|,'TU)%j/$^oF騦02734]JՑ*YzYmqm ȫ옡ItK*ѷmd,nӺr".BZGN?WR]䓶)Z}IܰVRit_ńVΪOK?w4I=۷_Ze3rjj"v>r~7R-;;TߞztD Y Hد:zZ$##cܹyyWE߷(zI HP)Ak-$ A A * *HPHP@ @$tӤ^1M 6cROaǨ[62u?Wk.lЀ}LSq}C ֽoq e4A:Mި::05zs/Ls9Xrҗ]4|Ȯo4~GWG1ƶD.I5$tie7Sc\;geWD35c=w59VN$13%0"!Dj1p9|"X}Lzһ6H@J,Fi*՝-BDt:٬)CH4EB Ҝ/Wx|d{ B1gXT媯sOvrc~Bo] OlZVo8NfL :`pw R13-&#FxN1ykMxKKTk];`ٙ:dp|UOꦹK(m\c¼AcLf D*HBIu|U&,v8SxĐz68Mge5AQKՠze@lНO>үK{udjj)JhBYvץB2BHU__[WWtxj(;(^7٩-e!YkZpÊүxgI5Uei'Wkwu *"<:` <4Mc)zwɞ*DA(eX0!VQd4;љ 1[7>/0ub,-yrQ."^XܺPvlqo 7?*m>ϻm^3nv!sKG>G&:1/6McٯݨZWrgjL]ٳ7fߣ=| ońuٛ~b z*k Rgѻ?@vON9[1ib^:aFj5ۃ7+؏NU(!#eRQ]:0}6C£U9&q).11`'"akDiH)pVܡ_<57ײbubljȶcƐp1L& rBuAYUQw"nXS.]ܙ%6pTdSwںt 75C_U: c$M V_SxTZbUQe/xÊޝ E۱֡Asj.䥉AMVR=ш(!D8`Q G „R" ?(RE~aګ7Ĩ ƘPoa6 ܐYKXMΖ "l!ԛUZ_ +w:"qLѮ7.0DznמʭeCRB93b:wNEy m>wh1טbwUg6/};q%ä1VG}Z.5$XaOU"X{ѴqKo_pCeMrvsXv3E[娐wTmOycݧ]ީ_~aDWg wt0SNNvƈ_h@}qİͧmZUI 2WV~Vj^]䶳g/|jUE $%s68KcD~fZ^`\R_"וjBFoS]Ҳ:K pMU5*+q`ZQr!ǪcBE. 3,ĪZȜM5X}p}y1&?+|l3E풬Fu=6*s`"fS*B%Ef)z\S^ݤv1ƜNo^tc-Hg7"u4##cܹyyWE߷(^ *{!gKx{D%܌@RTX /ty ".SZp\o4Q'A3+B WĊኀe8-e;/?-;A * *HPHP@ @ T%v4bm4(o^be./+A~{]O":4A<- 4%oQEIB4"@ T<Wc{d /1ܚ|,5A\c_J?mHPC|f kXwtÆ-5nR-"Ø)c}qw>߰&=2boNWs}'(޴pSdQ'b"N$}fNL]1]=/@[{lv{4烷vESܐrf aB仵+ێ%W־*%]7+;eC$`fG wÂL2(ZDv:> :ak).Т11]RNQ>:}f)8ptd=9eO>ZDaG⺄17 }wЩSQhN;q* NJMK7t:Nҵб]>S- ޾cXMh`dc؍RL?x:sT/?;^Nu]ྈ0'(N8Ӏl]/oq1.|҅(}藥*e0Cu|\x?GY:qM^\BHQ+wDlewE$C *͛)oůߞ(7w-K#ho)UPMU՟~!rpxImtxGCZe4MEZ00AeERt/{l9FE95UrRVq:BgN䊱FHUN>T?IeM$4xP\>}}O/jhVbe q_-y[Yݹ`K.\N.50D%2,jR^PONwlh;$Vr!Twhu^m{j)m@34+L?Wغlm]N1OOJ3~^5o=*Vj\fV].f JS.[U#T%f~?\s4{2(b#>)VC3ӾwwNcoh" p5A3v2p T9CE9<| zT4}m~ ;{"`2wBbJן]wm,ֲA!a #0oou۾ X&EBb\qE_Ko\3&}!đڽ3lL`2T%8޿wB_Co^vȹ75>KJ?yugnɭ7݋*&|~;@itsjA(eNʜ#_`=)>}WUXUxmgɻk `y-~tTUD GF0tF,LEo<呹,|n{kݎ/}("gȘ;wnn~~^^~VQ( DS5n 1`~/[[k94_Ad]δ C;kl MT'EMpԷG]h.7Gel2ej3qjeU (upb7YDgMyu"#U |xW:dHCBTQV!kpvfBɜz-gfL O O!3c.qCcAx8TטrSoՊB1p٭C|Cny8 = 5: w@@p[w5ϺЁRD$C{;} r"ƘJ"ȷbA(J a1oL)z_ua1ƚyaOqx_A$%ʠM1v8葰&KL<BLQZ|rdJBLgjG}?7<:v'dgVT1&p1 ^qy倇yYaH7/lIW?AegPO^Zg1E˵NbbKgVg^8iR<APU:kl`0v ER^_WWe4- ꥪjdddNN^111YYYdgϞC˨jR*+*ke^Hbb^Ks“\Ba%3G}>vX[$[T4YWW#M{cup,@Qf\zYWCyn _OP@Bn`%Lg+9Ys2MQW{uI=> ,^9#I$I^r}L4UUuTw2Au&3FOx2eПkp`Sع#_U:䒽m.-kws{/@W;'Wc:n Qws<rWTw} rvMrJ8enc薩w|Q}G/Nn}3>P }wl_U3Wuc y9Oq‡LUN^W'oCO>Ebv 69hMׇ0Kڈ9Bȑo#NxEB>QǾ5t~us1Q3`,k9|E1B[ C60¢^)>HP? "By!%/iޠ;Nl7 !d0zC$$ A~ne\0Fv ym8v͛ZLӴ'kJUm=ױ:eAmp"/Bλ JU sT WlhTGRT1FXc&/k4A`C /RRU J*pS@kΛ*Ea]шQ| eyHPkAw\D(G7Ą[1#52wjHP6xɊR#1^pe>yvYY`K_ SG|$GV$aWmcG6fLN$PBH^^)w f0(^S)UUu:]~][]mנ"lsV{Yj0Tn{bιsPO!Q,rP& ġcr˨H1ןz K]@XXΝ#EASSC#R *L-4e(7s&|s>rjsj}iE_(3%ZxhL X xOo"Oe=u^X!F0Z06l3a̋:|HP:'CDBNPB!@_+:.DSnޕ^g! C:f%aN0 AZt븶 *7%3cj5mø7O3d]}3zH ЅldMZ#(%zj6ii41 ;w9Q]XdYNSIDbv"; @)Pzczvz1ՋREz1Ʈ]QJH\ph6,lrfwHEQ_TvMzB+(U/_F*t:p;[*pm&(_g e)!&MR1rؿؒiY;oZ5¨suP+RŻe4^P(Bx|f_~`BETUuWNPzNiL]&2.Mes5.gsKQ+ ;l?|aɲᭌYɤqe:'Mڔż'^1@)UUU$KPeYz!Toiv dI֐&5M UUTD*i($]3Eervko1 R#yGNc51@R]c4b*)Gr4QØɵGkPF$5Qt4ierSɭ|۝*!T8% g  Fq<{Kv8wPw;yNy$C\B1sgX([ K?rO6(7M2gPϊe7_U)Z"- i>٪1\_zrǶohSR6 RTT䩢 pxHbyYj2,Au:^6q~j EW`0ySfntͰK{*@1 b!Dx"9keHZB(4JouQ^QY]VQ!Tsgj*#`Lq/ܨ\vͷ>L`MqՕР@I HP^Q)qTEBƐ9 :yiʊ~x{oڢukW<s|q'KWW49t]~b{*ELc+K>^>{ñ : q^!ċ;%_[t-0C!x=kPBk_G8卻0'z_5׸p/a!B Yf#yQ A/HQ1%%jdA`SDfP1S08} k,ԋD8A<iQ@q7SNM_1B^0,xq3MQƂ:]iMf?k+:N4 ^ThD➇$#n׏ IDAT1$8Bzue3xsWhӡ|X[\HU՚ݺq';bѿDh|y#B0bHT%'{LewA<#@ n "Ng#y))CAh꿘6r.Ip!)Gߒ"tFw 0 Nmc HPqJ&t͖"A(GFF/r-yCNo3b*^wC1J*c2Z[LV @Bys͛6&#t|rؿ92B/8F!Ǔ!IvQ^!S@ - /r] 4gK5ƶ*mˉ!**B%f`G9rOPp&x*BIMjWwK~931"aQ\r;vhsWvY2Fn`Uvw?ԫ1ڵ]DK9ST3/%7]CAB6w*\V T8jtfeCa9\N w//#1!j #.sPC]W>نJX:k*FI\}3-7͚[1w;j-̽6tyvzr8/lG>0$gD#l6T)B^T)p84ٿ$xG'JyWS!F^v*f("{0Lt/tΩ::[A`m<kfc6؏õ 0 l$"Rs_Z>U]Ub9]g/~kwEkV[uf giEhգG:6 K@ΨϑJ3w巼S.F̟a! ̿on33E/y;6J)yn;’dlllTk&#AlWl+ƝE8[fTenw#S$(Ad tqxq*T06BhwG3G\uNg:5DF.ulἋQw=_FD\yLqؓA ':iO3DN~s_񆄲\woy1Mel.˓D%J|Ϡ$%Jl/)2ˑ8ggF;+[sq@DƙqW|o|:&ϟx_Gz0osgC|o>?V%J(Q{eoDQI(yZNuAαKZ%XA]zL[926/~ {.p6@31%O\y3p}b}0y˕ˇs-ĸ9wO*_ąQeo3L'#k?OBD%JuEcCufiá:S,79 f[煝 Dp#Y@s~]әUL&`2[B"o62 vd+Mjvf <(G';qrq_,'7{f\K(Qv]|gwÏ_ַ_C7^ ^<?p/,yZ1T&o@As?\r2i3[7J G"H˲[Dp֓%u+#y{ KV(9;KvH2QF( Y_n%J(QB=D?oݯKSq ȱBpEsnqC7@_^TD pi^Nm2rGQd((؅GDRT \"B( !}Qm](gJ7N~wV7pᱴz7MK=}9wiUkׅBPP2~mJBkMu&D_K[IJHh=rO.ܘι_A%SdW19sޓƻnxy鴛ˀ[kA1. 6S@?4&n5e)#$yQU 9ߔi%J()f;W׽O}ooر_t4 (+*SzN~~NXF[r&tE+$kf~tJp3Ƽ':$bGIA`&8sP)]D%J\(X 诽eG>\E`[౯Wd,B%goË_ĒZINr7V;IpngKn3GާBd(Q3׼ !xU$q&\u Y!* i6yL Dί|/sƗ/%J(Q9gJ$I 8 Č5 2ygBA-q^ Jزw:/Y#1yOyG`\0[;ٵ:"BˬDT `1"㒭{/%Z`ce ndȑ0dT<Mn q+Lw7_?RI~F6a3zd2rM^D% 6w_%bѦ&m$.Y  Jufzö[N>>Idh<@ z\s%62\2ZL*6V[!E;jŨ?DjJDoNm׭<@kd(G/7d#_G/EĆV%'~'GWOpޗ؍{-̃zmq_[n~8J;KOGC[;>o|(QD^D :̍vǟw^޵K\k\q& 5{=3wKoY+?'mC_~B1!1t3ɄJ\r yD "- ֏2UyPr.w&#BQ_ \}@.3TDg|cu0 9ZsEaBrrƽunb>WɩɨSpx,WwDǿu!n gSD6iԆEL=;ut7uxxگs-?IMIgp: [GXλ=xgW#chr8K=Qu() D`q/2ocKN="p  U,v6/D /"*_p;>ͣz\ӴIg#Oa% DȻ$RROv䰼UBE*??~ׯ|Qfˡ"Czc޴c5.y"_r`>Q@HDz}Z*AMW*Q.9WtjӵZ 6]jɖ_jZeSE{fTRQJmDɌɍ>69A/=nǓwjDps7{!r/"@…B@Hkx H.)V#?!P޹}O3~\9m?<+( XǗG~Q< sG sLfȴ\A璧\dr`Tk||Y[qԙjU/ DI%!,>Eቜg <9DqʼnV܅*2ܨ%ﻶRz7O\}oB)d0c#+_~廐:m\]vC3B!5U)9OtYҭVkjjjԡgLOOo2$&[~Ŷx΢EPj,fNZIJ|+3]6\zрBMb Cd~VmUWr? 6zс\0ף<:㽣VD%ZNhv/W%hv[P\N##O%\`!["i2k׻ }!6E1d8A^'_ZD3C=@Wi& gM~+ƿW&vE^Syy׻˯mow3rv_zo7no %J(Q6 x Gw=E@%m=g\AlD-A@&M&ع9"V"Z-"8ȍ}{hѳc=g52uyfƙN@yP⳽&J⠢:SKcгX}#ռcjC w]5qQe{ \ |9gz(qF3*:ԷhQSd ^U*pH gcFks> QLUS4Y7WQ[<,D}uj)![…qtGp-AAq\ :UPgv"z'Ι/zw@\25? d nqhiR:Z F\pkܺMYD|ۯ'O0k26s rw:AUPD%JP"7RLF+\uֿ Q5x(]));Wq4_3tjdEꦛ) s.0XKXtD$y"[KNθ lna1ϫ22! -qwV$'hB׊zk^vVo=O=>Qv"=ޓ+:XD%J(  jH^W0^WvϣUHvF} BĂ;ϗdQ,B^W=3TLr::Hef8ΐP!E (Un3`4\>rT( opCdÊo9cufgys^F=贛4 |*pZ?w!ɬ!4@lw{[#I1} uޑJN "')^S`6seV`qw]5EaU;  8;ڀ=y*aȰokua&}9_zPK(QD>&LjDrl*2$ڶk랶ys.9 ](ID@LaFt%|yz DRqB6%4yο70Ƙ`ի]} 1Ϊqg;nG@*a2*gIRFF8XPxG{ڃJC QsU|° :b *<ۍ9T(;Y[#"LŲ2xOƇd  Nͺ,b4:  0ƜDD 4zGyđiS2ؐK.?~|kFr2fN7^ܓW?ַ񓏥{[?l{I;}Wn;޶'dITK(QDIP#oշR"5q$XQd gPPbMMbphĹ&Z&Ŝo bO>JHޙZP,#EDqɈ@E2mfQ_Evrpu% "D7ma0 ,md1U;, F8J0N \w+F3ޑ7 \q,8)B|=ᢔhYm?2>~xW_ `2vV}J|`"Qd- 3@΍K%X̦6Z8yDr$Z: [c֓$'  Q'[`8y ^K_[ߞxCCC׾9C7Vf2q19߸)>/(:ҋwH_Sln7SSdF7 2<1O_ W`i*J2\"naO#C8_U Zd@-ЎKwK9rP"K"c,`ae0jl;!l-~}_|t`G Dg()jHJlCe5Y; tgWIPC1c,oeB{"O3g<"Bdd=Ӟ|E2md=<Ʊszk̸3ߙ^sqܚ Mã9lO3wlt O<F.;x(8ިWBMyaqs&(֛nWl(6,:_\.s 2l67yVcPá:S,79 f[?˶xڍ.L($+2Oj2*\2[v"Iș^0 :5Atf`%Ngq_ӗ: &!"H D/|u}E,Hͬ2{O '8[ $?2ذw61ɜ5o +nr"ǵ:=9b%hu6B83ޤF(^\/y.JoN5()6%7#"8Y^ON\d=j*eBD"D$A*CZ> Ja#юatbw?^+FFR5xb͡" `jiN>#N_| "Z jRs&nd&#BVjd˯VZm΢EPsSv7YJF/{˯/ozOp{+vpЋGbde`0Aܓ 'x"Տ@ABziːqB֢S֞7+fWi]zEtfm(Xq%yp]璟){V Q^<%7Eq!Lb˷U*0Da讉hu%1U "aX8;GIbD' @wme (B&X#((o:vTJG8d(gnHxQŕfEQdJ8qqQs+ס3~U,w_;7OvGx6"/;l\F^GhH1$hhC@ hOOs J-^x^A")o ʅq !j; (  >R}Oڶ_rQHQΑ/u80 oJF@.#Y0/dÍ@Ey!ys]aze8~mIQx`TRyR(0# eAm$>,4q-d*+HRr$PBJ8ZƜȚfוێ|甐2l 8w oHVUEg \yXQ 9AB(jԞJ%(bUf2N[v 'q: w󻿮-qF? 䮿iY_pIȃPqFD~@D(J(QDIPW@8ykif|/[uomy~SVj Pa%B y `ށd ~g;g0UA"y#ֶV5=ôг~E$޼'xtHd͌s#Oκ"7l|Y @̝PBqڼdȭ)Z`Xf#c C;8ZZqz=ɣ붏nL<@qXG8{˺z"ì3n%aν_x:ĝGz ./\r dk%"oiqاɌ9m_]9g{D6vw>Ӛ,ޡ0HÓ-G'l<<Ԕ5vwes:]2hg<ܑw":766vSVs4TNLo˻9BIc8-aCڴ9a<ͭ'/CᬏΌs5ѾOLκMo}W^SAnHc41ǏLWw\yMC{w,jlJ2|bbE]K|h[>tקi'2hj]t.$Y;+j{ NkӿwF>;OlDɴ8r[tnycE;4SY7#K^[Lw1y'Z{{c3}#o=Z-w e(baE'+AE5]`Y)NDarhs WZt2G k 6"Y#SZ==/j/D̻ZE[jVSY af6S!9R(cX%@('SBFyBDJT:+Ӝťug^UYU$o'_t]weu(z^tTSv=\C\KV^dv7ÑE{ :a2 T84mdV F+ݩlڞ~}' Ф68&m*YJŪ̊#Kcm5a£Y3zdPXQkM@* YWNtWf ۯ0A2u"gSOgSPV:)">x DӅVY\ 0t2U$*wc΂Z;Kޠ^RߛDZm`2S گbutd6LhD%J *'>!@_Ռ1!-c]z+_Э~\1\PX =#$* b3"Q5!)N1;m[L"Lϡj"2춲 %Y'O"8OƐ޼v/쨝A n_"u) Bu (@,|d˞:pΑ3 *2q_XWUtnL 7xj1Dma5mY(%'"g\H `Q$I(D}JGՠyU6H' '-kX];l9gG:yG8U(T{KD Q?pW^8o&w_xkuc5@1;uVdX]=q bь3`@&B5v;;{q5y8ڀBJSP Lj'N8V",aƶ[uTԩ1)ln6 :ͱNZ֊2Wn#+7Asg&JPtRxjM?}]uKB68rT,[ݩw$['Z9JHu+&"JEV%@SQQ :*cLfCyGC%J(Q&*LDq2@}1V"T0lǕV򠊢]Kt53 =]aEe?%-H&0̳1WPc՘i3$i3?ҽq_p^Թ`N&}߯o\ nR[Av^9Rۚ`;9 +jŃ^qThpW_1g^ܿ:2D'6\M⾐T,z7RN@j14HԊk=^qT=ǵ?boyDQf6S'i#3PZFD'D lP,C&TLZmWW]@m }WSS#m}w!{c7쵧שyK֝V}wr'?po=8&4]m8>ԙz`&y "EDa%0E@+vܲuMFw󬭳GwO@ƤjT ZvZi q-R6rHO9 bYD_8Q-|\R)Jwz:rޱokκ沬‘N__Ç}9)1GC~̐rɖI zbYk|+fAFt(QD߻.;"Z]LY;U5k!!"d&|2f%/ )d(9tQ?yX dfI*@y'W4#"XE u􁓕zSBTylΌ:/$6Ru&*nAdF(,qfrwK^çzͥoH"MT(4?0 zTJLl UCIZ@z<=!y %NSw*V[aU^GΈYpU"k %ouGNw: [X&sUs+Q{ LJƜIbw_;S&.':;16 ~;ܿZ<`{_{2=Ý,wU0Qy,&'t˞z[ǟ悛TT[3?8/A]ș^3 _;9?RkuC[Ft>L>Z#"tG?'xɕ¹ VN:7.9Vq&i#[bGko[/G}au8ZGɡ] ^ﯪ CLvOh}h;=?=Qm8RAc'Mn|mY"QDuw}!!ξ&4e@ۋu*rړi(g AE孼J(QDQ z"=Wo+LrT ;YPQ{_YOkdP$/aKz>gMv`|R{ D % \ ԙ9af"ζã'^HrGV#x%3]ӝȓ Bɼ'i#sǐKigAeye(F/byd,m=_5gXPݒu'uc' YVKxHBf3&i3@YKo/?.#YN+OtTYY e]?)uVeYc  & $!BBB%t0nIVzH3g^oyz$fIOw޽s6&2#@0˚ę 2D)`z4W 6ٛ*mj:@ K¨!͵JI=Td 1a)kr_ cYތaR E1m蜰9U !0v1(TbDԱ$:j@Jmkf& ; d%es9X[/gJ9&ԀZ,}Xj,'kd ςΊ [1I!­kz}ds>XL[C)zI\ uHeB94 I:1g"S#ٚQNuY[W+nঅ[.{9z B(6wִE]*DyuϦo7sv~"|xF#YiKQ.WD r ;{UMo'P[&{#_|iAջ0axrkO/!T*)T$k`PXjb@,`0P$Nd`0lwv̎1;^12;T87} "3QNbem-{ .EE; PV o[ , 3"K(i!G3b0SH(z j!$;kSJ]ffmצAEJxy+-3cWΡ2%kPAMԀ~͛`3O0d.mJ sOwygO*v^4>6Cՠ96%C= &ZYG5Jj0dQTR%2Ղ % Uڇ=/f`&5kZR[Q Y1N\n]Q%oh' )k]оe]G:gv͹֋Xo˚ln{_m DP:E7Tc=&<55𾟟p-ee}.^43EĂH~ёS;ѕ7/|;sgw_ru,z]6tb] |SBw~xC@z-/ XHx%2ĺFTOd}ѻ`0pϊ[ FDcx!\ЉrA 2/H?_pٽ<ܷtٕoy}~W]я^$T>gڗnYjv̎|mOQq-^J~_y| jF8hf9rE338U[ RON3gQaQ[W6O KRH۾$PCdOJHS0=CyacD;FTr.8Ѧ˚ ʈa<dT>T#B0Je33Q S(91rC.  d]Jz)kP5Fs^ {DTRT8XbcHB')ҹ:O"7@TxH1i r#!D˪=C| z)TQɌ|EFڼ.= .@BX>HGsLphf,O,.3QH[|XHF|If1iA1& ŴuP6k&B&p/]xN΍:^>^<2qǕDEεw,Cg3LPfI \{GbaTU.=սK/)fB#ugՀRHN)վNQUV Ԁܽw(7Y{Lf`Vp 좻۷54>y'o?TDO2=O/|_^{rkO`u 2xc] 㒊Ɍ|BtÛ:>mB5Xg\%@LT2oݜ#= h\Rsj{ l-<3FgA0!B%K=mDlԳg\bh`62wu\V_) Y1ƌ?*ߋsB,˗d!ԌI$Y^~/PM]zMmKB#_M}ai"! RRR ^=֕\sb#_xB̼gT ieQ"D sew,TZЩq2N@0=IZ-칟6 XFfO_Ȝ ;N+*{&H$ jXGC!j#B˪;U!hzH4Ҿeouc52@rNƘwylHd !Dy;UkAպ$΍W%2M'Nj#-"x)Tk c]m:X&.8$xW~I,3YΉ|qqM>QL eVw>OdrSo I3;qN%hLw;8*k R&&\aDz z</L{_?x&Ȍ̬$RLdKM'{c]ei7ϡj#3M_1 @.kv𰀠sGб߻.5=a1ʵRH3r }3e''V߶xϏOCF,4,SczD&5~y;p[@N]Bs'~{lM<~ H :0atacP jۮ?\.P8fA30B`JEcB*!1#3RB`Sm5ࢺ5,Zyg-5IFT#cqϦ{2ԡeKgSιpLzJCCx3CL)b O[Jԡd^}„7{ca$3rJ3axqK pgB1ځ#cR߭iI*aQ=jA%\c󣣧zXrn1m 8I@\(jH6ºScM@D=Z۳PeM A~tz `a cD=)iz..-&: !HD1x)=>!8S@6޷B H&DŘG!mMޟ/G0AXB ՐBuqJ B(T;?ڵ?=cKd9Cxز- C#T#ru[:Ա=dm+g zWZ5k[ܽ{"5]wg/:'GTŐwٿE>nAl+^ۼ!;Q0VUSڲ. ѶuxW">>1qWUEvؔɸgSLP>Y yJM$/ͻ|o]I!#js8@k.鑜Q )ى )VhSRed:#OްW';MRZXպ[%BU->po9S9pۯETN9h];\0B!,L"cł-=Xdf,E#ͨ*N4۷;x' =cS n~LR еl8'3kSYK *Cs©j^s~~W9")r6PL[zXrv>^llM!9^Y@ ȂsHȼ |P"Xc$ҥ,% |JM.q"HoÊ|\Z={ǿ{B *=5 bFXB}q>~^m}ǰ|ɭ< Isfo е؜VΆou_03ݍKjʹ]*U,_&>H}{%a,jn ?_{*f B8xV֞쫔&es൛r̗JIu5y?bTiu b .8֗t+SOa 7.z͎]6g/~Dwrȴw#]I.{$&wpy7>; w%M[BXHY-ÿ9uAO`u_~,0ޕNWou=1wiz?`ɴeWuPi&C–M:rzr١-o{;u60вW./1~ NTq,zyM8~mϴZy[cĔ(J3A1Ab e7s.L4 z¯X9 7~xQtT7dI.䋾HZWJ!e8Xν !պŌeO1n$` oYCY-: G$"anDPRHy`fL!Ds/ٞP$TW0)ۿjSFlH>hV9zXqmw<94=쳩:6!8g~A8tSx2B7,eɡLfPHl KgPmϐ!$Mj I as`gz,*\'CXu[qE,  ׶zزB^@=ǮtD _k\۫s}A'+-$Jǘ}{>1{ A0xtlF \:+ n|cP^(K&}J2& 5so];12ZV[F5v};Ytl= T`PHB 2IT5)3`CK?]XvۜEC>) k13  Kıθ+GD^6/oq{/WF?WS9lDoYw=# gx#(In=s |2n\&eU.978B!g' }h\}7â=E7%(9$\!ֽnYz T,)RJ*)'frMzn2o]@x;p> IDAT"H 5_׌%,ij=,y.viYQ:2-v{qBJڦ 0P1OSz1sY s8Ky?uiZ+c$!X~22j^^otɪiuI0|r|˚+$p}0e8&@@UC! /%BlN؈DQ1rbܨOwvFce@uKv&鑬]pca2";gSe#Gj Y^'ٜqr)544,P*{gXB).kKē݈ I%zD4}CY3s_)gH{%"+Pf:# 5/ìbBx1D)h"a!CgQE]&}]Ga`(h挅3yELxD "3<QyгoOԵ3qbaࣿrͪG~9tb\`/FE5G"b^,]ŐTL*Pvnt7yM;)4ѝDy6-979Ìq+gCoUvqM*k`Q^H^$L}%켏+}P^ZZrom]q Q02Ny %\lfvXƷ~STc -a7 :,XmD[o=+1.Eձ0QTt@e$D;ɂפBI gi1}bRng<7(])r*v#*Q+]BR ۹xqyQ%?o j~a,6'5V7~auv<ˏOIEڴ'!tG6e3_;]݃\!T)8g  Ԑb?9v:19&!Fc h^~n-iQxQ5$+GT\ʹ 2ΥT30 9dsb 7m_ԲF ]yO}yO9jr9gOI 9ępVdU%RC=?;x9>^<1͌Rf.^*|jN]̩DֵiёtF[x~=+<|@8٩%9'DƩܾXxEK>YLr2rDֿX,?8zBIέJ s˟QĊQ#9ŐEGF!iMdkTk˓l9co|+1U摟u+t8ڏ>eȚR nO|g#_*#oKH42%IR>*!@B,$-128qJhB !+}dB$y(D3kGsfRJES Y%Y|jXm&H jPfcdo*9A#!Ő☮ceF "!%h!"8rrRR Pz40D/_-seBEa<"Y3kN勬PޱBR% u|QAU"J|0L|ٝk=_n;sD/G&б  vp3z)#&vǘruj -вBdCr .g(c3"l:`cb+Q?O2/"P\%R!<2 bf<9TV%cqgy?>Yu)ӉǻcJi)+lQ_(=S+-?(ee{1̉#ƻq_WDmz^Au%ﵾ)7% ffҎb @R џ4ϦM qk##/EdOs^nV>ףASj|%:tYHrJV\R'{/_-ҳwS"#0Q_|~ Ix*g)LoYTkNB0;~0ѓBd]zUI\DBMKkxڕ7.̌e@m}v Ұ|ʒUbܪ9a+! 9_}xuKdL!`ο:kzDƧw/^|eg39sƻ~~ʧd'ZT8ukRDCX߁5(&*/DC]q$zcԀ`ap}p蘕[ə@zzXun>yǯU c[o]9@*5 tPKja)^+\0jHNRd_j<Tbq^h "!afv9ިQ3/ˉS3/jDTŐ͜ ?ڶ)3K]QBhu tۗ;n`5u銛f&G]\fnݵl۷T5SYYW!|g:sRCFVζr鱼o3_~rB0wd*J|4x6ޙO<>гx.杗q w-׽s`%;8RHhY0ޝWսop4XLۿK g XjCdbNyj8O/WrǶޗjdܵseB|NNC E=cLsf7s` ^To,.[:NyzS0AP'# BĒ1ֱOC \ !L7Tt_ӖA [g=5 !8 *<ϗe1M TTY%R12Fs!~oI T rm3v߅!*NNjIlAd #쬅 <@qxװSgg]h+!0Lr0~v*!$ 6e#:,ٓJ`]ϡ),8$9~YiƘM*ѦВ-sXB,l{h"$ȎR9#wMSTJz,ھRu޺9] yzZHq-dfH73{paq_ٻO/;_ui?2'z}pmc[8Dгi03V18^=h'xXs~8e.ΏzfΉDiEBą8Cmn~{CYZhβuwq5(бqצzDOcBPh]vg״EGUC9ߵo~3mWP;XA Ƚ+u_hoYRP='GO>u^ʕv<ϰx(OC DAu8B05e.Q1J7DЎ9dQBX@TcK%Q!eŭ޷pSˆjE}ؙĚ;}ɭ]1iiGNw9nQL{w7a55;xq^ɞ C'ƅVn[ۘ<$+ޟ^y뢣weu3n]`D4EM;xkem3c%ekyr)c+FLS Εzʺd؜H>iR!!kX;Zmmөmh~/ysǻٺ5/>OygKXVX{)D􎾎}J@0篟gBVJ8)NѓTuu=VkPN'@=Xsy~KgwE<%8\k%+ Z#~=?>hędhZR;1Y]qۃWKT;7}O,Ψ5i杓[{}P='U_uf2#KS@k8{.k!?g˰yڱx13On1eZ9;77"jV.3VBt-a4gY%2:DcWn::>ٟT!eden >i GrԡqZѱ n㒚PV%V $#mkBuDϣ@G刋!XM[U!eZyKqQg~m&XsdѦю d][Xw=/[΁p撑~)O?^.6)d\UAt=zv>MGcpyȚq@_pn%raZik=yUxc(Szk.}A@DKķR{_&UjS\*7 /Dűǻ0A m,'7_@L&_*{<x@SP?cv̎1 PLг_Yb>aVD ^4Sгo(ޛv-7-P*czNލn+`avٛ Ŕ;tMt # Ow'!D=ɥg7643cS& ~3!{@gM=Kf]wZ4x.m]Y_L~v%2(V팯ym+}_|οL 3^8x09;x~gz$ofm#qc-r6o E[Y2Wo%I"eaC,'UCDn7(Ei7GM.>@P!^' #=Bc2'N~ORff4[zѦ־#< ;^;8Yi?jW6.ɌǞ7.vީmɁ rҏ?'P1Ez1&%)_enUS:3"|9RS5{$ >hm7{6Ek>m:0MY1B<}D##~@G;-X k޹)B_x څ @dL~sM[|KQ!p<׆r%ǁqk}o o"]ôR` ݟ/ndpy׆sG͆ AS5y-Fu7{{";3vKУŸyĿG!@m#@}̛My!sjIkE(WRヱu[mG,47,ff m.1oKZ+)"DiՏ靑%1þu&`kXU@uW˹HR91$d~=ṴϚKEys@㔠Yg`v̎1;f?Ph!JHG\?BsO?Y{CU2N]I"=F``0do~:A_z޵ã'~0V. >AGNL>;wHMą&wg|SZGU !gh!1YvcOvmo%Dmmc>e,Bk)ZDrDO҈h\IAiJdN ^@{R#DƢ;'2;iΥrc$c6Vhj6.݂7 rj0%kC@?**Zo.# IDAT|}ѿ7g}wA0Tґa@_?&!^Lq5Da~ojDr(G]VHxOj"}"OiKȪF Ϟwlx⴪b n^TNOL]˫_'̩ٮp |u϶osɆ7^!;s4[9Im`h a[j$;=NҽQo|W]95sP%y,mع Iz87cC_}j{0;0T Vϗ=[Φ n?M?j2LG|CpU\Kg[O=RZ蜗ŇkɯP$_, d ":s@adtۯw~O{qT?Gz*%XCM7#spO(h8Ϗ\\kC\D,ܖ*V̓:qlsSd .VZ. ¿'-[5FS`Yte* b 2;L/5Ԣϼ 1+E*^9vGc;yZu[M.4@(5aڬ56n|CU?Dͣ$/VsK0F&rbqg|Nfǿh=*>tOm7 +>'?Wpߨluv̎1;f2a?!!/ٮX@׬~kev}<mx] S`}!X"-EwV}iש#Âs|{D-w6tZ-7^nmvEoZݰNq,nX"t%I0vio>hc5B .{=#Ev9hs-yx ˌR#,?8wh5c{DO!:nFPE&{@LFN Mq}8\O C=x {N\ ;8l^n\(2;(;>o3j.H%B/{"KAQ)ҥN@ w;q >< |?G_ݙi(Z>W~ ftuzʇYbg/YYa\h_6LZ>ڗ'8E)u |(+Ւt!(Rd%xM!-jHɕ:7 >pyb} /ovDg\1@ [6fI:_S$CLaBU{dx''wp&ǀ=m=by'/{m?ad|^աMRǜaq|8Sœ^-G0>2)`+^/(~mM1Oq-bhV[q19zLW?:]_+A_lS_9&>E\<ٳN(&ͼgwΞH9gY8n|6a|j nM'n:l5Y7}31ey !˅Eby,ٙ]tj9N{g]eAb^e~aۂ-U:;4T7}:|Fۣܿ:JM.g= Z3# 5ND-}QǺs%1&|qGˢW |/M*QlĘҽF f=u3WgE)5njw^Fp6X8<$f3z$%\3N}Aի^2%S E!͢-Z-y~>s (R/u)}mS/ c?il^~ھhkDW~pgZ^x۲Q67o_Mgje΍lAc dbu Ty-xlS Q!{uC6'.[1~P:@88~>7Cxmfvv@ᣇX{$̃!et $IzRBwaa4,!˫9VT:,tYKBt:by8r=OB) QD3 DFFhѢd2Le$bhU?i': +W#-߀^W]WErfJ}ࢭ3v_{cm(#QX IđAc 3V1~;7tn; ZF "dW?}qׇ{ZX`fܡG"(\ V0gВInZWWk(b)Ī $/%N?Ώ0QԲp5fue,jT\(^ؠ&Y}-ٲpꖣOմ{h d~hk#O3!}KF= i>~.5A>Fe-GsMjgyrt¨gϞ7`su{KNddMIbՎdV\R5#7N7aiA&c=[NV{{7 0$:j OZL6ъxhDkfu[0B)pzk.68sTO_Sؾ[`ZvA)^6-鳩σ7\ߥL]f>+}O: @;£X&-);5?R\)9Af;~dk_[pF /P3?/ЪQ5!~͇5xQ#|8R1nhq?([V2=̒ ̲Ryا(cV>ʣ>? Gə=uINՇ}Q0kIC8?|`" uitCm4X?k'/כ9ƐA T.Zyń|WN <7J:y)vPw.kpw] 9 ovȣlW/}H;r&sPYHLɭY~^&gSh&/˯=bi+i?2N 3o=r΍|'5wmJ`\"n^5wGj(>RЇ~:k]X7kSÚ`_Ǜ9-(rh :_~3>ͳ:Ab4sUwo԰Qq_}Ęi]_1UA02e²),1θޓU^G-ÝCګsB⃫ӔXΤ'ooluʳ0̟ȤJKFuV-7F!'%T=/o2ӣeYD0]>mTS:{ ͤI-|AnoT"JlQ%[/.|QJFtzzp\*hX$v.+j@.D_KB~ΰFťRL{%j)#WjxǮP(8yXջK|b3ė3*Z wEZΟ-Y}ukZ>,8o-[KE5h|d%lʿ5kG9i*iv{V%@f\f!=bEZK0_vdg';Jd6Qq9|{6iBYRWl_= BXLytxo/$Jեw>-i3nږT/y19Τސl$ 7_Z!"ERgu/:) =dylZ`Wa~? )?GFF&$$ eF>|OOϒz2Zjiiiϓ*000;;cJe6'ZfV3{촌l$I Tv$Ӻݒ6o mhV Kcg$* ` eBA|]ߛ=7.8z4S(^9rrW Βbꦴ_@_%$䙐 (ATFg͆ ]6:ì/;DCeQFɢ݃=4l#DC { Ng9[lsZ#^T(G_tJj` 3٣ _Zs2.@L3d~8i7Y"(@Cf~ɻxҨqbϐo`cm9N/M~Ȫ" I"O8NѡhڸѾ)/BIe˳CkTK& h :A [GDe 5/ԩ߼߇ 6goYo)UE7(|ĪR̈́AM,L^d8%(xt9 $pH{kB˃)"uj"%0:th1$amVYg[8z+AZ<)׶!MMݶDGY}'ہ"mH8mS8dGxs\4nW%MZxx@O (0Ci@5#` \I cȿp_J4=JŹEϯ&#H>F{a~WՏslsELj&1EHKJ{oiC ! "H8ɐנέ}c: Fg^8g~EE%7 / l۶;"9bB(aPrKfU# 1̃3w k Zn\mHBdL_R5Nݍ]X8 @,9lA{di#1MMZQRx5?qGmLҩcG[rd&sV;_J~$ pV ?_,*i4Q K!qWStVɳ(MK.{y^ JI/;6cB^ E>4ɻyl ĥK&Yi(.ʼpz> O܃[A<)5gԈ‚…xgoq6:]CSp#:ad Na_AQ $ `!B@0EM|V.`,aDLMyՖ $){k+>l[<#k#˿~D w7A #MM~CY 0@D<(Rkt 6)Ω]}33ǷY"ǜHj,ϩFpc/rF,-E> ,2`/ȅ0NbVPI;9"B,W0*or#(%E U*9Y11.L,gOuJ !e1J0$j\ #xzaɩt fBz{a~ɃD^Wj+ lUR Yi'0<8\)y֬]-?@( {Q7pJVj{ #(=P)CYRjkEr:X"R Qb胰HA =/!ª4 pq* `aSz Kuz5?y8J9J˩6:M&Nq  ZL0#9B' ( g5 nc;=uU1Pidrh1޼PE!,2 vBo:KZ!v9. q( ހ`p@ @8"(ZJ-/UiXA N^"|88#1H \r0, "&ygXb.bxPt^9ؾ)Oe(U\ ,XYRfUSS,Ye̙Xʒ{*˥5n˺xB!lA,\vƖL,-VX2Ӱ,; Y!{E@dZE$TO/+49HD`jBO{z(V%j_峜V JN4; zObE d% -!,#%審jG38^ѽ;D7RK%Qr:iɦ J@ZuExȥZzt&0zz5+S#nxFEcU9"&ikv7w|p\TjjD`QrJ_"BgI1]Jo2 hyś>.S˺,fgqQa5ȲX5jKvh/3 %Tۋ X_mR > !U^^ӣF-GAlٯ0$#sC{Tjn<*-=X,.@G uDPޒ_xOL;70h˽|Q u fqJ0GxhzG؋ 2m<`8F*!X栾;X@wyl.8sޙmu7t8Zh%񚘗%IGOAoQ3RrBNy!S1 ZbM>?.89}ݻ6hԎR@C7Mk?v#6BP(#,9.J E'bH q [LP(猿3.N# l$MĐlXN@Bqv'P*YDG R( _ UHP(,(U T"S)* 5P(" BP( BBP( BP(2Z{AY%46Kb;ӶMjo'߸19#.B*sUt\ { d=0A%YZ5 ޾_[6$gWv-7tXھ?k^vQ>4D5(Ƨ2[w5}pu WǟN#F cԹmuso]5ɕOR@lNeu30b[١QУ$WNO$#Ej>$+%_T-ci2n=(+>I[-R2 m7H$†ZCY|7D]$22E&drobN* o:g@1cML&Ecm7e!px/;[*}Ƕ[MSt;>Znw q˻-]Z-kۏcpU Tƅ.l̈HܞNXO&<@h_}'rp|eQo2Tҿ^573Z襀뾻ҽ[{ p E=y_bxߨC',QS%V& m^ٴ e7j43U{ `XRP]ofrދ`e5~\"wM~c懪J2yʂ5H|Sn^CW0q\k>3QS 뗮!*ȨYM,5K?v\(Y5R>+m=/MZ5l R$eRxn_P訲(*rlcN1UQ3GR0䉋Ζ+C0K&۳bEJU5^jleWF|ؗ^ױ8N[{e*AQLHcem;dB=?[tˡKݼe!z;دAx!w?P1* I!w 9(X1nrWSJ퐱Q!?oڛ7cf{~fD8*L۹ukԃ^khBV,[ӈQJ ҏ@rj *9}hlJa&p }e=/m|颥Gҝ,$xlͻچ7&!v=o_{(/h^ȾW$%ŧvAX$Ȗqdʢ 5;Wi:O7cLA+\w\ `LyAft W3؛׸7fM|9Sk6?3 #?8p:!5K 0jޘ5*njӆ%˅8ogR~}Lʽ[ m`u޻V%{A~>M\!NM|TYMKIhfj]z{6?Q͚gEےUqeu-ۚZKﭼF6ncy`E\lAtnl!*6|4Ɖs x@v>vV+:.LYd[ jXژтwDYsh_ۋ7f5 Uj 6WC_Sd) ,2@閉q-a꺜VpLAtʝpw̷ "nt9"|$ԌUS$%uZDQo3Km(VRQX~} D|c8 zae~[D˒]&k 5ڌ꤁:Tfd|㵑?[3,̅1A P*NU~ڱW4e-(Lenۣס JKk27Wʦ gϼ}Eq^ /Vّv3!K*ӺOWo24V0 XT,"WQWuqќaQ7e}P*f&\墟2prEsy˕Rie/]K "gwFXW c@VؚW֜tydKӗ-X`Ws._@0JŏղX{]LׄOw d%.1=zl1 @AXԃ٥L)o7+Eâ_SfSۖ~~*qd_~o 2q}0P]W%O e^[I")2۷:K\?L4;d^cdܻP*L~M7aזS| 6g>;0X% $Tv!~??> Xܻ%6D l\; *{D wK+͗J{=ق$1bY Zyͪ(߬-d*U+>ľ;{6[b cw૥Kޣ#D-| 礐A$˅D4m@Q^]_-vGPrWݏow+Ym~qoqLbi׆p;%#d(_cxkߔ_~V=Y+܍J+ZpHjUB@@1%3g[Ȅ Y9Rq d0I@.J @o`lV#XT#Ľ59#羱8,ZHK66#jmz>vab JO<Ȼv˫V-0v<0bd׻sDꄶ.2K*|xzYrZ T'Әo"Ac #KnZ"YFtڿ?2^e.&ER*!0*L'I."B$i9*{]ۻ/8$c8F6CM(רC_@l'zĩbC-o}TaB ɄTaCbYKã8ʗ;&g I}Ăۉ|=*(T7c+HB#$m\=SvF癵P1)8[td:vmˮ }]ɪ@B >9@6&Z)qӺhpPb!C]8PcZά\@*ww!c^U2?rW r/uJfM7__ht$}'g (?@$%aj;!uqAa'/گL']^Oݦ o[d_Vn_;L% [ٵ=?]v^RSCP [X߱i o}J?t3-3YffΝCl>|˭ю:|,WKX+9޷<5:U]YBQe1j5}x*\xBgbΌ^lا뵟~Η_syފF^Qq;Vc{k3[SME_iюSL&l) T+d"~gMoę6\ "'n3X42 e.Š*b |ɍi>:qU]nK7~?Oٔn3{촌 I:o'IR)P4_ړA@@!DLϷ\B[1UvUAb3U&CL  ɽkUI!." !XARQ-PAX6$@ c}\e ۆ c8֬"Ca+AEX-PH~q`lG!"uk ҃T'r=%_*5vUT*7YFM~{ת`O.zz Uƞx?&>\폋`6zɞnOD_?OUO|VŠBW~> >eJ*ӾWj6U_\;RR T?gN"t) BP( B T BP( BPhJP( BP(ZR( BP( B T BP( BBP( BP(ZR( BP(  BP( BT ^Z OcHHH' C^8o=1ëpPF0i<Մ}=*KW*I P ?؛:oBTo C~>Z4j!/%#@o[OP(Ȳka]l2Yl@j6HfqY|ɛC[_2L b2-2:40[&EjuڭftL&VƆZw b60O36;׌Q͕l*5[2ƌnDIY VefdIXNkM<( J|A J䴙L&C=$,z^K-;tiflf;N "[Njqa( B*+|L*NwUB&_|5b9cXK%R#%Ntn݂xĂNZU#xZБՊ;oψ]Gܲ{蒏=+^{c'1X`\Qh}D ;z; }"nq!7v^hÿ?cQ&:1Aߙ=rܘ ZR*|Ӓ-z2L^СkO07̓ǎrx[PD,K:P( ?ŏ% 1T [_Y9Fp#讍TwϷڳZ^<g.B\p֬i@l$ak U9|DU?wWEP(#,2:n3(ѓrȑut=WHfC~5sYK5!2jICs R,mV.b A4\ϛfppHums _l~d]tCuD&K|0ycR\+g~X8d?2xȟ4$r/Cå"sc]M| \q΃=+rw{>5{ӟ v\ݭʮI.ZvӢj>m*lyX2גxAxѬe7P0gN) UVڼa㧸%N_y$1>U&P8奁aյ,U)]3St7k_׍= Y8|(o_12%-^C umB~\wͿ9c+C2?2:9ghQ( "N݁J/ ACAeLD IDAT2~ܘi7 tl*W2)KG N,ϳH9J4JTQ?5"yDڲhJWX1?[ M_I70͉37)#9\ؒ yX"f :NTtP>n`T\(rU7Ǐ{A}r} Sr:liw A[!-+ ILh hjN" .QʅR B@'*Ott @ bL1FF&}ɚ+ֵDGGU~^ y&O1Ff U/= ّM&C"xEL0,!$Mta m0 BTJ%}X9ȗڅھ>D|[nPkQl.oʎGwamˠOE_pUƆ G֘.AK ?0h~Au{f٠?A8wꞸc]m sQщԩE'@qr#˰]jݙ")]mV/#wc~$N1r}7&_^CgzP}0W&˄g%*̣{8,:R ^qv PP(JWB|g D`2re݂ 1X˝3Ŀ A_6`FTlX0pe/vjޣA/ ,^8?GY N@d;zwADg/=;[)@fGxoĭDVP(ʿ FV~,`<~_M9rlz;>|j)HyV֏7 V4Q.}<:oHWo O}z;!cʼk8jX:Y-Ѕ1I 7,K}'l[B>77Vu?7daKo^Oeޮ^i>/&KR)>E ?<[Ϥ^5,oÌX*d8sٙ 0fWBAPGv^9W=X{,~1nͧtb$kze_D{XD-BP:(BcfY-Z$OG'sƝ43zo{r-p^\o޸sf#F3G/\M{@ώ(swΝOPGzOԂ#mGN)ݛ] ^YӕÊeXFP( 7$lѢEid2Ȳ1F T9d#QvgKdMP(f=S*  B 8xaJ:6lx0|# 1tHE""hoU%|D42ƤY>N#&Xk ;Jf?Z-ZLVyuԼJ,={y'O>7'G*1O6ֲh ~3(hz?;rlڝNwW]9ҥoRF%;}U||һTanܓc9hV7?9729_;Ξ:%Yڤ^ۧ}~%& & G \kp & RBH+O8SY`qU]T7_y1X+?QlkǫSg68>06Wv8pVtMp `` 8[rW mx}<eR<'.Uc|H}s0W/:w{__n"w07.]ks_֋|ʫ-]:*j߻w9> !ƣ,=4灐A%$Xon]xdI{4ۯ:>x?9t+5i]ݾ> #|˰:>|3וdM=t_zfI]K|(q+/9j́ %W\[K4BHP?gY·y#O_uAjF;jV#?ʙV{`4/?7>TBOt,]B5L9f˪M!]SmKߗ<0ڛyֶ$.{̰P>o!.`o 'b*lOu-SB!} j L=zϟs'ޟP殬7:ذ'FGA'Nz.78hh@B[te?~탵:]ߘ :R^ѿ:nmn)yTE4_xSY)teoU{s~unNޠ;bϩGr]_iDW4+A !! 0K~xzql\ޤaF:ʎ1v?Č>L-"VRJQ:%*!;(T*@D6vv9l[ƝrfXd J/ ~6sz7IL^l[SR XϛGw;툱KV.s%,tQ9}Δ(ix嚻>TL8yNB[#VVy˅NwFO?"}Qqӗ;?{pMW}ƚCk0@Z0 t IB I:E'^|^܆YxMV8bsD6-˞y?9t?>q f<ΗBajO8 v>u|^yO5w *`/M9XaJpq>{=.8Xô?aN:݇n{j5PykqQGf+Lswyjծ?md'QhOּ{CA~)vS*=fTVz=~c;ޟp M6¬ǃZD7ǿh˒7`IIZ"|gLo8xUV\ZÇ/[,LrXP3VWW _GJѵUWWg{w+Ax+*+>YѐdD1x5|O8iߑk;TN_մ~:>+㾷_깟7`󚚚,q\VJ%М21ֆ !Lu4t:L@ymmm0HD)y^Z~m΄GIVVNxOg^;o0~_r.NF:#mioDjkkPDȎs9dGkmf]]N.TJ)]|g0s|Ǟ\Sh7Ly̨|WO'~`:7㎟ ~xQme6)hB!/ŧekR?rƋsEG+dO84ߊՋ-@!dʄP/W@ N FcPyxd0wg_~E9,529 !ssa'PkYpgdϼf,KʧB(<̒F\g_ѹQV0g kލh.xfBvts~kc@B!wjq^ B!B!1v!B! B!BTB!B!P !B! B!B(B!B!\*/ CB!:#B!Q=j`S)c?xv*]c/g?.]93^X522A0L㫗kцZk0Q"D Y)d%be8b8j!_qC)d.T)tua=sƧNۃB!}<6yo]9.'^?c_3添 T-fwz)q]wqW{vn;4Nfǹ??eU>t8g;vR*Ŏa  ✇) !4jS@R !\s[+w>5YlxEEED"4uTXX,RJAs9Æ [k0*++|3av?C7 !Y_!2 iz|PWk{;3S?nn/'k[%C`UNWyAEsƲΞZ;/?~-g<+mu w!.\b練&*qɒ%sҥK9S744)*)H}n'٩z}պ64uTZZZ]] =HD)yqLp9 DzHDӹ9#e\֖&xԃdJLY2'7|0+dG4@^}RpdV3d9?֡ݼi눍NnsD0SϪf̽O9/]xd* w;/ 33ێ^ӗ US;#T p8Nv8T*|wPCY.t:|uT*;ew}k;t'|ʜ4wUJNqu+`)Bv \0DK -xOSa^:4o2&_y#U|f 4~_'(uBҚ BvXP !;dAc=Lβֺ~ ؆2Y\5i Š 3Ĝ'="2`1%'BBv0Bpy6%"I-d;\Fb90@L#*BLKAIKR> ?\2@! "jָwQe'P+me:s(Ef+ޣׇom B!߀ʕy4Pzeg#OTg=۲|KZ߻` }Ӷ!p e[<0-MZgZk5el)R*4,D*L+1Dʧ@k- fE%d.L֦ ޳j] B|@5 ȝOU8馊h]e2:5CUG]tEa^ե^~Zk1?@>|r+&M_w5?Ľg>z#r@)5vl, x#LuРAЄD,//;P3r]TxNYYY"/>fhf(H xZeYJ X1 IDATElEUZֆJKKt'(<۰5F5kW6m?,ULB59߻Fo}Β1lnR%[q~oQt% {ۇw9q7CzTq9 )Q*-du]>WG lj;WZݾ6Aa纻_c42 2ƙW B!M_ȳF#U?y>MroHoGnEmw濪v/R<#bJf~ʏug]aE#BHvCÒ%G@5zpURN !P 7QBIB$̲*؃|Z!B^ !; Z閺vZ '!ŵ`XR!BBTZNwPX~?1J-ZSB!P !d`[1{MeN[¸Ces)|'`|KU@kB! IE$D`PiFtb&cf[|?T{oKfέle =(ų>],gd6>xt!A?pfmK !hhFQ1 i߭}u~R2U^g* UzlמuuV7ly73ĶʕGU/|']B!;0JqiAհdMy /4 !*V?C̸ӑg _ycv:g6xaǜ|,(]ROXXX(Ҷ R*???L\Z뼼bG1??8{|`% )6Zr{CO,FXd!z0q3.8Ԫ" 5r@E !ۊ0: !b" U ,AoҒS[{VRI ̫?s#^q^yC)I76qC,~ ᔲ@3վGr+S0ƚ 7,W~~~CCCjBV.ƘykH!l]NSR*-</C3:{.uUOM}1WoJ)ww_^5W/HGZ!#6(qnX&ecvcJ)D )#S])T!+Qe8Vf`"ԢR*jQ)JHk}dR2U=;6ZGbrT6?""LYR׭K76% }޼ni[ij/M \I&װMTZ^Y_4'a`݇o?ښw\Ws9>H= Vr?B,^8K0MZdIh\ҥK\JqqV5)H}ii55 IX-Yyֺ.{ {+7̀'5k֭iHD)y?XIEH4-]R6 G w{9JY_/yCs!L_4/_:>iz.BvwcL*Aݖ+|`7+<~)hO{i1!bt=#Zޠ19̽SyOfPk#mNf#HKv"jjINʛ)UG !-{aou L\-+/܌V'{!3!MAa!LB!_3cZp`OZ,g> p3g=d`oDL 23.7gپ]8=МN9WWNo!dX>_ʫ $r*~gOQ[3\̊rC`[)HC#B^|U|Q5,+ 7zz/hXC0ǃ u{jdu0׿).͈e&BH bɰ螠zoc -駃$D4miXwu̵yҌ^&0yV%BȖ; AD H45Dר`)#h4"9G]aǢ@v,XUvNta9dsH愣F L.Jk``X7Ќ^*]V (B! =ǘlFԾN}ٻY1zVjN3|4DoS.X_l̈CP+AC+Ɨn6f3b)O|K3j$R>BPILG pSF.tx5yAeD7 [n -;!,7N1"`/|[e.߰'75܈J!P@%},(6TphM2O*ȫrMO#balAE~9o;AЁ6_[AZrzFqu}3L4ŗBJ+JwP i ƙcѮ1+f8I,\ HeMyFb(fr8SW'#)ڧhc嘄ݔ轣BT7|noHwiæ@4^`2զMZltA_?-u K:)%/3"}7X' `(&$]^;!*)!BIv\Iچ7 B0""Bo⋈vJ6`D ͵ٖD"Ӗ=y[Y9f9]X(ɉ$`Xw3$sCD)Ft٘\ .PrU@ BqSt{E+lc4cimڕ-Ѽ>PU›? {nKNco$TDĭtg'~Z#.gʏ'noD5Z1eQ+mFt|Z J[N`R19=DQLڰ/\<$iuk_l0F B!*DNw1@?={׏.~ 3:;Jˋ;tx(qn/L_GV)ť#g0rh=,/ѼwՙN}5ѬNKFc.?D`kK")_J>A+pڜhkF /oqnlqv*nmk;<܌HčgUaFim[6kuNvPH^DQC! []lNG"dhAKM[$3$sJ!l?d>U'х/EN@)|YG= n}聧1SN;bR|gqYY7Ȩ)}p_c`Kmz, 1|a߯\_\d^s\ֲyY)Q \wSȵԦV;0  FLlsSVzľCN({w3O.SZy2jm#$s 6! E0b>`E BǨumLa4͂cܶoh}j^Q%tkCwڦJ59FakKwHKgiZz5"CF$Jb6oŇUɦ?u}暦%s b-5i/P9>D4bֵ(. y &GAN;)6 0b21Sf#du^kgȘmlX(rѹ])ClqzfImkrb/L&R6p/ iU7"ay!-hdIC|}=Z5KAMvM[k]{)mi:lܚiG!&a4@Qx$e0m"LI7 )slCpa,_|~ ÀTfwhfNskJ'jl̜C]:}  dXh "'} @)yBY61v*YNոc~{T,yh̀n[ݼf[HQ^D!UC- Jʴhg)vo{ asmDBGpH(vwe!wZ{#x[q`txU\ F6Asi0-z ܽZj%_ RݕulBf~HL0Z|꾏6BYb،Jb`K[pCZ\޽. P;.H 5UXJ5 q׽?jtO,v  8=ͥ :Wp  ]3UBp;#/+pY޵bJTg/O-u }&Ӯiuuᯁ1@Pk9#viQGguL{ܼHP Xd>G#[*.rdtUG;hlR@Ե75Amx\{cېr '$;ZTwI+gs#W-G\{>:8ʇ|[7~Ԋ9u#4:v_lM8vcA N^:˵ws晣^2- C %CK5ךws"M/%*_n\[,\46:|"/f״=VSArx|ag$fwu|B߰%ǔv7t[lhXeZ^|I 'pe-/?e+O)bIJe8c3ޙc ֿ`,7׵;=Iqa!*+s^Y&βƵ {B)g(nv:/GLǽ^E&u6DmfudNkJ&-{奣N[/+R$tYfuMb+@3N-sG&JAĒ)R),?%- ]mKXߠ;i;dՑ| ` IYy\ihI"f^L= YkMalFnhf]s 6ԭ_t9-="]~:):ZG,}汶pjׇ?"7C#LIeno>c8D!m4pذ=M~΍k2Ei V]}i^ݠJ 偻ELkf\@]3>c|3ΐB* 6h'VEip/4%-њ֤μf:giM9,jxI'8hD@.7o/xWwWAs%G|so}:eϏ)dae N[!SP-ʵk+č,T`zE9<``Z aj8zΪns׉,Ho̘Ѥ%8uíl_0o_4^(6~~epm)d8 ꞝֻ,oV0nw{dsg:ɿQ5;G㱯z4SìS\tϗ|A,WOr:v({2a/C|xawtРAUxV0Zfw˃ CV.XNNNAAAaiieeEEEH$|˹GQֻ{ҥ>feNumj2uͩY5V65'}jKQZ!;hFUv=։#A_I2I 6K9sl |{Ϟ70^ݜK Bٹ?;$kAw997f?蘒1r]/..nll Z)UUUr ! pTD\dIȮ)0򚛛=[zuQSSSR? fG?yhuB&)cEx 8sAq?,~U&_ٖ cf]޾|ῼ(ݱ]JCJɴޛ!<|c2yg,d5Sjvre\rʒ۶0Me@!8J1LjS Mcu?ZX rL^73=Y][\]+9#}  !]@/@`O7 LSڐLpG`ZLm|CBj{̏j?Eu>SB!;2 !=+fo` $ !B(Be2GO6 ~Ү2%BJVAh/GdI!>ŗB!P !ٕr0bV%t81jΙ*!BN@]o+しN&h/v3# h?hBH߇*d#`n#t'BVVN_wCQʘS)c}Qq@Dz܍u`t>q!bMbK9ZiѩB!篙Z gZ>}?_\~=-1A]Nnqx)wjg}Opj>v];tT;v>ZS_MJ,[) ͫ29_)WcՋ0lJ0m@am2'|Rؼ#WG,٨z@ IDATBa*B~|ۯ^rɻb]?`yKڗ<ռNux >pCg9llՓ.]pėQO]|a}o\?b .(dĈY)&0Բ Xf[)8cx<4)J`JK$C/"D"Дض|f#?lpm6hP"6ض}7srJM!>Px Pȸk܃Sn 2"U#GqHvTs դ kSc,׵q68畕ً ---a iVUU*L5L6668qa[kjk0TjkkCS"ukjj"`ߊ˛ sʕމh4VYjB!TdKC2U 9_5#&-K s?eV?#xY; [tG GX50(SДHiZ\cZ"8V @)dFL <B!uќ~v K mg}΂;&|N2@ngWnp/ _᧏\pڲgI;s$o'쳿ELc/RZҸ_՜-~C6*PR2ɳBu\`R)trWs=P)  U ;ҙ5=s>+Ak71i̼o,`"J!B =pwd "c+D B*!O)xM&TQkx.]W\Z&D幞( 2$= L˖t!BBcf/!˧wPq6Wa}G? \/w??;b'SOQ !P@%-+d 5"P 47PY^ z“O<tO 7:C;jpUUgAzf i-8i8YGk[=p츂EY‘G=𯃤_D2daYڶGk]VVff5h D ӻ3sr1rrrxFCVx<EQqqhɒ%>f)BzP]h$xJ3v9*`N~Exժ$MmQeL6zy/%$~?H/}Zc*{V\\1R*stTҥK ,??9l'4\]zuȎ\ST6n}Eҳ| BZ$l"cZk@C.#~E3׈DuN/:CvO/lO8s1Vh?3+guȺ꼴0sr20|Ak;=+q} 6ewҎ12c%]E,@iseV($$RTi\]'}<' KUz0of`l[ {1z@/A$!WC.~vf}<סR/rů=;Q✧/+>g֍Շȏ] )A+ȄҚq.BwaPb H'TC`4{C%-[nCԪ/3H7@ف/ j?B(/L>s/>~;U>2i=}ɫ~{?,6sZ@=rƂY=+|ίJ?n9:'6q}֤繹5{ e" ͂]명fE~aqiiP-%@UqfiGyZ^]Y#NF !P?~9#<؝jgdrtcikQ` >Swq#{}%Oy\Zf ~MMzW?w gw5%۠=Q4J$D"L& biiya5D"'8lϊXRRuSb)?3po| ZPT5HmJ){qkc՚K!ɀ`ݚeB'se{nyWQ'hfDҘ+?ߩS/?{^reܖ w_S_w0Sqfv6Gvaf0"*PPT Ӌ3( `$gX`4ӱ?$J>ܝa Nwuu8u֓{unw-_cJinnq*v\\\UUU$1כIwP5Mˋ,ˊ=3&M)((+"W"GL\= ~IUJ(Cx<1۶1~#BZl3jk7U 5Οr] _dܥGtcmQj̫鮭4E"z|.W}Ǐ\:zIpJmCKđ%)v9#,: v8:!BN2tE9_MW_g\PϘ^ x59:gޤ@m\ %5122Nd }B>ZhD1OlC1AE!NPAp=\`sD۹ڰ\v3B"B_NX+!B!P=X!B!&!B!&!B!0AE!B!0AE!B! *B!B!Wkf\t\NMS0Ǵ!k"*fL(IV<B*rkJebnM@TM%!0A٩zרI fӴiBrytoC͚p;玔֨fVnjhBai;w8( pq9dE›!"7;ҙu<^?ol-U~/ʾ,K8 q: gI3!x$sgD!i"91 HdLHOh#0"-".&.ak"sicxB7,Aฟ=A"K3cksy?~PS_ĮaDزu-l|ږϋUR-3_x$cb b׽1惘_o"݉O)spqf DR+Ȉ5j(fN<===ⰚB862Էc; 4^uܕdoMT*A09#GڹX9pXT3vaK*"oBeYGH"D^%e$2s̋%4hP_p *!y'BoyͰ~o"}њ$m\I._>7_۹+_B8FQ:Ns,ɩ g>{]19orBl[K"LDEDr7}8u߮BHζ<]!B XsOrჃo;,1}'D_wǕ>bo~7W.@Qj`Y*)kn8b7,>K7Akrjd " BpZSw6Oٌ"θ'('BSINNu8 gJT. T"#(%\Bp/nؖVZRZHB!BX0CxĂ#4 AcSc>]1A՟f 7 YOJJi0h-*9)a! /1%1.uuޤ(nB-"%&GGaIKLJF<$=19#A%/99Q˰xH?t&0Sߧ&%G{arRbtuf(W?!)>Va8?%ilZ@ht|rlF 7xt)hXˉdr%'>7PXbm%u0>$$%=4%&'ye0֏9IQYC#5MB;wtugƧE /6)>A[0R͟y0hKx!B( 1)iq1~&fX/{c=2?A5:%9Aap'A4zLRB\4eBJ|L 8ExS4¡\rT|Rb a2_܁2Z'؄(;h!QqIqdthk(Qe5B$-19)J GNAOT\Zlyz *wMW)7L9wEtMлaOKA%a+o9~ rl׬,3yE. }3MvP͹1ti+ٺJ49xhk4]iw(8 ,K嬦=stzu\١,+WmI4xoҒcZ_0҈Ojفm@V:: W]0Ңw^|i9' ]:Xy;N=a5r5;w3չ)U_2%}u+. k =^iuӑ+n@E 6j]oy~lX١EiޡWzt fQz.[$Hd5Ew[.=1Dl%@EH4]2 +;5ΖK_U3u5!~IQ{s +ц"ktm;&hSGIY8o-I춫TM!ݿ"/P,ѳOR3y=.H;\U&\Z2Ok^ܷS[?҉i,A%B5J,]ӎm;bSʵ[d4k߽Tō>}ȭQ;vTh4̊J+tK$jүnڶz;4iۏWnٲ>['ʘ>uJ:[޾znD C`ަm_YuظcV#yjRJJ zJSgBtcɯ+o۝rZ_ 7]qY!&M=sVl޵Eks÷+}ױ]l Z뾔5%7Vv}-zֻ;TvӔOhT=6TL,k_m´&"E^92Օ>7y䳪L""K&]mZhCB} fM1$o+ڨzuf*iﻢgIB7Dmƌӵvk*ʹY^ ;7{xcpAT`iPj6ZW'h+)ѻc/^ /}CqQ$+7Iҁ]b^x5 yώxbwE "рGƜ}a{onjŎ}{~VqSN|?Dysa-IuO'+lE_ʜ+$q|~pB{֮=WW=%e;jN !W/[{ekſݳ-rm FmʯPOdKVQ㦱twҚlΣiilW"t.g wʜǶO0手#\הhV,ٰeOΚu9M$!|Uߕ3~lwxMN^+޴ߌQ-=~=1Pc%\!Ro;KͫE6e6i[ .߹wGƵ笩 n}Ahݽ3+6%p5>Mr~:!Z48Iq;JIG-ŵMZR Du ~dt;sˊY{l"`@jTߝ_BUXފ_Z?U ? /DG|Ԕ$cO*+{ B%+Yn-]ݫ`Z1npϚNL?k&)49=&}e3̖QuUFWPoE;~f%u?v IDAT5[6fٺi{扄,WJy_{ድbឍ=*|Wqlb4b: #.P,t==2_yey ʬqoݥ[RaSY"C׆e9cx{f^W~mmJps;$mtA%Koxϸ=Ϊ?^$< [DV~֕`{¤ڰW~ iiһt;ݿ,V³PyO@.7"w'ny*Χnj椷WttV]?~8u Аmu<6s%'{G?xT[8O]{MG]Xɟ,D M#*Ƞa/|(_L^%~;ࡇ9S^~SiAN|gPUu.X|GK%+f<}UAMLi駿t˧FpRW/I:ʧfin0P+_ϯs5/ ?hxǓ~r3: :۟vv7og8u^.q|.ߖߗ<2sꖺ}^Tiܓ{z 6Nc`J4Ji(HoS ToX\&d?_2ݵe|UGBz Y7_g/Ysgϋ~x۰N<O<6y_gNXo 1$:t;PiK.~[C't|xMm߿Ɯ۟{nX?fxsD=ېgUa xqѣj..ʬ-zi}|I};ZW\9OoyV1wM\wͺ>|2,#nLj;S9׽u1gZ{cCeݜ)=H^Pm>v &y` gS^ز bE^<.m}?Q5sĻ<: )|{$z-e~sjdlϯ<{D,+M={1b)fR I"{4rIS(eٚ22mJ+!<hs9!ͣ;<tUP6lWG2\N@x3Bּ±GXrItMv Iu5W\p: i=͵LPuEiz4Y0۰\*k!]"n6'}4 .{p!)00mǣĮl@<^k.YUu3L2 &ܓ3`<27,@3M2lNfèyV0Է:ŧ˦apCzUa6H. Ⱥ"CD%P0-W昦ͨz_˜y l;΁l=e'+2u,a) nA.!s״u56k k*jñ^j1mȪG͠x5 I)i3Iյ/p̀BPGM P5L倦JaX@%4<|{6&dͣ4\ݣppuJ@ئ t劼@ytC5N  ]TaN@x ?4=a *B! *B!Y!B!PH!B!&!B!&!B!0AE!B!0AE!B! *B!B! *B!B&a`]TQ=Jf] *c#iͣ ѰTw_1Ti2רs$݃!  wP9WΞfgӧY>Gk3.g?259?f_OlXvAǶV5BGv@^Vp1Mv9Zi9m>2ߏ6m=6$rpl4- ¶]pma|E!q *݋>8p]}oUfQ^l67o0dϋg xϻ~5J;y1" {E>"D5s[oÅ]]o|Z[I١zg(M>:5.n$áTl7Ϗ㷮h̔9OIF!Hl$LU89: l MӂƵ,Mo~Szuvqrfr(JX""ErL.oEVS6p?%z7r_3y_B]*Os]7$o ̒_/9-=cdSou@УrˢH;nD}^x-4|_E  B=۴͌:tk(R;%WTé3Y'Oh O Tyj[Y5C1q(/8~O}J,)[&ľfl9c[c܄"*m_xC!PX&UE_Z.ڀ{00ZsG$*v]pa r u7Յk× u<A|l/q4z*oB!uE DuQ@ɠf6U_A3.|-XgC_yflm25wPu}SHʭt__V F^pⶳl:z9wBK!/A-ޱ/?JZWT>)/fGڶQW~[֖?G# 8$t9jƴfKnSՍB( ŕyH\2ƾ囿>z<1 ؘo' aW윹[k?wduŧo"ߞmx(c?gЩ͋o4!ܧ_nj=6˾mnCE!t̐]OapfwLFUlu ͨM&y4jy(@E!t,AA5M;(\˲'T4pmv9T]sL*J@XjۄiؚWcF˺* Uð@`DѸu]v _BWsĈQ,ˡz QE 'ƲFo#B@dwkjeUՃIǫ=uoW{+ WB<3SB!BTB!BTB!Ba; !B!:&IBB!tj[۶ B7AQ!B.BAE!B! *B!B! *B!B!LPB!B!LPB!BaB!BaB!B(V݁UxBB K:G匩$~S\'ELբuz"BG GMSt]$ BE*!a cYvJPe#? <!ߙI@SjO:AgTB!B!TB!B"B!B"tRe;$_pǶ,fOce:Lp˴rטk[Su\۲,vNJ@! xc[eY?9_BǿC:6sqP︘"t߼PksʻlYF։aS?]8wDSvw~# QC^1I[O|_}̈~i^ TBv>窖@HFfGH༛\S1 㟝Ozҿ܍zqKQ1AE8$11ιir@tnwqSg,3]";k͵\"s\ ܵAK98M5w7>73X.VB?+/ҷmΦYiӳu*҆+|kɵxoc7&)[,ul,p`(gqkrM'`,+c#t:}Mb%n3Oe;ڢ-Rp cl ɚ3y✼E~{uYK\VuhAO۽mya3Ӿ8Ɓm{<4x_8O}Sɓ/}+ZBnۅ Q4U+B᙭ J寜o;ϫS&?*Z0l7w?Wo≠U&&/"t,fiw)1l`tOycl|w]87׭a͒:{ƙ {dZ;kBsoqLpϪe_Kr skʜ<Ӡc 'h=8˟AA5uyuA^h{?>~w_f NExX ̲CU3bc^9ͫVB?g4u\<65c?*W23]~1;rt[ٓ?l~O79]$.ENLyV0Y Bժʻ㩻 iˊdWR:9˶%y㫨 ć|*B|1g\.M]{-ii8.ѽU/[Ѡ\4~l;eJUDT)[4JInS'.|޸)mruZ8x%?-5JKWNo4ܔ(oyk?^Q&mBǸ$~g|~V^ $N]#(0OG'= ~9(yVZYqO|33lrƲv _TFrC9OkrU|̈m`Y$*]mT-+cTj4*iR/wP:\Wzȗٶu`_#;`3M*^v>9MV-;xNo~|χYS(a{yqVgިɎVu]!(ck`Wxc-(^aХOL 2EDEK_}_8Ԭ'>4!2:1sJ*Zw/|'ߙKHsZ𼛦{1c?u*?*{LόU+*j-ʽjحoۗ|Dˋu2&x_.4^'fWkr^];0ALY ov];<Bt]f?vh"QiڂHW%i*X: J*<1-HM{=T0˲Be]SLx}cP_esmvǫڎ !?6!ʂ`JC4M%Q]溦>ٶ IVTUeDWy-TcYT5Mu:(i'L$t&ǽs˶sda̴%exdkK8-"&ᚎ D`@u]:!Cj;rsĈBA踐sĚ\ 9{#"+ {u")H<h_Ӽ^VVuCUIƍBYT꣓wA MW"t,QM%#(ҁ^ȿzU]V&˽!B!0AE!B!0AE!B! *B!B!t49kفn,$oMY0YTU!6- n*#d\&J!N ܵm}µPT0vPTUP\WU(w-Զ UU⎨!NtG^Uw~ϫ@LOR7ZO>}}Of|c|-BS!;-{lڇA\u)a[vY{qkҴO>`7Nn7Og?QxFBEݰ8wa RK<7vё7?5d«s.\Z괺J~/El:WӣW 8[!Q w+ { VVI/T5WN6i#mxӆӮXH| =t+Nst|y}K-E\/ig-s3}袄dRNv^4:`x xxǰ#&A%5y?eiPo|sw+JllS+q '_+շ*־] B **Aǩ`H-M8Dt3333''',+.."rTyzzzaa-!$;;1v޲')KZo>#aM$ĶM*iUi5U]rqMK=ic'*{qe3ym<8{|V$6m5ex0B ^asްapi IIIeeea(KvsOJһ5[h]L2*60\W'o{]u+TQ㗠VVVFRmy<Ƙm6yN1qw<:ǥ8Ճ6Xceߐ5K׻Ǭ& !D8!ª6=^kM.cH;M{"GudWH}S0PW? hvvv$!ch ڢh$y} FPzp !J?yS[S=R5gGx`Ee(qIɉMo]$c !kvR!D%zVVVֱ\|\c1.W~4Owuɜmqktސ\Y)GY^ۚ-xQP$-3.̳JtF^2iun^-!\ņP_B,8Օڔ22$y%5.$ؾnWUia}y;wW&5n zp;*!Du4#EBuh'wNLL,//4VV@%qqqUUU'\u ,dj񥥧%&%*;BVyIieuŞ|h!\VfSnzy3)3ڪ@Un$%dcoxoKFaHPYY.G]WW. ('~I뺿?km  U`E"vl /ӏT ,,07>"oa* v[ uPY!Bέ.ZwD@T]c}UUauBwB!BaB!BaB!BTB:!3EM B! *B̰ĸ3TBaB2n͏B!LPB!BaB!BaB!BTBY¶\ IDATB!LPB@$!B0OB蟡4-B'c{v+ +hapeaE-eข08ZƠh\̀D[u""I5jMvE+|Lx x=r0WTsjXmFKO`eM( "9i'qΓݲQ$!bb:<-TQWGYưA p($kU`J9.fE < $H—٦0h*a\RuM\˰\`k#Q4]%fAM@$,5;L oBZ#,Τqι8aqZU.45GڰᒠfB3FʪH:n!yK+^oBBk~GRm N@LMM5M3\4ce(ecp^RGZe{

€ xzF?H~ LKK;W6 !cZ& F_лgx9u%AȄX ڝo2YZwO?w9癙$W A5;c7550cAr8N\HNNV%,$IDMPPII&<^V'eԜ禵֣{(z[9e^_^^^]:*ˈ̎ͭpo?8:NDUeY%%%wk\@zQaQe-PQpOzňIͲ}c`kyٔ7UQ#+ TT+MHIqwg_7!~O"mk ov]>3KU(yyy` A5;i$IyyyR8{p9ZƘr1V\\. 뭭 f@EBkKztgYN,ZsIc{AҥL%MDM-ڿph #F6ÓpR2mlY pƔm'9s/kx5U "kyƸݵBoެnVB%䜮$%q/iX<$"tT bO6P ~d\&-}A}YXEXq|!~͞?p ? ]NLԟ ^)R F/!3&xu!&EBUgrsPe$^!Dy#j1@zY~6/_\ BS ^EDy~ (2d!B"Q P%|!BT:# ߓܓ!B"Iv HB! *B$$)ތ.]!!t s ujG  5ywBaBG&IA!!]/{OjgPB! *B (%^>'.E!&cţp(x4 OU&x!B".Zl_( o!B"vʡyzFi`B! *B('I7b7I_c@H$*h:i/yrXgP!jt.?.A/lǢJsun[Vr]7"!PZkq<;QXΙm۞'l,c3 $0D˶]Pe=z\qϣ.fFFF‘oro]^ FCe(ȴ=%d: 1dY碳ҀlÝ&NHD6BXjqbn,A)5GS۸6@u]%" 5x Pϻz?56z)rÖsXυtj<"9;`h f-Y-(J#†>Iq$0M}D^>i+.8wmVX>vG_qUo}_~1$@fںcnz?^?;1i3dV_[\`0:3lsj&vo﮻Rz>~'@_}-ĸ8$y0+qFӈ`#׷f*GsU_|_Z8Gy#[{D_3-K r2˿ h{0%y `(Ts&k!m a6|TD`&aKn$/̵pʪ/HiEz5`8ڰ炃'j4Ijث=V@>:G ૩bNV]yB<[{8NF6n.@ BǾ Wq ސ7X *PS틗/0gK+=n+Foʼnn_yu0ْFYn s8qv4Z0\RMaY& ccѶAgش#W_=U1odێ k:d:_fox⑾Jmd l~ml ={q m@]gڸ (Gi\7:e59c忺yvGyιxڣ\~nmQ-~巯t@~ŧ~5Kn\k+r?D.~ӏ<"K_k.]DN׉o~˭ǦFvV_rГ>Ux9!d0̱LQ`K†TS:yt5k3 |ʼnI,g&YZaojޚ/zԙ~ε7][_l}v芿.[+.8'l:o.h #b0 GW|ѭg]RQ¶RU_DZըZ*S +֤vt鉵w<9ЧoӉ(pWtrzPkˡyPsWxC ŽluαvJx5ܕgo[ue c)e"3SQgQJax4=:LfYƘiC'Ty2d졦AX*fqlk,!daDMM͂N%mYlFE;'yt:!pJ}zLڮ"dh["͎BTX*f{*Je)Kp,^%8Ώ40~  {׮m{–_ZySwob1ׯ?t-k~{G@}ҕ#7$~Vغ$ЏDgnkl iÊsnlE)mCu*T* 18 qHBki\ M4+&%j=H9@]DA" {xcqQ8gz >gVq`->["W}~˦߬Ed:$bw+/?bͻ=_߸UX~n>OVgwlVF| q z27&~JL :,_bbEM]*nvC$4r[^C 3O aij9iݖHYg{<-U<7۳GX]&784Jj\o?Ƿ2!4R4aCS:]JM@=;j0`R|I̓3Hzl` =emг390CǪ1"Zs@Zk=O /𷯇|?~.O7"&?|?-zbHW_:{X`0V͟צ^WR Q>1X^A/N CK| jxm*^_rs<Ќ=Џuǵ/NqUNpJί7_A&,K vo[W_?owȄm6NoU/9S8DI4y|?jV3Ո|[37_9193aYuH߿ʥ~ooi\{q_#!Jέ !2ED+(md^p4[pV42nI([^;NHMKo9%*|(]Ċ߽ΜyĘy)s#= 3IiE ;0..'xK8nt7]ԵP;|?_1|-yӏ m;L-2XC*83 [O%WJB­wR`ːJU׮eyD1 ͓Oo ! S4`0 z?/ݿ/(Pa:}{p-=Ei͜͟S3F~s~y7"g"οc:]/?~e&mys;U]lww:@0g` Fm}A̅vz ApNB?S?pm|ej8 H33 Q%E6>GD޿L %|9S:PSFΤ%,K8&Ӛywz[n]p`xޢNN, #P 8|5^jӊT"CO'E%<"ﲣ,#VCt=% םٴ*<gP 0DsQlmS㖷% ~.xYVz0wcK;SsPFDp`Q[}t"LҧD`I"Yn%h9ɐ# ֶ6|wgi#*q0["`h8q0iEDt[o IDATRj+i~Yf3i:a'l'Xh@&@5\2~i_CY0x䨜A9 ך6i*$ܺLE0jE !\%e?"q>٧H=h7;v6Ӏ`0O"g#/\֙n_[8 sOJK&넥Jkah:MOA?ڧJDUaTn?!WՅ}m$ (s8c IEZ\X_ٟ``uDNz~SpC@dnO^MqgBl͊)ˍ`0 hqz)'+ _c0P 7Ѽ S@7gFN<ŭiw6YsRotgKK1RkW A54$#јSwgF",W'wCJuߦ@FMDC4D9NX."DL `hT*{)aHQ%,WBfң]hC4\.Ͱ.kl~5Яi @k>Em\# NЀst9rJᯜf$)P~>GIƠPw")ݱ:9Au-a,(jm6^ Ш0 }jv}T;oÓJ87WHPUf~}~=Æ8*ч?rێ3<6ITtksODHI'&a}n [%zgԍos,; Pf|1ϔr6SV8$8屁n(Emk`04$ul8L|եR_5L| Y?o4Dc$`% >kXqx B.uHW+)5Qc (WɱZ`@z |N`! A$HzWXюe5`021Uz35=keEi^iL 0DH &\n\)R{!ɱjbZSNFdI;5 TᰚX̳n8ܱZܹAUB4 㪍埨3*WZI7@1BV#ebDP sF>ef" uʛ(R MT`0*=?DD fc{j;aiqYy34&JJ{ꭙ80qUipgJ#El3!W$;[zPW Auygoc_N "/:'xũ߉;Oʋr~g,>jӓtYZ/|gwDf4 3kW#Uݥ~Vz.>vű+ 3qڋ~nOt= C{Ҫ; w{."t,Tc,eEdK&xyZ`8+=E9T^W<ZqT qiOZApsD5D 9XН&0Մ ox!>P-pݰ+`nsV 8K톖 ,  5Va6:nkMTeS -Xбp$>.akrBtwu)U#KidBGR gZ2dY2D.L xԔ,d3!0 ަ$dFݝyjۧ@2II z!36c6mz#sh [kx?鬺OɨoK%b)ZϹO=<[nKO_~EqӦgO^/zѢErP6 xD󦽽]kX%!jwB~Ͷ>8CZ[~ѨG@ _Ύ}K2 Ȥ޺q|/ZC]R,zH\Ab3GLhj-( oUidZk˲zzz|)WIGAKLP'.YW=_ IWغepG_(K6ukrrmP*T Zg]!*,}k}Ϟb1_quSP̈'my.@WA_nٿ%˛S}=="[[lT7lUQ0)tϺuɉpDglɅB0ߪXnXX ##٢#6lR vݝ(es].{ Tظq?Mzl~qLBk̑KaToyAxm'!h@ZL3(moj=㖥5![X.yK0֭[gP6 x7R6r{zzBQRپ}{T:F uW]o~a ٰ ׾gtጽ CZKuGYc5CgwNF|a46>sGG|!` q= l*|Z AlIkp7HiH,&n, +x.S54ys~sj S==G0F0)X9ӑб ~H>.nl9rJ '\^眏sl2J;3i S>c{@gRm[OH>`S*y5] ;|ßo~㹿fHd ՎΚEX ecGd>oY26>mCXN73ԩ %qogϮVܱa{x\ PgG-'DрŘ`\} HE5\,dEg@ vvR>׺f-"ϞY1UMo&uJ;ާc FJpqG ja~̄ A1$ʡN8Ms.,DPNNn<*"xP `0y!9RLk&78IFza!9\j΃f|[^P*TAeOM, .cowˆj^e"xj/OexՐb8M5$=;ƺIrni?ۖ "`"DpQMײOJ_~GAĹ&kFwץC`0 #PL &&$cx&XGqhJsXKjI^S &+,&,ړbu2fv*EijDpiS>^ B^= `1DFKGFVіHXayO11E[ ] iXX)ZHrP]yvLoi5]L>em ,ڱ<3k])|w))j}DQ) m7gȟ$go?Cfcߒ. d)qTK`gJ%6C 3&eu˻ / K D\ծoz}FK`9@$@\@aq\*RcRpbpJRZ3݅bl`0 3T%֐I0o@My,1!f(ô4!T[b.g +IIirZ$2Ĵ?Ehp1ց$?;a.^"&{vƖ,'[XdN\beFIŔ7E!4 RdjZo@V 6/Smצ>+W&;A8\\kc:/K( `^; 'ܚ 4As#5͙iwa 91냈>ϟɢ)>#TCmO +$AǚҸX/(1p$xڶ; #\&X*,\ bN`!ԏ)uXD57Ŕ5%]fI 9F u^&=s@%IS> #:kko8iςM̴zK{vm֖@MN" "l{{'FaD` J@cHStmXmMw+Y↊r4Acq %1<Hѹ+`0  TL1$еDy*Y~ʼn)R-4'0"p,<&9Ǘv79̥Xk'H{5&SM/MV)1$U+"爤z-1`7(9.-q,IM|j4!*ka9c eSd<MXJeSs8-Q츣Y|`~Hz9ۋ7DfS:fX{'fAXse!`Qg%4ԒS,IҚ ޒvb[2RpIgr)fKVee B p'Ur`q] O?vM 1ho#8q5k̦݃j`Je*RPPg4Ak^R!Joxij悺9OH~]Ȱ\řךjdD{ CƥWfR>ko湽5cKNwZ3Z()7\`Kn?o D(m3" #=K#" C+ID-Y}OvmL9lnLB@,`G=ѱ]sl[`0 #P'A!I@;]ト[{ ۶;J۸qw;UMW]ZʂIohl+$9)o$E,tCN2s m^.g=m:6&=M @WF+ tz&>BGA,'[g,S[b> mMdj__%T4Aw%K'xrg9w"=C7_,Lqn)3l+仵jHc]2T08& rVsN-P3b[`S@sA񹍦lҎC,P}_(O\jI T!k-QPQ#io۳Ύ),%`μ&]#e^-bE&O -J=0B%Ukض᲎?k ڱAiLw|Uz IWWl,dDҐM\5D vTW^kHp@K1Y JKl *+cB4W\&#A 6[´#Rr߰&ri:irǦnMМe[w\"d܄9;I0"@Bo6n*~k sfj0 l;äDzI^k%AӇ>ZR6Ek@ {?qRE~&hJfUr&kˋL/p5Jndq½Q [@H+^~Ԅp-ԚZľr^N<"x_ {&؂6q Osc+! Вe]m±Y0ڥi ֔u$\VM;-`|׵1:ױ  79؞羃wDU ecAHQG9N R;̬5-l3q,\.&iU*޷y w&JzX{S.;uCMОwESޡ&l TzED6U;۔fy6.aHhFĤNEDwm֞*!D4tXQ\2P:8V\2$1Sk!Dv1esIKZG9>Sc-B,KY>g57MA&RUu%r|FY[C%w8[5 IDATlIGbʋAwߔMy8^\xQ/tkc.łH+MiM|@k#@Sou!dtJ笴S>J 'P#9!M|iw[c[9AM)& `~N}-'nh}Uneߜ)X ˥Xү935AGAS;l5l1x9Xç6{ղ.#eʧBQs'};ބՄܳ٦%pq&YF;Nt _]LRMin4)q<H.c$Qӷ MtPI;6!x6V5$] a}]C }Mٍ(h՞#_j}Aۄ@媞YA! 'h<+Bk P儈Z)'<V>i /}h[Xͱޚ-YSӎ'&.8:* 4y1v{^O : <Ν֒]-BJ̍*۞B;RlhFpI+*hUHI&Ulm./7IeU.UsԜ0}`KL||l89-!dDA)Kwm us}5"dlAw 50tY$ibj@(Jݯ "a'9""tQWxrC59;wY{WSo{!tGWBJ'R* Ž6No)mP *p"h}:D ` ,83\vrؖӺoβ5["KePIҫ? ʍ2$\g0 \83}s)>C d9ɶvs11~Us=C*[& 2^iְz“Dr7^t,ooj%($c w#t؂?XMKPca[z\?`Q/':'kKa~ÚH wHw4Tޔcc+bOuo:=)-%Yf`Qťza!öX}Y](H |MVpEi &='0o=:5Zvbkoܡ\緈˔@ձ@[{ 3˒M$Iy̱t~@)X.B'.5g6pQr\>9c^aR_ %6āŴr(Oq / Fʴ{Pȳ!TКDOnPD8K̔[rXѓ%G Zfc!,VT%İi/9}Eg6ŊN888l-'<ƫb=c3 N\jϟXXHD'-uͻ¶&55Dk+M&(?!`Hmy>I@6z24RbEguE Q㻭老 Yv,-J"4YsJ9n ZD֛X>ŖtZp H#BJZCJK:%ђxLT iKf5 B:T}Ccl1AH^1PT sPn?iFA.9xjSO\D[ Jє&t-u 򾿙б%˃~5KN"]K4kMiV)'xP[b{_'cn{uƖ8E,AH4,8 [{#Gb`;waSd9#-T`0@[BNMrubj-K{{%Gm7g Y_5e( kԗ]~4( "hnΎa,:Nj_vRB6׼]·-Ǘ>5"RkP?>Uy^ְ=/p%;@Ul_pWl^ЦѺjpPI>\kwE{HԎ>Ֆ]Itxp<~{OryM)ͤɡoX']60MiAi& V9S|{:4!뷇˺(mrAP}hMivϓc& T=#>7_*P6jT mM;#a#D<߱Gu4K2C'.4̞F=IɍcѤYo-̥k#F0.krv}qi(dyb^eFKBg5AWX)rȇV,\SͧاoNJBq V gkؒe5vm}A6v鑲*U<6pQEb6 u__iJsh12Ib~Ui츱n  H%]d &zU Om [`Y |>&90vQEg}CXDw+g#edwET 3lJ NOZb*d,yMa!ål_r7E*IjnLt#l=\Tp@ wH&G;K_hK8ڲ؃}Χ0p`^ t*1hoK;-MOuG#%DЖť|XeXqmwM0d [[f_\ڧC#h[-i)s~p\ [,:BnMFa5-0.-kF}CڱX6юa4˥ ᲝUlw"yt[[DӼ2UA vF |O~VWgfzݻ,#((XbDآk^],5~:q.y/gy̩3sL'y$ HYa =lѴZ]ǁEe&Ui#4DTlmgk/9ÚVTb ی6/mn C6=Ņ5ꒀVd`ѱFcplxP٠G4*V5Q;B&KN "7~Xɨ&4nXς>:EDwWL &e.LIlՍˎKkW°F6T;i@ JvWWW͊B*׵[PY^ݤzGܵao)-21NWַQ^2Emġn0I@naBHtv?'V 7X|MʢU&~c8 zWdh eayy NR٨9(Q;m>S!LaB)C%je[F$0# 3nj7F 0W$4w 5&?S,=٭'(=0FtC~:n+KkSS=TDgI}qD9~/%: I Rjݔd7E%q4RY4BL76P,t'Pzw(:O&ΧcZ#Ec/;KQR )2ȷ# [$7e G"'”4BAY!{+t '+o0Â{ze v5\Vodpa_ IA䡺htaFf_my4!vvG<jTN](&`& gUhа\ޤz4"bI%U:b@$7JM2#Fub B 3O*f(cR uD8LyTXc \_0) Mϖ)MJܡc\A3XKizbA]ێLX%10EigÌ|\{S,>ZqT;x?:coj[d7y*L gpKZv##+W@hX<#!=D \6ЈBU:ZC7!`‚(P]M Bwffn0@/pSC5UaAb[к9j`'^W$IHb#yRjVPBnPވN_b[ {(":BACmB Oe ӂRIp 1ݑt EsO._l{^>Pw)Bhٗ{.sn?L Kδi:mӚVsΩO7F>\#J"JI MdC(:yP yiܶ$e1Hu) ^N!{2 }˿٥xWʵ43^\յ# AB];]Jn?}eP xIu?; F8m9zn7ϵ7m>sQ%;Է ߧR CS%?DK'|ǭsqOvjhRdn;t8D\x mB.ar#Y)vsxOju݊}!jϷpߖ,!/:Zr(wݻzl :׾Bx2&R-٭N#T81ZD)h4ԡcjV 3عiwLOATaڻ_z_z") E GH ڬIYe5c M݊ģ7NRֶ]([y:=5FW1Vn;hE #g7DԷezIJˆ24E6 $:"Nn64u&O"):ԵQ:Xlh>4kYk",Zd&00)IjkαHLQ)pET1DZ]hX`7;O:LU;C>Xߦ,:猷-Wn 17hۆ:4oO_򇦳Z\&zݤ2*d0T)S+;SʤA/C to6@8T \,O^Yߜ>FBUPQ/DYAM*] ܇Mƒ"o6+ ߧ`Doԡoj , i@s!cjP  ̱\nvĘ$Ɛ!{82%rRFQTJA ټӂS$Y^'2v )J^`K6@P5!Gj@ [7.SІ+sN19{:}O]䰫'Pk&/*F\QƇ)L x3E0\*SpY&p(#7D(PL NX(&CwXPxMt\IFrwF2XS̚@HB-YY߬h#WrFD Z/|t.x#G߸7ew M.H57J[GQ Xt= Jl%nLT&X`\Y,pض?Dҹb;l5+H_ MMDPVkl-pUuG ü˧vWsQŠ#jP(8!#tmwHHCli⁚Np$6XN[#8DjRS qy\|bxs 䭷\f_q x0 i,NiT|(ֆ7Fa {N=4PCs'»{I];ӺϒPI: @oޗq/&-fC1w2͞,Ϙ`mh\ ?hbtqH`;6#Z(P4n_ .'yÄkXF:x4&a{[ȂYΪ6Fpmdq1S!#׉b&+ZCi##?9V^aٞ n 2Ą" ~9issʀ=2l5K/]JGN~q/+n-/bPO>o<[緪Yֺ_*J‘oOg|$}D."C#E/1C9eLo" eN^ww`oB$V?o%99Jo/~;O&iFۯ7?7"kǮ%<&cFO) %ͪ 'IDATd5>>ۥWaNbT9X(u˦Lh; UdVX(PSX$M#юMk ,H.nZVƘӨZE\ݴ-B$&1a(ʘ$JXd1]W%+V&$8KÍ`j즔Eª*Bo!:ҵE5f6Cxah`" P+ hLRfݚ &M%bg8+EVXj2Md@HsEVIdPYO|DZ+A5EIu;Dx>_,S`Y]U1Bb:D"ebi dL/*d. 5A$!j:tEw+w4oKD, Pѥv҆k}?پ5+T5ҿ:cܺ4wI+2'щBT^zrx(BXNGq9ɳeQH&jkZyVw'%'8=z@!?m}/7EfܿB~?L);7;?NzGGY'ZrDkh\&_}Ykz n>Mr*>_5ͱ"Yh(C߶qɰ^}v/t^$1;]kUɟĈ*8#84#r">v6Nj$`n)/haMqGq֪QYn@ukȕ94/E.c+}pAVZmF8,F$RX/0ft qGq[) ;rħ몮wR|#|ءc'q#8$0=1N|{O𜪷aoDj`߶߈eqG GqGqGqGqGqGqGA MMJxIమF =np65bh eT)A$(!APSWU=LEK"9LMQ DxI䩡8ABȴH`!,ɢdI:,TU HbeI5_2M%!V_Q"Jg,`nGb4Q3TUgKx/5L9 UL ٢TWU=f" 5 *:e/T%_q8~{( SQ4(Ѫ㦮 xiEM3uUӣ쟢QEch$2SW4a^y3f! &=MOmzD5ż(/4EŔ Dp[Ǽ(XWd yMU%( $$G xQ0;qō~|ڻRTBu[\z/W|Ӡ#XgWh}姆u;}xPQ n27YOv`r'λaf[ΩמSƥ-k4q_VH)ncc$ o͸ ^ P~MweY(PsfşJݾoz0qVMi3Bɛ|ŧsK"f^=2cܓ#ި|噷[T~&q/g,,aLT;;SGwe`3iobgXμtJ$Vső0xO_n!'dsn;eFkݵ -;y@Xιڤo6ᑅo׶ 4qU( bZ3,S'i\OUΫy~՗8ڡbI^z;|U55Eї^]wZKo]KgVFFMKn9rwSgg ]Y]:bu0so3.`%Oz}rT3]m9c%wQ~wnl0l&2JGKs5 oVǟn}KzhI';BVij.~zj'i{酥;Nl?urw-kUEaaĉA0Jx> M>tCߎ>6Nw6IӰ5uEW![*Xy'"ӫ)s lݰѝ mpC3S:q3-ETSh~ļ}#S۟}uM.=]Zpm%_'6V$y nʵ*r_p:{_MUbeLgL"x IKf=w?c-mO<@%%0k%brxYǁ/8⫧.8wԤzeRy| lٿQ5ކ᨞|ѭ_-~o&|d z%WԖ:p VGyPoSg_.3 C@M&x(쩀۾{uQ?fg7֗rYy7ݙ,oZ"LuG޸+䃯T ٮzţOp< r̟8(5RZHv#`j)U/ .cok;dl Sko[4kzӈ&[3k"ЦZ Y`31fƪWM(_W Hݻh>F]<iO eQ 3WSg_i/[ߑ1+mWД}Qܲf;{Ke˿+E:(E|ɷK+vwA&_]1\I@:펧d5Eu*1 |5uE9xcƢC"a}Z3ջ f*y5v| L5li0GfU:/ᝧ4fzCؙ5|ςY10G2)/2-=IS}Ի{.e(@/E/}U)L|5<伋^7t%\wl}1,9D8u3~Q/x\Wu}ٵu f&et^sf&,}V@6?^Qg6pO?zOaJ54]tmE&sټ5d;ȞjUjoC/©򲧞=͛ϾtphaЖlak{ťewpj:r^ZDVZ&u`H41$,q2Y!ϾA-?xַ_S8΃n|%^~q+Tz 5W|vC^x3h$2  yi U(Hɑf?{~g֑-(8?90Ӫٖ# )㒾yyԡrxS}5a1=+&MfƸ;J[NP9p8O+2$kkҬ9[V~oۀ\:za崔=5Q֦j7qiFzaArJ7>$߽ÑtOf wJ~}[۬C2/7g袂oLy3/),Wzա ԬR:yECyVπY`/'whPyPEC:js&64sW,#JhRLKʸ, .7~E[=9۫j&![f]4ћ+5mx40d)pE e2=SqW01:ʾ-vEY;ᆸ8=Մꎍkkg?a :p7{m g_;lVR+&CuSgЂ#-g]~~F\09Sϛ{]c^p蜼}5z Pp ٗ[9Hg.)=ڜ R~E"S|O=))(99LP%I b1B# KQ@ENaB(085n1[30R#DDG"QJc(30AF71FԤ`( 0~F̊zC#f&3=QJc|󆝙D`(e2cF)@?m(>\_.10bJ0}A::1J)1J)1ߋfOtCp|I首tIm!f?`L JiD0JNZ5) BR֥Y]maƔ]" 'x׏䚘('2yf:aC`]>8w?{ E8zVV&;4WMNc_xC݊~=?:k]ZK ) !"n^O7BBBz?5)k =<)Exr+x\Ƕ%޷^sꏇ@㪏?6K,a!H[_~ 8Os5=JΗ<Vr NkQEw?φI̥3XҞYcM{j젷GԵ|hLV[ˊa Q[zeפnw~8`YX}/kVT\??CVe)gcd{! lkS׎!})ݵڃ]uJ&yvL1y+r֫vPOh{(}~wN,K]2i;7r>,fJ$I_e1yR~l"o)3s8[D3 9)[urI)֚rr*5c1Azz,5s(t?)%I)6}%%,"Op5AR4A}@Hc'XhDDp <4h + Df`}0;mgH!5jP獏8Dʈ} #RO؆* KOǩ`WH[,c)u?u΅.,&] ΓsxX{@ `씃Z=L!9R$mߡlUH#)ȗH@wMWl:ꏇb+ :і|>saKis 9ߣ5Е] ' nT'őʭdYnDŽ\X8ny KwfTCh z3[(4VRj1Fe;>֍X@#c?t¼^ʘIi(«č )uʡ!nΕ@ɋ s|dP4ˇL*A8)G s%Bc1B!0`Wx ԏv(%@Zp(^+t:\8z8,w A2]G)nAI~RAas#ll-γ71?o!vSe0U'4E_J([NiK f]{zw- H2tim9cGEyN+"ɡ**F]^KyVX=\5XX!gܙju_C8SDH*$%E4c&0Ս\ Ή'V?K'T1{h1YeCEG}x̬?Z|"zg+&CKNP;XlˆRpCW(쏃KԿsfL(pJԀk}:+PXX࿽P]Wp aH :d1׿3&&PCڹ2L { 0Ɩb+$"%X̗YU}/ێ MRqYm/R@ G"|9Ϛm2wTle%A^82 *|g´GZN&I'}y>oRcK}+TBTH7/*uE?w@R8}? L]錼팭+X禍j=$ RܔCg m $t6x厱y)rq"W%t!+5%:UMa4f0<Ps>%r=<;RFLj&eRGOfECk46ׁ;h]^O+v2^G?/ey<]' J*r򔥔5ό\V!Ul$ 3neȏ%?z1 OkHsY8zQXc0Hڴ7\JD<#!]?X@^׶EtE坯f?ܙpiEg@'mBУ82C0#13w6w@Gjk\V!`vVGZQNAj=mdqsYTSYPxIrdv6 @0hIj@Ķ! yC͛%s[=+X&\L1%Yp"B۟*kZ.7rd?֖: 4}gX s˟G,1eK^M݅.`ɏ Yc.?.[Ē ]d%#/̸4ͽW5:s: S䁺ٰ6G7gV'ѰvZ :y[.j, M:y*^N(Z0|QJEަU+xϡ97>ś%}!2d;㙾xKS2vq_h}GP7KF0,[c_5E+9g΋+r'^?S"F7<3Ӫ|~;Urن$U>VQpEDĹ`9^+wXk?vvt(8cu\VeŊ\/_Ȋ Yt(mrtd}=?"obW%2V oȨ/!/.K}_38c!QH~,r>ܹ྽->ᥛꓩ!uLÔJ0Gɨt%;c,;V,`&Lewry͘/}.Oɓoaܙ_ֱ_}3;*]͘~$oLœ37s,hAG~rrr"3=Z <<>asMhv K䐊0I9B_(Ul|^a QHdfrt _z>wbd$Q:( /c LPKߋx! VzN4wz,{ Ũv ;xFsΏioPd %  _ Gp)I ]ѽ-[\/IuYfPg7< fSHH~U[ EB܃J•>Q-ZpۣOF6p$,r2p!53x J K(| >My1;r_]Q﹤PkGLPB D bt[4o-cD#-z[I SHfӚ'#?л~XP e+xFTRegI ;Jx>RzN6{#JK)+-p^1ҡ9H]O㦑"FrE?ji3t~VTwx>SK!U=ǹ􆠽du`(^~SZjhŽDn a#FF 7CDJoĵ75`pf6-W?Mᔌ K4S6֘5UO-84e|a5?I]a#oYu%2ڳhzL; ΠM9gYVdLl.]׆gIe@cڷȼJ R?isp(^1WyX\Zk'ߌM;ٶr l?81^x "80/mA4Ŀs}a1%Gz\oKۗ'|ϒ~fܯA}O' 6LڴO'C68q &qt!6!|n2<ՊOl?[5XfkgrI~'c^Pm\c}ǘr ^{`0?C_X;<(.Z8z|o{"˾\#'\ٻU.Vh52[3U&VP:ilsZMחl: )ز/JLL%[LaB 3˭NVB.=DH/kLeIjҼdWSYi[Rgxk\e9%Toy\$mLQRjc% VU97_̐/#C, ֿԋW)vwy.}3U[*@.}̿dw:V0~0c\Ts;LAj4MbN)~^:0yk葀;ZWɦ; },r|{tE\s2EnKνm{c+uEtH=,Sjt|=EpJrNE_a;(`ZV=9IkDǧa c/5F?*4uBVg'NghY <:R mH~ { `ՑgŸrq+<nhՖK=epe.nyɰCөFX]u{'N"D{匂Va$:YG>@i.wԒnA۝6w0|{99TI# Ryf.@q:=Y,/RF"%R [dku-rZ$MCתBUA"~+ou=eRdxCp2T/bJA9?Ρgp AE|7˓,.Dk1iEQA |IeDs6HӫlsI$|)}6;pO:v?+i{58/vV0|s&9n^}6;߷pcLJ-vQ\հ r.WrbJsmx֝4[}t0&UC^3.yE4ҩlITh SfD:$(:+tiH+*y(Cy*3''FҤP$V4̎w PyT?Q"b'4u=8tLò:7Gx&;@v99K`eĥW`|6" 8Fk9I2vX U!G\(rKԢ Yѷ z\w9l!'7l7֐Og߻cC-M*mENF z j /Dwt"X\lf"j^z2"]V#?沱p_qE4 `Oh ,[ׯ~I 岩TD T8STYi%B߆k]SZywG4Fww==箹P=ZV+yo/n.}g+evXVYUOֽX=ʤ*]4fζy?[us9ȍ:}}Y3 iTOV!򒳊ɐ{g4y8`-%?UXT}.ì h|sG5Ͳ[ WpLFG{ƨv;|5EϏ *%ЄXjP"Ta2{x;jx7[hlEtLѢ˙$OaaJV5Zu;y-8?A3I2tJҹE vq_ʕ8x{oYsXu;~e;SX+ѸZ\BYЫM_ސW E-4B~3'n`ߪ'.i?'&OW@9 E20*+(]+XytiD֣Cl+'0qGhucSh#!TΨŵwp=YRNBA=ۗ>LZOy4>}Powo+q͈Y{*_"S8VϦld~:>2w{VXrC z2lAaBGδRYs[/xcl;neԵ߀yVbjK#kg'g`(G_^>[}CdlcF?c{ejnLAy9o ~\WVώ†Jge:gPD"iz_*^k8[`'KYβIے@ U"Vͳ{|B$Hk L{,(Z%" \S]s5))eI8HR8ZҢRH&;)BdF qbXz 0! G1L{DQg; S&m4nNF[PNy;P_;Vbk 8zu_ ^ru{W.pAw9׸jҷ~3"͠9r>޾3/Z~d遅L_[( ,5@$eubUܕ9xIQ=_;s2/o'ZP#3~@Sd-Uq.bUsܕ9]}^yTu*n&g@^(v)!;;+YuV4As/658:?'gӈ:hAr}>-nlM%4 v%GqL*fX~rH*]s|-%Bc%=7͎+m4gO';YQͅi~rkx*ͧ~Oov؇ 8D6U3^,vTE6/Mi>V>ٴ{#g%+qr6}ҿȶHot1OlFsg\3үM(ܡYx^c2'(Xusw1| J]T9^3RODF 2+tHH mYr2.b8-N̚ lH,+ #|sX4^w#MwOdِtϲ-s.mpiX3XߘTu Z^wFt ;yJfّRgb`A(z`T@pu灕϶ mR-ӷ2\Kk.iKsSN|Wg#|>'F&ꏭ֗K+ާrJX 9i鲏?$nិ>r ENPzyXw<Ôsx_&)ݻ}L͜º^WY=oWx flO.OZ'`-ѻÅ"jYm,2mö$CIoNRu7tt^W[_Gsw1閵3{\V5).Y9^~˷7'62G:+{fF !hbg n>3w5}0"~K)T+N@6‡>`r;j,fBY+grѝSjAYǚm\Q|s̶7/7Ӯz>vzͳ91ڬzn גod-)u/N")8yDop+#"J'FsW3bcy0._Y+ a$E+a t`/4͘Į"-x4z첂l/'Tö`^q,Fv,q]ĩ~Z ZQ]|UX#%NÒ)T]X2#T[9]'ڊuNЮ/4UAٰMŃ%/іhvo?Si=Ť_8F5*C.FVdRT;eAIq`uKEfw3bp];/;v: YՅ1Z5H"oeB\JAt!u@ 6Y@jjeIDS.f) oХdn=3?qfH,vHݟ^cʶVKk[lYC7*YSvࡩl43ݸmgƳ<ǩXa6E,iAFc: Ao }f)kV?նm@N!W MT@ɮ^a (XȶAfuEs zuN),<T=~#bNi1ؙpm5vN%җOcZlr"B&9s EJaV.)+XNy%gM]%@5U%cS\tj_!pN)wBPV˯E&7_}# AHJiԤ MOFMiִ>UV+ԝtlw>g7?\:GH;ߚoөHF]'YJ-t#MҶVU1ỵ֟R+N\]u=g\iXk"5`tQܷi׋6jРUO8=[Su)ԭӈ3.#/ٙRaRM;ʅ%Wdl| iҼ& J:yj湾8~uj҂Nti T=99[0QF>%4:uzf/qO[o ]إkfM۔Iݙ@՝FMhzJ]*ĨVns\|U9sG$D=n|-TnB㦜zjS5AV<&ޗ|33 zI+&OmƩ O$MdRqSNmV߱:m'Oh2z?|aIG5zqiuipjw5Uvxr5˨I|^g)xt&oFF4G7[&bi>ߝW;0aJ%fىkY;fwNUIͣ0)n2^/CUfgP&4kք'W#MiwAMfł`[X2W1_4ԮLo3wl^=(ǫ-2/[]ܝ'ҶO.kZM[s˃Q0%;m{z%;5+ny ƍo0}&l}nf|ןKNYt~ScE,bxf <}=֋O N9?M`=#YW-x _=[S{Vz$Fr_??t!,!2yogOxDa+|z3|ۍu ::X vlߖ|1 ey7+{/o7Pvʬfx=Qn:Nwr#O"_fPOc@{mwYX3i}7l7a>S>K~?0}=Rv/gf4_s]~;Ll'0Kk½Gsk 8>'ԛvki <)3[7;=*\:NknIK }0<13Jt'C߻Sύ/-T/r_9ͽx>&BD)[>Ƅs0ِ)֙Dx83+JXŇ͈͠^x7)v j}ЅBl(+dypx.үYJ}~7~|;s} Y={[VHe漌?>y cکO(U*Jiuض2V%t1 cΟZ"9^Bկ3gGkƼ"ukMØH u &㧣&\t{6~8i+ 8!vD`5)%of#qZ]s=ÙA9O}ڀ 2v2

qJN[y_KB !`TO#D/D'wBv-*DZԳ.S%GWk '\sS _[uTW }&{nKK@ԋKt_WV) t&#d^tr̈́BDD93HF `jxSa+ae 38vƖ A&` Jf6fcqMfs淫VX,|q%u[Ta{vZ1.O:xh*쳘BA5܃_mnK}'L᝹oouaYuD3Iwk߲|5r|&2;LDi~>_aC[:ςh gqJ|6[ \W~,IW\Uo'--A8R\\ *:z\8YuD+. 1{haǐIO@lD oE__'cF:nFHԠOY ^2]hST%i<^qlOO@|a¨ An%7cS3H*tE!I'AЈҫ8 ?֍@,'ݓ3mPGS0"|Ai#PЉ 㞚 DRIQp[!}'% WUQ]~*M@T^7.y XWۍ{Q$YM=|9CΒ\\tӮʫ[d6_XA'aAL;gs-}4ZQVn|5Ϫ#GhP^ǰ)ƸxZ c٨坤ӊPS 1 d.iB\XJHO& G h2 Co+)FWѾ+t :*R/*iHS̾5Q*@Q91ƹ+H}K]>|BAR*I!ѤP[[DЏr *IDAT4K7vv yZu-5V)WkA82Y._Yi DoW^GYq78ΧɤOh5㩿O\"r\߹fHMߋHC9;y&s&. ؎cD! ,"" 蝙r,RLaQ*US+TMDe$Q`7HDu Ґ̴vDeaaF\>AV-r ڱQg/,hVAC'#BsIKnⶫBGđ˫T .سT+jkU!rb#A98rxN9F^G>-DaV66ˤ+T9OUM,dCfGz]ssZTŊ^|J+k@޸3%l@NuT,BZ\ǶC+m'ML2SA_U@*@@z jDC"BN&3 Pf'm|J߻'o$"K%5KLk`,ADG* ԍp ȫ̳G3,9ېcGa ;0ܱIs_cC ޘz $n\Nu=v߯p5ZI5I$TA_HWNWFһ4j4K#ԦJ,+yfD/Q-ovG&$¯t^Rdqe5Cп-J'G'8ABqtDԸ7;,m}ɐtEPF ,:2Vϱb2m_~Nb?~3{zYaNcde\VVΑ#`֥5QfGyo2$t B Q>R pD28}C k|gML]jhC< 0˯DMu^"bױ 3&6US "!~u)sDD"" " r\"UN&^"8EO% e*a_{owñ }(/BBJӣ$WQ ͮQ*@[R0"$# `#gGIe榯A-Ҝ4mK%, Ie{Ľxj1O^i엹Vu%0Y iz`jBFeUvDGUiRDW_Rfad ڮ~|n _-.~DAIK“*n2|R?$ m0P(- RȤ~qWPSDw@4V2AR- "|^@i2@(ח0911o9W$ٙD"T ,du! %ŋd?Ҷ JI8{P[B"l{rAS3S ͊eq [ Q,mmݛUݳcboY10sF#I610LMM !D 0 { =tV]u]Eu]Eo DR(:T*j`pba =b!BYD9߯[m˷1445Kc/_R(./p0Œox1SeYl YD mmmebbb-+{^%.\weVY,pͣ:;;ED ~T `0JJJzzzBbXT^^bwh?Gx@ g/KX[[[_7s.*r52|X`W]]kNYX/$(OR-[zzz @ @mڴI__?$$!z75uRi,*siww7kkG6j;>^p$i'i N%DH$J}Gɪ]ð Ppp;wPNN:<-B%-#!+;9yz) F ^ͪ!9!Ef25ʝeSycyT7:;;]\\@oCD"reN `h'YX[c@?cqۣ3)ip;kk՚`G'CAK|\B^.y-(Cvz siyYE1FY@яge{!7x󼒛ee5JZM#4c6=W&&L2dm3% o;0L"d2܂ 55$X^BRܼ^8h0MVt|4B(rKA'Uq땚ZBZndl4$d*cܸqn"+ll?aB!?tR WΘia4^&9 !yi:eW4:B} @þ)֓ ŢBh䨈hPբ92|O.*)U'>zN|J; AU!2*f,+;Yn:--- qU/+)?٫ԻG@H@ Uxzeo- SvsrD*:Jn.|L&Ddey2>d|m&&L m)Bbx$aryqY6@=| qԴl{`'{]]ahd.kqkǎ>{e5.ٳjIA|Kh?qrU+e =; ŢFIX{N.ȇ2)(;j"+ MWlzʗ @F"vK#uu:'@}] BT[:>Վ_(}lMM:BQx0>1g=1唇lYy~ε5uHqx0b>km->PW[/+Jj'X_>ǭ!q>M&|&D m6xQ(7RO$BwmE[~z  ‰ᖘ#wn11aD|r.&4bIJM^BV9"{eM_" +K=ڠp8!ؾul ~mC,gwYJ--|;Gjdh\=)5O"Y5(ֆFm BEOajp&G;g2oxh*oxFoKMXGm I2U,WV)^0熆.8BU {i>|"?y3}ip)ml,tpPȭDyg]LMK6e]DEz426`Lvnç@Ygɢ=;TYX jkkݐkWܹswhPXa}ޘw,,!T\V`>8/..]S]]݄e۠I͐{_lBfjf:fB1Ҹq۲5$oYΫ$~XKOܻ{?Ow 5hL&S\^8|ߞȽ>K p SQ˫Jbjʍ{$[6*2Ojjj_/R)m*" YG2޾yK e~۷4 z}kkIUMuĖostTe <%pIP(,D^9 !t:9~D"tMM<na1~".^>믿0Z( qp0~7o47|̬w-mDb[{f_K7>|ipAU^׋. `LZ[%%$쪌g->#g?q9"Y魣9>ցկfMU9+k d{XO.zaEy%hH;:^!vhij}HGGT:*Z ߻4}ueE[1兽"|v\Gf?yJk@Qy Myȯno\R\ Ei`d_yQw=jk<. rpU+hQaǘD]]._$$Ł*)*͊e.D"?ڱ'<4FpԔK&xcy Iq{)@8:::gokTˮe.(5-#υD6zw@=d dP]Oάo rm0 KqF]af@\fcP+JM>P!oWT\;r(GG ݮw\.gNS,Jx<ӑ7?zrTՔɊ%! !d Qg!nW4Վ#D LࢥU]WziIrTZQԷZ"I\f*:qRjlW(Hᇵ Abf־0ϜD"q]{v/<{79oW.;7HH.ÆeXrp XbccM$>yRVZ.8T%>Y,O^/=ve5.ٳjIA|KCV/[&%tIENDB`glances-2.11.1/docs/_static/load.png000066400000000000000000000154131315472316100172220ustar00rootroot00000000000000PNG  IHDR{L_=sBITOtEXtSoftwareShutterc IDATx]w|?g[ʦ@:$ )T|>߳<i{""hI!${Hlcn <;=sl?.\kT ] 6HOwkzQ xNrҤưVZeqsPt\kz,<&b814d_T+_!kl~QZqiɹ ~<_MzN٘|$6e}G%%%?b#zLIIqIIqIac{>LNOUWQ6>f˰Ebu+^oc0KPi[qÆsI`+@wo]"[v{B n!RD Η˭XhvG͟CE?<=qKIW;nW_O?1^q8~v_Oۿ&>H@3CkL nCmB_z9NƪK߭^ntɫ ^Vm|ҥҰ W޷M8aΆs`)zwG]S|s;ou|od-_ᰡC~u CgBetª/ ?J,¸2%Z ui@)jG3<;Gpl[`)+W&W]6jL>}3(?¡GҴHq/(}xN~ĵ/uRZ%(f?+ =x~[삜'mMi13 vúȡʵb3L.{b>~X1On>a{ t+2"Pݕ/O}i]*߈eԵQ]~Ǿ +6EiZA| H&Ghއ\`k"Nu]&]_K 72/5W C"c&$qlY`]Bμ4l'Dڥ$2x3Ƨb6U_r!yR(7摵_j{On,="6rO;]CStЭy[piƶg%v@!@4~;!) |Vp!Dg6CXGAC̚?{Dt kʛ`Έ@(KiLi@ٟ$ nҖ>RA=;9{YڡCTvث?:6jQ:EQ2~՚1|;9v(FQګ&݄7gorr ~ܤqĴ0݇K4Uաן{v~g`-s[ >kCy13N1! }Fڶȸ;ɲ7 [C~J)6o(Vw"~Rע'/(oޡ^z-ǵ8K:`/sSʃ![2 edVb} < H=ڗ1atNčj+#9TnjFac O6hʊAsg܁ÿw໑QO(^-;<^4H[Ɔޭ:d0AoGs15{9İ d#s  ?3˞Oi FGu8 9',ږXhDt pԀzı-bC TFe+ESY]3 g}b&o\E~0`$H%Y+rܱ*|DL57bu;6E9.qkΝċ5fg@0g;h7+'fV8 Fg6$"ܑĻhVsvIX'Gi qFĚYɋm;>Ku:I.΍_pMȯN?,~;!Ӑ KA]I# ;v'BCϥjaL߱so0dL:|C A5I/ܩBQ^W }=[&Cu=gb\";XWG1BqPuU2[qՏ-2X v"[&)<쏗|F0?~PcΣ+z/=/yjMlww<~v-u[ k/n~-24d]3R&GO 2z)q{s%@787 ӣr.&jU*Aa҅VMVl\H_~tLYg/UԊV%q2o.:{|˒fǩH=1qti⴯΄č.yvXǿ"`@l C^bVbF1" Qr.'UbaauV_ϋD@}I_L5iY LXFBڈ,զRE eNB}M(;kʒISwQ53׮OէE;l@Zr%Urn4ɕ`Qѡ%H,FxPóP]O#(F`$ T+׋#)[/y*sLD&+ 6TNlxCuiB{QX>yɞNҜ#UJ iФlauA({$(P"Bb]Xk`P)v`]-W(t`ۼ I&Bʣrjmʌ5'D>̚ dD-8Δl2n{.X&y r3{noyU7R4-QYzyD uծGIj\NlEg$ w]^]+~\և>M/|pױ5z yԃ'+\id+óA  -M%Q n= ѧ&}c+ :Dnq˂X)7hQPxx l !z{;Gp4aw9dW"˃;P.DEXHFyr*#䐼9Ȓs3y@=&KWO\~c a#9qhtRx*_xWRekEB%#[-бOE 'BgRq^%qɐ[p"S&(5edО@ɖkbb5HHEE=2tA&vިQl*ܟmRd_V(bY~E_yLdq6OH@cC\y  hqHX(lPxӟ{r}XC surJI.Д4g}5S ds.Y|X h-ϭ[tȶoQx ="cwb\>uͫNu3r qk2V_^2:N,dJ{(^8y ۳ҍ9;s[iiv;#H/KmO|QC:Kd MR?S`NXikpۻO=M2떑os~+>[Qu6de>;y%™]˦w:)eJ黫{L[fggB=зG t|JM4c΢qNZY҇s:ZgMQe\K1 !n'ztT~KU7i){~uy}].$"yKNoX1ﳦS\.0Ul0^zА&+lytlRfG׉:by3O0cs>MCzY_qv?W\. d@p̃;2oo-;y=>wHΠW8 r+JVT*̲?9.pW#uiٹے,#ʛ̚&1Նf.\gul@*nԉo4o"гXNp dnDь9)BC6Ě~2YA-B/ Yn6w3_in ǖ#&˱⸅I*.T2Y.CvBKVHhTuoFMJ”=Σޝw25f=BE1y^bF o7旞1! l rvʖV#_@ў5ŏr*s>%Դ9cW[%.Ҍ#X7’ tfqgJ65vkO5ȵnӶALa_ޭ'F 5% :iV e2C$N#qyogpeGB[43_lTtO%ʑ[Cdl΂$kdՙw&nV9˳xJ#S3v}cl^rBàkh}nf Jo_:+z&:fE\[)I"|j﨩P%lBB>m^oԸ::`E䤚-'_:_i6 K*B#qSB. 0C*xD,PD fXlE%:SXۃ \ Qdl,u2'9bJ  n^w-xN׉UNDAԁuQN1tvގy3@PIѿaX5IqYY!S@-GˑC2%A'bs@qF;F+v$eby eȚMVec "q"&s prO!*}IENDB`glances-2.11.1/docs/_static/logs.png000066400000000000000000000603501315472316100172470ustar00rootroot00000000000000PNG  IHDRV7sBITOtEXtSoftwareShutterc IDATx]w\ӟ{WRX&Q&XcA5hѠ&j=$vEl(v:wrg?wpИ77| <7ζٙA6 B?ic@_׾AhPRP[VR10`mtbkeF!PKhd(5^'V. 7PuOuzF3`\WKir*P#no0. WoS}5_g Po"*o30hg @j( *٩xk.V͟ՙЎ05bZ_|ckXEA;H_Ywg r]O6 sq}÷['L2Z*&*Ww| }MupMR1#0`5Xjkj?rd(X'Q@wdܴ6W 0B 0016x%X,sa3Õ/˵ߩPsg3@HU~s΀ u`Wq3]3N U!Cvq3}uGqc 4rMWNiҸ&^YT{H^IU߃l"Pu[ 0` `;MǕe@4H^O|:#0Sͥwãuv 0`@#n ѱttܮw#N[LcY;VAƐC5s]LG2`+iUsTT#j08>ACVw?W0B 0З0:N':Y+%{6`Dk%6Ml!p**ڰ 0σ 8Fz*OuҐagd@4^Fz-=7*5C!p8lL'Aûr2_eIwP` Le(Up4UQ+y*` $3B,[)zH_vzaT _|h.Ȳ\;ڏNW1xO#U?4 j':uC,=燅u\D{ pe_&A_P**2ʝОz T\{R NҚ+ W>7X%G*FO I>=}SINrjahcSb=1oDbQQz±C|ycߣϕ}z+ {ǚho84t q n .n: UWcckwݩ;E䧏UIdԩ}0sdokwW<.ymnВ΃?O1%uꗿ KۏZ9g$=Z41so\.U;ϋ77r`C_0Wy|[$uk @|/`R̙iEyooޖIYJ~?s٤S}H~o|¢?VvgX)O,ZǮӦT E% |rb{;y RNQi;:q9<.DZ)EBQ+B9κ6m7(u<๷(-nb0r$I$]񔢨k;ؒuE5$ ^תz $A$ׂV5?KUzcV%I$) y Etң*M-+jyyXl\4 jE$I$?d3cGcvP ItܜBQ%:MC5׾(΢v I?(Q.l[=_&[( 1^X{L(*1*O8TƏY{ka2JZޔyh1?A>s\Kc6Sž5mph=iϣ䤇 W6V.h/_PX)Wj d -H. #}'<dz/(,bj,` ߾¨^-u fڥ*Wqg<="P}U+Q;:fi{/v'٩/waf},o1x) $@LWmz֥*{D֭fƴycch{j ~'{kqmTŬ khgr0 hNמ+.ֈim8*Ś곺Is^B{v~/\;,iRГƧA}-oߧzuqzL+,A*f}oOaO6Pk-iؼ0#}fNqBȿ ؑn<:,q.q? wEJCF~ں3~֫1xDm_BPw.䔛qLɲk1qX B:4 S//#\fd_%( rh.y$~ʣJS[͟U21FHWgőx<&Ӝ?Jnm]wpW燎 ?oo]:@grk֏31ݬ ?Ptt E];ȷC[|yۘشn7}F\0pM9[MRV_1>^rO&GZ0@ (=(`i{8XjM2_;bLZ }|VjҶl[JL=Tǯs[_QWN̤:unMWgeΕ|0Uϻ"LWn"aZҿø?snʍҷ`^{Jߝ6ҏe%Zwn'}:9.شЂ2T E:/:OQTۋ;~{&p~ߑk3UٿuW]jpr9<?+6z! -յUNo$ scEQُ/3_dݶm%H`d\U_~A@bFZG97 :|[Mic2)=:a^&,(wg?Nx;/&{msؼ$!#07q9\6}j(q =BWBgyUՋUؿNFlq+fw6S~)ƪn| F_g vxlM'p5^hPYiwH!X!.u 0`F%៨xU!Zrz]HUc!t 0`.!dz)ިz )bC]O$k3"\m@j1 U~ǀ RSB ՛I5;2jɍ^/ E6"$I BX:a,'qtCGaGB5bM-n^/ŀ3߷" 9[sg VEn#%)lԱ=(jl̾\ @?!$Ö:<;L.ю9V͈B>OWwsi*)MS k-TįTai^,V㿌 &@Vѝo eY4YdxH-upҳֿ˛I9[F.|VEn;S-A<.?QSqwxR~;hzOϤ@8>etPg.H ~^~͎,Σ .|ǰ$#&+ +\>rV)6\tvEBKXI%-K/+X<N\EyވBXIaּ90^CZM%@ˤ.Wʁ7ùXɍ۝n^'tHI)Y^*N8[igх @z [=%;n9/2~.l yqS3ǭYFᾩLsufD]Ws_,kiH1Sr]q0ۭe7 ᑟOZ!ҭe'ӡcL[P@8)7O< 1^-εA^ۣ!R?YnL(;!*7=kesdPߵ@(˖1hzYvjS9"&#G9Ԧi7&Z5&O՞'\L/].u/)P U+SY3X\qڻnj3fF]ɫ^^i?,xS?J_J7cK2]b@K0˝D◚ͯP./G?7IW_~d?B ^Ve˕Z .b2UF$ۛc#:9X!zDu)곿0pI{ȦY ˒?n͝&zgW_}'U]??ŗO _X?u#}\W/zU{! l: ë’O䐽L]JᲧ<y{$2kr70a^Cuϩ5y >Sl.=Xr6Q(gDw~P"AZjLcVPy!z_Wt^$HQģ4xdmcM!x|(ڽŞo_?|. luӡt!vֲҭ'r755 =5M?(&QƑ3 i(x!}x?GLto^xuB& o`wz9ˡۚRN&zw`7wy+_ &d/3o};8粕F,9/f,P%Y@pٛ[=ezjnkP^^8P";n9 =`qY$kKKfbz]97^g$R~_Kܝ"^+Oiv$kGfWpnڹڦI9 k;u - E؝NEwcG}6͡i!*ucH#z>A3rY.IyhZY $i XBiBS5wPC@||f=5["Y' VJS'mܚjBK):9s;f>,loNo[59Kw?\y>'Ťgi>Tί1cnٍӝMvbc4۽ҏȺYϖR~Rw5r]+te{wRrS1ʋ bv,h/+߁BZvsG}&)=v 6.!AAr޾\EPۻU+c. `11T4:s:~&{V| #Z:Dedu4qZe?s=7+D\t`kq>%< PVE]}k{Rvˤ3R wy|,,Xu jl6(}$A^kG];s#d4YpD27f>#=N->z྘_5$vn]n8TG}˾M1vx%4 q i>v^ι'R4f+$%@U]NNxO{4{"Y2+6%Ƶ^M_ڭ,,w_%FyhYyv)nj9[[nf 3e|{,M^Z)NwڏlZ7}nD / @'(!VwmbsZ16BGut|!9vÊdж'+fL_,|H.2n`YqD/I˳Jkeye*/ IDAT*Y8l}C'Tp_I󓋔&锛V{zgR%\j6*fv*wDEr̪~!QgiߒƩhR!%TU{.z,)(U]fcdCja_?>9?}1.l^/ߓgbotĹV,os§ت"@3-?ni.F,yypǵK^]R6{?nTzwj9y^3I#uu5d4/[ضh20В ,,J܁bp[5oӮ Fkm_Y HrDz1+ EJQZb}U@;[r@<)E<d!MfR[?IOo"fő*GR>"P䊡+Is_N. V;z%}wN+sGEWU׊PňufjV\W曒?/ZCE%& ݐW)˗ U"2ɱ)VM%GJ$Gny=>pr^K>ϓE8NӦu)U sz/4'Pi,-E2n$@wVԥ¼&cn|g뒵er^oM'xldh˞4On-,f%~1/8_@:4@~؏lܑ&5r]s_\BY?磼}TTET"^`'2Q !ȏ_(j.W<ٶp>Wu+ϿnLa@Vfjʩ|] kL& @8faL4qn*{ZXL ڪ !b8ﰆ;*p},-oOԯZSm J "ݗ7];ҧJ@l>wvB495WEQJ2$tYv׃RN/,5:9KcW|%Ouo6st^jamAtEPP]m,k*$H 珤OAldf ]<6_yS_o?7;cRe1GιWn L_s5Jm7ƞZ6ie!Pd}9˱=CzsZLriiF\owpEP P+Q`8';_Tk-1@.v9IEYqs^ϒ#dbO>j~ԙ=2.6A4[a=B7:OɟR[Ṫzڲס iR+o&{-aʾZLvxsYV ||}}|<|ϡz<$16FlZbhv!aivP¤GyV izNO4+$3yNΖ|%(d{ȈA, /* DZTT;pjG ȋ_^1 lyGU={] Yr*ۨ4V<:<<ݦԜ\1},؆)E 9暩K/ )<` 4#rH~|v瀼_M1 ]r-O 57$woŤU,Au7vg @%o>=}g 4S`'rӪN/O)n"@YKI_=Z;d\yXn:Ey;n蜊 6KwmsXE2Il屲<=ĂۘC@<ңcC6)X~Y\>nk]^aVX>/hҽ,yk1:[s篑ꔿڿOG}j(N(~{蝟JJs^<6o6o_^sU9xs"j_ {$D *%.}?fsz1]^6^%1OPM~0P:a,0` Y,T** i2}]az2y]vxqPX'պƪKfX/.~w*B4㑾לbX$I$$I$4b,HUCA I:dV¯sDKo;׺a]zCd4AlG<IJ;ily!J¢kxeSSze v,Rm-0 ZIc] dzKvg*::_owLEU՗?4cd$dHʾ_?R&09q^#_Lo3ʯ Efud_|]3Ck 8ֲ7}S ᑟO_DG-ːo􈲓1s}-ZzL(q˓oH 1Ҿʵu{ϻC\#utn p﫡CPޠSer D,\B ;䋩KqΜ]R‚[rxbjXy`ҭ= '\L/]Ŭ>T( ©ˬ,.8R cR0ٞJa9xt9_e-9e|B+__tX߽(6nbKq?t oa#EqZ1u&ҼvCw ܆훠2 ܏H %&?h,ػG7qizuĒg1K-&/Gĭ\RSMy {|r?G=][5%wg+\O"sYrHOy_<& o`wz9ˡۚRN&zw`7wyˤ~Oiv$kGL,_qh⽼6w F(K.TjrIRtHR.^PXU6]gϩC'jfگZUI>Eʾ a}oyÚ^^޲kKo۽gLYy˪~aqyRT(Q+'mݵ~&Oʜ۵"xJ=MԴD~No3hr?o!@ۿUc|}O 3ܱwg~TǐF{*/\\ZieۻJ3 etk2wRVDoH^f,ֽ򀮺!sk. ~Є5<5ҸԀq>c;w uq> &ȍ==۷5sW7MЩHn^)er!f=[KIu90=h dz/3#ymIVUstS7}TrZK7~E==snĔlµxT&:庾lD>ɧ" ,%U8/MGY 53RܭoeaqAEe% {7jEtw#+)=Wۏۤzo]Ҏۈw-o|"(wt._<  @=51j}֍_~)f>|_d/+߁o4FɆiH㴸V:xzdl{E"k#ע[׋\(X@8l VZQqCn`nj[+o\oҷUmW [7 E Cc8֗4"q{qy{#snXF<"Zfg'\}kj8˜ś4Q LIW=跿i:!sOQB=:/ڵbM T $]UتmT&H5޾\qGeV. xeZRr c0ܛ/Jhr>Df. Xڃ0 S6~̅]GB^ʳJkeye*3Y856";kp8 [|`kL:F21X{7*?2nO'ϮߺJsX߸O۩wM"@G)}O.[H=k/w\۸u%5ˌu:_Gh/z։LkbۊXu*XBE_p:ARR]rdձ7ǫe#F~5A|Omz ԳoJJ QE O Hs_Vq,曅< |Tr3\HOɂkt$?ዧxiBŚPGٵؑ_u+@ﻛvZѿ?Le45藥 1Xy':,$W +4:*Y`$O^kƛqC|z 朒g"V-xEJ`6 o@zGnTWq8[+9Y)f+ 80?#q˜j7P*Wr͆BY$A2a0S5Ekw%;@V>_7]Nt ޵{›;Rb/.+5`t;[},,|mr}n.і=iJ[X׫X_b^qtho OeuFYg>(6* [Gy{~}TP|]kNȁt?L/3Cm qU}E=nշ*jJ.T"^`gS*Xǹ#iR}PVڲ!b8p;*\ uGǥ#*}Z4b,=k Mӈ԰T*#8WMىYr ŏu{1VzEf6T(H[g+K-TJ|ImL9rĥx+(Uup[Oe6l+SOts`X^&|Ѷ aX-ΕzQ)uv0Q'uwQ8{͙+7:ҩiԶ}oʏY^.0p,2/y((S(-m\uf3n7:+~I|awCܰ^>~KWM||@`y%]?hB~>\ \gl^! tιz=S1:z4liF\{o__w[6BaP%D9ZN/ژYjM_ mASfJtSm Ta=B7:OɟR[N޾> =mوÆ4)7Nye_Q9&\]>>ގ\`rC yC' ri;xL;I2[Pd IDAT>(R ERh,J+11W.j؃% /0w=4׻[g1́*^o'HjˠmkCKR~5ۺ۷>S}g>LbUg`~3-iCGɿ|QU˫BW^U" *fa8aG񼠙[FVWO][wK?,VvY}hW?$Jutد}]@@Q;:IYJPyYvjS9"&#G&f[f?N+P8s1tA61۳$Uh~Javy%===:>:vΗDYK=atWv%/%~ɒ~puo6 [v! 5qɴ{#,z!-yd)"hqDܪ%eY̒| |U۟W}Jsorʀp?gl#T=eT9ߵ#Z}*KZ0gobҤ[ZP" 2w^V;8naEU)J8kBRi+l?u#$_ l8dϽ_d|جiKu|Q$~WL\(A~E8u5c_J{̘=cv^jԕ<;.SkU*}jti`ۨ!NҲs K<ΒC޳]w>s8E<e;1ll'Gb1Yڵh^]zx_|Q{NwУ9\,HOɆLMG'^yU{"9GJʛClmP.C2"=߾P<]nyPCB%{r0.64(to^x64&*L96XH+ͣcL76{Hٵw< K Y] r!hInz*m%r3R(䦧XXS4k>\{Uԣ}7^O{s4yXxkDe>˩Xlr2ѻ{{$s[&kâ?r,XTFԁt'M*TR? ]j7hޣKYd-x/Ƶ/+ f _u4 ):Ӱy;gQ~^XytR`Js@^J7 ax ]{{mLF$/y3:ԭ.뎌v Gx^]q.ʾwr!{/DHY|lNjW. lVg}^'yefNHSJj+*y]h'{c,<'z 99\M7N8k-uH >/ǭG:<<#kt!~ԕ b|7pNn?\W8)nz&@ӬCQjX^ڪ}GhC%;!~Ϡw'z?NRIiCг<ﺄpZ{[a2 yAI13r0=Z)LHNM[/$;&7L˜# ;qZr@") ol Zv[^vӎ3U$c2,!={?;e/;7cSIӜau']Ӿ =P}Y˄Ҵ+tǖ2~֕ՂG;m9Cx ֚j_m\(9Km5ﲼcz %54sǬIeES' x]Yvӫ;qhWO6bu>:݉ꪫ'oקk>q"xBrVOV瑎.?O7ޟ4iaR]1OngSkO_Lҹ6=i^lJ>m(/k VmƎ1cؒO,z91I.=V]iKFsN}: 3Oȴ'uFkRTU\mM{;iiF1`m$ku*e]uVN9R 9w'“Xq>?(%m^wP]{I1U[׵͵Z-ݾP\%R2 i¾& rіeJZ'Ȃ.g'{u{[ՕH6dQquZ G/R>:U7NeWko.=s.~WPy.Gvekpdm WYk|YC\xTd y;%MY]ohU2%ۧ3MZKy䩲Xuݔѧn*nn.%!0is$hrC-l{UwnHڨRTWtgsdhZ^SWUu:^<yc=n|Y ]o3 /Z7(PviWQc1yb.V2^<5yr+SnKT;q^m}utpA5 k/"d8+ EnI/GlaX'7kmX Y9*` #; jnϨk}4_f@mE̖[s&TbSxrR`(88UR 7זU/[x-kb~(/6ųY5|Wx| g"#7*ڻ8kY،3EC'33yرqBOH'@'Pj9n"NKGp* ?.,z}\9er0Nvnvޑ'6f'( }_ؕ]xC=Grc;t JLz{h{ٝ|w!HC:_6^\V5SlÝɐj yݱ$O.cu/_o?}7P]Afڦ 4)9!%׏~y X^3j#D ]%s`B>YOsCAÇ+3h]{w#0o?.~nیGǦ '!- O_+ܹ)Dztv[+&AXy,8ac㌩o-J^9c9M+ "ȗ$VPXU\h־_k_ <?~񆾋]*#wߞ~3(JܡI68Δ8veU:Ҿnwr";7,R颇nVw3tQuzi:Xm׾XEo(=h/j\ź<=cݏmuh|x𳯚fN~T{5 K{MTԗ~@;=i+zzGj%_9╆.nȘ7x؈L=k{oX.u)iw楌₪៻SN<Y!cLX_̞a6`,RL h3SwA JJy*:nКnc\BcYJlo-K5jͼմUnˋqYkAԪCs:INWڃSMDUᛘڪQ׊ 4es-de*#A2k+Ȍ|q^mP;h&ח3{ʞp| ,2"έyW`m MbJYGܦtHO%_3D5L\Tu 4­C)^ ][ޛa} 4QSU3q9ZT8#4QcIj`N_tevUYLD'Rtilc]Fp_@fD.N:v iP:`&ן3gي͆O5{7Ϋaө o֕6Z,bW/]kKQⲗ\| V҆M:y1*GPvĝӬ(X XMSbT5}'麳\ Osyɏ߀Y牙v5)Zj,Ք0>wD&'$EӅZnћ*WL m]Bn\6"<'\ Pc4pcrSqDw=}&.b5R JrJEx%gLc~Vx~z#i o]_l?p2L\CT'_fVcP=t61p J ?4ZVQIH0p83*ۿo =.~(WT4֖c2g3pрb'D ֟jB64u5pG"ϝnBq{M:=QmqvWSRs̯/-`k?c}B^U<(+(0}bᇭdD\ #2ۭ:~ɧw J\U<^&}](^m ##⿬CT~ -.}}{n ;xWюWb~4j4&x}'2ҹآoO#dd6X~Ju .a;CqC #)ǖHWREYa9Ί%΂Wg [^&%UĘtsn/=zL#N3Ƹ4ayńF^Zzfq^Б붻nI2|PLߝ'rkub\Pݸ|ӚGYҌͱwT븟ŠW<0z/s?1]N0Au?V87zʶs/oJ,Kڤ *sG^;EC;ظ"P0pN)$ pq̮9+ 78ЙU)Ǖ"m#j?H\a[}3sy)6 Ř='n|RB;59%rEz:ں׭ceuΡ7k#L}ϣ* J|N:.+i#&O:]8>~Z!{hc*@sDlvj߭qyF}Lǿ76rкJ.=1sf[miیōߥ\6Qր1ڄs1 L8SxP 믮-*;4X|ɺlb?n4tU=Admx A aoeTMI-3LqLxq)ߗ⪜h׳ϔmlt$MJ\dq%9 肆-q%+oWتWPԧ ]R{\ {6x%$=퉭WJF.N'?3DespA]K-3͜geکќ**Gkhj[2TMdOT웗_&T1Hj/ MhxeG5faߗWTbLJ*Sv[qL]a AiXD`T &=q2 \wRӲG:};̂ J31zqJ[ǹtdRw0"^<޾ٵ@s-3-VTєpiEZ74GZу x. ~O"pj]"3tf:_I+^Ets0 =6*x3]a/u]MemecmecmaejSYTaY)O}%U|t/r+_'-3*184w% }٣ӕif>xUIZܥ@T@TW-"6a~]UC'shf_Jg4pΠ9C~UY Y=l&R><nv:}&T`slc=Tq"Ƈ\__RAU_K kJ:k9 }5MPz4'ryĀF_ZdWu6*5ﶏ+Z\)\B9+݉İ{ o+]ё1axMYhZi8Gr{bR:v=&=# ֎ƞOWԙef<.5kT'[q99o'<~d =0ix!z2:3V`s#-6S@[ @ @ udG]eW} Qz!&: z@ m#jpPnb5mZ7KtS/)`Ub$l[9ꧾlQCK=wW;Z|rAcLة|ك8foKro_/hit$%Žx׸J4~/Gʠ庺TM,z ٻP6[i)T%hdynVrS^z{B8-'VP?M.MQQ;DNǩ??4C EiȊ1OORCwS!WL.'oq>zDW&mX#/񺖸|4] t^huO3H =|+6sq;>ܢMp4AI! jEw DBYEKMFz HS!5#4]sӇ.6S.{Oce}m)'[-{eb,.VZW{;l1kw4m/ocf̡F7]Ɯz&g"t"=iR}Uq2Rql !&h =u1+UVl0ʙh7). y{YXNmΈ.{3QyItKo=h=d4P @Xx)0 viٱg0 RPU#2]'gNEy_q1P\LܒP@>>y)P .y2,m/]_l?p2LܨrI! SheJ N'r#CBډ]Eb)EZc.H=zuܓw Ӄ\orM,R8l0POJmg]a#v35\ڗd}]HԤ+ԇǜi$&]|uTw&^PZŚZ @\_ Ic%_ מc.,Yۭ*.W`B { V$hD|+zU(v#p{HS;HOQ /8-|м1DeeUBp xm_chs|iAgԸLq-sJE"*[Qj)5YAJE4E/hv ?oU$)V?yL"*|SDIAwU0FY(4Y > hjla~@,iĥN&JVO^cҺfT|\Cv4-c dFթAeJRbq%g7$W*peMYReQ]QV),Vg՜0;f5݌&Uvα>1wï e@'/STnsGk'Z1! b6cVA^~P@/{gt5&IYzBDyZ&x>Iv߭"U{s|/?o:rJrD7`D=;\0*0Sl6@[lw=68f/=Åo>& kQc7MFRm)Q̍mRf#"\ا/ʾ.)nsO,Lz^6Ҵ$C@I /bĢOb!L }Oc@ʩ=z,64AYy@gS휪725)XhI|ػWDzVZ M=HB>L?eW5c3[OO󹉎7vS_;,MU i-o / @ʎ@ @ Ao|9 rCE =4q+񠙷Dv/&\^Zk 4>u_xשs9!KUhCs:IҪ4F;8bO1Tr1|./*Kr0z\.memֿ1[ڀ^J2=(2zf ude }{}$pΨ{.㽠aNw<}Uvc/9L5f1 mfcv)[LKCQQgr/^cWIbm MbJYGܦtH(hoyyQgցLZ>ok\a#'󹼄ຮddn.FyUܨ?I72zuu*t7g6%鳲j/"hcV'IwO-;kd>s}&>Es֝v Q7$]7=놊ɍrO?i./gnF!-ox!zh U{uӫV[)vXD^S9 骫Hڄs1 L8SxP kHk9*.syO.jԏ`!Q$p,g(;@,} !`MoYw?mh&ңy{."gF*7eoո4"lXIoʍ_<iy Փ&'>HWH:8bLIDATכ)~+{vE [qHh -e4z-ӌd:賉A̾2{26yg~'~ت9s2DE1$_S4g݉]ҝ0XwM\51ّb; *E]QXi1$&K5p8g4iy ՓȾۈQF=;su ^5#o=t%slEu o"fL }g$վ-VTZP2q(L94!l15F3F 2 $;Bڰ떌3fS(,S<\@bJAP)rמ\*%֬H9tI* XBГ97ovmk0PqzU7\JIa6"&A2-P Ca/jeEvWiC9wrJ?T4DeٹURf)}S&뭸9PDnyug^3HLa).}dW>H+Z*^:E;4=*18Uz'n\7pm5McMud9,NJ̪jw3S\EV xfh.=եy%nђƁ"sXCCH,`˄//|~SP)ar*Agp2U-f{% -ox!ڂ'N7Hk7qgxݸ<^5#o- Mdr$D`> RI~[*wqEy#Qr1 cvYQaŹM 8x89{Zw\>fĸm%@Ġ]wr?NjKOIP1ف gtgC=s;bنlńʌN ֆhiXz"q,A7G?(/Oo8^E @ @ @ @ @ DNIENDB`glances-2.11.1/docs/_static/mem.png000066400000000000000000000135521315472316100170630ustar00rootroot00000000000000PNG  IHDR C UsBITOtEXtSoftwareShutterc IDATxw\SWǟ{o$a!KQāZ"WUWh{@lT'8p("*"3` (K={? PE~'7<+{mADo@5^AQ{;6탪Bw6r}{Ae;)|./#*@eTpyKs{Pn0nˡagYȾ ]u[H"?V-e O@Y)ģ(̍ }l C省)H McaK;pM=Q vE ?eyԏ!ݾ9pk~jop2Pͪ/kf+~„E4:"'l)Yx/}i?h_"i_㗢V>kɠےC?|@ZB [" rwћ trj5A{st%oMPM:4i:X{ۣ '.Vsp5_YfYgj^:_‚凳Z菉T4_6n<6{Ʋ[1J} ح B, P  8 MC:XL#{kٝ-dS]J-A7(k*BIv=]S]\߄8)Ztmw~?[c6y~m9־(qU6G[lՕP_ ^LFYP/0ͦdӯݽ ~ۭ(CƮTֈ`^o)]QVfvSۡ ?i, };r-S3Cmݾ3dZ x}3`}pRJJ_}>ZJr7.v_8s %6vy!fjۺ敡{Vu)WYߖ( 7na+}?z"l`EEvo;BWc1V*2F^W`5mڇY3'yϏW鈠|<ސZ@0hۮE4DȃS+ 3մjqz)>yvzo hA%-'7?X`ae9tQSN2C@A[rgǞ޹r(g,^E?w9#zwzwl=Y{JAi~OU1VP]"sw_ov=[V7@;[i:JT &*@x{?UGI\.S>oWٳfIf7$;4%73/3nأ=cu~qR7 FAQu8xc:}5* 0`6-L;2 b#tO &ÏAfuC(R B>cƌY+ ,`]_owd6{ǫӃgȺ ž:)C|Ԕz(nfb!y ^(;GQ)/NwD+M*2{q5^e_f&\=RU62DbvXn<3zRщjX_#2;-uνGtjiTV5!,,(~"v*r jN;wѣ=D䅺̠ʁ?}FU5~JڅbTٷ]vs\~[ӟB Iqlu]”|a;JSf,<O"+z^}aHEqa}q:>r#@T<ݱ̋' 5qUV}KUm˘b:-1ɹךy6nucJOY}݆؊}WёDaNA%({@FGSzuHS wƛ e_Qt{ OL#ui2mW܇woO'tt)_'<Ӥ'Uι3!w_H"jrB|W}Q7b]o\g|(a[=x3UuPɵsu<2wʡ\!6u/"&sDDdžc>1c\/$cED=h|./ߧ0'Fen9~ߦ_y?Y j2E)*HO_^#p&/FytȺiM s5RDCJLA:N=}.R5 O /~s|z#!{۫&4\ޣ |?@>7fR۩ z}Ù^JdlsC 0Op{4{Ʋ1x<>wˡl) ۆZl݋s#<,o=YԲ W.Qy|c*u8Dž.Xm*U]k"wz}sO 6o8- HI:O0RBוXdj\f> JL:BǸ(zNs+nLmu]#;_]A|]TSހtSV@!c1Ԣ#Ր7>]GA[<aG&ۨ]Z8_%}SE(H UTִ8{Tc̮Sg:1twn^!&tn4yQ+Oڙ׆7J_S p6zk8|uE"PA>NɸBT.v6RDsEkjЕXh哬ZP zǞ<@Zڿ,52\!j㬍٪fWZ$ڎD\ߺn:6Q:J;:Rt%$&G]\i"(݆821o!Gz߈ x6a)&h|Mg㧆o1g|޸U{4>ᣑ߿٭>\7~lTF;M%ry|nj]^D<:m1?IHHHHHHHAS~&/HH@H~n|/?1^H>u {_}Ue/Nqf44J. FMUАd ގ :4>Op(Y# jFkm(ơݨ&wfh9f`(QQ=ُ.w-wMBz#AuXb.8OOYvR~wnHS+qjwLgΒ+,:5XDrKWոW_BncRJOIQ8*M}/@å'bqU-{2(oXT-EٳC8]s ȑ^JPvt|'ALOč8`4gt-Wem_\{z鑓_V LyDaVVjL"*"N ub4`zDYǵ1R,.AS㸨A~uX'_[΢WӺXE7A۾Wؚ*ڻ}*4hm76Ԋpqad WuL9*tt6S0&tֈ -ޯ)=]=wA&hxu#6z7K`3-i+/"nTa%\xN:mm7=.n}ZN}&3Q6=uyYo#߾>v4ٿS{NWG_ؐs03V[sTK:l7ykf|t%>3d~ס/EBnH?!!!!!!!!2eeI<>7$m|=G]JYlDO.>ǐ^Q0vvN ˈ >6}!ήW^j.Rz2kzژjqL~ERtJ% @ naCJQYem)4=,+-&CYoBw&ի򓄰&WQĥOr~:K~hdG8%\7(<:".1d"HӖ՟:ؚEWJH,ytˮZXW5&]dɗW~kڵt03\*/1` QӚp,6Bk `8'2מwhsieO`-# Ո4 =;߀U˹^EtH)h.gtU|FIVQUC-+/P ǣ;me+4Eߍ9<݈Ҙ,o`}{`RЫ=H]u FfKߠ^Su0:seyo!iyڡKԭV^F舒햓p|b{vYZ+'K"W_-:NZ6/̻sꢯ{_m`֫A 84d\ ZG!4./.Gj ZieWuժ.mέիmg--O[Z}BGiKO.}]]Tˮ3J^c\MW.Z^~MWWHƥ :(OgȂ}K<9 PE$~_TmM2nb͛n`P_rcӲOP}yxA:#|߁9r#H<UK784퓈 ,h@9בEzCHc_yIENDB`glances-2.11.1/docs/_static/monitored.png000066400000000000000000000276361315472316100203150ustar00rootroot00000000000000PNG  IHDRjr}sBITOtEXtSoftwareShutterc IDATxg@ڀߙ]`,*6jXr-1$I1zi檉Ĩ1`]4T/m-,wP]`q =/y; @ @ @ @ @ @ @ @ O>~1ݒy2ք @|3#qY" @bX=&ur)1ٛ 0>*.{;a 5uJem] lEj3t7;`!;:?6ݶOl"l9Lq1 \]Lo,}mS@wKɟԪ[XׁcFM2oæ)릯ҁy3m(-{)ɀUKu&j7?^OM()V{'u?9ݞ?9L% Om%sw\\2~Qk7M 3= /]s4zl~myN 5> i1/[?~GcvfkGӨ`nφ$4e~F\`ΐ$? ʌ C/˓R>t AZqaicDϱ貔b`;Eio4J-2j| pB_Xl -fqpSb@[n|;%Ifs+mHӟ~#։R_Usa,gSA~H?C+6܈tP{k)#'ɓEnL`Y%_-r̭._7efo0gٲpQ!g;*U|^H 1htjR)둱XNχN&ҳ~wޚZM@PR%y;9RxV QDVkjaz >_6(zp!Ϸ: hipx8D鉹]$MJL㳿/Un/ mߎ1g}"BkTS/橫`D˺aGf0SUuBSiZwnu7-󘙖^"u&` Ƃ/ d;'f.|7e[+#or:;, uv@iԘaP%D+wNOfts(rFOUn)L3fJRssW ӵxsk_kUf`ukE%UqoOqs0wx|p&Fu3 b܂e啄0: &OIbu4(AڕRlۧuޓ3|/!hvWd*ivn9J|O73Gm 1xzW;Γ X`_T|?gp=nQn nQ&,]g˅ -'7b'[Qx */_wpeC%^`x~HnȒ;͵oܿ:ϵ4tʆxeϋ$8qH/ m_' &.`xz^eA).-(WOad繫HNyAnxT[Cn~aݶ0&h5!ϸauArR I0ü^C4'|ZzΏcs}>tǽC\aA ܚ3{'N̄QSS 1^`߱/"9mٚVuI[Uh^=*x_w2HkݺO]8?z{ns|:IݙRz7)a)D,F7_%s^Ш#; x"Rhsbu'»xa@k.6$P9R}yVj leZpM5 (AQ,MN麉n;$jPդUiH8ceQ[2/!f(mʝy&A]24`A_\A4Kpc6N ozs߽ii2*PՈQ[t%(o5p`5Ͷםo~i\ D;ݲ6}Kmug oɬƣ.@(6{==PKu(OpsE%Kw@ꬪ:\Rhlk+.WݢιE4$ 5O4 [w(hC?Ŕz4T3r0Mkh43KRm1ŀI`[χ\r)LIpM/R_YR\(14^-6`8 gYQog]&s1ڠUqcXL0va?S.\Z%DNvצ7~Fk1j,VU5#zSM>j`ܐ1 ںbUMΓf|w[L?њ/Y-)_G}#6SAq8 Lv]*rS R6v0+]2X-lU2枎]ěW^ Ko6&S9|`0=&Tk[W< =l dV{cuft*۔qtSCc,-u~>th]+#/:8.48"sNjNd)1/NFG߈7|Ż^`SkĴ ryic|ROX=MXO EHf5$O.ʪFs0D~!H- ~Ň3tI ?W!zpħU6֝cFlfy3\`,wv:I`BI鲀 `O;0pA8VoХgg J |nlֽV@UjO|OyVߝIS^ȫɹԲ~#]Yܩl~I.:`h8m5o5I]kUuVY|mv跒2ىӊYkwg1PXRZlh:cGq\uo6 #ٸyW2M9=B{s_* ϟw1cr{ 秺nU\| < Z9aҷɵ8x]^8 a gI/Z@ @ @ @ wB6_lVGζ/10ce(KSε?ei6R_:S$s~Ib`"FZz(<[xMK\w ~E>n4$m֞yLA۷Ӳ9gRر]mW7g|U]nUјTM<>F*mIevg G KOR(w#֖':df.(sHrBSĀձQRfՓjgxN~2+A_{:B[]yQ]㊧ۘp֗-6]iQAɩ=5`WO->985'-݇>y+Ugn?: d#IcKxof~T^,\Sۨ#y2w6|NcV g@^; '-Zk 5[po=Y'־3ql  H~ӉwDz-%gdMH2hqе3K]!qK׬8 ]MZ&<8J+J PӏJ]ְ/ "o9+j(4ãEaXЮM zsHn͡ϟ 19`Pr?s,fpՇCoh4/i;}=!Ml-d3k6寖k'ԾOr^?i]G (pqGܽȮ+s Gy%Z9[}2Go-غ3/8ECpuӻͶdo^ 740s-nݙ((lERL4Sa`0S&PqYx}%JQ6EX)Xr;鲶 `<e> J? ȾXW=ݾo "7ySgSloIsw_mW ?䷴_PS#ʡcVG;nMh$6|H'۷x>XwfqY th4@HVI3EoPҁ9t6mG`Ŭ/o`n4#~Qҳ^YWBQ16'Ӿ@w-W,bz5rWkk]<#W\-Kj:[13 MW\I*SUJVٙ( Lٹ7W@_*uyoBCD65UV? ;J j{J(nSLkI! Ό j?9_~ޣ&,TLiU&~y^޿ը-87T,V_?&oh}}'@2l2kc'ᅰZC> +KM'}w>kwm߳C+0 gqYx]b+ʔ8s錤w޾i>0,:0aA}Ew}!+8Sjs*nlpO.CG:۩g:wvH}˗+ ږo[,iNؘm3ex 0v ɻJs8ȫ9{g\7 (<r)W .-<{$TRYD`rpt?:eߗ6PYMfSodhߏ ]'|:a}R.xq}b2enSeᎴƛ(vxA˭;aOO;r%q}@}@ @ ם1ݒy2ք @ho[cX'! Ea lEj3t7;`wY tǁ$9<ӪȾɳ^%jn6?}-5){sR/UòL,oee\ũ&n>v=>:O0|gHeF!xI}ꀥӗORA^Otdeu .c`@Ӟ ^7{d^ͩtP>ewG󏮛 zfwVRd;X][xrH'h>;#jqdgT}dmPC~ouO}'-L?Jj(Pp̔O컾Lk D>b ڡ.AXk4][]{`oK}vuT4/%=m@.5e7>m!Y˾7Kl;"`qDž6 Ĥ杏_~%$j<#A}La)̬Qr\{I7譲[.yI bǿg>rNwjɿF Yț * PvwCa34Lbgm} 20T:IBzaJ!kZ)瞯k߿֪kW9BnfAP[F)iVt\=xށl *-%D˝#;dyR ,Kxg pv<&u}oXbt4()#=^$g,1@) ?SxjՒu2,ou&UE.QP٦3Mꈤ4Y w]~Jվea>`} 1x @{Z_UopI?Pԯ4 Qhw>M55` ߽newq><]^[V դ-푝Q[ "~|+r`o?)qZ=M,tͫh¸7Q'3uwKWd#̹Ӌ5gI&#}>IU?V3'` $`-;B#[3ҞUynP(:ʾO4Kpc6N O}:>.9)?c(i[lcx\:-풝r} ;D6ƧogZխ;8UP.IDATS \Z I 2[qx#K >mP8cX6`zD57J qОzc,>oȣ( cYXLOXr`q`w: yʸg$0fʟ *8 vŤuw26OQ Ϭwޛ)b̶~|_om]neصg:ɔ~;V`=087ۏ+`zNHgUWRP Mme(ﻢA}ţO5>eo١JqޑE쓪UGNy%t)Tܬ!hp6>iB^lvM4s'>yT~go>S}tAUٙԞؿ;J:LWNZȲuֱ6E G )qi]z>e?>{ڒu1ݝMPgwҲo+ڳz>*ʷ!>! ~] gdG @ @ @ 6=yh),{ɢ%ӮwBg7:4g:cbAʚ|}'Av]e_KvA^|ܬ?]l.>+_J1Z}ow-Н¾V8(<ȹ-tdg?=/*yRm]7Ǒ}e}U}`&q緢7e~@),p80fzHQcbVeNao !D|0Wc-w|s6fn;>=w΄D IT-rr*K9Y ?gZ'&~.(sIBSĀձQRFU E4Խ0@VpXܮ96v|vnriJYpkB?*N[𘤮u$c`7um-Ym.M 뻬a# kDIBDi-> _uv|' `Ul4Pz% 88wd]qҾqG}'C'v7nO1dϬ<#4ZCT,ҕe1' kXO۲wQQJwo >,O}Me9dokd߿;Ⱦup<~x_LCϯ+r?uƜ1EZۂ^lfa&n*y(|Sz>)'7p76Tm:w=}Ⱦ}Ut}D;ݲ6}K1&Ռ7DvI*SU׎ix$E*'2ю8YtJpox0s:9;Rhlk+.Wݢιܫmn =<}߹~:8hgV5˛b`ǹ U8Yx H~hqz>%&tR~`J;^YR\(14^-¾/ ZԕcX`ӿ}}~w"'M k??#I5[5\jQ۷6>qC,^2j-W5s`,nS|:Uu P[[ȎO5S^"pXӕ7K,E7GTȾvѾ:o$Ʌ/v)P!m-/UYh0\{K ]VޞL@ poo ։;HZjTJ#UAűGhЛ\N HR.ںDAy@ @ @ +XMKar%[pݟ]0as m5_[}!cxB}L-7:->^;7طӲ9gRر]mW7g|U]nUh <#T9Oٞ5-{"7C6dkϼ_|&`׾;=|LD?F К R^'̛,B d<Z;?loRZM\^u ?̨WT1CǺIF̽՗.4/A"|z`د}ü1pëQG[;2 #}nkg;|҃Jͱ#5޷>&Hde@2`0XʛX<>K=zm)qI7v\5\ʪFc$7SSh;E|Zjo2eD==7ů&eޤ2"vѡǽǛ |C-'K}^P;?֌:zɧmM%HˇY2\F+#ŦV~'\W6Ii2+:3@}ǚ7=SCc,-ub: |I̪luJ~SDžG$IQԉ,%W (r}϶i^#NFN~8hOS|3Ud⯮7 e4!>vv.o>7?ܱH]:?Pf(i(d#J":d:I: "1˘PYM!Aܔ }X L-rwR}գtj |G^fn 39ނHb:'J>𶭤1\°ʪCG2jUfЀT$!DxX4ZdmP2gr#v6Dtq0ښoK@kckr_CTT3?tLCO߹vDN€ _m*[ok#_+++++*m!Qu/Vj~!Z;jӽBG6<EŃC+8`I/d矬Oּc{Gp(_q-|W?^2> IDYE@ AtɖGD]@C `>xV}lV._r Ee*(:N{i+yQrZl(,)hjv>pGn5pdW8֪sr\hN+EEHQP@>,>Ж[)OZkMm_}|s*t8OjO lf]Ѱ?cdqz 097=PŇjHpl@#@2!2IDQ(JoI<" {'i֚<;hhdpۿ󨬈K_VԬ BpB)Ɂg7u?(4gD?S3@G0ן D$F%Ө e7TE6׷ʪOSގp3agF,j=8GO ?epb6hJO3&Ǐ+6kЮ |Щ]wln>v̽(O>9vyw%va\iR%ADի)& Osq9ʍGX, tmڵ=Y>jԜY/}.zKAU[,5+[a~|_43je#:;/Tt50 -qXĐΫ h.l&DtT7F[ n}tkǾ]C%[KEH%S8Z" #Kh Y2'0"`P>-MMCÒd31q_qcc%ud Msgm5d./<jj`,SA`>UCj>/{PaxKWup3"J$K@N;B6@ DžO;VEʈHx9l)=aG& 5uGkT ([I{^[ԃ',$ N" DR$a=U{nj9vxC8D>o9Y,<,=/'6xy^:yxgZ.nX{>{>̾}3]l-˵A魧m;ܐz$p4VZbZmeM. d0Ǥg2ExuLp76{{M?b;ܫ/tQM#򒒂֯e-sH Mψr % ֣r׏͚ Dž/>? ͣ0z@Lcb~@U9եƆ|TNaD]cdqq8|J; [98-9uflO{_ҹB (}?pU""XSF黻F7sQ'yڤ/[6{[E|?!#ypR̞w2:Xtq˾r2*$6ӷõ)BW~t ]41}ǎ;zcn'Ԟ>Qn;w2)}t{ x㏋珽7&<1ȲB3cy~c5}鱾K& 﫦QFBџON&?v=7 lxԴ@"N$݉v4?emSfGFgpt@hk,&IG_>mLN\'h=TSA>6kcSzh,H\G]+P}n摩WF8\<rou\>x RRP+wk!(r4gK5BwtcY}oy}/ߔje:¨Y(Q " zlә6~p.^B3@KϫsozW?DKIWU~(Itї~Wfto  !J<)h@-d >)_?9gG{OK FwUέ].Ap .t\.%k/LY7vi|ǮIIt'CZ$шj)dQ:d3$l&3q8cØ7M^?C*֧` C=(xɳKr#,9 M&A;xke$mR\ccB˒ s=Od#yDShz`@7R#i; W6 eød}u[xgƋ히4ITKAHÍ#1S $P2=.HU%I(:d (ʹ}mV=w[CioXvT.Xx*;$h [iQ r9HJ@>z_XK l]iJ*JgqrȒ"ZZ5dr1 _d:sV*5HJVA Y(G "\$05<'I=m$r`D[(}ԟ0LH"'rz^F#QfŽC%/DR.IYOHnM1tg7ϦWZ"fUku #'K|E=.wwBb(S p5se>ؚ&6FAv%eksceg)-E In-s *fK& yOؓ],@&l!=|G'l^LLl'E^m{h u!⿬g=0ktHݵ;TࢉPˇսF Ay̬ΑX{.wI!YWvID\;Y".p!{Gp&]ybSH&Mʡ/B8x5 FY)$L|]{|ۛ>$vbT#2)(K['<׾^Xd}OLNIᕨ!_nC#solL@Ǘ0=wO*B(>iv̙>85~'TAcg>n`z\y~Əv uW6#μ[ uv}C.$ 9>Yg}kVW >:O9#=}#5䓶|ߔE3XXCk~~n'}uQCS~/qxu4Ƌ;>[dZ%EIaziCSqǼz~҂/|m;3Oij;~y^]3*Iwuޣ?^hH>c*w3O{SՀ;JT/eD}/~Q-U:\"mٔ31Bm"01K/5"H 3r7NzCbyc}7cj eHR3-D^Q73Kwb M@ :\.|p?eA_ذa_7;o?K%۵]RU; 4qʓsG~ʚC"@pIuϖTdذ)7n5q?8鷧ΖG։A\9-Zk +G_=&|a n޲.A_\QtrC =䞇G|FN0EΨs?4Α'tO~2wC|DJ V-wJeh96! IHP"AK!qB0{Jnʥp*b:Ab'Vx 6x97=bUXv@viO|r;yT e\&qĈp,)@I ʒ,![F o2b?XHvWuN߻c0jلP%F{Qvu@Z?@kTM}9DDb81VKdFzpmF9-)6`+#@HHM rfW" X"3:5s< ZA刽̮3􋵠%a:vqdvۈ.qq69-Zc؛yǐn QqiomLUQ6[Pć&4ټ{֯C\BJcg?rsW?=ntU5n>)i͞[{_Q+j#؎MSxJ*΢};͚'9걳'ǔWUNk!~9QGnȄ{6,!ob6gJΚ;9걳&EWe i&$au{it/9Fy3Co7\s!"oFrV>[>iTw˩}Qcޟgi6cʸvYSrwoٕSf;тcnI#h>|T7d?䐚rOF\7eM4[ bhE:tdָAl;U~ݴ' K[ "qԨԣ{k5!)U;V=ItݗIm~+XOSG5F1TIuSg4ahr5KP/i#GW;䮻N9M"hXTyIH)B&ts+Ց ۬hM\Gg SPE8)ktn62tU[ Hy+:S!Ԁ0C`jBPxdH+0Crk"߰Ơ@2"yQ[ ]{_03*F`ٜmgI!S tͤf}lcapޔTǴC@"&%5kD`:bƇ;=f@mT^`[oȮ+Y o)!`ʒRA8vR^9)Ar{H2ngCyd m9+Y|N 3le4 l g|T5 >$f tJaAudIqd!m.mDU͝g!bCU{{?bg,<b1ThKíVĔj5$J>aZsFAeB|T[5eޙ](jK ezL^B'Nᡚr^{wޅa[6UgDZJiI݆`0~+o>PФӺ-`lWvW͠SZacOJJ>uNܠ,@l{lhg¬EAAgKW?[>:2j6d}LHC_UESQr"J><~]UrfY꺟iWޚh(oN:jLޥskR4K+#""ZNXRFYˇwN+;U4\@+wG}'g̽{@1Zpߝ 7cF *^"`6힥z&oQĶV.Q %ԐX\Pxw-sIDATtX8V]PݶM]d.Iyvh̶rssV_\@ߖ:65_*$p9 Б MD116CV ި}!V̙l&q:r!Jmx@k陲ΝjݽޣGbjвE'Ǭy3~q?y'K=Z-ul Wo {]p'٦kfX5E6+HJOMcl xo5,޻hٓέC;crlֽEN辕s6l[}ކG<.Hퟎ8OwUwr%t0ԫм*~{Յ3۹ܯϢ*KlMy'2~eEwjUSZDۚ!<)\[ZLVapc|Ƶ1}r~59"BsӅ\{:JNXe%Okỳ珶]}فQ@ dyN6:*{37JSe}K}TG6 -rn%,/<Ū %t6XÂ۞: >Ǘ^wXp'18Ɩou{ud[K4ge~. +SĦƓ'[a/֫k8[μS}]zk#n> y.XUy>~V[E/bд\ -TGe ,Fy (iı)Ig3t4òI!b @ei?4QDoRM\gzO$Ae g!l3Y֯qyg#/,7Q>Mo,؎T4i i[C/|?ޓt"(Cl/!ӄ]$.#  x*g3ω!G۲1fen߄R?dt3.î@-3ve*{ള:ƗѼMu H5Ȥթtz$njy<xcBQQ r6*fd<5EMuHU_-L3#n깍8y °.A+,6JWTk8}HCa IENDB`glances-2.11.1/docs/_static/per-cpu.png000066400000000000000000000512141315472316100176550ustar00rootroot00000000000000PNG  IHDR+k3;sBITOtEXtSoftwareShutterc IDATx}wXGg ({1bDK,`]{bby I4b] 6R+j^Ja;g ,o~s텲sfΜ3g̍86Vɏ 02雐Feq! hkZuHGn?&ǀ+PT$R7^^? nЎ64IG7yT=EJQNcT`SU O (p?c?{Z8@ %@S Y^ȔrM>V4l ~s k0&-u!rMh~Q l(@]'gXf#ҕ$҄1y7fTScs<4_ox` d@OH@oH54j+J Q*BfLl&9upMz|LMɼ|%$T[.䯒Gg~;yU˚Q͖=S֮[F6qMAe52~хUWIZ#|qEǺ[t9TXY! ~4G,mG]ۿ-עbRe/_۝@ctBmDq37S>kWn4=-Wk\۝@1j?^k{t.M?';4{%?HO)OEqhT y]w Ndx2K2xΑ KZ:cFffFffFۿ u|]a~_9ːp/8'[V͓k Wz_XҚџXwBcvCQm€pݛ:4&lzGZҹ|ؗ2䊧40 k"&p*xIVk$i!!mϨug@qj0uF)ʆ 'lX3D>9sU!~ "&L ^IUO9L 6iOy1 ǎ7D^ߕ|ڬĩo鄃e'7E'e$+p6NNi&HLLdB(.]z\sIf~΋܆$̔Q00?τ%Cw]IuVa#|Nm:r"xЯU߭XH[r/J(2ׄ,+ 3dZSҔz1^4#aCc{<ͻNĺ0Ys}@ .y&Soѫ77ܹ8w <ftgKrݏE }jR ɬ& _;O5q824sgع[X赃iz='l _*b7@[rAMJIQ'x^yhmϰsIˏ[B"m/۽Qq~xZ  .y&Su7h܍-Cvn{-;r|M3ϯWǧ>lzBRt=dyj^4: 8/'/Ύebq G>ףϯǿx%^Pߛ062 k;+~S[dn9ےܧnVd 5%>_IXkG6gĮ sd ;b<^3eޙ|a'*?H{ރ-_6\Fj8}\֎$N]7!oכqBw5g+ ržӘ K<8H>4##n؏u<ک9:c첉7?0=*qr{oq}'aϯˑ7vb8kLY: %qjCb`ցR2Jʮ-;4e7 eQ=#ֿ&~&(!P| ݿgȶ_,Ɔvx"ӷτӃm>s2`s@qx m^,qq|^&6}0/զ<3C <lԃ%9~秶Ϝr@x]::zB)̘nĵ8};=Fqb _3ZU]Ln=sC&O].\SRɻrnc|G_BugXRH D$%FAFyh5e (qyv98q_ "̊uSZ3DC>1Yn[ҳn[u)Klt4CCu~p2gM1\VE)W\]8h7tBiy;?``CT۬0<P'W'U|j+|¡]sWx2_M<'m c7qQ/'c{E&zaRT2,bdŦ#u8yir4]sW﫤ǿLy(>_z<ąP5TPYTT.i>'#=pb^zj+BJ2_Eϓ~A?L U#x9qİqM!Uʎ]]pVUhS}TaIZ͞x{'&Fև"1ڲ9^z񩙾1'[^[ߞ $7<;x҂g'gd3!^dT9?м>{n_Diq3/Ϸa.|""B&IbS)5T䥥EOΟһ{`ω?%>ʗ(5|sfgr/'HS@"nPieBm4`/?<;W<&OsB\.\y/, DX"HB1l/TeTcf~+lj(jlø]}:?5<$IWn5kBiDi4i~3p)]z#:x(,ziX {>@VN. ==56-*0FiF L?z-3)''#W]˕Piqn̢+GJ=2X-Lݳ+]w\rPgB@@wGa/fٱ0+^Z?9.箚ulLHfS0y,[$.z~mլ*eKq8wpGH ʻZ|kCen!ұ]G d5(J~ӱ"6Ԛr-2c~c1ZcrJjQS t[`h)ժonA(ҷ5oap-J]<*I01{M[Z\ZQ ,*r8]R]k,Yɮq|9g[/iQJMf:kI5!(U*rE#byT hрR>-2٥~w>qgj[_5oaP-FɩE^ťU;G& #ߛ8`u}q|3rBgĕɿ/[~0ͥѝ!)}qnݷS(+*m\EԷN4(l6TJc8Ik'̫1$PSo/4vv`kzq`L:8aԄyK'+U-t~K(a1L7z ޖZaJn~ x6rf4P=A`exvP4M~ܴg򷭃 %n΋:*m] y*=C.p0A{ 9ţ%$ c+F%vM@fTs[2V-yOyܦپB*se5fP'ȇ 2u|ll2Wۖ ~kw+ۜs快B&M@f{UD:j!\l[Z3{bS:KťȦ9ug=}r!?!PbڬUQ? tfvM@׎2IVc9#9U2^H8!\Y f^?īSRRSve[~tp=`cr*YoCH0ׅC~dGu`F^6"g%z'U$2;;PxNa>Z緩͗>"HDBh`z ]¥?ΚsI⫦,QϮtO;# *TFSf*a6ϗZbkI%To+k*ե) @8w$"/A˳co1>_eBVm1S0쀀BqHV_.K]^*ǩh"1Gjqy83g_Zbe!q.C3 \ \>vJGJWM I<,}{xlg7D֊n3;w[JGQeDoj.lkO>Jy;Js dBHD "mF.tLQYMrn^2޲T-+ **>A0T%?|4i&kr{T-Nר=fDbFC`*U!I6@VT~qFi]Fv/?ZQ.䥾qvm>B\`yʈʿrKK IЭAPR/J`=4BFdHWufM܁_v,0udU]feDe4+{n^^v}?\Fdp2ڹXifrrɱ@P3cB2LDAm\FL`ߔ jҌ (|>=I.<}dwL9$e)evc;J><<ARE]f2ݕM*>4! ~_4g=qXcZJPCnty$YQHeDtNZ]Y^ 㥔Y^^(V;Ures"feՉE'?dE;3q`x/JXR/$ON"EۥU5bGBp+~<_d1hy>cکS'Ȫ[Q^(yukxgeK DF2tu6767 ԍ3`41dL&ՊP-jX"K 5leT2Ԇ#7Q ̋"uOz6Vi|i]tb3&,Y&cL9 c/!hR?HChf_a4i)!6CjCFU=g|9Ijq#ǪS kQjyxҺgy=DS dqO˅2[ tw>&܀k

[j4ᨡSͪJ/{Y7A &?X[#LVAלVUǩ\N̪rێs _y IDATH;ݹXq*3t)Lbqfsg ]݊Sk%_lǺO`{H {v18whW*jz"C c8 plyŪ.5ܻ1BQAqv[..W6Z(kL90OU¡:6gDpzDR@Fw>y .C7VIla:LR$ĩy^%U!;6ƴNiWLZFULAg/Vt-?^LDL̒p>_yq-w݈wx|wbS`z2m+w̓0F]YeG΋cG{|?yŗG 奵}54:kz߮՛Pw,*q\U}7%X5u=5YaTdV lF0 +\ȸ[187%cYp;Ys/eB[|Eyˋ3d27p噯|C5م1!tM67 ΕRf p+䮰b4Ccyjۨ:j$lA_ɩ5vC6P(1rּNǔoQJ"'dCˤ3k֭b eoD"QQgv k;**̻CѝLjk}ߔTJ`f(O7ֈDE:8E;**̉smcDF=4 3dcGe^ӟXj$ljA&JYY1gN_nQ~aaXcqDCؐDb-yeZ8}WeP/~(Q}ln2SR@E2L\IؑVC;Q?vyCr :D-wACzLXwsIE;9j02_vd^'l~p3!C!2SA1G$06eNb3n}<]|^J)[hmj% dZL\Bs}c1Dw/:KtL<0"h: U˂ՙd4kc kh] M$[R^Lo7  <06e. 9%AZ:Rz0AUɓc!{9|=H_{eU6#oh BWv%_/]*t*&^/Fu{-RJQaT |04G(B=1 s[nh5`._Vk?0"Ch<P3wY\ؔ↉Әe2!SW} lh!3>1֑-j$jQ{zFª?c(qGVLƮ-5=loXHLc>rɎ-\890@jBHZQ_4\Tz%,r6s>7;Mb$S\yN?,YIR㘘㼩&C?aYwa쁅_Px8%ǃ sfㄤw˝Mݎͭ½.Xh/wO>8aO-n&(!×'$ۣ'b|wŤcaq"Ls2b/Tgȏqӥal}Gt79aN _ 9?}igx{= iT!n;7$UHKZeebWK6eOb=zVnQ;9Dx4Y_ ]ZsU& O7`U:0?MtA778kٌ[+CBݸvJ?ㅬ$fWkϨ`곰? ;z}WF)䉨,͵#RM2o4  EL\UȪ|c/;=&F4hqsN]i7kIk}ϱ/ }†5CDW#&?W0o:5|}̴Sqjh ΤG))^(j]R^>܋ycֳR]7T@a;899?).]z>8#ح< SAҶ}]cЎף|JNn:|r`,a´cQi7k.W8g4jO[OHx"9vk\z|F )Ǚ|aj8eXAADa6aF#ym'9/br: ¼\~:l]);):1-#a@S!O )&, .=] 98#?E쎃YCgtݿ ȝ/ݏJfHGr2xP=8Jjh AGռg)vחM7cmQ4)R;n5w׺^'+2qo맼ӼpQR9 tQ+ܓTafΩ#q7U6MNL9z֖!;<.&:v|4 RD Eέ} MڿSzpVO>z!;=a+D©hI8 d`G5WR%TqpN&zs̝۞s#k9w b'_[p[7Qzʳ7<4!'qt.O㼡5l5!Nddydn>c"#a4u(qsuԹ'yYn+GCPRyA.4:tq`tq'V쎺_iqb뷶wډD鱫}MBw1:y9{TӕTr\ƜJշ'HDͭ%M}~b̭L=MԦ^~ 5qJwi"#fG2[F⚒|ੁ!}BN}~r/H߅=7f~y3=3'(׫žȓ?o}$W(p~#d.L\[ZP8J;fN2Z/o ce Q$2U& \wbXזOgFO(oWU:`˵!*m^WVoƒpe]9|f9.ۑYfJ"U+Ƭw-,0gmMY7,)2' Ug}ߎkKT8d?ӷlŌ=ƠIe5<`sYIk<+q2DC>ᑤg6gܻ!Xl."ydZr 9%mg?U}8yC UeRXj1D^n]l9t@IbTPYXT.i9;#]-E3q˜L'N].6_VZjљ@kn]OZ#Zoq;b`vaz9YQXX& j>nƑy9X+g7 9W:8{שa󤭿_)1vĉYTT.i1AvtuQ'/-gLia$_O!!Sc&.< ErkWgm+GBs鸭N'V!O_ENJ8|\cNnTD0+ d?+rrX'[:x)G.,_1WSOֽdžՖQ}c"14%@q1ibHv{nIfedf_Ub,,ϓ)#`^2je:_0_и.c|   @2H* D@)9#lRH?/$ʓ<cÍm'5kެ3)Gl1~4_9Q3<%•B~NKDRX(Tqb Ҷss% Agf}mOGLGf͚y7i^=W5(=|øv %W'T*A'6g%s~Y_\ W =h+l^OΫ+)J=lٳ{*#av .0jeł,TC_,1,6PcV?y t͇jtU_ >7&CbL4W¹Y.NѺȭHvO㩊U9#}gʜFQl!+HAz֝47``sV_)h21f-һ #3a4"l T>OݩB66bze q?cA}Q}"~3ks2X {9L|4Y3}4CΘHu=cn y˷/B\^n FNr-{.TV5 ]Sq5Bi-5{Սf̈LF[qraB1Z(a{[Ĭ7竡ЪoX ]β&(Eb] 'VTH,'YqrŵUFp2-+_)[IcsO.7=NLF:W /*5|A-(qcsN1ʝLiZBR##)3Y>~c$)ji`B3:4R(͊/,ѹml`"O*Ȯz6z}Y]xa;Ӳ9$.#RɮzNFk'[IcAi ޶e˚‹;^OK_jPpo|/TQފƺ9Y˚;d.cztn@!' ^_^!uzZgHmfϝ'?OQy8bR\7%UEׯoꪑLeT[NOOJtlE=w&'ifS|fJpx(iĔUF\_Fo#.fFPjoO1(3'J&+h8Ë8Cxq $J!3ET2`8o O9(= NUO>6CԌj 缒01؝Sj{D',v;#(` Ft& r_ *#@lAz{YVLjӨ*Ӄ]:G3Cq.c{g=u gd}8UÈ3VL!Dgǎ9%*wnԢvron=rP{2.BVc#i 8'z'|nD;$%,LIJD D`.@Xt ܕX$U^btT;2'JI׬l!;h~6M /0|gp/wg~$eU5iTөao.O׻ߗϡkRk2L>+6 r՟W!Jjݶ5{m1)CYEnߨ{Խ—"3.8mRXu W!*d'1WMZ$/_u$ZyZ9[/Nk1U^,J@y Jҿ .ӣ،[N(Nk1ex/2_ꏓwRpX|u5PzN0^.򬫗*YcfyN3~Me:p3JI[~9O]Kfӳ+0۲5*2;:M/[&ňC8:rSF%ʩWdn>ٟycT][\榕){;<=0&oȏ]Vٻ1e.N#f8;P(IY9HX7DƊ U,MS˔p8KT8?_:hׯvy疀CW"rex6 s3OMA]Cp֕Rk7SB׿4ᦦ?;gH+w!s^|7e q1YI\FuN+Bl[N4@Vu6ee#),D_uYQ 3z_$YkPmmJBN^5?(!-C:ڸ_*ϮAX":8Ommy)߅pkj\ !?S:ʈ項DtD55cb\p\CڅڸݪVS$V ?rj[eqlrz=N54ЪW=;˕GyR^`>{xnW[o|V EJ!79*6͜w;ϬL=_= I)w|J \r!)>)dGmӛ8}݇9Zʪ gh{f9a5nǖ]=%4I]>fFy]zymGHڄeHɊwh%4H*+ڙylNԦ^]YWvK"Gr_ȳDޒzIqhé2qYq.&-/'eqzW'#/gWdWA u9h]'-c\v6PͲwe5R j8h`#AC|GL^%j|Vd??zĉOb{K:؅C(%,61 ֓4sat߿{0l\pB# LZR7{!nimA:۝Dt@u YztϑQ՛WiM_?[L@ȴ ajD7nJh^3_ -Ч QgXݴ@1I)I)fPh]Mbrq\7iI77} 7\ i-#.'lͩ]ђݻX*nYB#nt"n]݇^ރ;dX@Wr4^ ^LOLxpkp{/&'&^<;M8:"{.\YK*/#&'ʹ~A;L­}Pe 8qir_2&q"ȸC>9a!KC8 YDŽ 놈.+o 'ࢫsu`4 Ѝz{kvqL(ίpzLذvJU&%4~8Wj$o:E&1ӂC͝JNchQe'n\䜸ȀmW4_EW5CG9v=9Q (>3N?<<̑; RSw$0`K[hsҴ2t[qLYӸuaZ5|rctARB只o*R*](L;ŮM9^*5lP]?ksqw SzJY2H[)UT*(&lBEk^t>6E'ets+'X)98&sjhBX4+":9u3yi恱A{LP,~]3hռ]zZŕKhenVf duq⚵&8sjG|Cvn}.V^b6+iܽETqؐlW]J76ܹEHZ +kXś*nS^yhB+D !$A ".KRqo}r\:ߕg(x07ٵ3D&=)C\ٯn+'@~r+)fuV:y+lbX 'k);r nT\c\J.UBzB=F_#fxN297psʹ{$qHSfUyG6!N]ܫ7'l>LhZȥN>}7_%Xo(!k'sn?m<'eԹg5i[NƪJe-(]g[ܽl Y#Zn8 qz>=GF9sR4~̩'ȸ|-cӧ~ .Q|Ҡ9ʵ!0 e6nF. _s>?}638t'6髆E,-7AqmN>s۾8cf2Ұ a:Q}|wROmjLT=5\urwߜn?lWp<N洽lb/wXܨĵꜸy2%VyV,i?g٭MY7w/'R5Qp2+NI㚭fֱ'"iFyf HAsOdErfmq>Z7告TF!yl=ɒv3zͽ.qBɹ{ܽ52ln]VC'<ݜ$@KR.Rgͽ$lUSUބLAU[O U@'CE9wzbmNSXM;hpa2dO~y0!O#C&؅՛U'OױkLjrLi;cuh԰CJBX_yiElU!Э8qA soܬ{p'N:6HIYfA@UK.WL_^ \ ]ekϊzqp}0y5N0[ӏn!X Y"Q\rBUdK'VYW>•B%m9_5}ESp]*9q'\APy5nZ*7 [TA'x0zlgub"i<[qob`k]3SǤΗk[@}aJS4X/W}%n~ޭ%>RwR(,^?2A8r mbֺ}->W9pF*AU)tؽWAΫAϜJ_C'RǢpC>$UJi;$' ?zlZ$jX^oV{we;-zBH+U UJ)-ϺCH+U r_ʹs #Gx(X,>}`>Є~`n B#n 1NM6,#r )Hx:{7r젧{.$w' X!dwg ۖҗS!?F,e`#BQ=YA'tۡ/ykhb?'i| ᠧU.gA?R=bԬVPBFH쿇uLC5?i;GmͲQ34.YsKt}67NhmGJ)@aYKzDƿij+'tC 1Sׇ^O"`{k'hn=9IENDB`glances-2.11.1/docs/_static/pergpu.png000066400000000000000000000073411315472316100176060ustar00rootroot00000000000000PNG  IHDRF]sBITOtEXtSoftwareShutterc }IDATxgTTә[@DDQĒk4= EĠF >bĂJĀ DԈ (A!Ҥ03}8 uk̝s9{S=5BLWM*#"%:_  RB]w}wYue= 2?1+ -A[M /=!>K?DlLZ`кϾTX0YT=Ka{{-D˶ZD37p̝kz~!<:J{zx/EDѭz4C(BX|/з놫/M7v!"V^<{tC&pQ/[kesr _#V]݌ߞO]r z,,81 @v[rVX<| 2!?GqF3o#8/>Wkڑ2sMC'vZo,v xV¼ *М~_(s#1Z=5s;;|nUp@'6*UQ<9GʫF+\AĔ^*ڟ^3"b~LsqqˡV\ՈXZE4*! u*-٭.~3$fܯGst=%Դfn""VYՏ^(~ egjhhhͽ!B;^eKoL@1b%-e?0s0lN0` DLmPI:ۮi&*QMnY睗̟9v͹R.뇩Ƚ_R_z|n?3vu͢Ix*@uC^XXXvr@vP%!b!0+> d27Bac z^UsA*c*&ع.Ĉ,U[gMTU# KTuxBUGe{η39r|KǟnvW.c҇=T0뗔 a+O<%sVeth#L= @,SD`$UU׺';\PEm?MM.Sݿal 0q]5LJmKT$#5+yEA9"VFm6#Xl "^ p!Igd;mso$""&oT~Bc‰kt!r7߉ wمIrmDGFkZeo^ǣeB](ݵ>~OzoAvcg>~[s%-I 9rmAJ@G\Uy>?xkl[mA 52Т!dc/bluMc N$-vb k6Bf*)tVMK=3z,-=s/fjF#c߾ZK~e.ǫ] >ڮ2i]_9Gs'N$ |r]i@:z֎4d/tI/${8KvXJ!,"w޽Zkm|pCTYLm^E Bނ#oo9$a~?2|I xLS{i兯.nwj4 zIaA{~}V"i⼴2F#9XM{/H;r6fqrR:oB^rNfGGw9ި2'"[co% ɅW޶cDDUPME z}*P,)M` Ƙ# 8=s_D2'5WmnVT,%j D,%4C'Ɲ7\ )aXʲamF>L\G0%"ѭãӃ+ˋ+,H2#R` BP\BSEb$4&E5qPEoJOΰ?/yƨ[tw/ϣkfMXX$6 3hkȜlak$O#J,:|P=gwrg2W=ƴ~{/rrLs>To:93YL&$dt%"1AcT(W\Krn$/M:A0 |7LTbQBk>b%Bo2t` ZWiN;K/}PwG]ugrdbT;DX媴ʬ{7]Vn}ը.#cQcjbiM3~;wSEsc)U+y{~2ΦonaaU{[^ l-7`ۖ 8P&2^ GӢv9}l]KM$>NSiRbע O^ hWq)G6- M>bӋMҵ\w0.:D UqsGCyŦb/EijOXIENDB`glances-2.11.1/docs/_static/ports.png000066400000000000000000000254411315472316100174540ustar00rootroot00000000000000PNG  IHDRr-sBITOtEXtSoftwareShutterc IDATx]wX>ӶAY+bDE,QcKbO4&1FcOEb!hPPQAi lbd"h}|̞;s9w}=8p8p%7do1D y;p#5Xk7̰+8׎ߐƇvZӴ:GK: v?IWz{[ t}{IfA>&LͿ66kٯ[&a2%ǞKI *"5ybOکymx Ŕ#sѩI鱧ZTMγ1/'ވoE-pؔԔ};Nf'Lxm?;W{xtrdLlāmM[1^zN%*&jCOqkGX,9|`}u&Jv"ۓ÷cNyky#6'QCvE&e a;y#w"=z6eÅ.\:][_淙4cD{ SVG܈Xoe]KS _UuIxzy3})l ftzD|$zvhx{B&x) ɔrBA芛 g`Tejp |,;B-:㌲Gy/SIzFWpLyglBMRd]⓮&n6_몸cѣs .|S/7UR|;>'@øax<R/oRcʐR*@tB"#. F Pe2,n? W2@:v^5"ߘNq(gآ̀YK rO6r5fm,ġ\de,I%szfkwwߑf\I\`?&7_,bެy8PO T7(Oo+="NLƉGjs4wvrInӸ~V26 U;G`8_¯d]txmSeݥINK*~z]Dm6~Zrd>Sr%8nݮcK@JA ,N>LYİg. ')s+;_4y$9||L{3(SW&yKxy f^G9TO iEfʮܸӨ'<3KoL+VϏeFn9V1h-]Uzbu2bM_qظuO) GQ؈/Vy0) I u-mǀVkna?X,܎ ?mwL)Ѕs/r K>R޻|+Dzk{O(,*Wd%^:W2iv(;NRJƴ*6ٶ&jMu-gz8V}p5Hv 0-M+.gu1<~{QE&mbi ϐ}eڑip-/! w<0uc{N#b=*OCoIPmq l?3ߝ .JD$-[rhܾN\OM :]q8t`@gmuK،n$znݺZu :Tmt։g{p&@،a|ž=:u Mf n^-k[??hmUK=qf %ʞBS?Dk;ӥrwd8*`.ӆ^y oږ?=0A8=AP@`P@*Q|T {G>c+#K))2ʂbZBT=z38E`gt4qaL%%u9st_}޹EFX^M teILH=.2*R*OetT_Pa;Osq+_l;oߏ 5φk0c F@ P:vCШDibXxn"9CYqL5etT[ /u9dc׵UmX9o9:&2%@m{a򋌊ao78FrRuBn|!KϬdS @z|UuӅd?& Pg;Ҙb[+G~?7acbߚFzOzTO v98p8u g9%Q~ynjl 2s%Wnr:>o(:l- `am'uὄoV_ܣu_~?wkw^,(q M{RczE<ŨWy'#CgR5ԋ{` x|7bt3?x~&h olnIMp l'ވ\ш n~_Jk'q]zW"5ae'^<}2$DRLܑ?kQ6ω<4E`wCBhZ%&iD0:F1hFN-NQє=y(z>DiFq~Lʭ=eKhCC#UY phFD倀?vGU}0Q5iiFn12fG'v\zS0䗅qG,UF140D5#?-c`| N#C8M8px D==w/Yq#5p]t2U~o3Tnܲ$HztD"5*H`Ug34ؘR{Q\n]lډm̈́B3WSZL$Aꁛ`|#:]7|px pF0>x؄÷[{kh1E ]{]%fF-92Ow5s+>&3'+#r*.f0|͍x͙dV}`c_6}]< ~C]d^ 9S%hд~S۪$Şwx;:Zvp@LC#),TJ߹R 5tF#I)1S9`QҀIq #hr[9cݹzIi:X>-N R!7wzb u%WJ9hXB)8G׸]'ͭοpre@{i+I$aTE_} C) !Jzb" *F=KR-n kS&qq]a+_C g(&]/`k`Ź(Ҷ 4S8XfU=BS*Uֹ-[S*ٵ0&IE.j.%&?24X4afh&Dih34 $-~\&*$Hj RЌ3k Whh締A^h)s%?RjɣW͌ |*&I d x&14Q7 Q=0l~yzl(fou>VoΆ?f00_CYaFTiSG=,E?="bދ߉@4uߠE:xСkG8pgoN3OLJ侤o 7ۀIE~ў_/[k}jKtJ `ޟS~x#wRA!巋7r{,.koa¦:tY};&? fʤeڤ2#-ֹeT9y{^͒,=>Hq=1tI:cN@/;uyQQD> ZF-)ּ1<]j*cv}kQBa{}xQAOުlYT9y[ڂ/g(Awf4c˾P>zōvX}U98pC?unh]бE3ݩtRdsV919voTË6y@V @:M#l (˶g|@s"^m 񎋳mAj!>NȔ޽s4h#SH:|{K M &S{ \pR2m!0j(v1‚<䟏Ͼ=ujU]xIX6*+.Шm+8=,6sB Kx8, |=VCӴN=CO[L!;ǁ;wݲ}[~^u}%ȕ?,!V>{Ofod[g}P@.41hʴSX"։geqb.ҔFX-09yw]zq~#X儘7EfKG{ȆCEC7,ުsÏxug,٫`>{)O6#87[V%v]B\߼wהz;Be U@1B%Opͳ:V¸.)vܞg" F\ |G6r1v,^*]efyV" .8@i<[`fEfrwt>!)>9)tcUjc&]To?dtWc9xH{a.9!c4ty/kޒ"PBh uP_?*^kRRdߞص1$4x4~KϢgea1sw9:1n\GK ݀TiG^0~ @Nrlx﩮rbgWv*'xMӮ'ğ8OW="aӺ5I_vr?!7n$FJYɦT2-X{Ú7'׽%Tˊ' v.^^r@{?yX٪;G.n9MO̊߶zm=~ڻGutÞ1b+40n׾߀Ntn;O?p7OF}/ortޤrbks_<š؃KL̓Y>ZKN顿׿;fkr|]18p:ܣG&44pcEk oQɛ ϑ׏0F*'uVE1x ,sZzRjjoƸ0|#$_ڶdm1(ѧ]E hGQ4fRx#SҚ$l._F",jQ4DLjv]<9Y?H?JGJH3@Pq),]} 28{{ʈ@%~}wZT{4}2 ҧCdin1Rwq@{Ô^z Y0vNgm8n}aq~mkaF%D_1Yd+8O{z]F 1٤emd2o_#ÜIX=5O ͩr蚪(eOl!뎩X`"niVF> :yڟQ57n3 #7lV2H/O?Vΰ2=@Wx/W!z\ZpQ"7Bloh_4[LR&OK(-p{+}@߽S90f@e4(,M{&†4AsyOiQ( ѷYB IDATZưF5B0$7@h)m" #ུ 1^# @"PV #$ñV ('(/U9idFDzji/NѬ+ V<о\7ӣU"pĈ[/$/FtZ8HS S1zt JUX нotK1q~ɫknMdD4B˂VdfzLp;h^7`lE-]0I!uo/Y-z}!1<+qfKnC1M2S+cn~ACLxDe{c`ܺ$@,2iv(;NRJbfҁ]F )|;_,>xuSo5\iݲ_3LqU>#qMީ \g!0ܸ=KWpj?8p NC9Ђu-[8I<}V44x'̰r{cOߜB&Z{Rz"%Zf&1CrmL-ch[?_Q*N3Esi_W1>zZFDUT-w|Qͷ11pm4*C;~H::1=ИsHwT$),ZТk+"x`x$bYEԵ#tAfF*\l̇Ҿ lF}}bW*B9hϠ~VN!6Jv OG|h.틦U3,>r=)zR?Qg=o%C1kc!('>Ʈqp LU3avx^UUMI]gʌK//,(ӕɫSY5.}FUQꄮI~2BLA icV/B@ٺۉ0vi_\UQ _;ca銅{I@W/3X٘UHش.fۚ (/d57U[hf֣y 8 ͼm1=8pUS2ƫ%1\p"pRj_]IK: 3~]60G62\抝q"o%ejpBСcLa#ms|]Mu7Lvm 05p)+"UH`-UA^Eⴖ61 FcZF[M8?6!Z9燭xcLk=}מ@Wl0@s̟Y%P7SB՚[;镈>07 f 4`\PK[F蛊%i\mZt$QťƵ xU6VQF<_xUb J0f?#Dq>ɻBEYw0Fuo{GoDy> Cɤs:0'Y $^7˄%n$ͤ#KHE#Z "  _Uh*(S<.X&[VSkY-,<*f]SX?E"SnӸ~V26 e en4Xy/5 fIR@LQөz52#;@gӠ4)E N=_WmY% Tf}0 k'5mW.5,/:Qg"pDxi!$tG /{O בy< <^BL540TݿWn5~fn4BydQi`l]c9Ns6sǠR]rHa;KxB`aldE3 Uq$bYb@Wĺ}\xhnn~w~xJ= ;v:XuW@dz OH \]=G}r:ZB[G=u*@alOBE#u? "pNH2DDnʆ"kʵb1&A7Xíp8p8م-rkIENDB`glances-2.11.1/docs/_static/processlist-filter.png000066400000000000000000004712301315472316100221430ustar00rootroot00000000000000PNG  IHDRA[sBITOtEXtSoftwareShutterc IDATx}wUfFP@AVIX$XbbƖ1cbƎb^PPT HSzD Ôw9Ac}Y{ysRDD!"SDR"2$AD!DeJ)DBdI4"RRJ%1 OEDHψ_J)!RDX$e"Iι4MB(%"n_HHI,¿""297RQJ) 4I4e>iwK"bL'anOC)H?szx '!ۈ!ge=G9{O d1JcٚC2UK3O@@rDDJ ㌈?bn4w Qo!-TUU@cc#)~|cܷ!cA1$IBR ig "gqdG"s7X?X$R$21ws"\_ ' z !4D0? IC8gTJ" " b QDd>MzP*"fG53 "G7o\[р 6/1-#ʤR*)J)#MO^?M4CsB3rL3QY&I 08z!`,+fDp z12.I.G0=K{Rb)0yh:&1F%2p؀Ȓ$QJI) Pv08\ ϵ4 k nK>دn|J܀#@C8EDܺ5$2b]G=kUdR[PAT cz1!c)JЁIhArXƭRq )Hڕ",$2c@hR)T_(R,'"2h% o&- B! ?7*h918I! Kr;" @ 2C%sA;4,NE`}E8g*"3#mX-e odhRw=&p(h33ѯ3"Ã.SˠŴ`0 lKM"Tjb}+$yĀM>;Bd:y"?p9`FxxF-8giZ( 9{t% )%&^l,_" %LÜ?6^4QTrjb.wI p wK#*S$R _,3! <эƅsn$eZ$F^db6DL~L.ﲟ@|žd/AzM9wGan9e9 pj?ܐ֍), ݉V) 6 Vt2`8STeR)!&iSZP2 HKYedZp<+3w^fȈ!2(E)G(2-G#[ p!8ҡ"+;:pUNd68d(F0D/MQI2:7e($ -! CGٙ&AOl O3I^R9aB Ȍ`+pc P9 = ; 'D,yfrK݄sp{*{qMj~"),W*=sr/%XtA':BE.z,ZV-q+lT1ye%`)dWuzQ YH4MڌFeXH,˄.*6Qa"%]R$aI!dv1ͧ\)r&[`ŀ-K8 Dy=i67~8HR Ur!K4;1X1Ƙ&*0a4+ԈV!Z.TJAfn&DL)#$p&8 gN'"$QP`l"xsƹ &#%1<@ok\CqΕ]*s@;ESGXݒ[)9pipыgYLU]!:D 7!MAQ_r(~l! Tj/sOE*'TFG;iJVH $ + (LC<#+] m\e@GFTδ{K $MgDavs|F(= IЕybQ* $T/rGnDRJs1faѰeÇQc#!"WρLE5m~,T hpb#2]tR4;AVm% UH &F@0)䬤'Ѡx2aZfB9I((]fV= slTcjF#h&7cdz3O븍 ,8fony Ia1H0@ңCniBNzyZD6`6U:F0d ~d ȏl a(eZC$;('n0#ry󐚷D}P_ W+!2DHl"bP$fv2&H+MT0|m}hU/$ r#4H#dUSJrz*!`# .4K!2!:)m3AСR!sr-746ⰺE/56⻿ikRȶ/Sv5557~QW²RnMA% 3 (8un58T8-[OXl=g,=wnY@l^mP]HA6\#Յu>>od6THIDeO@ꫡhExf݉3!{]6z =l'/2ˊRA%v3 %qQ^VXi+;e kdF/."sUcV;A|ӓ?-Jȃip38M::WX+: VW Q*sAKMU-|OY<3W -YWb.#ځli++Tw$R l9` R8KҴ9Er`^ J~ V0(FYƆ_D' =p_\QJ)2ADizS/WiM)(b&Ld- !BJe1_hY'gNV0 @5z` yD1-&}/4k^JuJ7`TT,tpb&?sq;WYB+. r2KZhwv Ib#ܱ»6PF`34B$hI5˷v_w͏VywC~vv2=!!PFg чw:ẘ Y 07C͍? <%hX[^Ma$87kvodㅇV4_QX!D\ df+VFM)j⠶~Euu/W/0%g!j _N{kr|0pbD #lϫ_ݫ'Ϙ9ygL>cikL:OL{)S]yiꈳ::Ӧ8mƇ3fN1kY͜Ѭ~}'̘YϜ>vﱭ=iL?mʘg8y* Wd\ vh܇6(GU0H9~ʭ(  [NX]W޿m@mSp2DT^ko9{?}cZm/]ҥ2ّ}{/MեJ'X* Jq3vP @ X G~=O*|%3UB<"ϲFjh Kn> oM*PRCCXT` BEeEXJ1y:hL oI{]bȓi3 $ t  i DJJP$ҸKH YeŬؘ5 bQfBiSh {Iلa- gklCpnG=sJx([Xx*ayB(g-1FB'W~wT6%հxڧ[Zأ?ڭq^?Q.gAbȘOavQF<t&jި"tgHJRRHv/ҤGINR%qu4CDrs?`R-~PCy$$U!RdLtpԈ9q)- L}mom7q}.j_猛㪯jN f~Qฆelm)bs{+/9\6J3 /"@/?T=@Vi[uu,SV~! T"?a D~~ܮwZnt)n4;Ͼ:DT3pJ[ؠp{tρ8岁wݴǬVѢ9OG,aq2fLM JtE6 康h"X_[;qqk = @r[ZWm Jk&e}u#)@ -O4~`8Eвl|mug"3׷=0yAo5<ǺCIIl[|x"֦5"4M9RPDB[+S(uӫbac^<$Cɕl9 5G?4\H I8gTuhA$l 9ĀyWTKns$iƷCFR6$)Bo":D 7/{:al#ށ+:izC};|*[y.xb-uYOmۣ 78}e]3)o yMmvZ*=x] Jԯ7Ꭳw󪮿iU7nZvkԖ5.|kj뷬[0ӺWIpعkjjj7b@9WW?dYcÂ.OԐ5}Yl}knG>9_2tlf]euc~܂k?=>-uvoz5CDEĻ\86{EOX!k\3.hq7:ގ s@6t_跺Ma_KժyBTa޹u:ۧ zyjրЬ){.\炅{y@Epe˟y{̟No3`Vϧjݭ j_=l݆ڶo/;ɻ92y}>}M{NmO0sNOk[+h>z9S#~|Lq!^:~Te}ZC"(pdϟ3o /Z͊ SUUT??gμs.Qys͙3o޲3s̛3oyQf+/]G= ޽o ,-Yt`3  |џm_ַ=zT1ּW?GL:v vdx[t(mxw>W?ܜBιgӗ)qTUC2Sߙfr@|y IDAT>fo=壷=r %FP0BA][8onQaC˙#n~ڇ6EhW?{ǯI&5v|[ƿz`3o8qO(mw9<9~}aolo Yc&=Ǯ:7fvqߘ8!g#̇&{}QmҾWq T3/=t*{Gt#rʥh6 ; Mp[O%EaMIVTV&iJ*4Ag.m ]'9sՀ3#,˲b;2[`x"%ffŢ6 YV,ƢȲh~%Nz*%Udh.MvqBd 3AN 1' WTTTTT4I f*i ;V$3'rB[9HWձHg+)%f6*Utn&C79wjNv>D.x}^7}~?yh~ky ?,nsm_X=yM8j6[_pPqa}nvpP/z٣MXݲAܻc#>u}a1o|Ql;:⼗E968n ޽5<:y}~~>͊ԯ̛_@ٗo= v_`["z +x6tmV)d% xߎ|Z={o6[sa1 G}ۧGdNq9NiwcҲGE ][X=ƦWe.[Wܨvmyzl8|1NlvğwnSԧP}K;Ok8ciE nκlsM%?Z0M-#;dջ?>rﯪy3F-V;~嵧ob}\c;oO:!ȥyu( FuY2YQZMDڵ$L&~?{v| }zoxwo9jSm\r sjT\` ݱݱnOVگ]X 4dz/E.pi |JMu>u3h}KL^ײ)]|%_3}pĐÎ?O{u?Yf-Xӈk॔[K rv1`)D$$@LҴP(03r5R%s @HJM% 1:Đ34J=ouq qcT)v6O) .85Q'%pYn=b\RRj=ؒ˖ 9>2KFSi$ Q̊ž|9?Kt% U!hּHɬؘI1\A\wPmٹ`+ʈlg%|"c W^>z?u?ыgmہ>h /x='V>}&~'W>OsFrS6*H5CJ^ѮgG3o 撱>qzrl'rw <5LTVRF@g]}p܌)EF]6V'R4l3*<{+^k5@y~'>""q|dl oܩtحu:vqkt^|⥓?{ 7Z\5,z//^MZ?hɇ=M=7[`l٩[ˋ_Og׷V\ / b93>ɔ뗘[U—DVfwaMpZ`ңq}V4-Ѕ1"ˇ_y7؊\&wmCǮi"l}uo]~cUP f}]ȊkVd@@a.{hw/-* ط@MylvnF7Aunԅl44.)5jvIUQkAasIIeL6.tTtZРqgШlsqIo,Nq}1dTsAݎ.y!%l'4&RVK5o߱r [s |F1BNj\պcck$z36:TYDM{-ȆsVK`CUsdp?׷` _>h|)k zuj1Ђȭg.)V%F4n"mh)m?t9[ ZP(hb ab&S(׆>aWGly㇒툺tB=N(V!%O'܇8pn왔"˔7Si E3HeL)$I&n&I\dA`OJi JB4Hl֬Y$HJ|#*A8p RQUeLTkH j H)E X謁U'[u0f+Z Xo*9x&]t&;.:>=N}`?q:/ݧ/gz-x׿fimT%6wxpT>|ybtcE7DY}?$\H%v@CcuO `ª-rF@qK1HbmCp倸iICvZd++_M|s\H쐨S`pɫk]c?Sj\ywDPig@ޭ: wƫ8W%li۠F̛aLrWuУE≨f~HlZpZ3;T{r:{ t;Ul\`:Li҅zuөuۂ&UɎ <9yk0xlԷ9G@0pJ[p "vEYh@R5IiT&g ]C3D;q#/5ߙCz5jș4Q&P_`hD}~[~^_?jU5g-*~yR}@5πkEbop߀˵5D] Bq<ƨǓ@z{WO0|>uqd+,haekaق͋f=eS9 DUee-ӟncWm;G]7&-Znkwݫ^x*ػ]6uew,l{c`@Akvi0PwmU,#BD&lM'Ib L T%JU$<-Byrr( Gn7N>~9|[FM>8敉,|ܞjuЙo4G>䅫>qj'dkw6lvͫ+5;nmjZɲOk@|sޟO@ыf}htEGUq6㠰XMX6uC>l o:~KXu OGlذxi-@s=nm jyo<ѣF6iOҁk|8*b_sY眴Gu VccWB1X?!l綃n{EmvU^ếxN?ҜGA>kOw6|ח۵kkHj/S:|h [\}Y poJIӊ^e-O=i4f!Mh4\1$\(y@;u?^wq虛#rvImK\vڱc=ŅלGR>zvj>Ŵc3h:$`#K,ύ1` bSjԭ{ݻuޭn;(^Ҷ#>[]?`ꊴ `ݜog}~czSO΋ . - i`Ip0t732TX,,c}(//CDE*B8H0# H)fV=p)]X6M\S}Z`).Nm XRS'  Gx8wy5VJJzM=?M^sY,Rα -vYQ?U"5  l7 pH~qʗWqy5A/*}JuE)$ [ӠZ/:<2rixLoDsw-Ta3Plͼww=k.{|U\ww֪ͳ?ыv[C|q_n̻KtΥNlÒ?Vm=U1q[C.{xEҖ?RMن%3'<6suo {{Wz!{ 羫  iw-;ծN)RRIYZ(RE˱D~C^κ扷Д 'b2,zM "y״]7 t-kO 4D~>I@qqrt*vWDQQJ)90@ΐ*"F IDAT}}@(h#ZN|1 d{P@8Y!+TVrRiH[ɵ_M˖ht 9;kOq7]=5c"0wocWJ !t_$a9+UTT bXJrB3aANk;ԫZ9рu}Q2DYpBdH<7iG+gs9&ry4B[9#C;d}v m:; 30ۢx?6i+RtCD S % ceRM#:Ml$()=""n[!] d,8j&+u&nRQR޶+E<'(α,`Pȵ^o^VRR;u7%+ s} h9? wlAIQPȄjn_sf!%1D&iE1& PAoB95 *!'< rNtf 8_i n@9 ͤ8ќk2dP߄@w$a PEE% s?Щ' gm Bg7=EI)EB()[Tǎ# lI;5_[u:G4ytu ~0bxx$6љq$ H!$I)(r?"?R L8hh RR)3#ղڍ!HH"zHJZ[IY25j2tux} J5Bt `Ӻ>;њL :E}J$MոG ".򀶛-" dZD-= n HǠ!~u_ Vh,KAa?:nM!DeY{!X;䛐 M5Z{إ3S۸ 8!tw17\s ο}vSǶK 8TlqC04a>dJmNU%% x6MP7u#h(E:9gIꩪq*0pJ]mm]m͛lŢ V0kU6nZOZR}dU=O⯶liwŶ6VUE@ $DAGsN#E H(IAr3wwQ<{8лjwĞsGrMl/lɂ]sd7wŏ ]&{;UY`h rB󐬃.XxfIs2\|F"R^VVV̮ٗR @>r򢹋 _C'-xф/;W]aK弩{ RFqiϮU=׬ȵbZ7/*މD;^te :*,=Ab6Q}h߱I0.z@΄,#n~ZxmgD ;&H[UZ`a .hR.B! '"Zi'|a #G(}"jK'g| ]6qm+{RM*HOL4ӂw/+AQ0fsؓ9rv.4 _w[\fCo{,ĭL1z]EX3Z u-V >.-.I|4A t xG%d pӬ)v'25JC+Ttw /pYwV^,\rm~gEvH2YDfqiKJ#B0SjO miE0^ɻy\weegqN\A\jd'>( C>θy/&"e~3]iOZySofa/'Yr_]NxD~f_ǽdz>ڬ{I;(s m2'U])) \zuzT VhiSK41Xܜ'~&;o>ϴeUUY]d"0Nj/G1yؐ%'+mŐ!pN;*٬,-^4R e3"IRHso}n޷\И/ xĺ4yR&fdR1ME{g3^?BJTbFAQ_s'?1St9<)oV踎h]4exaR+r!>㈌?9hͫ\<%+NUl6GӎU}$%$D&?gKaYq&퇪DDVv=p:f%@*L&$pcƲ1'|E(c'|=$Ѳh-;`y>gQX~ {ъ=ZR_1Y=RJnDXD#RvO9QazwNCଏ^pk'DƑ1rĞ@V J=ek 1:nQe1Gy'N@TBO ;"sG  p.l֬I,Ht {-cJ8ݥeK U]*k^ŅթTi8p,F?sm_M36>V^԰-\[HtI\bE|FO|o?0-NR1 IJli8`+?hg[dz}}1%bϙ:JHl̔W^6yػ-Ӭayz!Wo[ߞ`9- YTpټ9_\c\yϝ]oKV:~㫦l-۾Y +4р61o@Y0pG!lY ?k:ee& +vr΄{%YCOO*t5wsw>s͟3+O~SG^#qldW!)MJ!#UȪӖ]엩c^[m_i툓Wy܂IݴNrPY[Ue3;˩6,jtrv6X)[1vM]4{ٲɣ_QWonߞ5oyGt(Hafwų}ĕ)1xWKM]<{)|ھqXz׼8|Y|7NurK^A3~~m~`֒ w]2k.fo̘de]^^5hYM8j \pG,9ǻUH@~qN=kvn^ˇNs{c&L1C92{!+0̭!fM=g/ti M7S4rִ_>\+3psΝgu>?o#Nf/M6wCZgYeYMx1'?f)s~-*yk_2맙3L%UgσfXY%Z>w^WD9X:뫾m*z8]uf X4v1c*RMo}몥?{m%Wu’)o<3\}Zb~|=fw8mߏ&/[%3F>֩z"J4sm;yv{,ܛüE/(+"bg\G?,\׹? Ӷ$5>vYG=ޱB36n_\S>/e6exO#b^ǾhO,%|K$J+v|1?])]:ׄO>^PUh[- ʼnz;;)!lyւд=a[7=1 <0ukNy֤bd 7/ N025'dZ/V~ë6AZjZ`])"`߯kkXH ʩvUJ\fAJrO5-m}AλcPݺnzzש9u`{v96V]pEQ &#ɍ+ThqNi+3t<)x+.dž]^Oz8}/_iׯW|tt-DwPDQ8 {p jwƵk{tzWS JlycW]E6ॶ3@o ,1UN '7,ۛ@.xFg33if0Glw\~o#-C5۾۟ZV͚jzZԥKO|yz6*P9gjX_g5;O}qUcƏxᄍǝCV7zd=]~(eX.ksI4s~ yzꥻmݯ}d6ϾѣO˷y;J-55QB})tW/pY=<\/qUۆvq@َ.E'Y~knwt匿>Vz%˅/=uͬ+=o{>fϷWAlV/wʁ`3_|q s{]rqH3Um~[n'SJryu_mxg>4Qŝo? 2f|!,D O3 >U}a=xR['U)ѸEhtj?Ə>]{ջwu7g%+UW}wp=ֽ?vyz@"p,:>+ڵ Eѫv݃f/%}dkm~W^y:ٞ'*k.k};Gٰ:/SKmF5񇝅 S B) S RAJT:SNh-ݍ5oq-׮jf_X|RܤB@ ԔPL]ws`߆y$Mh~a[O-}첋oqq;$,BF#?8Rk2>sN̞9%lye=;PA>X^zQ}7EoMToT>aK Xr\0LRBh<2*Ȱإc$?3eDʵ~ rs{'|N9W& 8c$I?\e3m3"z%yW7X?uѢ)kt;(%^GFܿ};Az6 8|45{?_,ݾwdPśRW< I:`q]|)!f/:1}ĒC2 ckUx2=0yɊprQ4mP۲{C~(z|hɬs _&nKiPw":R/zutVzqH2eٳc҉#ǬKQ:-&lJ`Oh޽E)PN45fl=KVʇ up' 2z Sڶ9WO4pYnkͷ r g(Z)붬כut-qI7E4?jس|={wlZ>1"״탏_s[v+py<(eũwveS^4v鶝U:±Tk+37\' i$ɿmG}oԴOʹLG9 ]X=xwn}V'.8@Yte+lZz{Ilݻk/GnJ4jV5AS Ą&dUGC`?Z? 7 ߷ݳa#7 V9=ZW DN&XDG} ?yC_ع״5m3pf_Ӓ]vN=9ͪ}ӭ w 7sͬ~H݉iLX$]?tESOTOU!2s'Oq~kuwĤgdm+vZi}dTf.?$!FɁSs3jCu77.ۺw?Nkx O>{ *$"iVJ3B}G*@ 0@AjABB0%J 0LT ԉ?>{~]mʩÇjܼaP]>)DB1W(B$ 6MuvFAJרs¹?qRUkvUl o]e?Z6 7.9Pqdzy `ph""*:D^e*#56ӖfmO9)T>b ;{f>=M['@g4ab9e+2KûK2/Qt3w;Vq_ӣOk/WZVk|GˈcFl+P?Y Ȱ( T (D/gn㑇{wz^<: EV^zNZ;d˩M>\V׾U}QfK]a~k.½(Ӯ{ҳ7u}nw71ϊAü;벽E١+ط~ & o.= 8}l.[)޸FnV#ts՞)r(Xz cKTW_a(W_#\{;@u\E+ RBcȹ.&.-64BONF̸<_kX^܈"BdhJT,N9"7`}ܹaia. h*ek$A!d[#\3wG`5W7dGNXxn`헻 vH$P7d~@XQ.O@BcNm$RIBHx$~/Np) @,ߠzFK#0ܺή|{G=]4 >퇾}煫?[1ƶ'+;zxx큁_=P|!>ᲇokE~wA5 HNS$)H`gM}םXIyYڎp(boW%"C^s^}6ɬ&vn:֯H'd& $!Ϲav*$'mYdll#wY R"l([z}w04q RҔQS-ݛ2lGaJ!!lΑY6 (Y|8Mա亮RqT$Gk8 #PoqrˋZhuywn֭ߙxAaFkA؆ȯ "Zn4-s>8&3ߒ-GD'bq$2DQCL0QɩEm{{-z$L~r?Ŀ*b'4u}n^|l֣{?>j*\ѥejs$X?rbU L9fM{Ԭ+OK!T=طL%=E6@DOPX7ED36J,=Ǝa.2d@{c1t c- HD<3&141;(||'oyhé>2Dm'<.э.Z;iv\tijzAebkWXj/+?֪eѲy36>mu' $f3)bbquv}"́Bsg| 2aLGNG/s s .o_?Ϙ1cΚru**e1@ l|rN5{l3yJ Xvw_T9ѭ@Nl4u-A4PZJH]>DR4kA'wq4a#ŮO?'o÷_/t4Uoo; Id`i'ؿt6:w/gOA<2̫ؠJTnP Zyڕ7^{Ki^'ɭjҬ4*5UΩD{6>%WRX\zUR5V=k\9zQR un:4iJٲ@s@obê5(j@K2 Gr+V(!(0vqʪzv6Ug' 8Ȑ<5,q9TNnSBs !?M5 6\[Ȭu/{l^ԠjBD:n/%uyKZt&jjuҲ%Qs(B= RMP?,. B!D*a`m9gȫDJTi]ÿg )8g(@_"0oeR!""c~V]lЮÕ~F֕J5?wuwT:M)+v]v`Eݽəvp/߮>~njJ~v"g6¨`5v%FUw_٤v k_ءiu{hs{>p9gѠcލS|_f+C[avQ"+P^3w]Rj /wptإ%zae<7+`:UgrFe|DN(kpڂvŵrkqU#oۋ5ڶ8D^\rN:>9 OS@gY5:4ϫz[V)?_ݦQjdV*=88={y y'/ Z=襴tUţdj888g'd^gUYzW .Ɩٛ]_%6-ݙBfsgQ7,!}bp74YHI ~WޒR Rc,/7H<p!IY9</#;1bȀj޽17ngD(aۊ㷄Ư_6 IDATN+W^o~.qju2W*ЎqFQ?}(c|@I\4Twщog5pbA^_vD!N}K_}a/~MouBElY=2ydA>ْb+}~UNlo8 (q̇ᗾܨ/[Rǻ+}тvO JڴlC_ң~_o_uM"WGdGzrrcGw.;r]ճ&UOt8~~O}1W~}A'|;k$mt!̎給/9cGv.;r}k?/Z瓟Wz`~ݣ>`Ӱ|'cx{~/K}k~h`xl{/&>vtג_mhyS{㛦Ͽ2q̽2]~ܫfG_*/=sfƦVÌ1$n;C'sp~#L!{dE? zēM,%.S>f಑}O' ~k_xu5f{f l|:wpr9E+޹SLSF=HJrdB/ww.` .V'пCЦ_}~@ɧTJJ }S_7uU/\~ˏ(-T6DžIQ'#4s oրJ{p5{1?}OWD "2pe0Fn_msǮL\l%N{uMJ:'|~{%A?5ySz텫޽Ѣ^|Hڴt9Om[ Zힱ)ʹkEj|ϋyhsBD ҾR8͔\՜ 8g{@AA*mZI!Mi*NF } ~BC?K!T{mZ!CIĜ M)knNYD<_yt)FpjPBPa^]bIS% F18{4pMMRYu/TLFʹC{69 DNǰsy$RXq ORUz;{>7}XiOg2Z ##Ni :Y̘V@csJbVzB>I+b JT["e>6zTT@RCy|W@:[c]e4?أ#HaH,1(^poKB=DJϪ\~g N#j̀)9%nly&qL5#avxm<~YojcfN:Axd:1xaD>f5HRGňǬZ(i wź`ȚAÿ3㧷Vs?v$ IBm"璨!z9ŷ]ǴgtzaUn?\َ"`́ؑ-c Cθ ld5cIB =aXL*9f1<ru<)_xXVvv"Pjr0Ƒ&X)O ͐PUv Lj =b{o2FOm1gP1p Ph6SnhQRB!.)S}i]J"tPq$D T 4E*YI@HxVn2YP6!UPg8 ?r彨E{"Xڠ~I8rVUT]tSq4`F )M>9瞧 "CA㝖 K a!"_:7fcaF-yͶkJu GHh3PdžsG$9&oVf喽ᜃaj]s`%*8m`U"$Hi>11vYi1+} jogT^2>l'V64qԍ/)hfs|wEOQ$64Y"uZ;0tB'c?j3g1BKVYGJ,ialuDq@A 7hFHc8vMriq Ŏv2!2IJ|G#8UNcɒ]WAXb/%Յ9CP4PD0v,-ʉڂD-_ۙ"0):VTA&_S׏oR\ mT]8lI}4_s0d"\ qЕg+bXi`rrs1LZL!dP*<ӧa"I$=ƕX4 Ё-lUs!D썄0Q+zQ]'ommo@SD`:%iݩ(ICVqA$q+H(A!=F#'tk޸-F)dSSciXd'ۃT e\MD:f?L"85pᖢLEyCL${Aq+{]1O>K&0*@R PZc<.m3q<9)snm#Ab R0 49HbTO\;"c\yĔlKhp:1!bQssc2<*Fv3&p {Cᒧ/da`Rrcv|iISkd\$zAEu#H7wU * 4a(.EORyZ:{ FEB9݄"$U7VL-[0 zI ';nHڝE9l7Edl){gQ|)D:d4##p",¾291qWbQ5.>,v<*1)!yUomW[q0D bEbj`eee ב= )8Lo}hGefh\tRZ-ɤb'%Ru&v8sUt0 =uEW" S"Ƹ**\Ո 8/#R 2F@TĎmud<`33c u wC3:*QLF-nz3Rr<mbU.yLsR$eRK RBCq832DFڙwm#{MuZd;2䢘9r:i1bٮ1xX豸#(!AJ V"$E#e:ۡ㉁CVCȉ\5ӣVF n"S}"t=WyR+qT! [RJDPPU!R*4)$\pRJΘ:*93NJG[G8aS䛊~!%2D&V,UC!hn6APm-ԣJ¹3\wpnDq\&Zws]ZK$8tMRF5K6!Ca(!7F(NG%/#E\ZuXTbp lWHT4{3?R&%cW:،L|}w;FJ8;M/Ѐcn+1xj=KȯG(@8<8(xYw_p4e+ G=s?z}'7ysI;+ "4X" )Ô45FЪR0;;;;;ĉ$%LbD Q# {KK2 L?/" !Lo %M) jaBaHmkP_P2-AU5l;;J̸!T g% #ӈ>[toa)y1_3"v$^RVYed۴ Xꅬ1?"c@ 3S6E?\)C1UZqyPsSxQYSz2EY*Piw0XX P(**BeT#fa 8|T%9c(j6O PJ= P#"%_ )ՠV"a%Y"ȉI~@v6$ILpwXHlo+'h@[tI!C]8r;Ҷ#rxI>;i"ЌML{&,&%j%a;$Utq^搒yA"Y0L98/RsBB g2Y$9!flu<55*u$I[ԃkc&tբEȜ[vȕF1>VUuԨE3â *:,@kJ&Z#~mzZ6HR "sn۸YLQIR@S;SL~.1~2jZtӵ/:c+L+E:MҎ{tn=C>1JD2Ii/4tLܰc%9r t.G9Ji@ #HKn@#DZA, #А3sDf:f!ǞbǐK.4hPZ\W 9?-0SQ)gJ/)L }!B }2%s&QaH"}`* B))Uil3C wk1ӝhR4H((mS%!ÑQĔ6bqIɠ?U9zB $ȕNNl\H &9Z&GXmK)B$θ1R)2m}"}GBZ@+ ɐ)')+C)eBvψϐTJOfA zGʯ<0Nj&I9, d(8~·ۚ z)^ 0djȆ.ʆ G p#\0{B3rrI6 %pRb!dBIiTpj(g/8H}L#49[}hq sMCkޡ+U$зA@i!-$Z{@%pl{TKYD&te`mןRR/EC#Z #qdCO9s>2$IęMxIZd@58[әWHѢ e-d!x)Q'j,F IG. FMER$:z~y8TQB[)'?DW:/ՀFlHY;E'' cLBPI+] ?QPӂ9a- )sPN!NΧQVAK5 B)Gqixf`ҩdI2aHSӇJ[_v!;"bS&/bq/B+?k^g L~"# JMFԞF#B!)Y(Bp8y,,VRY٫nCW7p`@ bO%=tC:T*0(M 8ܤUZ旛CHKLS;mTՆ!sk#-&l#dޘ$$9S\(fVx+럨b>ͯ,rc*,}JnXHJ&PX(B 3,yĴ-Z@TN<8L r{U{Hi\[>C-#J#7=*U̦jw@뎤0 cc8W]Raa4"t]A<B]̵.%SRy}) O3IUkD[ !!zԘ0E.jQ aZ D΢jdG%6`]Mu884aѳ@|%cZ( iTGPK"8bmqUIg>ڈIS%D;= 7XP|U  TzѺmE\i7Ҫ41"imcinQQ dOfaRJ#69 <.d 4 0B[sKŐfÅ1 Z'S2D ڵE"Y, p0krysA tz3p jH7%fD,6ct+foԝmoڹЗYWɡFwk;c pJvIÎ&4 cgҡ{WE{ Lם(?ks}aY)R*S|Al'R\JM yCȸq B=56j !!=sk/pf>)7 = E & Ҥz&K "MRBH#=$%)^Yk>''ޛs޳g_U~̐~n0!(@  ԧ: 9) j,.L E&=J+U(.0q0Xg9ˢMK gw$" ʹ@8?sMsIc߉7\I'$| @Lcj*1Vtj{pxQ1|%Ѣq*MVJF0BHd,h)aR$"*0U۔\L 6Z`߉M(O <d|%1Wb F(@td CBCHVke6$t1d.B,u~ܕPk`mi4Fxw2-I2e" W$3[cn !Hvx4*! Ӱ `uSp@7'3OL; ?_FHTz&nje!ݖJ`cd[XlT7Pa҆ ^OZ|EVj ThzƓ,<ϡVhL9 -[P6+YF[<B2߆c98odsB>&"b{E yYKg>YYe1#036$)`nK`ş@ QXo,#hV\(U) 5Jk<]bLs'6@WҠV #lOItxv]/JgnY&4`M y1K2zغuQP$p)0!8N[t -BER0%(i%[ IHioMsd lw<px7޷ YY"d2B Sا)4 .PcPc, Y~bvEF?Pc SB?6R8걉Rk #9*)vy;2dQHi}YPf!^H ] ! d,[檗YhH[; ح%d@͓)}[)"Q*s ks򑔹O}WdU EGDmDf!b]J %`JԠ0[4OP°"(`D28۪uw#vjڮRԩSZ]z 91p*\RJac33&3G#0)8`7mсJNhl{$8z&v]a7y~ .8AZ?9 ǂYEpxh>[]snIB}ʝ`Ljv>$%Ip^O GLa:!Sh dڐKtT"!9Օz2ۣ Lǝ.7R &c&t] 1}<؈M{GPO nS~u`Ɠo!Zǯ{1c2Ϭu-Riء20ZHK"8tY$RB圸Ed(fjͣIl} L->*6r$|? 3يA!8:xQV6yUcTj[t'#Kai2F(lMeE@2~@I)3 * (e3$9!9EUU*d,'j# *ٍ a7#GdP0:OTLE`\;k_<2}pv^hW1&ħ,F<`d|P2K#(xHQ҅Rhrt|Dz~|~['?x06HUb=9zk#:]"48d2!vQ 7Gݣ<*μ\Fѐ#R|ż ::$WяLf AsO}1u[cnNK/Ě1ďn+BHDL,8ZMCΘ :#h8^!4iϙq&"O8#QUWna)e]DMx[Wih]ZN4IHj]DÑ+&U؉Sajh`멟H4Q,)hDMG5}Z74Kz뒆CW= uWؾCjY<+UZkxJIIZK5^|X&l cଇ@RHDDe@ I"B։УWxnHkmu4҈ Nhؘq}RZkeK:4DPY7yO-T ovAd NA.XRJk°ndZFʱjs!06I:Es nTHMF&ys # e{--u:FX^Pw:?ÇkPMy n1ź;D){+4>O.!B g+4M@6ٹȐ2u'U(G/="H]m8Z) Kys T)SOx̧7XRJ# YyfqcDʤ̲\fEЋozB9,( e)Rfs*Th#T*S<=u~HǪ;"eY9 X˖;o V9߂sqV/v.X& b%_SOVO#ֿV!QT 6C.d|=Mh4`EG{\%@DO%H,*p|u o`c Q;vǛDۜl(ڠ«}]SxB$2Fs(PBX!B% ؋YrR Zˋa{v^W{C)T;ɾB&lXBm"^*+P󡎪uqlK( "D1 ˚ E=ctiC"a)1MlMofX7f}m<R6SnTx,]INN]\ 8kq%BboT'q jjh5b̴&QѰ>qG’fC Ƙv!z[˨aށl;,e&Ɩg\:2dL(*Je@ qZ Y° TXUR*jBfafAa=ǐ@qb*i1TQ+BK8nI7==-l6RV3 V "Zk mT1:d-ȢB+͡U1D`¦%!dY.Pw J+U0 ~@ϔ,"N" {8K:{2`Fuz??K fX삍!@ٸޞL<ʲLfR(1)H)C^j!i$,sw-pmy f~hEu7D%R<_4 ֝V.)r/VKu\TkeE"Y8J7FpR֖�Ot;yTGIDH%èU3so|ȆmRZ+HssaXpo vO#6Ȳv(J CD 'HenfeRH;@NwhX$@cVhPVt;I4FD$$@K@>oLUJ*Ju i V-98}#$'b$&Qv2Nd3Kz91dMO; `I+e_2u)~{M务D"qYߓѦk( !g|?'N$#!6P" `e9~*˼-{Q- U(b,f("cXNfwK(S$õiZB+eB\wJ)Uء}{{JOA66Li'LdBPvǃ!"Dc(pd=mx`Ue ρ ɖe :t}JZgVߧHY&i\ (#7( x,[X60ԫ\E\á`o s `R ш`ʃyDy;o^V q;BXuea9Fշƶ"FgdfBE}B-JbY|0J#}<@&2*DeƄS؃($5,쁂kb|y%C$4pp@ 0&Ƈ1vMA`ⱓZL 鞫Ѽd ѶbU\CX[%F!@јSwb>j8VfBr~H2ˠPPdcVH~~`WWXo|$k~C FH]Cx_+w``3PD1DeSŒz$EР[cHʽvئ((!cZZZؤB"Y᧥FR,֮56" -q~DrJ !h \ Y [[XzJ3?F)*-a?vM :J$J)]iX؈3B\L}!kŲY,6O&.TF 'd&Դ?ÕH&`4v5%t)5[PH!$ZF!Zմ`]7?DOGfpHH&v*[9ʪ Xen'DuZkC$ &C TՂd ZZkF뽵PEO| IDAT;4i(r*@S*[kH!HRShsFy5Ǥ8̽w}%;蠎rѱ18fgPbHpr4ikL-TxjhaɆe-A߃iFR$2Uw>@6lM0Ds(>IFXH=]-4[)'H&>boF Olȫ^_ >𿷀zX/+x0dI3!!>uC猩i = cdkNfZA-i[ 0"j) GqVZ2Ev~ZxS`c; [Z!D U(kD(UE9e>5L E2BHVGY T1St k^q=;igņ2J:#&KAͮ3 \QZc=K5VŐL=Vϕpb%pA4AM\;<̂*`o.ME>OmxPJ{ GXŀ`ZzV衉}"^,dϜ0 JșFE0`Qd]95b;yc53dq1.SJ!exd4H*pv*lg7;ӈr0F2˴Y,'@G͓9u=$gLfh "v⍕"6ט;#[gB6CrhKc0g,?d`  2Jk;g}f2yN=歫PU3"NXi!Fv]byQ9/g$%X:(0 D;}M0AiFf(?uiHmiQ D67pi%]m1b9֭3W*۷Vyn" "Np@ō}0Q+|j\_v˯֙g:S-h e8@DAZY3PE5y|kLrHT\31 h봳l 8X( r;wcl hj0B!y~_ ƾQ`%"Bi#0(H!13:,}=HA*pV3?gk]9\q+6v!]^/]kKu^M 68mkWZbE%FȷVZowW,[rѳ._:o'l'mY{i(]D ɮ|ޖh|K0tĦG<=d؈gAG>a#n9 beۋ7b>s# vc3t{nYnQM}awouaW< O?=+,lqF0r'#Ǎ1j#9f#MϘ_yvRJb'2z}& j"2svޭ6Kh ic'Ht;Ac^`%F<׫'9pȁ#G9r8 il^>׏4쭷uݑ]+hȕ9umG/Meubpϐ! С{?!7<Ȼ;x/w?t"ٰ.J\cA1 |gw |}gy1o.hvS,c\D7Ӈuz(2)N==d/h"|XDepBMMM:tZWU< Q6~گ~џ09q <5+7GZf(̓܉a?glA5+zfxEQ0!dVYk-p(j9ؒVKPs<˲8P~V\ >Ǭ(ct_]xۤ[~ݺH[gSijHac:=0ImwϿw,>ԴM]׬!W媧m՞_y3;r/7v* , ήly\nmn`=<[ j):\gR+^R!P.9us~vw,>H00<6[~:JƖV_€5Mh#m„+Kf~]:v#V(+[ 8%tX,?4wѩ/ktv`WTJ^V"`tOynyyUOM=60..,hYG?k'zG!+ҭ>;Ey,3FC7:37 I2дɷ쒣wWM{ɟP}zg5y3O/:s~({,><0Bر_>Ձ+`<YP9Ui-v8d&"; >y5.YW6CRkx^F3T10{}u97Fbb `v?-B)MjM؏N%Y8sSC)Dui.Z$r B]mS;9Kx{%.UzPm ɮ{n$iƣ4D (]7/QK*rB1gݷlEM*?omX?^Mqw7SϭEou{.z[v Lc?<=Nufw+)Ԓ)+:tԴ]l+vr DTJhc}OV>;l5T HJId8Cw:||-Pe혉iqiN>r76M8觗繧[nqI;dLބzCsU~󠯜pW#ON8FnonݧK&eh=9Gt͞!{܍޽:7;Glg+Qa. ^U~g+@JvtJkW*ժ1ƚt`)m]IZSL0)0 uy`'D$D0[`QU6ΰ#rWj8D0AotNv`1_ro ƻM`-S\o_Kh |zIy oOi'Å#.c2DHu0[šwbыR"iOw ~Oqjo=/VQݎc)4)TA&뾻maw&?TA᏿osw[5f )0Q2lYdQށ@uoZ9 |#m[<Ū=47jtÎ QO< |o h{BTRĘi`[W%EۋPlٝA8l9X{Dc_ۿs syRo)'|p1}7Gksh5F06icB|!u6鷑x*\[0xXg?:C @o0?7q.>ϫ 0^Xץ PSjw9/=p_??LG6z7fsX0{u|w tHgHmuȤh%t6]w7.Mi gQ~SNfdE֛LY,;m,':mV8(N[lѾX4g9XBqMg+4QGo;v,B1ȉk}4at'rRa`VpXʤ7"c;fo-,t*$=( fj?G G%yI,Qy$\hcad ^%_ҽiMlI)3j+7Ыo{The٧Ɛ Omd/_ 0_ժQ\شVUYϞ?mq?k.:zq?ޱKIvicx_#A,J?0t?-w/_Ҕ'ŏ"ޓr7'I}J!5pG;]d߭"r'WmGN;+O&:| id(W@`rIi`魢㑏嚉 M-0;OA2VNC_.-MU{g}~GN?ߏϺkrc6Llc|F$~qY)M_ 7-~su[1iɄfNm9&$%{9B0ud8}^rH ꄟQҊsj=m+}>{pڵ?~A' @Db񋠏 0JQ1A?nx9g`K瘯xp3xV̨e~Wmco 3xqri5l['wݣ:oc/|突7g8j c>|[BNxg^@d|We6-6[ni}ԾuN[z֪u J6|֗_:jؘ>#9nFNِPubkxo1iIem7RѪjm@);IiZ&2m *s7NgM ,#zS]SJM_PO]Zk|hR<8vl%!TM{~j p#wאG:4FR\M)u2`6%"fV(Za eY&sQH UՅѼE۷7zG"=cg2h ئDcgbJX2u {me 5\W:Iκ>{ܮUtc<ʯ_ܧ/uGs.*;{,)K@ { j)[BHow*2My?sMޯ>yzllƻ}kS IDATߗ o'cB7*{mjJJ8@Z9{z-nמ'k!J? ;s'>ġHDJ+FGmNZ9]b ՊYӛ?omvso?9z`2 Y6xfOO7\p-4 CMT ^]Pࡉkj]JG|diEǣ٥kX9ohƴVD]VԔ)t\ B[AOm߽s;ɱ+gNbr rPfR W[[{Na c;FkI^ !.]]ڦ| ItO?G'>a/4ԑul7zg߻s~}Ot1 P@P (uҷq4LN>-0tF ѫfOoC5YEB'U/%P4úIlئ3OVg?| .^—NtMx&hݷ?x:'O}?<9!q;apF2˥jQ헎:XwXܖVPmp^ _9n+l᳎>_紣;?-jm!K&7&f¶|]Z(N#0ZiU(㤕ʀi?6PO~}nxeC(:|RɋYR@@ @+ p]h`QvwX!Q(-'2s Ha~ΨRT -k =GCP/w!Ee̬ R* H( 7`Cw\ԤY.͢Zyn@VSKCTuH1'~c/Q( AS߼oW*+<¸JGNk]+ ΀Bj@mͯ̽;Dg>JxLe.ۘrU`"GiZO8CFS8 5~TK#dںx*إm(O:kǸ!rY|1msjW٨'9ߑZ>Z@ jiS}PgMm:yοmc7HpWu}eW]<۸gT,N܋_]Q4p񒉙GgY֮}{@Pb"Vg֚ճlv~8iʪUS'ں=uYv=n̂Y᭖5}n7j_;lJ8>Js̪?Q;WrB kndRJunMksg,A3Nn*1( )}7yiUl]6p-@T %SMwج"̳ԵXaUmY@ZIaΝ+J&dsS?@[УKd[՝W;s~>_{وזR:kLTZG9ȬNZj3g)^V#>HhGza? ^wO@Abomї_.V<+u)2jrjw*/YgE"S| Do۽iN;uL ݷEl]y }~S $B0bƇ[/5펽r?Ž[㖾;`乫;t'w_Ŝc[u׶VՖϚ'5k~v!zuQc%C #fcx";T!,0BbkS,S?ӷ\vjzt NkZOVU(Vq9byAca}K@V Jh}ɇ|ghIc‘x5vݚ:n mӪTi;V'Y:s֒ \ }= ^Zme_~ٵ?/M{+.\zв&Zc`mG=DJvBv]c Pƹq'/k:vg3ڝc b/8޿r-rw8킃W UMa3ch^]pAUx7@8+[~g-4wO%dhc2KF<꺛9[IJb6J80lI^)3 9,vgw600(J l-mIiY(D܃@@00@wpd;RjU+$%F#J.dHM~FX(Q_yY`l%%>l1>whλ:en]/?2'y#Z3']Sڼ=}k~9,iiO]q ‡?+s# }.20׿8@ی|uî~/ m[IE9.ܬ?u11gZu.{i O֣/:LZ2uvo?=xx)mVF3jK^OZ8l_捜ᜋo;oKlfw~7>_ϝ|#m)ɵa#JS^;c)%-qz^4C{]^a=^O.X 0Ac:K8jX挣{oqgSǷN MKufŤ>pwcfy@d22)B˜2z5!6i=el<`ᔥ +=WNx6H5P/]>yM¬~<> Ec\k/} EuɤOjV{nLw] >;R;`~5p &wISFI7pJ~43/`{ P֣$nu: F;|.懂+_]bNŎaa&-Q @`6JǙ|poe$K ;uqcS2 2İW9 yhexCքoPhr\|0 4d6%dEgiiسD;sFe&덼)_"8vN}L#o)iPQR]r*?`hMnxů/Q42,2}h-w9Rk7`N荥IhX&c c( Ǵ?(.ͧ8( >ڧc"I0m $[$# 9@R&K];Oq XD>Ѕ1:P JZ 6)rŰ"LddyU۪jQK=a& i&%|ޘȻ!.c`6\zp A}T9H8 6A:KP8*aDdLX' D˂P|D"k̉zh78u|̋bFIU߮XGt:GrcALl#X(?*ЄtH)",vΨ3^z3QD_m+cyd2(2$p[cZ`$lvϬu^N6/3m#r[b"n4a7xpS:O6D0.KBi@Jٮ}{ SGH\v\W/zQ;џ a&T/X70R&jq-nwDC A]jFʢExťٺg@>97FIfQKIkw\j+d.y"opRqzŅ!v4^`y`3I(yg1Vj2ȁQYn$ )ZQF1CEY/۷Ra!ȒoVXLX*'F(q5Фhzfr n獋dqB@wS) BY>wu4'0قQpySq PpB"!>NR%bGj5bx&+"NmdCEM/]Id \5c>h "mK,ϫMm}@D2<lwa˨ʋمA-HN,q#?IRJ;+lĔå1M1AuD'j'1%2s# ]McusK @0I iVѦÁ1CٟF;ە8 <ϵR@Ē%PcAd*#n+3M=9Q^+#0aƘ&dΡ)&8)!&ʰ 18Zq> Qvmc^5$!XahD#|꺟߽7mA.Q 2BM#xXnzf+85xbKaUȰE#5op#G,4eQ^SiT@rs<l (bDaOZNCt3($ORd|<60z=)e^ɅZMY1;O$KCmE$Id}$4t"QTPqp`!%T2kJ.$0Č1Ao=ʈ0Cv} ȸoDnä0 {b־sA$wTUb tG;dl"Rl޳Ð[FZkjmsN}РY}ݤ>+ŪAm(E((7pNlgx(1'o!C.&BoSZ!-:LV)(ȸښe8"-?BƭED ֋4 q( "Aq 'k4y)rmRJpH %o XSܙ)P* kF$'.`WLwj[ɊAr#$nJ!!ҮLPCO8տU"vs}=ě?gE6VULrHRD92"(QQD,&3bDQQD "9 03Lݵzw. ޻j{݁|\-!V:3pJ- 0PRYLYRKqU: D蛕`1Ş*rZP Bw~fHT8*%6Fm=q Pml9`":\0.LQ §۴/ȷiDBHp7`HZe A6Q`waz{8 eab鑱ڼSE`++ "'B 7s]Ge0)!#?(++g,3Ȗq2Y8cOn"ÆDT-k{3e E a7VJE9d(HB. 5Ʉ_MmI)!4 "OJPn +CGnlGrt90m-U*ѱD"%h @u!8|O{yĐ>ux1!2 A-+D u \M_<& /)˕Ƿ?IBpUUTp.HhcDBn(LZӱ:@1|?^2d=@@sMIUW.f! ,VBKYgF6tdS>QlM#zP@Lٯ9 Ce:K!TxȃA2-WYI`rTe^j60 DrOBSF0bրM*׽N".L֚M&!  A(6'k-9j$57 >4 DdșVC{Omb%>E)2jq}rS.kR)2JLl0;tfM@XZԤC@ѕ"- +-MI -'+1L)yG̀[g.j9 |@oSA {EqS,A [BUPgy0mrcX9K+oFtt IDATN(/ g2҄C.9.G@!gA*Nm!hBܢ3:a$У kУAL,¡ BDںlIA "|I9eT h?#yAu];ҎT?ָfzt{hz=(It/-0X̡@j$%8^y 7K*-*.X4qBFsg"e^}9be5 {ԆX;qv'kN ^IpBHzLJ_I6$38"p(-SE &>V`^( |>WㅁUHef:0yԕ朩@f3 f%If3D j%dYIhid`r *[sWc >F5pDt^uf,b`91z->kZ)˖^l٣Z9:Z߃"g]6MaʠZia.rb+Bsdk>HZbe7h?Q?hKIZg41*-tH] , r;-;<+YDAxKB1i PGQp$bw'k"ƕ m:w$׍y$Smь$%@'QÙ4ew y 4^=zG/w N@DqbbInpW[R`^p]Ǎre98٥VZrx—y+>]?ߑԨߜ_oȬz;K_*Dd)톼\lBd r)h<|OzՒ"x%߲$||{N-\|ƞ$j%H" ɤ>!ܘ-ގIk)O̞֧2Iì&qq} 1cv#蘼Xf]9Đ,cB.+*z>^S;y9_L.-ǐ`gkUmoG5Zgџt0K |?1ᕃRd 56SXRK&z(\kwc`h $WߐѼgm֊PI'{V"c{=WtjZ݁ëzs{DM7Zb yͣ9cTV?=mqOFoYT[/R/,O}qBa* R tѻ8f5䇑j6/ ξ]>,kp٘ cuʄc͙s?$ڪ 촺 g0ead?NrC>Β `,|YVQrn{5>2\tgW:=+=<~o8n@cPs`\p{@*!g7^n_UϾ3MGˊJCmDɎEqkߨ4 %QCȪqӷNnWRl!> !+@yi?9[oϮzՋN;zHis9"1 oS51Uj:/rO)SL.yBje <_T<_4Y] "#)SiYI-sc{2"!#jug/:Wjn*ʳgJHG`NjOd L#[?fh HaA,ejDڼK^/g+ʉ#A(Dȫ_e+!d.)H0JؚY?y4?6=ysoP?kԣ[YϿ-k|O~{mOy ^F0x_xѺNydȊXսmMDTmC<9x8cZ(qq -km>x\_WQ~yʼn9`88 N1җ1^OVAMI.8]GδtR7gEQwִ:f39RDo}Tݘ~kӸS_11lZ_OO>mķ4V.y,֕7&[th0vWFF.D9x.#GD@ɉ e-ԖfWLKi4@i2虧z_s~8>S 9;iÂOet8z0`h0&Em o%TAVizr r_@t\u̕gvk}I}gwuv|ʬFv/])3(x];v7NvBxYC;y, Jӱ zk]>lR\FނV!󝏇o5WvOل :!nyq6d}.9S|pW>ʒCqA)t헷{x|܍7  Kg>=y"y-Һ:IS}-F}zЯҭf8g R[}hW~>6w =ȲNPψ09,Bξ5ƽ@|s5=[}0mT"tPkƩ: خ-k J(!Ь7vCgu&6dڂRTӨgf*LJtz4O(\+FD*OQ#N)HtkwUju :9{w^۳c۾rDD)r2h[pwaϳ_3ޭ>y}}g \nAQ8lzRSBMm!A1Ju+ae4%;'{U-?}ssyJ6%lDu{~B̼/-| Fϙ ZukwG\Ҭz'=;|BHW&L-;oZ,oK#찧V zM=ُc{K>_l^|9a+[%oܸ7ʫ{sOCK !:WcmZ0@w S{:#tϡssFwOOz(?LqY[; S5s_=uk~?JR7n䕭ao0gk15{<4k)t ɍ;z|bq=ُ/-pbnǮEwٌ7wzşuݶk\;)惡+"޴](N,=&5:T&Nylḃ JI{^xNk"Y'yR*9 |$g1pZAàW#4i׫;D<S\KA! mO膠s:& T"`%@SWG[i/u{<Kf㑶n}(JWWZ^ͳ[ }pPq:ų ʖ&MIi&C7=[PH*򀢼'% Z@ٿ,|])rnUsVyheEBzC@/ h.wihѰ#Jj6kAb--8zsQNtr27:)H>03xr7CV=fQU>,lU!`|OԿGMz\\p=Tj9(`ZiT;'^~/_ݧ@;u7{s&4қm^{˿V1d]xi; tM6v1fXƲMRyf>>zw:4^xGw_x~T|KӴ 6pKrߋcx}kNWaS,Z3)qM&:R"*hWpdZ[Va3q%A/jv8q@\?]ࢯHԸHjܹJK^Q{5LYͮ\Hwz]HIͮ{g,?L24@DXk^t޴>Ma",(OIuD"Cd~~X<):g:X)ߠ6|A.H'XF.uK838td͖ZD@#&+c[3d #0 $dn,)LʘNQ\Ǎ\uebԦ)ٶ0 julU%j5ev 0n WG 1j׏˖7nyS =Oz᝽uť]g;ʄ&W1 %Uh"QguQ߷= ck&[;]?q¥ar)"rnoSW3/:QgyQ߷r5a#ѫhm_p~wS|œop˃['sG{3]O;K'V9:U>n_z}!l9m̛Q#9JVMm75^׉.'UD49sYk ҲsrW}WWi(ʹ'vH}AIo䳧`m_2QgoتN-C=HJ>X|`syfryde_::z-\}mSqy,9?^^^^IJNp*@'ӴnI֯iM/{"DVw-hvsidO#\uF^`҂@@(dyP*6(ut،2LaZ8^ģʞ:&X[J݉_\ LuRd$kt(9c-㜢/1/Z F1S-1<2o+z%-Zu\T]E_^zRּ8_^|u(j>0!$PZ2NL,gJ);V;ֺotafBȨd5c""_ʫkj9ǯyin/[R"լ ҺHpvH2>7>5w&Qy&' 9 E^l}lߕZN>w?ˇk 6Ǐ5voz݄i:MBgBrꯙA_ *8vߜq:ClWJ<}o:r<%SV}o:Cj8~_<xdfrޢf3qW/^`]ٖw,Z|S |F0H | 2ᕗ{RP {@$R #'O56 y_ݟ~c՚6JNzb}rM!:Ry>7 9YQHHr D'@WS.~=U7Qޟ?wj|Gm"s۬F[ll!,]J6xCwrB1aL&""T?'}t3 V/|i{f?~zMyrx&"$"4 i+qs6i6p%o)ۇJS(7xP Ϻ^Ͻ~9]-a٫" VW[<8yaom/ 7xPl)U?燧{wB˫|Dz>䨪vx!A@ ^4TfX. iO^~aOVk(xϖnMEe|VS|q;)VX,I*;)oU5J9fO ` o;ڴ .)4;30g! q4*X$4z IDAT8f> qAjPی{fsntv9C[/8:'8vecP-sD3}jdݪ *?!8157n@. wBl] ֚tߴT⓽Clzٜwx{P.j|MMWp&fstbEK4*CYÉQ .GSF}3Qr40yle ,5~ΙA5Ș1ED==mܬOXz% ]v !8ȨlǦl^juӅXIKG`) "[V5 X7][x}L$[1= huJݺԬ«·]3 L]b-֤Qʱ K,k{{jӪ|I*S_~ =+ nA9.q~gaϗIQCoډ'g'|JnZNoTm @ k)A˂7c_9:cPVq"i FD^ѥX ȡ ]pTR{.my Qth/9DDcWQrm֫xPҤտ0M85(M3VWiu3N(eP] 4TWdfr4{&@& uiGD\?'[;U Mx+G=me D<¼G@c, _zw9s.s&1 s7CDsЕ-op.ݴDqJNëw9<%& MJ )؊Եz&wX^Y O 혶34ODH\N)VzKM~z~ oqA|N:-<"WxWyZO=IIkL$&\tLVmQ}(ݴ~RS|pX!Lύ\**B 8Sb (Zg6#[TMHݫVkVM?el-Z~rJve c3sL:}&5$2HjR-X^K RJ"=غW?Ry5k? r4{ANa `j/>wn}zB@Jnumz~g⸔mUa ΫF{X_>%,C^^EKoË aۆ%/ܵ6;:a{(W߭V;S uÕH11MNg'ҒZR^ߧ/k:q,=A2@I)C:Ԍ :e a @%7|>(ؗU^fHmvJ'B(uJǴ>mW@,]jN8,vj)Ֆ(ff.,qZCuCcCUe#l08]EѮuGڜ^'f._; C94|y{Z%CysA>uzU\[QL(- ~R0V<1x!C< Y>~I;CDp2Lȷg&\SV5mN:W\XyouSt8h9]dŒb|#iIYR.ӏnY.lVEJEH@X,&~0Tn|Z$U1@XSfk{-NinpF|_9Ù()75*2֋Qp|o>|q̭w|Yb17 Ջ!{@nm^h̯ht(Mu@9퐚0 kl[?Bc x]3΢ uݤ$!Fր?Ei^Φ=~2xHoW>4ͱEkm&ar6ޡ}Zڪ7TIחeҿsčTm!uץ@qO謭h ZySR^򧳾yOd-x֍@Y/>rfi@m{5΋J Mla $d0XRq'2_sT-%%+W)C И3ȌTLC( 7|Uz%YGxvX)v)TkyGVLmǚ[yޏsD+4lCa.`4=KjNZ7.'kJBjf>6wb ARCpN}mR:8y_g٘el5;$5qCU+qɠFz'@$ѵϽ:OJQ<(Nz18'DPͷ6͹w8~ 9E}A¹ه uZ6ִZ Sl׾J}|$!hлΦ5m[9f٥>Yrʏ{P rήGE9 k{WVM_§+gt?!jp'p @-TKkV#)u[mVk8-VKoV#)uZ=%({׾5.}`dK.Ii~RR8S:Ykm귃wxߟvk.3wiV< ù8< po"`\s>I=+J|8ƨ;`Eiؽ{DPɾ5Gj/o-+ /|Na-z3.Vl]ha??#̘a?z$l7]T]wϠлN-u"a oJBՁ !3qLEF_{޸E9wXgG(7s8 *vg/_xC)/wYrV{ e9HY6vk쮙Ld-ZpY&}=ܩz̀/_r<"4>Ev =~0nF)0%Y6i%{=iEҨ+doӝ"9 /8eTypzVw9#7ZqoU;Q$/+B$p$RԿu =? M08qc.⻿| 77dg{S3.W}!#cb:<ϓA̜1AB 6F@ ewv5/*=N3FŬf[. ~Ce!"}q^5O:䖃G%KxU-kRу "kԾo;Q^_ OŰSx;np;k]z?\q̋㈘9׵3FJpYY( •}S:džw 8K.rf/g*hC30XH:g~'S{_+3l N;^ d/*n;?{,X ZTm QJv+.33C  yu9Ej& FNԨU}|,/d\Lã[s85++&IIX 'gQʒUJ;qKg a%an(+ڼ1vx|Qy%K{C(*,ĀF[$h隱5W? N89Z!a!8Z$hTjIW BPz,/}а'n ~dÂ)>τٱaRZ_=ϓQ)[{ U2maa~֧ y)<Ƿv θ00ā2dG7 򌁰knxw-QE#ygP椇tk}sKpߘa26&o[3y:j=r|ʝ33`kKi.WC˯\ύ?N_s@ UNУ~>,˜x"u>1 G~oUJJ--ii1>»{CWAo՝u_8.ֽsƧch—zv {A>~.S:b[':`gG6 /kŬ6uL|͜D2O{nf~@(X}=w>|v/|52 [iQG66𣙏?XަyOҧ3P=?s[ڍ<2v ëx[hZC$"G(KH,77mf/{)}Dmn{s:3>_ .Kis.A^ /7mW5+#@%:W H-w1TI+)"1&@јGj=1ngy>~̽q%IPG2K/ #ulD2A&%%Tf)y&<8,oGU3f^#IֱW5guC vO\ʛƙ#V? _zd8M\96<qf?II?C|^㴽o#~ ~~po~K9cfac 97.}B]zImn~KzgQQ|m|y%cF=6}X:ŏZG"SY*zp;W}r  cn0цwiO-Sy z|zgpH4 2#`i)oPPt|Wq?4No.78gzۆ0y. !(O7>!˱Tq deeq}t 7o~DyIqy RU*CP+{BH cHnd:. z 5;FEKiZjoB£b(2Qj)$.}{L7' A%$9ߒ^j)X(;luù".yBj)Gf!>! [QɻNqrGǙ K0JB 2Jv"0U;+ %eUrWFBM̲vDrQExDDg|L-L0 UEzab6yQ Nbk:&bg{K=Ϟj;?!+l'0G(j=JZҺ7kRӗu.ʷOȏ@&k4NXCO?0!p J+)Jy6o:Ijq =_>TR&LC(bθy~.&zjcvӄ !YB 4U=V !dRY]7"rΘL <0Zd( 5”[&ZGʍ*N_Vt~az*hBd 0f 3 8<@p!Ad?pKJRYB0DDž 1N|2/Y Rb,))qVVV&r # 39K/3&0U{/LbL8R+1)3@ ۤ'piUH(rUT?g= ZM4$j9R se@e4, GDvNpC2zQ\H E` IDS A`,ҩ_/ GQ;m B 0Ҵ;h%+6|)(!-$$3r]ػ -YD' "8:x:XH3&c"}ҙ1@Z.ct3 RSeNnd5`Z `qΕt2Wkqj sNB,%c=CRMBhC$K.Wlڊvs0f,ѡ)6!D5?ʕ"3ҋZ/ÈiI(cRvoh@5'e`* r*$$)\p @~tP4@QLX@FD aD@ 8+;;Z5wJr!ҽYVCQs/w,w7裴<2ܹ rQx1MדGbdfJ&c\U(8w\5 KdL)LSM) :¸bi(ZٝU5aLF.1% AGGJpE킏*C+GeV+WM ǩ&QYݦ5' _/A}AweŮ}n7 S(3:TwHe`.|@mYhv6sV]@ۨn2&G~s8Bt00B>Ry-۩,b )`zI %P<><s*; ( &ܜD8EGNFm&qU9 h0Sdky"QA6D0))^c1:s'CӧP8p3.Fc֚$# }I.fdFʷ@mh \mJ2EbC- K`x0|v.TqF%\iziMpADiSX审dʩ0F5IQwU{IU yՈl#d[X wM.y8a@1AEkm %!K*Ug>B݀פ97"esu?֮c9Z y,wEJ" | Aښ_4 B- O2%X&DXSw'qV,1P՚ʌVByAT$P)`;&뉢J`TQO+ˈE?FފTJҖ CaQB E?=#!8A"}}*Pda 7_Tp8P3θ%4a; 9 Wc CQi IHt!:f'T4TLz/PCUJ0ܲ ±,|M P7| y&z$34 5 ˽$ZdmZ~Ť3R53c(ؠH,Xj!/}t?.}kynY:?UekZvل3RN^_k 1m7D $B+gdt{%mvš#&Vin[qu߶uF>:! {>5k:p$w汝NgM !,F':NjzvwdvjBS؛\M!;+ |U9k-_5Xaє3SmŚѲUf5W^zͲkZl/勾ѐb69gO!R}Ɯ=n4sϫ._\82Adž+ڸje+WIrE'3+7ldHC lU! pb_~9IAyg-\bOnjč47aVTks:s"0"9"*9a$Q0b@s7964Ё>jرss/3?ϩSol~\bE߽yM23?7|O{jzl|w~Y%?~ |UŐqo:c%>VO}/P"PنY?(9M$r,Jcyg*rɼǗԙ)MG*lPP*3EA(*X0@3.vz@(cPv]# ^^6wY@`2EW|lUV~deޯvhzV{4 у# >goszÄ{('Y%=o~y}& ЫmK~??s{vL T~J48c/f4ko{Ä μ{3m'?ĝS\ô/rK` H48XG Dc8*M~=UI/q\!MC_D^Cjuy}GO2`؋zh>gtmK/~bܐ "ge6%*F(8GG_[R(cr |m˂(PUȥQm"c*5ʈu"s"BH -ݳo/Md`tpbߣ7:zI44)\=wM|*D}9[gwU_S'Vmig"#6A$y\+nA4xū&]A|`J4Ñ8aߎ{znNǨgLO=vQٴn]0湁 DW>EeEa2U$.[RDRi-nĄW)矾4rw~Qzm/FX5muBemԢ3!Nh{ =!"@4jؠo/iA!a0T5 HNK\-VmH#ۧ pTYF1HN D"!Q璄!}i"!PT3pq|32ʾ;$.xdv/x㊭/ޗj&})O]9:Xvͺ5׮]ig04PŀGOTS:u7_qu>_r;E{^י;C*|<%0~cҹ_Mxvzi3NnT5k֮YnM;Jdfddddd0οCXl1˶Rgv>{^DqBN4HK|`QgQzv=߾][M.e_߸woO>@:K$[^ry >}ݝnA7Կv%#X6ETZR6iGkޔ1='&W.dټ]Z[H4O/^pߺz5˟x/sW"~㞉??͇O\vBK&3sg>q%5m-fҀ [_p?'}uUl{̤isg.Zk0Pcy*ӱf;;AΓX3Zlߧ/? ɥ=dÄ,g_ J=Kjf7-1ߞ!Ԑmh8eI=4.b ,'/*<^N:kdfLէ0K{$3.ZzMډkqq}PE>[MF\*lݲhZchdPI3m1{)e+Zl4jkѣFqGf@j:Z鮭m>ɎdηXl>}y '}W~[$WᜋU_쾕mXO;~(A@}tUCYFlsC ni5jeGkgwZߵ#6}Ȩ#Vyxe^ҬcPX^k!ADպ9g mYv<4RÒpdf[aNBjf6H~KoAnT\) Q۷m?x`VKܙEd|\tk^1iʿ|n=pl^}c!2Z`'Uv0%5~^VKX6 ch3hoq(__I W-Z>oZ:u c&惞lWQDc1_Т z\G4H'xZ%Ax4,|yv?e2uA\lD}K֔*t{ Jt:*OT$8qcuC?xw\"*uI'iV?#t mj\røSquW}rvEb9Ճ?zWwc&Wzm}ssM)j37eA׿Yr vO֭CpoGUPc(A d"y;5bS*Q떮_'E[ m(JD0 "^YA@ѪHl c8vɦee:O[Moma^NuJ6.٧#5;ʋ$g7>SsV+ "z;wwip5;XnNXe%fZyP#&M/{^ Yǝ/v^իh_^:`,?gJw#U9 /i\ /vmչMjJwuJujGU[b}ڑg^dݙܞ9vv/^3]>fpJh1RSx??(Yi~}>5A?~Zw>6y2Ѥߣw՛1?P;Mڭq? 1"Xf] S]-M@lᘔD"j!\1P-4Qkk"Aԫҡ~Ղ=k|U1{\D`f$s,^2hjG2rsb):B@^: ,|o IDATp;'qh;εhL;s3#n}-^I(|ÃܯBy&"'Xvf}0י)='uƎ Nvqzo= !5㍧kxࣝ:kfzyrLAE=? w>cr]/9cgplAt(ܳdɡ V/] i [3#qxwÿs܏~bṋ/ޫv| :r~}ck ? qwn<*ʷ]AF$M5VZA't߳?,-صcݟO|C !e-7e[Kwb++͟NxE+6عO?8kJt+<ւҝK~[R5]-=㹷gQ~%~螵t+_ؾ}/~Y\˧LNq:Ne=%V^_^i&t*,Ri DZi:P7*DeřW+N1S;J kw?xVbȫ[YIdג ɕ/?>fM7{suR}~OT0 €Adȅ隋FWy9^Qܼx4WgA2;y*fnrG i;?Q9F$ф bw[L!KoFVW.ӷr4٨)` (@+ !SHX휷?qӬ2,),ts !1n<&봭ܑ"D;V [9 MvtzR6Cᝇ,( #'`NvJV,  ӾyVoUэ_僇V,8J vo ]hC~:Xa|K&䱄tn`(Q.(΋MgٽNrțQyVqd-k}7WH|\  U/13*۲0٭y5ov1*Y:oysHxpvf|-fG\/1rzs6a, TJnDF1=c u( RwԞ +Ft|L _)b$]9s/%~Xm6y1m@Ȝ9+k;!Yݽ%qkTG/C5cv3OiFw4|s(͡y\0-/:pv}($Hm]\ 9?}Ã_]UL9jP}nѫAByd9A('P~?F~s>_1SO? ҙ@]c*Y),$qhzZxh_ӓ? *uX`ӯЛy?.M s5}rYa1:cf,<(W"L _$4tG}){ō4m;F}YЄb;]b̅]~3\s˳y:s Cr#T*È"Y "zg"T/)FR[hM=I#I}ŐS;O\71^yPXP&VG=zjfs;ѽӟ/6*H0=Jhd(C i@EyP\XJ1./y<(<(_"Gv轢7Ag/PYNd)G9l2ޠFt]X"3+G+wyQwLTcx +k2_wl2}UbȀL/%:QOf/K4+ *G *jUN5Wr2m@xr7{L63rfLO*DEOcFWQX@* s\s]zgszGVo^]?E25Պ*Q^N xHU+x uCJO#+m vojXz9u6Xm_N_0؞A4qI˗|fA"1`dء"A"(QF~O%sF_z}{_ٷW=8s~-қ@oΔ/"K ?R$cO0rJQ~hޢʉ}O)X27aJ8'I(޼lov.u}!>pbBg4OOI"2O$dұGDz[u4Ѿl]uJ'T??u{yvs=DXvv; /!%F9:n7diW_D`vz& Aڲ[f~/2/YZ]sR#`2}`wR7 Qsۼ•\,qUsְ{Xs$Nd{8*aCM #7zQ؟۲s$@։mXlފS~:])mչ6?؁9˭]~xT+qb*Vm,Q?eZtl4?aДL4Ӯ Qy]Ys•E, BU Y1V?.D$JYT!_K+aST*%mҗ*s1>ef>Gv!g5ѭVD?%ܪQu\z[A̓l} o%^i!"H^2)=o{-[nSV)b·4 /ܸ[(2귫탍hpJd't5W d!dͶuXo QmmQn'pɩ0LaA19]w=:؍Dt[vUL֑!JM!sLJ &6hP/ϧ)|Sהh!gU~U|"XM҅m;ko'Yj?{S$gmA6hP7ϯ7|?umٿF) ε/ctgUtNa$vs{6VwΏj4Hru]~tT}gͮ.-lL$PRYԝOe {Ok?bz&yԓK0Z47SWfwMmq $\uhh I) y=t9;S n~셫-!e{o/~8;Y;^ѳo~":݂x-prnrٴߋU맗>ޒתmm۵jq#7_ѽIc_Uu (wo]<_oߔ9??R[*Kr{ ZւekZHbVV״\g]3SO|%Þ{;CZ{ޮQvg]oϚ{ݙ图ޠ{V ۿ~d2lۦ]?id]G<<4Gm~@w">deÛ7:w_*kYzШ 뜚5ey^Xʷ-WNmYfjI!V ~Z7jؼSxW,h3dͽֶIϺ*.危rnV]dC fH&WHV.v3~j2E?C=KN=I6Ϲ'o/C%JILu.ظ o_(̶?qsկG3G&'A+w>鮐1RIWCgHXUgV[=/N}˦>|+G؈ ƊVOyqwϟ{;[y,)J< ( ’mѵ9}H.v|Mz~j)/xػǎ=ϫ@I/|vI1kؑ9Hю[} G%asj|l??6pNT{а>%3ܲ#V⤖49 @҆DHV8V.j }:?nfE<6miEW3}n|ś%Zݑ[s}-KNo%dU v6Zt-+Z}3Ym7O+w~:rtQ< h7O4"9k¼<>9]G>Rk԰g߼m䈏w#5niGJ\AtX35N#`#"A\p\$K~Sz#?ꑻے6 sD@+s$^(> mSc\1tb~:a* >\ (<×gݚ Ft$Hˊ6]h&A"׮6ve7L({>K(|d7^8c* DCZ0 `6\2r%" "L蒡?1ݧG=t|M7ʦ5d?xcߒ(y/0Ct߫]:u[՝ |PJa(<2|(Yxgfw 'me6Jp𲇆=y>yr H1?3;[ ~=7rO%?|S! ԑ=nD IDAT |vXfn808 :^GХchȞgL*tC(@s&x\%[]TX .ݤ"Vءn5̂L |O|HU:^gSfIM1Jy.3NאR)pYUL^Q옏N iɎ Z|m tz2\ B6*TI.0¹+_ ыB4c rzj!B|yD $h}"#"S{" z. J3Yȓ!#9QBB^oBTPlmd]bˣ*I 1d>N[k=P@ UEKAʬT!Tĉ `EALM`juqUϤ]uum3:>9"9y=0Y̹@k UWc>D@2HWO;XFUCPhg(-[boz-6r 6F&rJF U~$c%)_tO11" N1ͤQ7M©j밈iSz $U)SGDgḴ2s<ug%FV<7" :Zu>w2B==4槃"vj?$w-5+te'EC0+ࢿ4.Ɍ?5uD6rx O4HmT.ήFgwp<Hz2tpL-$dLs[ 6jKA":(![N'yI=cNDn4iI2NB As61&PPg<Dȥ㚜# {U4dprQh  :BG 8׽ı!.I%tf8RL"#SVKlȘ3ܾE2x&A4LfՇJ%ߤmfzˆup:X t1ؘ)oTʑ!}(NϪ ʏPۿm7Mb s =Tl~ZAO5Ϊ>)3 L~ tõ.c UN*y_ $YViҢqϴ0Ơ)\=Ft= 0 ћc>vfbµ+ΒS#21+0*WHfÊGhihb^KESE"\ P8߾o"N¬}2}dSY WyR%?q%YR)hb~dWK'`X^IHޘ}ABhL}$3'Ir%,rh%9rRQ%nA遒JCmKW~BDvXQ8wEGt@8)آ7#kd; 0?> hZ9ߑn˰T]LΧI" `(==vwaxTs2SrOYNE#4Ƴt͇#Jz"}YN%F䨃Q 9Lb_p:'iZ.v' c_r rE" - F% <ƵpG&[kCĄF CJ̵;fNE&TH E}YM&׃@8|Ņ˒jD! ͆67(EpVOȕs.4rїBLq M5KzC&T\yZf҉M3Ce PcUŋ̈́!ƪCN%acB0:[(XYI[sc\|2^J*@&(E4:{9U- GU{HVFa<_ꄡk5O怭ÖZ 2SƄOG(Tz ߒ)+A3t{<t^EB ##r)67D$jVmTmNj!TB+%ɌSw x$Bȟ E-jguxGPhf ^4ckV:D&Op`F$T޳ͲwVME9 0GDfc> c ݣ3C1cwgGC.SZ[ zDUޏ+$wృ46|W*r+Z cZt-d>YsdjneC*4t`$.&vЊź 9b3Uz02Q,c"&h3{ÃWz`6&ݠU?OBޞFߘiž1]vԨJ 0K fI !N0.xC9!VRWc+F@[ @āl[I9ε2@tv˔+GSi2SAH3c\ŁތG-ԊMFX5 7]%|Isn$ 9#8J8~(RѦsӁdE! >8!Jg@**6"j:|ckW'uZ(6GRLeCej323Yc!:>G!Ypt{mp YLWU&ݞ~0$ÓqՓS쌩td7 k 3O:WXtyM'sIZ, cOYlV9&Q+J=FK9'T؁X(~άIUb#vwtxUjM[xLpk~DLrмjpR$TEgSǔ:[PQ 0PO*/2-ҤX|2u013\WMsr$\:{Y$KLJWZQ yVP[xo$Gka՝R@&415 H(Jr^z}s6]$Yoe5qLamV&Uv,ksB< Hy͢DD瞖0.2$i iffNtWX01-h01cؚO3\v5\ VhssĈb۴M$(wتHaz%iIb)]:Y.LFH#puD%rPgD36PE a>6އTE*Z!&kaq옦BhgZgyhFh;rr r/(?uVV(PPN R8ah 8]\ܮ&Uwpj'1FÅKKp䑍2$-Uv9|(@qrsJRe1-ॸ`(@I0T`B 06[?dt(ccp.BV fbJbbV -Q`IVzCŤ'm>6Plp":u <Ɣ_!R:?z 1pTZH.AK"j\sϊv-%)¶Ԇ=IGhqTqDP!QI^KARNB0[# ,*]~`24~,,J=ڶK8l.0@a2kUqUىJV%țE$#*iQajACVAe%XR +i+fBN~.lHTy<IhMZ$qd' N>1e>Y],X 0 q!@1|hB!Qpjb,T;܏1 ̱Q235@|sx*xXY6N/sd/uud<1z"8VVeA`o'?rt P!x*M$R̙ש2HkGyD"\! ͦC@fp_ 2Wh(4]&HҘQ(QIמ~` uΖֆ{Q։Gk WGFhC22tx "ssoSY2po$,v]2`݆e DQY4]{Д%H'H{mkW6F=cX"nE輻PJXb"JqyFnVafԣ6i)0`Wrjgn]H)`Jf9LҳK S鴌s.t,TUXD]ӃdBų 6:Qjj汖ga7s9I{u]͵ሕ Jҩ @B!1ƈ8ZpҷdOZ({&9!P+Aӈh)EHz 1P\U*$) _uަ*maѩ!+2 PTbBd0/"K&="r%IQvM` `KJ'{R+zeۍDdZm*B0!<k)l@ ~ ܠ4;ڊ1F AFyF "CޭEN::GuvkPJ ,OWh+=mc4p]sREМs"z3?`x\m@B8ɯ]p'e:- <t8>>D$rR BA:J%w?\&1dBR9fdnf!P;<}Ve+v{)@GH$ ?!QU9qbsuC:_ŌrxQAFPQ)q&q<`}$DFM4ň8()qDTZeAQ8T IDATD@쵪ZB%3ZU AE˅ q;F)[_)sXE!AQfT 3)n1~&0XY&YYSoUTl F`s2W3a 6bٯHh84M4#LKVET& NFu5IKTC0ai6~kJT)!:YdmFd;!jU8\ )bHskrZ*.Q9h4ȆcîS01(T_" (_ LKw-{lٟ^"Dy`$Xʝ@k ]Aāajs2b=jIB7lHLPRa9G4:&2$ОloT3/.ME8SA2SĵjM4UH(fz}B 6ن))H!C` ?S>بd̰L*F%U hXeF ;C 兟>E9UE9$<+$> ;DNn13C++s+,tZ#- JARכ%-!YH,3^b,@r$m1]TuÎdPX\_3Sv:xk _@E"K/  f\lyXp@ #4t@s JHjBlyC|՗:S 3#`*z\Ϥw `,̩ )"_^,#C3lv( -at!*U*)GhZ&uY$|\-})l+Ɉ@}?MDdS1(|32:%EnMRT," $9I1€K0$<%B :'!I`ϲ#gRa1b{p"0YNhjC}?=9F(zBPȎØ (# 5cGIX *{ۊI1(R\ A4bԎ1Hb1P7n} CuʚlJ#'L?6KS b'Mj'rm&SIKSb3`vujc۠EC5ue*ȫ+}AsS)n,h~V* TeWgQn| cOc-ufKC= bi^.ĨQ-'Kl57hMt-_֣b{;,T-9CEl+,[ `;]^i8 +PیykKAO:j򢗼Fz$Z;lHIcd&=y $EcN&RPD!2w:mXSRRhLFtf$##i*WH[Рɠx4O&D !bujIǘ/anl6" K1,";w$Da}":9"%\N CQ.,fQ@@fCYj$9VBnEcReMP+7؁!;Tܯ0KE׍FStڗTn<!~:W.z.ᒉ *t̮?;BTVH,f0aZ] F]H2TҫUU n4ˁsTaJ0Ab"j#mW5 mSb_A2dUm)U>kH"!5Vk-4UPh2g fnm9m|'9jA,GKI02)3%*6|UCC.uaѪ^Ô]%A Ѝ:o^@`NxV,%!2 mRdfts:u )+_flᒕBD %g祙k:j8Xl"ET'lja@"πM@].5/$4#j33 `-%SUgT"DEt.3¶;AHŔ j#\uB 2d‘1׊<{.1BeE>eD +bLmh WHJf=ca^>ɞOR#!]%X M'i #F) $Ό099[DǣQu'x&0b!dǠ蜓7O1[ we)s僰X͂v3^P8B/Ra!]0H==œǩ Dh4Yѿ[9I׍F,nhKYS©Fm*oRaogD `RFA )Y.1QZ"đ#BO:Dn0nnn[sme(<TtdqG$*0pOɑ Q$QYPR2vLi&ÜݕeO5rØkC΂l(mjb`[3'-*s*"DCo -w%,IU&Ndvy>`!*6%̝lUoigxuY!e]^UKHrN f&JƒS!R$&JJɶ S1eM Sov:ia M_aXP33}vk-=g9vgq ] %#j<-PAp/m[>ge`dXhؔvH <|``|( ܫ6yM#'6sιfD]b#S8vn<"9x$@Dh07:Jwnqq18Lc z@ϢHF 2rXp}}s鼖1@Nc>Zb9l}V=]L">@ ܾ1C RBdyJQ4:P;Qb_J8r'i@c @sJSvi"R͍,sh01r 1J{!**0ܬD8)S4 !Ju'$AS 䴄2c GjT3j ϭ6w2 9@N8h!ʗL4b7-K4D9Xc #h^c ,s'd0fxsb ЅE$!ivIx9KMhN5\J 3y:rN)t5hD*Y'[9 =iڭkVe9/C1sMuVs klOua-؏BIW\Y2Qن7b (00zn1SIɠ#jnj#V㏟l "40͖##b\ B}o u.\~ӑ' "# \OFFCA:  *(L\ߧo#_y/u"JKo:(QuCp:Je(Lh쑋|+\kkDd)ь_,Q^삫Skmhyn]Y?d]'s# =8h' CZ'M/ ԙ\&Q7b:.!˟P>OR~δsc$AcQEHՔT\ᷤjtHhDݨKu$(l5"pZԘM0;|9G1)Sg[A:[qٹYfy?G/J-=$ FI?Ӿ$Nvl Wg AmfLVOD.l+hm1K,Bt]^d&Gj>f3FfdIl _[ S9uF 1SpY8(5:cmc<"*]1c$1"T1Sܜq1Z)6*8e &6JL`VҜ9ZZKCԙۼ+V+X4Z&ɻN! KhԶ*h8(F9C"s#4 ϴ}JX@eԜ!F t̔S]*rT'Sx/U[!l VVD>B"1dug=%-K6Za cꆄ؄I6[ pRՔz`ͨXߐi8 üsA݃A$6J BʰMaII~eY'G}U :ﺮh,Zۙ~p65ڨL5dplHOxM̊!0j' -`%9;q@+N";GwCSFc04&Dƞvslj"8RcAH=Oju͞fێ[X5~yy;=hqRV_\5~yi-jHTi-4R!|R2'줵$A ~Vsq׳WI$hAd3(mNsdP7eöqi%]նl{^*|%APB@G`cI[i⿱ѻY_1e7+¶j 1%*hfY~QuiHe|eޘp=<4 tkz0k ->8sr&)盅{BuIm0#Jshőc@t:Mly%"`2S9`t.gl6bkG!:H.͹Poi'FEg̵0ЛCv*S̑͡4S53`7df>>+3ijz<>ixe8@1ªKvޑF]WJn }`4V nD!^ΠЪA(WFq Ķڍj2d?PHT4O@*oB@0o,߯tj1=l {XyTMX`4v{fs9bH֝i@ |aoV:Æ.8&97Gj4 %8lRŐZƆKd%:#@=A /h(L6 q4T LNˍB9yY ghl]<֯AWSs1MJlSP2BL9m=j1yc)-ka k%^, SGtQ#q>42c+ N#lTIn64Gskܾ5? g (36R1 N61vi #bi8Ely8`̆R+>Ֆ )PZ QvHVOPפ B},4YPB%˹Ye]!MJF{aʁ!0[Yʼ^Lj99EO]"0M@ u_m 4x :rGSCAgTхB$e*yrmƇwϟyW~^uОo>.%|z!E9`q|.<;f~ v9DQ҇d4>|CWu.SO+.:#}˂IM;1hc7m_|[O 7=ϼW\qgxvQ 1Zi3"yغ6ѻ_pA~㞱j5nKs5O>E.s޼gu˿s.fCWרkez3 IDAT{=v빗ze<~7u܇E^~~퀿yդί[?{}.>g] ]UJ6B"̶\^YVMY] y9)T bJ=2 (r6Uo*=J ̑So`USɺC E F %@ϑsDsAp#jcJep(2Gn,\]:Mz)ee3yk 6 PInqfMUYTԜpax>(ӎvgԪv Amx{]E[  j|߇!Ftyɡ\‡k*&5]4]y#^݃.5k]yL_?9xX:PM;O1 hr1'c'BA*`.wN9Ȟ4[_|'%"CXcv_; Ɔ~U_Mv[{ב ] 'n8[.:cwwt=|;pqrg/_=ٱa{9@vZX%.lY{ijVkhLQOXKϜ3YU3=ֿꍻ57<3ӗ5oyի,c{L`v6jfօIsJyiy#rbB vDThK-13e[Lab$D %}"`Pb^6٪Ԩ] 21F`;O 䭣`QgȺ_7 4ƚ z8ЎˬnHvh70ń/ł|!!FfNnX\SC~7CP*vR* N鴏A]9$88i L,Sq^uT==z_zswΕ#,!r)ҩc Zif&y%"~uN D;/}H|7g I ))a~4u]vfZn<γKd*D֙Uh.B&$Tu^-,&ͫ]800e3aF@Nn?")fC7d4#$$LVh4dn?iؒ9GUDf:-рju<~_C#\wM~1)P@Ŀ^}ȞOpOzeOyNzsVi t~h->Y4 nv̫݆]crJsHK,U2 KuRz#!'vVjVR{&S%FǙAZqRM˙ڸ9$2YƕjU#w rJTRrd:fi.)Y 7 S-uwCXD@,N8(bA;y~=ޞKd)qBVf 9G!<.z_OkZ4I݉J#'+TD4)!B1O]k[ؚYC6! O#7<= ;I/V"'9"z˃MNEj0Tts^{Ov_;_;zwǿMx)>=W{XwcWm_?Ϟ}F[_~;?Ӿ͏{w"~o}S'#8 OhFcIlyA 9 20kEY`;{l{,nZSҧMzSM;{^~?zUY6F?wMwto<];,Aɶ|M'//6-++Hw:dnלt#y땸.w$sQdʗ>2To;Z5 %%E"l:i z/Q\ty~λ1MWSXI`|ӾPLRY פ/*WZdR55=Q E/kmRgeVW$ H}?R!QH֯ iZm3eRxbgGĚr'#d NO9d벚Pd,ԛ40P {CWCM(b4dm*ej(v6cT4HIAlPSU bj 6'<=<;N5<۰.6xOOvDɪnN'0+)Ƌ8!f23;"RX+-5`aMq땸.isx[{=9}o~dTJ ~o>>u}ڱCκ)Džwn_7MH\@'?|979{/GX}p?m7og@F}K)~8?g=|{^o|c^XUL' Fk+ƍ8װi~+ՉAG8Ԭe ~Zd*Ϸghyz;udWY}n .}CyU7$ ;5?6[}h /$H=xաnO@mYW͋9l ԉ- aV/@~E5Wv:TjCۆ3@!#XQZ H۲ X{zf"\=Sd5W행G/m!$W5s1hhR}m4&Rі| H3# c<[IhЉ:A k04jY"P\ѹa>+mLLwd٬Hl{ַRYꯎK>75f*CTbF ЫGQ!Fh;;MWsåH9]jћ/+w_. fwr, Ze4!Ӂ8&fS ;/>> iBK.Hnw./<^ܛXn|oK=W/8hR>0'` !rd)K_y"`Shaӭ\lʦ3Mn}x֯w/@e<t[~si[1-ߵ FWZ\*_--;fYZ`cEKc/ْJDd ~IyN"SrfJJ~=B0-A"覟l}) XtkןY.H!h؇0ecC?}yBR8"Q8΃C=;`lAm9arбE $mj4<8:d'1Cy vd_SO 5FT;:̙N'!Ds2L'tsoU$O~p+}5nlnq=.f1>{͑?#C}1Ȝ@84C$Dq٠X1~2NVVT rUFOx}uC>쐃;> !D5+Hȑ'iתWGR |ecP,!i)VkwS}}*486T-2W%D2ٮ-FJ (ϛlaCaZå> W( LyGY+b`NL{'9Oeu7nO7t qE`;o .XxBUq-I^H @[꼈߸pzIpr_{>f߿:j#G额]|or+^ l[zڴvw“|R;l׼av7L8!t{-`Voɍ8[Bf8`Z].aC7@m@0SHE0Xm (œ Gܳ>*PMa AEd:i cfQoO|D1; ËTЕ] k0iËh61XT%?ض+XF9^zB4~ C`¥!KT5Qir/>ig ~0O&t2 ן| {mzкfY3 dMqsWOz;|>=1[ƅ] uc~rUܸڋbm'KVqNSNZi - d^w"PΑ.'A+BAi#OSaGi߯LVTB~ڧܑdJWdQU;"6XhRv%hB7 Y6- $\6F0NFF|4_[G@  S4Z,u6p\tF{kv8[_@p}G ~߹"ky\?,"=^x>`1HwlA) luw>#;+|O|?e8pV>u51 Vm# .Z9o^{\/{^[ jrBwz]>&/-[;p޿n>uWc=k\4yI@?_'*x٧n&=~;~?vcl."-_\x'[x` \@@o턓x"[cMG\WM?OvTQח"|]z O7nyV:?W=;W.-_/'yrmbFN1ƒ`(ɥub"Z{,Eq_/sn f@8 %Ϡp 9!jYKt @AMD#rj0/[&'PøOff%B@P%'Sy;E k ]?3&m1f5vݠ9@H{{ؘ(SS(Q4(A:p_Phώۇ nȚ.Xb 5 r83C<g{ٯ%Gq;2jyxxīzAfd|Z@\ qOv*o8֍z?lHbO}ibןwn8vs l9̱g&Oc_rñu];}?_2Y+.^ßXnHZu]gԂ% G^LNo{>{Q?si<{|u>:\y=>˟at:U.5pRͲ(Q8JTLVi~%L n8,_(ŸEfe "]C29QN+]*m-({-1$NjO00NIF;s1@ܽj9v IDAT7n{FtF.#^4W>+ܜ$ %-?{@C Gzaa%l;GyJ@m%[[;>9R2o-_}naƥOc>g6ro|uo=հo;Gzr+oջu_P N?'W⧮w=jǿݵikbg-(_chNiTqf0eCD ]Ё@^'~[ F֒ܠBM*bM`Ts6&i4a0g?Za(Of`i3<tWf0 941QQ_"B)cs>/q'Y?䴏|{I곏-;#W9K#BddU/9&7}Ϟr#0oM7~{豯ifPXl0-cp@LcHUB:M(q4!(N! 5eQ2qQ9~XHj%nb D#M7ic,s.r sW4Żdd +@dX&a@΁&d!2'f6ʞXbjgH3b0,`QړT!ͿY'{+Nj9,MkJ\# vwEfa,^:JѮ)#<"sc"B@Zrλ{9Ɯ%8iKsΰX%# Tٗc4^.rbĘpC J&$#$%$8(g3_U*LΥib戼3T<0!փ/p -\rIvz#c 1Df-Ls:SXkD#e&^"A ^f pbʪ<`M;f3G l>+F&qbV]Py>+ >'"< Ɣbd:uΔ2#FZkK 3gpҢYw+͉ 5)K5^ 9Z&a1 6ؾٵUk~V8\IIו`S7f{qPLau4Ex9e&(e&nIJW X鎟kl'ZYAֱA;I;ecV6ˬ:+ |0ёR7hfW#jtx-KV\+֍zS WJ %ե4FSGl@*i֤F:X -bo0'3 ϰS 0sW{9pLa] cYKl0FaiգEU\-v"q ,*W) ;W&6Ґ4ĩRJKCH8rj\N 9)D\Zg1h-hٻh\BEJb$"9 E,?vT1=̉EJsNg1o(8MR؉ }d+uP͵˛#Y>8,}% $ƻn̂"6hu?XfA)rg[ 4D "R]t9pő%$sQ*{L>jhTзKiHpS@MQ2b^ur l̑Z5ghys"h Ձ\YޜaPƁTar'pQȪ ҂;A2ؔRi؞bf{BfF 1L#j&( 5!Caedže楙#TÈ5l4q&WLmՠIO`%(1 "*fd$ Wwm+UD%RyJ}"[nT;G̬9.CDE Jkl*SK@0"v_ќh !Ȕpr, A{55.bPAXYjvYӟ*jZ2lB:UJd.OȖ`YKv:2|):>PyEaCX5KO [irSD)UbLSyJL$r"Jb4gyd$}5v~,_# 3b$rLZQYԇܢwuJΑs_lUDKMv+" 2L Lt=TiRv:ww+/ %%fZ  Nr0\gɞIő"b+UDT2PPbX=(l-vMl  k@B=ZQEkֵdC^5l'un^r.Ѕ3RL&b%Av&B1ba)yFҗ3)rT,SFF C%z`U fjV<ʋ_Z^[@"hs0ss :ɭA]H,eń TDGEbq5S00Aͮe5;@R/ Վ?p u3f?2HFd>|YȨ*dRT!ЧLk$N厮{~3iCAȹHLҘ8Кb"1 \^yY"mإ!2G⏲g E>[c{V9B2ˢ-8Pz1bӮSM ޛC/+b,3r$Y6̰*=&톿xSHb˽!ٻ`rO'aDВp0ƄVFGE#3$ CӒ =SMØnnë3t:*/W@W6A)= N+%X@$*TD +*4!$睰>!K3۷@l)-pKTHFqGV~[A1rʍCr4iQ-Iq 2#TιN9fLƄ4sgg 9*"p:zAP% 4=*N%k [U b9^0t1,PCLI ਰJ.{HYRyOʀ5(q6$ȍ@sB 9R\%i73xd"yW <X9MRL igD2NBYDIZ9C7 틪fW#-"_Ҩ9cӒY#۷sFV IcY5IJ ^mijeB8y̝&pm3"IvVU 9,gE+JΦUJ-kMeQ[~ rIloYiZ X:!I1. =fXuCHD߹AfF2/Eft54ӶXUcoQ%_0(X f沪ĭ`=Lkڰ`t[xol@)SGT͢0\㖪CtET @w]ˌyYr4t)b2 5[ yH9x:N'te1Vx&%M:PѨ[XF#rpL;_OGɕ.o'Z夞[o|SLsG|+ѯ|s8g8L*~%t{?%'~}^ͣ46=/|s;g{5w{9w۶ϟH]2:/ܪ{xg}X 㹪o9C>L>[s#x҇xֶs=yz[*㪻=OW<]{=;횘>Ҋx $1G>˵U*kHL!J+ʐ[B",Ocs/UXH,  "Ӛd 1 DzH,"BD'ŏn4)dz:t0՛$rHz}6d1TQ㒦,s-Gu10~~O'~%rA2$ 2:*꘴\b(4Ԧ'My:.//fTTlzDuUWG,*D3bu~9P\SkVeitI `mh]8>SY@c^@R,UinG˾ӯ6B$\4X4N{hל?w.Uu>g@#]jW4h/V`O,Q${"FE,Ql74 EΥܙ^$ϛ<ɓhޙ9sk~X޺n*;j󹏧Lxߎ A?2aLVUmmjkU%&L :ڷ =q #pz,cXT~x]8.Z_pla}3CXyi+->'vDu!6 #"?r}IBZU]SSS]`T_}8g4&zȼ=#RO\?8[k63O9ԛi|w؆˪ 8$;u9QP).ӚͳMvky=C4]~;Ӑvd@3ֹ։J;3L\\[ 9^4`cxq /m,uѫm41i4pi'w}pH;O=KW{^;};Ԥ)Oڜ~7z?M-BxR]yۏ >aj+9AgR Lkya7'x;䍿\7 {_{ǭi{Y2àȤ( Wiea& 0| >/u[fDD0ɼo_\oJ ȄNVZR*2u=f fX;pJG嘾 Q2iṜBtgB&Ijҁ BGSg ۿYVD93$I$HEf"iӅX u?Dq[XrSc5Rs^Ҋ3tT UUUUUs3TPq6R"~^U-7OqK)=bcȜHFj"z4SN蒝- YTrd3H1R*[#w>1{TLoGJR#Mv'ܗ-*&16Xڧi#5^+P )Ds` 3ebNh A^h<'G’|F>t=(`uu'S8%MGZ9Ѿ^]q%%[<럣7<7tWC UDT*ʂbUf g-6(dqT.e ƌ'-uػU,n(v>S<0bf |-owjݔaMa+)>p[b21@aMn/t:gp`޻hrG#g~[ںf" >oz1'~b??*%,v>嬝?;IMyvq.ER]qg&ƿx]//(4 uSq3Nq֣hn^r^,4_7Jڟ5ǢÿL[O~g_t+.|#IėͅYTrXC?[7([)D=YcP-*"X]R̹6'6wO'{p'IN.4g*3&HZ;K><ƎpR MOYȑv | <' PA&JG0a&IXmb{>}t͹77@eOGߜل\~/M: HE}})9hMhSǵdGow7&}6eK7ךiQr!KubP(pKlɇcUm8osD79va{ 'oJ IDAThFs;^'?~/蔇~(r\HC]9a}n8W}p J!mOHv{ڿߜjrAeVܐIRBR$쇉ڵ;`0l2a[Niŗ387翶*nC?vF7žg1g}F4b}X/ˎ9멷Wv󰥣}ڙW [!wN(is~C<Dž=UR*}vw^S;l{v'<mU>Wx\, J);NZ7ub7c9{DOs.f#DZ"~ {qڵP5I-毷4;qؓױz=vo^QQ\zy\UCtiY9ӳM#J;uVtb_y>`CvLʤc^ {9CM&"MSAsç<}-t&ްG !z$6a/0`Mڐ'<0n{!Ko"dT :X @7$]J)D01z:٧L:qN~Qя?Y+JMAC.:o՛wռ/9EUK:LQ 2"iSͫ'GpM=[6 dRƒ :u6CfwC}}RBdZ-7Qqn__Z>ܨu<α'7-&&nE28^Q^uro̩S/s{B_iCrӕ 9{ie@$UC_ Kٵ >e+a %T!H߽/*=^G{᱅B̠ĺ`R3z1H~ʣ*~i0i0)K0rfʊ+,A̕My5p خ'^nkǮR*t:ޛG?q$X5#`{ldv9sĚq _7ÝOnCw~5﯎E2%ϺG{}RAouM{3c7) Y/̄PJqL:8:)htr(R1dnPD"?H^kndktA!/"11 o^feC `8OA 7sVG޲_~޳w噆x  ",^*PCLeO,eDbk3!97X[k b%!uBy0IR0ale4[`IBIXp$񺁡tMvکjW6kNޡ ~\G(h |;{pxJ[թ#>8غeMopčc^8Og:&_X>joUKHU@Z``kln2 V <+Tֆ=t4BZ(B&$ML(+K6vu&ClU8*JPBTR~ gfqCw>G?jizCa_pk\zxIBRAnw&c={dqhRDUt.LW>SNzуU^[~[]Rw{zכo6VVG;7?G htmLbUՓYLՂmDXFeW<};MHM!36aA:# (G2liu` bBI7@>C }hMH2QaIˆP,'taƩ儀@NCdB,a.CbQ@Γ4AƢ,۰PDBXl)9)OU_k>7 7!Eyh?`ܔK+%hsdnUVb3Hz-z>7cFќg )H*"ÖcUi,L\TBH Al$Ec cWa T7)1Y9@#UջJ~8kzm|*tX Ad0XaX".z'Hlȧ";^XՀ`ˬ{9y=K^Z{F_-DQ!ʻz*غ^ 䖈&*?ՠz(Ҵڪ/%bbエP V5G gVvHm~(9BjCX[@ Hj6^YSnqjU/~GWwK7 ӓJh"(;[y-`MSjzݫ (7qb*qq捱nM1Vog?Ib"g9ꗭ S m^VMNluqhX/5+b_d!q 1ʨjêtIZ7i)Ԥb녏KW4D$_8Ӻ3zE@Lj5;bq}";@>L3IϤ, 2:3 ۃ fA!RKl M ʔ~R 1RPޑ#)وST-'JnLX΅C"Ăqr%"(2]I \|=AB/AԽl"B"*fOEc6!sf3Tؤt&~HD/_:u98[jR1?b̜s\t̬\.=|@>Qk~eyYp HƓ$yQ4#!K~(5۽C-v#!j[l颍 {j(> l~{1DQZėco{cwk +,N͞M^ZY*E >s-vm%Y)dm+o@qfTo#YڲifK ^Q _|(R oH΄rŧlhn.p+LY]C_}k-p .\.ҚQorO\l(}آѱi[^{thZ@ӏ~k/8r϶v?߀vX1eRc:bOӽ:[-` .ZƌJ_N"`@oP*-xŧu?/k^b۴ݹOӽ:Ϳ-1i_{1{W )S (ۘZprP]k֓0}9/rYn‘i^(*r^j=vۭ XrܣCDX9O흧zu.V+-Xx:I.{{k;>6lv{9y>-'#_j:q6T#8*t0|wDL8~ D' >t&E6I (K]P0cVc"Ò7(1tO &P3YFJ%%3d_R0`B=u'5x`>\@$I$[Nm~@tA2TY~f!_ggJ.d)2ʥR0MRXEAлşW")9՜r62}ch@6lWo xz=):[R0 Mug,ҳ6(,/՗J\hK"{E7F[LZJ)Tmps/-ь',A%?WbniTL )nҾmy=p9/;⛫ocr\2|v=h#G@ `(LPv]}oݪʯEC&wzUiKW|sŏ̮lS jyy217]2Py_]=gjqw^vɈ]u8ςEobcr`%")U(qȑǘ=aу'Q/*uN|'1jVㅈ92eD+w1Drػ3T-c- ʕ3a21 x3_\~A XY85N"EA5eKE e/BE fC,)s3gR*DL4I9 !g ) p^yA;0LP!Ie4 i`۴Z~$iTj&cc(e`J1D%"\HbJ% YZH2DYuUu&2Cf("ҵfrq2|`ٶ+^ A[aIpfFgƬ(M@~wuB3& <˕R=o_٧^5czRwmGm*SJ*!uٲ/}{ٿnˋ%b3@β T3nN ?P($ZݡT~W}SqӨn6/J}q߀{ lZ4r#ȜN@MtydFT^;^֭?;dZkG/#C"t;@Pk8 yopHhjgG$Mε]?i.6ٍmpk>AA'w[gZC2"%uvT )˂k]qgAunג&{T]B6h|\T23g,0'*batӃ a! zZ("R{')RJm.1 ,E QV.+RjqXs|G{S4G^s sͰLZbc.!%d M!qwkFW/*cp$I"Bh`SVȢ0By 09Z.Z-9yyerp볡2)))Z@jEeZ hO)œJ1|]K\xqǶ[_n@ D&2%r\Cbd{Q0A&b[19I\¶m)`Ac܋*DI%5/ C4%B+M/f`   {]VG5LK1-:{qKQ7)]`e\cbwĊy-F<]Ǥ uʅHV/AÆA d]8DJic3Z.݁kFy&:1M)>a 7 E ]^iEK IDATVڡQ;gZ{v90yլO3`_g K}tjHA_k0"y8BJ!x I2 @(er"Cr\t,KJ)9Äs\%IʹfIq ! td1QOmh`-""q@0)du4 X92SA~ݖ5HE0JAgӛ BԐ)sT:ViVWW'I$!ABKUPù.TCn[։ẌcBLOZ4ah1| XѫF~Dg&3FڃU~g,& N~p6G4q=6tNHmѸYk2teBfg sx,x` \H@qX)Z)^@~CJj 3(@qeev#h_9 7}yÆᯈʖ%yH@nc"gKxJ9e*rޕ~.ԌL=g>drd660l݄DFk!N\gct{P0rZ 2 8E;HnF$ m"2&ߔ:e\d]0j P@Pjӧ[=[T"Lf0i<^6" zz\D If?P$Řu淟C@ӯd]=ء)"TacV9ytp3!|zɋaCt`Ab)EPPg ܖyoZtH$)* n|Ѝ1 aE6Ĉ<y~j-%Sq RJ( #7 ~-JMݿv1c!;lY|qv:_i.30b뷭PZscsE,#u4ѧ !,!6Pd pФh,u\B@0Ƭ6 GԪ\IrW]xhS.ѧD6-@U8l{= 7G*ʾ 'GYjhE2Հ$m`r=)1h$AFaA4CW{"‰rb55B7'4H׽ H!3)EzKf+ )k OؐO+!bJw(C*}5Gy MǞ qMϞ)}8%, P2:*h;2$bLIȎYKCTF.d:lC%hI< 22^EMarQ-DQZ' 2 J$Iݺf\0f0WXap?>ѧ_^x. j8iŘRkP& .$:LWnSoA$R$݄11x dz3gSUc !O u xbTѶ1cnpE U`r)=?4I.Jw-1A;eH\0)r{ 'g@N+LKĚ+*9@@dt@>@NvK@_Si)K/PEpc3<|j$kvI]O4`T Ns!2$'q/8MUT*IpݠRp0}I\.K).b-VP0x R\d΂W,1P0X]TFd&;HJ 3y++wEoiH%:J)h3De% )$Y2) zO54l]U19i"ռ1Ibʙ+w7:\YU~,t#O_"3jNªE95s׀*j1zIBRfnP00Vqnjh(+5}Fd m6oD ~ ⮙JL)O,oY +(7(nwڶ)4uc2ݾ9'OH p; pc{0KFb3KP.A#u b&XDy1,T`p @ Eae@c*9ǐKw*| RJE 8-+bZHjjkB"E&b8+AiABB4T+7ԣ@WFN`EƐspnl?܊h'@!ߏɀBl v pdVgPjscϏ|_SbdDW=s>jm ֋ɘX|9ciϜٌ{af^&>siNH@ ݖ>L9u欉>~m ZQo;'S>ym(|?>{}?|AwvX>}n>:ڲpd'EGjةߘOvJ"UjcQg}lBjv?}ГOO?sh̬;6?+p{Fa󩁋*g!vD4g@ˍq 텀a~@c04U"06rQYPQAS2侀>fn 5 3ƤY[gi2ƅY9S!ؐ "'RGe UB,˄IXHS VnVM>_݁;1N \Ȑ3XK"BfY&2 c܊475@a\xV" | u,ˤnJ۝|e`YVRBo{ms.o)'2e/~7/Ԩ*MS}ӛ޴GMO!Y{ xs}7 $ =U%RH^ I'a Aq;MA^ޘ2k\ݗ-~E_vҎ,$VFۍ(*˙O') B&md/Bkjjkkkkk)wUr̟Toja;ܙ¼nݷVWoΣLU +{~-'`NEv>3qq)Qӳ ۝;䮓]+_ti_pRc9ojr8mQH6~kS7Y[TJ'O 8׿{|J[nt:/bR@,k}zw^ΩN?S6rmqZ^|E>N8xU{ԀK!"K[t4'w3;L)UU[>sA>;kޔcK,oI$i. C&"tyǯЩ g<^I3{fV=;}~wִߣ)#7iVCĵ K !#O& A0H*Kt@!MP3Kl3!WSR6fѤ8ľ2<@D Gym BSߒG8x>yWB*3x9DtP~΂}uVzO>R1ZroyB(5!Ȋ޽aкֆJNن{+V0ua_nv F_v/V M|ܯ?w}>919}>KcFl_0K=5cmnP2,J<:2z=kUn@G -ڵmMc&RRCQԱDuwiNzféS'x[s5e;S>:QwثV(,ۺpjw?6k{jWև\˓&O1G8f Qkw?ޝ{~Sh}i'1wGx'}Wz 7ۙ᱋8Sn3,f壮}W_{@ԛԋzF{YmK_{꜂Zٿ:~>ʛզyV7?p D0_rm&}j[ijR]DX/᧦f4kT^Db7"[v@ leb/?kqȹg;kSP>0:T/ }(g sB#n#y܋^5 IDAT Jy}p2vVZn7JHIJ!XoP s%ik)dfh`8tV.W.;U=3(ԁ(Q2DT0)xR_WXSOl6q8K:E:-^g< jc;lҐ? 7,6@ |~0a\`f޹y*0r[QCO;8Q+3p0r̕LrޢVkba_g^mSý3.A'ڨ}kqb^1y2 PZhs \x@JBc'А>#82 )~!giqPi]_m_8NY낟R}W2d䌥i Kz+ ~^=k1-`=,|7V*XmWw_y˳JDǿޫN.3Ѽlk["s!ߞRjg$nA2# DŰ׊7 $2E5ذRA.sA:B2*ޫ(ۼzrl>*%ι-#N\0 ,ܴtB7ElZ|ԕUh2J=!h+s,'vzVryo-`tnCw|5VU`FIi#{vYlugaGvw>;cm 10M _[.p[9Uʍ~82&OsΘq{9sNEHn 5A:(RٷhUkEfv:<{ E'" ?/yXPet *>؏Hc@7TFH,s09JptDdm S7YL$Pp6x[Ze mE2}f@"DXy<%9u$?*!t֍˨P#]"hȓT&5M I6 nBCYH)RsθRFQm=ȤrQnq!RJWru1lNQ4MziJ4IQkzGBδxMb5QPqF!$X~nQQPC`^Ss|Vknۇ^q3Wu˅ b%DyPJ HSh#nfxkڣ.xF+P䋂53K(sGrG_OAV+0tX %aVjf o~:HJ~*]N|ޝnYcFTw>zQNlIo5mVŞW4D2WLCiBzfn08U/aU: QZ%I4GlI{Yf lȽ@݊:m٨nҭM(׭1ԭSe.]^h}~|̍'stR ̬nE6^}?űnfk)ǁdLQe0"it*%mAŵ:PfN Rn2Y#';PtZvj#tnG!T&g%L33<@30 5jP`RXq46($۷L&E7 L(9[uP0@.KUD+(̄vaR9KMDgiJ:3$I @ +?p %%*&%3!t"m`! ©۽a-܊ $Meg"À`Ρa$+\Ν789{ԧ3I_(tFa\quO?࡫7&-XW:|]-{mJE<Ԗ[IUdw -!(/zλTA "7>2N"eeygj(thȈSMHN.do>ǿ{tОyKܡ=^^h05l`vUuQ:iތ4V86@LFc•Z*& %I<-KQP,0՗տ/(ɪHٍˤmcVM f.>ŞVFO?GTJ_4N/]fo[zҸ5jêKln֊oN_a~{4^=qF3"1b3)AФ"Шe@%aQi4bҤu+6Cƪw;߿2j#st:δe 8i-+tcDOبH4%Lo>;[ [%,aXrNn+2fs6n٢ ۼj妌6OS2Vwvzk|nԣG-G➗ kҜMLtSn%"2}K†A ]Vg0:%r\xGF2xHJaMF5yUDPA]s"ME{8]ª]zj,@xTH!2R_9gL N1lo‡`{$-3?Y7:>, \ha1 XH4YV. m>c# O@n\lZj&f@߾[V.Yܛ~I"%4M$e14`B M%"RRDƐk!w RXmX԰"7!>EX+Cg`O|!)C%ͻwV>_ q`+IDػK^xz r\lj>w__V0?:g[,l1[][r1r91z+F:cYxJ[Cj܍Ͳ6(A@ )Hq8OY^bh:SfbݷS^k/GڹW}=N^?}{fUuZkݾ-QVG$E4u‰ET&G3D0qҤ4&ʣ55-ʈZ&NéAaT'@ ={5^{sЊ[uow>{[$čxF`YJrpKgnŴFXl&]gNOlxq<ܘ2@HjN)W6}A8`o߯[d1sr4p}ɻw~W]~1l;+^S'`灛?{u}w}}LhuÏUy\Oܵ_y O=y -W}7>N՛ dp{r/u=KsZ:>7wҚ._~=}:ᴗv>?9gܶݻ8]>i#c~}չ?y)Dѳ Bw]>i+\qҮݻlsk'w͟BSe>s]w۷Mнh)NDadJ•K=Nؘ<9gq CXVdNZ>\777<Sx?uKK9ŘS#4mIK2iӦ\?(y8”qZ0wr6Ƣ^2;.Д(8mL[9gdHhռ>|8O. Ja\fqEn3W#o/z9gpZBs|=7Ͼ?>] z - cw3~⸱<X5,p.PNp0d{z6>~ͷ:7w~ϟnmcC@J)NS,S 1"#3W]w<vΞw^uXxez?q__ ^|ys_ry>=A<ZƑ<_w˥8σ_НWxǯ߽wo00kJ"Q}ӯ=|ٿ@\T`st.{Y9y/j.}_|~@D`8~̌bl4Cq=W7nvc20>tۯ䚏f 6g_̰n#n<0Q1?[_Ŕ_L9kP:i^y{{%/ S73QV0 ״Քbޏ3_f#/Ƨxрs]w]ȣ?ES s܌ft+'Rq6%uձc?_P a.!V 2()fqc 8j)%.rƺ)n"ǖsP`c" %$,ݙӧ]1O(GիEI0vc3`4| W)! pʨb/rœO0Vo^梋Q^:qJ)9F59e ijJqDZ2'EnRCt_+R4%8CǏ |%poAgyX&h"Uv@ 3Q#yobJ̣xO?|?Ϗxۙ ` ~ocͿ[_~ZnWmBfH1%Lfcݶr-{aڱ/yUA?{-G7ƕWᆏ<^_~$WOY,|DZ׷'gWɞW\/<7?&ΛxSΝ>o+粫o(|hߗGJ{_z7}@_O/@0Oo|O=(0 ar}XVms셗>I[RZ>,h\[1-S/D 2d`^ㅚ6\""DibLS @9i6 D9}BT#:̜RL_A`n0@c(`"g2 'q 4^A/SxRf9&h(/Ͳѧ2g9]NL6lrZ"ZP:ש09ZVF*or؀Yrk@u ~#= 6NFAiɌLg+ׁ4ӉT atVa,D\mT4!Ȝ  :؆/]kR$}goBӰ5 Z˝R)j9=E s'rQ/4,r|93:T $OX&A0 ǹ-4$Ԣ ʽ#E!ƶ&^ ,D 'yHDQv?DddQ@#jOPV0!ӿ"I1 /nEd#n,ToPWCr#]C(. ,bGzӷ.;7x؟c%ʨV/n!& n]U33ODCԔ7dfhr{M ju[MN?k_xnA.H@87ICzGq}}E9NS@8JC0o OөrrW?B}2i+VL A031b):/Vl7FBh#4 #i(,tn|檷6Rr3J=qYu/ƞ o`N f_-PņT]EX6vdtuC7AUGr ,.=fȥ#70 KJpaVun]Tclj &Q>,o[E #kZ\2}ۭ6ײ l C1朇qdf T2{5kmanri;&IM)( 5p}#nGT"lzuz[,j [nLuk-#?߼:*1ݱECaVq#nK*ިPz+! HMElmf^AM iPp |Kn>)gyˎβ\} c"}krN(4#qcsSa vB@ ppam}0*[K؋qڣ<ըJ1#NS*4@x1"V b`R95숪Xc!Dv{b0d,u ySj,L-Sj8s/bzyq`h$d(dqA"J^K~EnYו6۲yѝY9֡G:$}])+߼?^s9 ڡrNj;@rɖhgw|vDW+"q1Aw,5YMf%aT.lSLl1wjW!Edy\fBvd49{z|c ~ƭR sAx1|0 UH4Лp zӫgʍV ,_1+JƯqG83=\P-6x[ذ-s,5vArы{<bP{(LAw{U;Yy$hym-OnRBVYL|i6.돋H*[$ځiALS7e gfR#,LU\)B}\=Ip^eRrDU2rꈂb;eXpĈL2: C@7~M <ڵ2 ѴAuA(XncSl@kDrr077#7(֠ΎyU@wRo:.dX<(j;\DilX10t|ck?ecV(Q㰸I^m%˱͚]|}amRlTV$/1%u$\MzeW4F^&ܢ*:3˛hÔٺJ @"32>#? :#VI\ЉmJ$17c'Lu.DqCD`̐T.0r)* аʔ,$R+b@86֣ڵՑf=u APIDATyJ,!t]-'¼=ҩYFbVGJE(:S)ZޡfbⲯͥM.YYthV[ EL x^;rp`)mvHVD˗æBW5K g1IJbIe.ÀW g.Ϊ5s35^Mxތm \ v sy)΂ϥ4!llr AJCy\m%Q`̉CU0@n^KP e ,)%pnҼZ 3[h~eVYnz'ej)հх;HҠ >3Ot熸EVɕsk~@S xo9ʚbs!yzxwC媾M&1pyscss*e}˄hJ`)2\Y gΌȪ(W2R.x*j2'KJBJIg2BPao(% +IfWC<2{<j}!rrH 0#ƜyA!#9 1Pdbt_vVgVVR<2g;2)+0ZF}PeCcZYxdtudWV6kEfW qаNu#̇fFni6F!SʀJqlz(6KD8qtB>` BBXcci"Α+ j)ڊ3 PJ7rјk`œ %Bܐx Loū@ rZvxekwhc'm`g#!BҸ%M)Fy_f4g ' Dnͨh* tS%Ҕԛ^j Zy~ [y;,,ׅfתoq5 wgnP̙%=̭:?!ڷ+!B[m QX____b]vGJՄ9ڶm1iKy`hc#̸퓟%Lg)6~r H@ebjukM@HB Nӥ,M`|v"ƽi܀8MqbKDNؐ+1v.vi\E2HoK/yzݩwS9ފ2x~/k&05{ɇ7CPjIxXt{m̖c=ΉCQ(!2cGX.4\3^FNJYti,a1hu9B.ȥNp3hԬGO Q*F3iii`.}F;#Љ?]LF)b͟Up k'Ibjiˮ37]*[Lu[U OZ[[)I5>( j.ص,@N deXĩGCfzkb8s*bKsk!gΐ8La1KǤ. Q(Q,U#rʜsd‡@C-WJ.*(L&a!H1<$Bc1֣Tc|J у/":=&a!#D C`⽝Mݐ@gwW7] nY'&1S<E1#w3 VŪTxTxo sǹ +bǜcL)%6|f ptXiJE ÀoKL{(ڶ@a%=Y5=YdL47[)c ]raU/$:,[%3\8I H#GFWU`duHWHVS<ǐ%nZ@6C3zBPdnV'B)qɷ_qړBCcjI_,4r" f$++bk˶'bi3IZ!8LYwh a!r-¸\ qki7*0!J-w(.Dl> Ow H&5L] W]*5B2X&`ua@)vDTz >QeOCcL\ DB8ÀH)Z:e+ ar ^!Lى-!8;AЩT"b+|1/_k9GZTc}_V1aiI)PN!$ڇg;NJbE@2BssŠykfΘ8!P:!aU8~q&ʪ5R-=D1((*}0)r1&ERn9\^95=t=VЍE!PQrq1&.d8\Q4z?i XZN 3 ik (ďH>gTj!bI; n0a MD3R;uJ;Ese\ONS;M$jA$;Y{TZYdGv#q 2 `wlg$d\t){BCG8?*, Xof!a<4M1 `F+a NQg՗No9hСF׃YjWĹr"1,*rf 90gO~u; 89g*pz[lV-#hK[(dU]T,V؜TtD!(áQ@$o Ze9zĸᥧ)*]m[W( 0!/-A CŪ7Y8m,V7Z7v"CjTqO:2Jg0*;b]t`jTSF`Vo iUa୨kX26- }n:\\85"{793`@ ̨ @$ua+Dt^m4Z)i8!Kl@\{Wd &.M%4pO4]jaBEj h)DȂ˅g9KItSѥ/H9BD@2(Sjݗg  2L. k1~ӓ/IP _Y5"!87+ B4=%DO)! nC_Gs>ÝH+؅(AJL@OA,yMLD GOD|\F"sLT8- ۄ7!L9 G̛L+w(r&[p4poa^;dtM٣ec,`*q;RK%";[[3i1/,M%qaLN( PD&dgBJE _0wb="fwpj'P8GK2eq>f| mI-@'x(4 YW "#>nDDkd-zlczaEfU%,,Y( Q(E&d2UWXc@qQrsR OD!L7M42 "D-kZ^,[`2ՆcȵL`yβW3ugA# 9'"[_Rȿ5_Wʥ{b哉8W'f5w Ij V, } bZp]{ˤrLȄ'"ZEk@b(Ր^Bs"* D9 ȲxS <^ıߢ P2d2LZ3(JFQX${Yc2`Y{'@z QIXWSDXV<܈);ן /u)OQIW_"ӌiDL!?rEuPr1bV d9z tURÈ ctфʁd f xB}%ӤVP//POrEskhš>BoD!ahEn}Ih5%̡On& #8F*YȿyֈVP VS)7ʉVe2,'bZo(QYh3vm> ND=JE7UY~ '2!  XOV{S'Ű!ںBs>z3]dC̀ B!foSC qWVt;w{Ҍ7׏.Xy):kO}]sЭpl?J;?;dUj#3 MŌ(:oMԀ愣U{~U׽,l%KS3j=A#VI8n GuRŝ߰`4( 1Ћp옍؃G:a*T<66wHcso;n[M6`/iڶlu_ [gL8|D1&YY>ON6@\;ns~} wVyPۿ3Qƿ}`Ys3 )Nqg6}?OK*xJnz qtC+fѤrgƗ?MPyw'3Af,{Ž =f, yszo:5Ÿ_Nm_u$@xݪ'Z)UnstGIЂ{=_2nOs덧M?%'G_'gC]S =-Ky)a>o% uaҐ'RDi~˙jb"0ȈVXMDE%l:{2qU7*}g {N;৉hg]1<ɽe=XTiƖ K]tP4#ZQ8KɮеS{W篜GNYʾ2]8&۹kG]{SWl 0PUЀJ[S>b ۶(sx7]G)T^_ =!܁'Z:nҡ쵳dkަޢ9{R|h‘?^U'~5[i"J+x6jӾὐy|R:Vf+h;j5DZ! Hc8KYI :zg}m>SrرJe9kgL yWXb\e"-I^>VDi/v=QNPw" by_$ }ݙkجVEit%::ԟvlԐ¢<qܡc-A<^5eLqjN{7,|2nҡެk+,JCln~\n6x~i!aQ^- m@TuTr9A+  t?{,ٚ!aEũHuYn6dAi3"dMMP:#Q-j0qͻW&ijtb;6qq⾋h}<8ZagR!!nY֧⤨Hpt,B"Kb(@Mar|ׯ+2W4 1yd\B^B>:qKZNM訛ϑ4ĭ?߰:6v鬐}wo06:`kaѹб]tZv$n׈cS/HjuH]^@]qhދV~iStb/v.^Y0lM3 ;1 /$+#Cu7WYDڨt )s- vJGHրԢ1<ڥ^S/cn0HSA.Iyr]u-ZƕIYϣ]5T 2_n:wp_ +(ɏJ @QGoꩤ& jn):tѩ!@Sb!N R!;<"ODepmԩ"YmD,6AtDQ3m7 /U;&χ0̇ΊʳjgMumT>?6TϛQmX'^wnpӷ;  p܈$^y.@ıޔeFdNjfKa/Qw?_9 PQ~re3)uiڹ^a=& @no+^X4rݚ}(x Zϖ4RJIQPWrIA{W#,j oQ/BJoOt0~Ӧˆ ]+LE,J;tsl=1 Ł@qᜎ&l d4=WHҞ=H`3c_X6,|\tvs 7 52/6pId_6h:6V|=+#22䘗:;D}:*ޭBRl>ׇ=`ҟ=P)0,691E@?{y]Rۘ,t@I±ͻtv@<oµȔ>p6Fpbrn7m^|g֡jٹWkpD2?lYo(Y|.\9i,aʓ$B KAlau\Ry7k|{ҙR=7*qu͞7^?|q>)&U١Iu`W}tPL GczVx~xaXDd`/M$#SzOkm⮼,NyHhG3ؤܛ{0mc T4ď|i޼y+5fF`#Z)Č;Fi7.K[)6ܒ&uf޼Meӷpց*X4o޼Mʀ@v=DGNekB@tl$:"iyYn >$u*{[.~eCOrK/!:6*(]ZZp.M8%f/x,ŝGw6iNשs>*ǧm$þ𝒄Wb6@^޹$6q` p O(bP>2SQfiFSB#jK C!THRat P ~6N*e7 & R Afs Jb͠31{5N樄SHkؤL%G֫؟^2&?y{{5z%R , ,˅jf6/1])uevƾfԕ3<|>m_l.oeՙx>ŔBZ+%6M 25}T:V+ڃt\FBIq1E[l %H]U)79;C^r.-eCFCs˅HkFgG?>W~?ξW#M'xxR.[61ZuzpcGylǗ ;t&J!^xqbV6m舨bJ{ѯm(,?~TehːɃ@e~ ?,]iIB7g9,sTӔӣ8"1]hѶE֝' jSYiaU0QT<临/˼N|toWjiyWt_=b,)*jJ rSFQʛ- W3:>:4lL'~Upn6'WP922Dr(Q% -g4VY$R!'~) AB J#)5_{ۀƎDh>d6٤"> +惦0tz6Ö*3aO/MaA?C*r\32'mS'giqŏ)gSfֿܭэb+iZh4ViaGЦ=[˦M:z>x%IGTnNyf Ĵ DtvASeC[F+!/$bt096:6.1,0 ~ڥ<|Íߨ),(K.W |p`c b/gkcauYy3I|#_!Fx\s_,|qsͅ: AT "A&9RDN44Y>G9zGym^BTxTDxt\F8Ѭ\Pz]R 8sSżLr$VnPKgV9jߙs1߶i_ӻW#g|(6 ]rψpB[n>2{ızm߆-{L\Ꮃ+5 * }'o8fXƵu1MxhT A346֮ӤۨY2>b_i?S[44޻_ 3#]&ӚWUsՀr]աe,ɶLgmn^bm,:S Cj]IqPMzկZ&7ԆyUD5L4޲ l{M/0_O:nUM n;ى ^f)(#7nn0 }tT<ש@ %(&R_#Q*0sޏ+\(nѰ[mǢe=WK=wr@)rNԶ߿t_+Fy]j0X[b椐)7t=6Q}uzBkO=_6dW5egHc-kwd f =/q 9Mnu.3B0Kj1gC 5b#r(?+8\ܪAA)K?ya׳pjۖ6Ήzp~^[y B:ߪ8qJ(I{ph޲)4:Irȹ((J{zzɌlB:X+Xoh }pƜ1|XհwLPN8fj{mϻU"GLl>N&YL<=IuȌ =81N|>U~^eaۦ(>yŠN2{nkkZ9{昭09k3h#CO!@[™OKyסiRdYA.)|}34Kg_/bM{]$0om-er㖰4a`ޔ it[#\|t/ؘ6&:םάʏiLrL8%ӁR(tM\&䕓%^RwVX Zb[?}"ѧ?~1-#ôo>7(E&"?rXpe#-Bt~MTȔNsτ_byK&a,i2)!@+WZ~4#Jdu&D=CD^zO:M/e)Hdi U٧s4K"8"Z\I#os|3?.W,#`B52c0u.cZ(x (-lmmD |$ tr(Nu֌;F Bv80 x-4)hMk"bdgS m V ;c2 *ɿƗ$,b,A$"Ahm2'pX]'/O'~D -X80}73+b~lUCPR*dzHE( k&>#xOEӮDւV걵 sr#y:1լˇ3@ ̌͝Jbَ7E%YR6ԿP6x7ebȐj-bY"\6lQWOը嶊a KkR &8\k nQ .rbzq(hV5nOLmKB6ELBHF_Z#bH.}2hLj@ҢT ?ƒTk S۝h5K0 L~drj#a[p,6.G̒.1# bh'RX>hAXsefj6`(Ksn""$.~n16ZP - -X>Dڵi4(j|CڢC4ۚ &j\%Bipz[<5>r*ŵ4ɕ](`}cY̠JaJDөl3rK "^;A^M$T!1LoB S8q0_ K 2z)Bcr}x֔a]؜xNz|aKƔCiy,8zf[ڈ7vukYw/޺s%LzE b-Lm:%rjbkhP u3{B,`d^=S΂}U l;hor~V]+(Q'9EMwɗy,<khS;`۞[x8ŮO8rX *+1%ѷ.RJ7=ߩJ_o8=HYX;L̑H u;N7o]7~zÂjsR˙r^ܿz,8pnMsCiSD 2C'eg.z'Im*<:N9o=vJbpȬ7"$F: @bxθBIVDUr=f<=]WhN$Obot$`Qg,xTT8gݾٰp$M+mjl=?|CB Ö?v_MRw=~`hMߪ7Myg E?7Nٺk e03ZkȺB}ot)K>|WZ5c}xٔ^ڵ$LIhKo. ޛmڵPDPdFIm`FnWIW.6k׵_=|$5}ɻ{?dsYodFnLPɪ~a~r&pEߍ?L ㈮$:b,_Gy 7guݔ%Wf'Yc Qnm(f_B_̭zǒLj բÔ~r&n 7B*bߔ&?YAB U مy1 C&;tsm\ӲwGÝdzSH=:pe7s G!!%&!O DC I()•{EYWWOH6vmØ*u ~&#ad~զwsmQb"`r֑Y{ԙ^7>/"|G"&uQ)tGu "BI/_ˈu\mZh *@2'C>)m0T>}Idq.:)*^+a 5{ 24CsGB!"8P_hDǦ#7=tR|q %ts+x}#"o9t\n6=>ˁIjH^}=|k|5EtNQl䄆,:|]n:_E7칷i}7yT@^kFmhǀFuڼQyzunfʪ|=wjި,ŠUloG{56|JـR8? M YtU'\B^9N8QuMj91Zu K)0+z_ _8g4>nV[c+y_ڴ6xy-@rncZ^>PTmq;O0qçկ8Ts7qnؽѼW%}yZY'Bg)8'%ĶƫYxH1Wi6lԒ? ϕynʌjE6cgMNԦŻHU/_Rx1'%({͜9ZI~! +Dpj^#'OWjC#]}+W`YoLjVFtJp7ϐYm0`6Іސ\C(sf bjېjcuLgA@9NN]B*\}^TXFo9E@ViFio`YרkV.֊CkMQwKKS?G{JJ=V{Z_VRlRN2f6ٸ^T!C4z([owO<+b5;pJ}+Thܪ5DĽ(i@<"ߵAGv ?vSV iSfNIo>ucmzvy׳`hS[](ϊ-[Iˇ|iڼn8{{ʗmXe^mQ/lS!S:c+4=a^7 ZndJC 8fZSVlH<Дc  GQf*_^4bظ%`K95|NH3V5p B6!\7vq'dwmLL{t頋&?v߬$˝nz+{Vm&Uf8_W]~<oS=wmDG}dvr:'jl۹jѣ۱jB ^ *f4n9n*qn^4C |י0@NYkmj#os#Ya޼u!]uGU;1XѴrif64Һ9t_k?r}<mI t#CMUfB9vmΠoz~1ju'[>9ޚe>rmQ:|9z}<Ƕ_zՓ?uٜ'4n3VN-uS2G߹*cm!@I 'Xy=0 愯Jh>TOQ&+tmHdӼZ9[/F1hk7J}67[kA#UuS$) - 8. { tu{15oכ\C;z7AAQsFܯ%OIm.z8/rͶ_n^y3$4lRjg̭S \ ;>Tx>zzCA7^*C2rtsRN^X]UNDTmծ#&l9vږ,Z]Fj@v|6}X?YYMW~O轫db 6snYO^O2V1N(8 1*T%޾$&G>~lkqʎ]{q-#UdvֳooƦS]ԉ7<*aDDgy i\a4.7 PB#s eDÊqޒRJkc %\BխHY䗩Me޽cS4Q}]|8"R-(E9v*|J !Inv6lIϔ7s wQڰrkql~.j ?hwtxJPZJWOi5&Ԝ'[.j?gjxI`udЈWv IDAT[y |й>yǣ>hHm{f_sDT̀_fdS:h"ˋ@ku[-%IEz^J#K ^vYE &Fd*!OsY[X4t :k YEZNCTƺ \ufyLkkۻt|>лWnֹ3%moˊ/#B0l{Vdӫ>FQS[Hwsmé.aioA^T=KKQu+(|kd!oB,|ͼkW83cQU]P{1e876p@{H~vu7ܰ?wfo~fz'AM_K"U P =*fѱ(XC,,C%(tBD)m~\+ƴ9shsW% >ڜ1qev;S[ Q1Y,}ݮae]}‰KTڮae'N]?YbSGVFkS43xyݠM1&lM͟8Q|V~ù9(rM[~%3Umj0~`TO'f͉~O#t5`W(&±# ͖ŒP>X2MNPYȈ[/- NMF%uSv_|M\ݢǖ!]IEkP$&5&ua^AĢP> @'((Чur\p "/NRE>.mn\ l5I9Ъ#T[:hueH*w\ȗ5:n1ݣog( ZXQ[AÉdFGl |,Fnk$UU<( nCsQcDmCc178, Z,nZ SqD"#XMp`ix~]lH3{gtJ^{@E]RAvz%WPڐ4sk0M AX0h|mXq.h_o M\XRYPu`CDvljOqxѩ;fjg_K?<;uڛ8mVuL+bI*WZTd!b[Ï=Gu6ٟԳV3лR0č`J)!Ԙ"1냱Qۏ\ub`"9"ള"ltzV~ۨMFm6~ $-"MT@75&^;FݠvH1}aX] ȓ{p&j_Acgj@u M~}tyÍ}d..7s~뜨 J;|V&EzsηW's"7Pw.w[^ݺu 65v{@okLqZ|l\ll\\l\\RUى)Шר^Hᓝ;/ۿ::L\ 0 jb1YBYцػyyUR;}69om>:DA[֪<`3"K,8w>cdP`s>Ni|}awt>ӴS+OѸ[5?۹yZ;/bx x'@줄BFT=k}3W4-jĂQ0XF.ڨ[U&ERvT^ɍg^,},Jo[xUvqVPL^|z. 6޽&b>>Ȯ!_z{2BG%agB5 &ǝ҈=FW+cϝJt4U-uO>s!J% &С ?uk46fv_3N;7nԴ_~:y%NCPk隩.7MrWׯNFGOnW[+CTN% iUvvѥDw.}sQ߫!@[p4ɱ7 'wR*u6uCuu͸ F1/GĘůwu<۵buHOЌV0(dt?G?b\_:mzg 77.A}KNQ~/@^2HbKBmxظ(]AEJ6޻Ǡc1]BVsPֱv *|}KYs[_&b߳h֚҇TmFYYW~Yy YS{,{ҼBjt`akبI:<^3=x=sys=d8 i1Kloґ ;dso8fO"#9\= ?0x_ *f׬NL^wLȼkUљ4S[=X9fx~!$DꚩkdRm*&$c[UaO'nH'q 1y uƛ7 M^={右l ^&G0hbO|ђ=yD㮥[g:诃-^Ȃ f?PT` ެqYqou.0C5&O:cQTNgx6Oɏ#CF<ݞ'M.?@Sc `^+jޯ[K[޿lm8_I I:<_WE償Z8{y˗ls_0fw"-Jpww>_"(玜w-^d7*by/db`w)g<3;IsjhkLfU9 N^[~L:C_z۲38ʳ_fVMJ;?l?~WŢg̜XR_M%5D۸9=۷(kM[qh7D3̼ÈXtI&EEi3Ks]T$ Z0Q8NqC1w=/iRIh#Q}YMY˜PY͵FS?u|T>Xb! h ŵ@^@q+NTpݡX($ 9ؑ}Μ{;Oo29g-kG։(H ]dö @+We&GgX z ʷ7I߷JgQ>)T b`DgN &_OA2RXo} /rO>|Hspj6_"¦f6lSF""g:,J%(R'X;|rc4T6#" $K YDz;tB΄XqYq̧U14.GGav1GzѩH żPLag5m+84G_ 3*^d'',16Su7ɪgDxkyIqgI^oTt-xTsuy aKqx$|=b<(ڔKDӶzN&X#^V(r:z!I88Xb ҋ *@|A!i/XRƺAf3C:i1.W)FJp KI~C ]~k_k6 z ZG*TD禤 $XRMZ∖s!,n2wŎ7S=K(v 5to '#XPAc AQ&ȟ c2# HN@\M?6 bc"8'5U%qfYȹv?W( 0G?!+ CA%SC/Iϻ5<12SQPBK(RÈ$nKJ&Vx)-"ӣ6xڻ^l?h!W{JjI!0.!6X ~ȥ@޷ !YU`)d T6!?k݂3[W\&d6-F֭],ҩ-kl(@pQ1* Ľ,u]r^6o7X $ ]-n HG@G!6K_cIQ~#3NfYr6 \z0d=b"TS/Ol?Y}('E)p"vîD|6[.ch~~5oN@=SF"Gߘ!2Y|TJaKV(Dq<6Dj^@I$ .W5:}neJΛBsՍCNdfG_Q<03= oXAUރQSD OZj;uf"ռ%9H *.QQh =Gs~q-g!Lkp^/`A@@uEe]ͤ~}2kQA"Z2 2QjQ[o"*[TU:W.oLY6x鼖`v;ġegb£;Z.Qeg"c"w4s}F[O&bd,AT~8xOOLi>K?!"!Y4ϙ Ċnf(gڐ;bM&Ir͊JRsrbVZ"(v r("& e*I>UQM7Ԅ<%beR^G%L 냈a-z<[ (>P~bW ^rbxlDtĹ}KPWdtlxtlxtǗkVZp#&`U#GCZ̎]ᐭ"'p,qie19毺՟8mic~~p!8)4aK*9O/C.+aCWtw־d)0x6 J}voXА%;'=w1 wʹ &GPu6|xGbpN6hÒ x*Hto7, "{ ,35I`*qWɧ2 ?sFniY?O57 KIvៜ ~볎z \X BYUWcJ$ .<:[] "̂ZYgep7TZN'K6oHXɌsGt̪m'l]tc;j` 0qȊb=refUbo# =y[9&W ϞwѺ)80 &8jog?qFlD SEz 2**DƆG/?2*Ȕ*DĆG -6GƄGńSirJ]]gcBTΘ.bcĭ7C#v,CAdT~0*8xWwuׂnDEl[FJv`bwi8]MOt.QI%誮on=F%H_d@k6LneSn?8v=$_K}b>9Ņ-dxPdC!OmۮĹzE;φ] >SBZ%Ay!}BA:O!GF{EM"?Ʒ@~,dL =G԰(o1R891#^3 MN9"]G>6=VZ4(kuٷD6t,xsB*b1~Bq0CS  @{(ɏcUS8E9zP YVzQ=zt"҄sr!3YL׮ 6of>쀆 }}kFu7h(: 7hlïڔ\5LXڧE߷1 "kU^_qSm>4m7ohtt/>B6e 56!nf\]㧷a+PMT1$ѥᾐQx^qO7ϸ^nJRsu㶏oğjMY9e-t17{.>4!__yCu9S!ڳǼulٿgqs>CDE^n*yBi2 VE*"OAxb]E"fPE$'4,"%bM[@'0½.@(]Ź >"O &GK>@ tozTƒX i>ɉ6Pps긱 , x JQ({``)3G =gA<a6ѳx/peQ#ܣW1L Q;ErW&Du$RyOz&޳WСZmd9X&+`יy"\Z2*bDKכ)AtTǷ} Knb>RZƧA7 2kJѡB>_&9oۉxq>c۸̽/߸C AQw IDATXfR6 ]ȵ%NzKv[ *SR(5-9ŃǞ>a>C,J줐)ہ\Bdmh:rSH# 2 )ڝVKmATU M=7Nh,Bj@dĬEPIp(Q\SgwsQ-w8H08DB'K֏R0 %܄ ?5r9~,!#xoocZJʙj(N Z}4Mw=(979E:}G9HIv{R~Ĭ͟/ӣSQJсFrd֝ۯƣۻ؛نdދtȍLcsOYJQcr[`tFZq@^7CC.]LŢg I$EgShnI\*zXS:׎B+T, k+Yga&lKzd,Ě4 R/A2uYjlsDE;hV4\Ъq T M[ԘDn#1 y752;55O[Uц-a䴏Zh\M@VO$,йuk_;tBhBXMW o:ib'BGJ4iv!!B=q\}]t/W\9[柋UnVT'ֿ}#dfv9LcҾcr 㬏k5Y7ۋ 6uuX1x(HRX*v_{@RxМQ-"cR'ڱJJ@kobhrf#ef⣻TXL `ZfxBXf|.*pt Oma*g*]rPL9T-h`F1 ɦ! _kw;5i2>~jp& 2?jΎJ&N5̏ ͹רޠ 4e>/!¨3Gb !BAP)U>pm߻{FS%p.UYe!wЅ72#ILv҃ /k{8v3_w^YUh_%d MNmo. x~v'Uo,[m&:@8ݑÙ"}p  ?`FlB4!7'Q"I +ɁX"Sdћ^^.xyDJ(TDBZL2ʿA!~V/śE ͚ObQWRўy緰ĔC olؙ3$9˼ ^w(˙+j~q1uį,QY7P? zC}"D@RJӏHWeT$cD1ֽKHSTnZ61nC쀳Os1m}*seY)/3.LxS~ҩjzq 9yp" q]j/_u'f[ͅ2{ϝ;yޕj=e:jWvڤC=Sdt,h_(`1W̌#{1]x{xtx)bPgi_^6DtF"40F=հ%)i%R[C Uw+Lɹ}U."YX!%>Ǹ BG2McdN>%oyM'S.̚Qn;:Cn}3{npc/s4`/#pqK8?{/Õ眽9 ~Cbt>no$= `5;Z/Ћcf_?TlSNM'l[I2mNxA3Ƒ)Sǯ?ZB]v=fY9}YcvpN]GѡP(`ufN7ϡ.X.:d^:ym"vNń3_C,1D)m c;i7!`9TvrubY ݝZ$4B. #_BƆ*WB'v1: KjZ&MXQ"Aa?Z$=E( BV#&QX~ *}ߠK!?:a8=0+qVF!["hy7$(H[M36 rSbCTQ[z}(B&:HZ-vK&E/kLKd>!U>~K'@ Ԩ$ţ7{5; kb́B#;yņM"Yb:e}32[3oSԪF Xύp0$)RXRn/i *b| .ۙkio!%׀DI%:Ҵ1 L r@˛|rベGGbTN ; `Pa4(112\/جTK}L&9i|Ha7h33| ;RUoyzLE5☓7oG6OOVLU39O.'YOxq6[Gl6n3Ӳfx8Yr DDo˾D we _Ш&7l1f᫑A7"/8Rea7?p#`ߺIMk@1`_hD {Ј#=UHOhZ}tYαv},\NqlgwPhĶ(?>`8=ƾn1E&GKJLKy Tk9mө7*%SWr΄hַuQAk ^yٰCug8U2cәa!6i0%uV7  ;=^ ϺtȀꦰ.~`r] }R$-ȚgBWtAfu7 ;sF>saט"7D0Z?-˵aaGwlV^#v@y 9,}j7He4{$[3mqhZ" Yn5mqxkMsIN% Q w%ڷPi_JD}f&i臦R_Rӑyv5B6,q T{}IӇr:~.Iǧ?5DҮm{)eW'N=aog0'*<9u3/=h̔TsWdaM׿ >0E :SBgoKYϵr^4`U47@=OSO9UC|4ȣX4TZb1l=q61A l&~O s$7-(d )] [< #V/Jp%]eZQ|Za$1e[Np*<wNn_^ MVmrM?~Htj9꽖}ekعцKwҭ v<#+hIH%թ؈[zGU@Cg>z|~rJQQGTVW}&"6":xa}CùZ%] ソpUFGATF^|+<*&eëj,xNńױ^?~!4&,*_KzrOAW8cو3U!2*Ϧ  ~vvLhlF6 ~hvw_)^MrcV[w"On\wW3rjWM_H=-1xd(ɉY=nڃWo܉:q߹^˪2[(>0_vJ#G]]oɕЈ( WF\9ey[g.e?mvaF{ЈmסߙɌڶbѯԣC OH:r_ONULN~s>lEe;8Id=qb6F܈ݞCT:⍈ki塐4~ߚ,}-PF6 84ig)  ;wQ7TVq02 xggwuW""wK+ Ca>Fm[nsWfd?t{.۞Z7,!!ЊR}w\wؚv\t ޓW}%j4zȀ@C?NnDGD ꫗naa'6rh_]Jчv`BF ^Xڅ`k*kOX³CJнgx3Sw]|ВUPΌgW6Ұ~t'Ggk ;wQ_&qL綌hRZA@LP۞<4n# SǑE.0DXac='a}S 2 (Í2 Y(p@; QN Eϕ-Hބ(āG[ڗׯ*kE&i trʖ_[ؿ[[-\Or&sƭI7߇Cs ugih߯=}̯\-­]>nݲys?~s 898k8yǬT 6)C_&,ݢq5ϜTg4]m\{Ynڧ kO[7+Wrwi8(@w3ǭңKvɴln%.4h շ?Mb@cK="ošu-$[q]>nӺe.=ՃS xu`^&mNn5oyo?L`Z,Vw:R<ŜTL=LM*;E Mڔˎ 'I+U,O`ekߊ+BG$بUhok۲iVG\Og/i|x}Le=T#, ,>Jwsǔ ^1$9iתiVG\KgόTZG[ظ@M;}gql6i ǭ) ;/d|FlK-0g{TEm)qDW#GkUq%~(˴\ 4z{^˞eh¹?{'YӅ>aGZ ?F{knۖ_7lptsI݃}~׿װu7*MX5 AkA\6NӇV4g@0gnD]krP|vXYՂEC_?pШy `M52nt||m~ [5~֜6-7l`tt/>b6^jp٥ "{;@ 'N uI<\ZMpe*19@:^Iή[uX^(C8CQ-oE>xs>.0t^ƍw0^So3^|gC:,`?/2 r^^~sM+E'L}aݶ{Z{+ѭ^v_ʖ5!ZN0Ĕ{D(+7IQ {Cvt7}iDcaU~ߍ: RCn JB-Y{W/^ڰO>J̹qᅲ˰ax[&J$CW22&L/i]&?=\=4>} eUG=k" R/Y^<[ Id2ᛶ\ONطJF_㮈hln6_^#M&z(8'KvxyAk>M~z5!:;?EOxcM>MO8s' ڿyѬu!Y:[7Vp*ͰO>~cx,mWV 2vkMP- 3Q#"L \ I=W x䚱ة$p/9nЋ|uOU5q+E[E*i[}e ,J$)QRRc.;28Ujaᖅty괎ΥyZW9KyUܕJBm۔׬LgUUʒW|?]k|&皽NRP##F2.D BG[W6v]gRϙ+5^OrU-ų@^,I {U`0/AsKʩfӥ~4mH?/bL jr+ٹm{`[cC.^HEmǹv~UGNcT(xr(5{Oַ%M@c7Og^|WA>T&%ۉ|#]$~Ka N,%a% r Q w}t>61KkB'DI#Gćl`}~3 ֡eĭܘ];Ƙ"!T- I 9pN|װ h\r*!G51'CSY9kаYM0o}3axN&X'&dh[m2p-sq;㝪"^7 -附p#.hpGY@!X鐶}c(qzǟʫ3g[l9QAZ4e>/s7Aiݯ U+VC~jQuM**T*uLiX6Ɉw:Va(TJ; :FcYȒg} :3s9;rҤ&34*_yhu#E,o~C:LxqhҨ bqtOm[-KD}Վj`{gUϽ I^|>?'3^3yby׽yʔT0ե*24JYZ.Oe@^݃3? `ӣ$d,CgҕPU\ àyKƭ,M<4\4)W~6Xi\޷6܃\D4lN}2ݷv֏hh n+׬] ט/Fj'#{Tר jTXΘ* ͡^јx;)祼SP@ӂc)$"r4)/ GcjN:ñ剤ւU SSjU!$CzHm!#wE#[U\uN1Ao[}ܺ'uۻַ/~nt0GoC쀳Ol vzΉ]kE~P)V~^~u:ŸGj] }hCUamM.4X ؆ ^wKjժWVJ}弫52{Zxk5==ޝ_7&d>2vņݻTצQyFl^󆵨We)KF.vbѦ[ۖRY4i[֨E;zUZXƯj>%@ ?ܽ*: O nz ;ܽA*U3~r~pMփSƧ6N!E~Fu@*wǃoq/5|^<ӯZjJhGjիT̕ڷ'd󟞻;bʀ:Qo Ϟx^ߔ*>3ԅ'Y7oUצ% }QC?@ͰN ZmKL%~mwu8Jt03BBDF*8 4_8cϼxVmұsF\jh_zؠge{5v{O 5c̷&ǵk.#3R;<6n9(y +|>4F1Sa>bol ; HP2`/.-Y;}gը9&.; ߼3]'9ǤeM{ .͏VoqhDA/{u% OP}={>ܭ9J&c.Ό]6yټu+'No'"|c,`?zƖ'y":o,se4AtT:Ϊ4ݣ\]u?ϭ\H}ΆLLtF'v[};/nNG; sfYб7xm} 6ANҮb~]G]Kg7#gڏsw@EC5B;kiQk!_e_˨(>vmwYL]s"_M*i"0OiWb懿ыZRt遯WwT>ۈ)jcnipPf1 ~k{_6LMG49k)z6xxi{[>=pUL;i?ƪ%ח=pՖN?p;t 6e\NsԞ(kvt:kZ:)c M?knV4B%Y&ځFJ1͒һI Dn`I)vݾoT̈^卩'w ٓ!=\uFgQ;lEI+$g?Qeh( -|8(m4?:k4Sh\Ko2jI''K~,KxƜhoGd˳JKS/*CS$1hI2 bx$P M/v2 l-#9W "_-5ʱRV9o \(H$۴Ҥ܈BmF`{nZ5j==\#??KR>)f G C´{di,yV\xΙȱdqr[" ?a*JRJ`6*Z+!)r6u3}ud|u%꬛OZ(BdA(hٶT6\kc6ØWXht)/.k!"3"f寈i]/#Bsˌu3("1v-w5iʷο~M8 ,$z/,iÐ1+$A,WM/d˘M̰Jy " zȃ,/lʵiB&u"C*^yD @"wK(^Tz mFQGn'n")P>Ί>a+R$CƩ tdRw"!P#"nsB֬6'G@ vBdǶI5tqH ڠK5Wc/"X7.RAgRL& uCgl)E%xIzA@a80! T/?y["Fz oWO܁"oZ)|HTH#%AC Tʼn,΀DKDh9\j xޛeq~|IݜCEЕ) bE_boW5PT h%WBc2(dDŽc9D)u#XyEaE C}3ա@!1+zWڤTF街v_Qԍ 5|Mz˱ҳ߁*ŭ)V+>v0h_Xl <#*=;>ᙙ 1 3^8T\PTLXT?0jGDa.  :0&O PiE7x\ѩof`aP1Bd&DZم\`z 2XjEbsQ6=#(ȴ5A9WEDD/4O*'L7x~7"d&y៝xqP~CuXhn* Հyi w3:FczFAb!cX'A'\[`~D|t6ߦ4G=^^A< gj%ɇ',9 VĶB>]i +9emd^B<]zMVFDž|M~K>ԀLR̯_~R Ήu W_Y@]XhK~^Pk~v} #3 ׯOܧuꂷyə}vO\&+!o3^Œe!cwmT27-o N'l1j^ !/֩K_}Gg?IݦG3gkUP&@. r:מv~G&;f$tVV\bӴ/2l ( H0N"1 Fso% s8) p|sw _7k' J)ed<-Q%J7oOHl[#5IYOcDW Y8mk-6Cf^0$—Y_hجq+~ykҡd1cwߗt}k&y!w$؟Kd ɋP/H9ģL L D[Vf}E-A;u(e>ꠙےu HΙ!En];BVf-v6@d5*<E/v*dӲB= ?nsTz=vn'.D\cƴVTm1yéC/ҾA`9z;Ɖ)a_gr)xܟ"oGX]5ҹGig0TFW2C"oGLVMg"nGmYss ז-l#ãsiڳJ֭QFJFͽ^_r":uk֡Fl2I={G<{E^QUrQ;19Ư_'&& ޿t?Zk9;Ȁr5܉[һy~k>9 Ol8uJvZ>FljGwu~\3FWA^u}=xziTo# .hu^P}ds;@.nټE97 IDAT*uݻۜj~~jP8۳pt-nW.@Y"C{o5S,02ӳUb8ThҦlvT| L$+"UYqWkT$67_Jp*Ysf:eFt+3Fԣ!?߻z㯬N U z3,l ȘfKb%Bz~yPP^WӁƤ#[ 냇 f\##,R@gWAb...۸dKc\q&>Ѿ wf J(`xwˏE?K~~-|;58LVOrgP2ypkhN:>*RAז8)UA f=ZElp~TaITU*6[ƭK WNxx͆vɏ߷z{^|w: |4(ohǗگ*[ ^ߌ|:[:W (͊(4L]jL5,UdGb?tk0G%?snֻ>[{+Q) oE%6C} w`ew' PUCYa&b|?_0AF*$w !;Tow A |H%ʕq62NHҸ¹+d+v+kxWwdv-"盄tpm䶲:y;<̛YRQĶ$Ԑ11 c4Tk>),О9Zp &/vBb,K2&ߐ@yY"iAlNPLJhcVdRM^@toMXɽn/et3/ppvPL:,6AZS,I JwSuX+xKjU|Lbp]!3=Wm %h0Ia 9B+|`c^MvX& r(lWѢ$(.>4Mu)Q쳎E{!lKYPxR K6A'9nOrJ@QZM9g-'PĿ<>s?g2I! Jhm UBmuڪEU]k[tA]ҢUu[U[-勒K efyg}w&/7Hfy,s^;r0yR.f\;ʎA"Q!GG,&lif׿_:ӗ/u:CBkWBqLꎪ<υNx֘C{VIS=V _J\ n_Yx&s{NJKM::pEE᭓{3phb^5\F1jok2#ynϩ\#>9Fu/}۟Gm"YpWΥ3g^~ׅ(NzN留7m!D!,"T|,vKJs{~fۮN+I|te_:~1acCם5Qq7LX2\k?Wi!uA0eA5~'PZcqBP߄ zI`|Q D.30{SJ|4@s58ו波Ysbz311Ohjrئ=Ǐiفl?bbjxmL;5IwX|ʴmbcTߦKiq77Nؘۼ4>ah| XV; s`Щ*M\j&rлJm#&#bs3w־N1$>we?ܼa@X.#TYWw{Bj9b+nѱqd承YsQ7^GHT:5oРY3uo {~Fݞ^>\P!x'yabO:6&zֽ' 'xeĀN kDkѱqdɫrSš ^ZlGʄBCjƔqn7znm}i7s}BHH}vl?.dCA<ؙc:6XgO HѠ4^mqq =WʴտM\ʱ-ju}߾+ne|ٝBsjky1UGDGk>ެӰ:y~^RinC ή[}![}=Zq1_J\iK+*I-EbBYy ]8=%PPV'KzwtH9UaiyL7 YSEӹy`:]1/T3]++iOTWQl?k2`cCV@"s>5=l௖ wl9tFN.rk7$Vsd[n !>8#-I 2Ϥ_xecyW8[ߛ0qo]?}UWmb`|(-shڪۑmAkʈhs4S w͟L\kۗ/:oƶ'~"yr͇湝yָMX[ϱ[/RSGgkxi(n;o{5Fs} K&KHșy]/FD(Jˡã8_ğ^bpDZK[ɟt(*9 H2 * / nArۥ2UFOIepEJyNy o$8<|~~Porΐi&p`I%*=X%ꦧEijj\U1қkc@ e̩Pa."Pt fah@-9PP9L[@\~M2H7A)$rQ#Q|M\3|d8yC\MfʼEd:ՀF|h675H* Ae{y4ڂ*zAmo1H"t{a[@3i<'Q&P8\/r!>Qwt P=`Ebm+4c@2hh\)vOḦFC5)Jn1I *%)Ò>ּ:Cy !~0giIpN\Tyz'`7#C{˧QFn!BLOZQeʁR+ f̬QC? 8J\ひg!Rs}<$6ސύ1=wXѫx=$-P@6?t: ڄ z@:=u*, F7cڲc(P"h9[Q"1Dbxrdsk%"I*o &`$F4HP YL,`Z`RBd{AXXP:>.4)Fj-JZ[KbuŁXFx(O$ si9qbA`ljlXd"!y Y!1%ʄ&1/P8 ebYژrHQ`M%.t0&Ѳ5A0򾘰&栁$m `yN>W2'/W QGE z8`%) ";".72EGJ1MqL) (>!]e β"-" YESQt6"Z`$Z'E 6$@:/f4*Da0u8 ̂Af1To6:A϶[wLHǓ{j]yKYr0IN]Ү,^՟~_ݯBdͮ,ޒi#q:ajk Tē{jǯ2{ %NOw_xYtuƮ;yKh4I)bEb!OL+h5({fmnQW瀫ff +Sxi`9ξ@Tk8]@lޖ `ӞL3W|%"r*IRxhқG/lXB+^0ZYpV1[(1U@h ,nj „5)Bz0e{􍌈4}ΛSRs.ABYO;dW7{ܹSds:G葸o7mgB6&obsNDa0:@]~JĴ߸oN \ZvGi}=޷o3~!sޜs% Ywp{IqǞQ[40vj'\ND$usw7̪r_βh@qlU5غC @  !0hmIIKAIyG:P ^ UDxH᠅Cj|(E!t-T0 7,g$ K>XMdEX_ Y<\lNdR%8W-ݐt(9t_׋FKܗrpo=SA-[3|tӎ&3B;+5ijpm2d\~ؚrpu":8k㖴lY뱡Rʽ>ϛv{Â!(Qը/?mT?X!`Rޟ3w%j䔃I:Ώ$$?RRV9qx_r0)'.. _゚;=ZwmfgQWDz_aωI>?١+Rʽ>M߽!OEil6o:t~{I)iRe!᭾ϫKʘpu-mZУNlŮm>i7RO]_oھ;G|Xȣom7jǭ8O׮CTBj9_=2w^8gwAvm}ZK //5iԨǜ=$YSߕ?/GNo-_z(B=:z,=`єq]Z5=ӧzqJnٲe{T>/_٭C|1a$h[6Cd;閭:ӤAKvt{']s e|'4lިn,U;hGD+AIDAT7'I+{7Pbp= ** @T:n ᠋!x#$F61AIO$r=]Z K]7AB'1$ 7taӬ:}u{B qW}xhWBUg,@BfҬ: g<6J)\4DSKBBŵxo¶{+TOP UB<9;~.\w>,Cv*Ur_O+^:w|վὙ|T6.5M_~╖eu*nvsgdng)׏0h\h/S,tʵK)_qRS˙|Oᕝ6e7֤ M^jU]@=? z~{w-dxS!OX^]xL2~@D>/UJvEo($":f7Mw+DD9mRBBlnԭi6:ᛤ{WvrdJFϗhBYnCidΪrO |Ʊy.Ox:}ּFTН{U bbo;fhGJx?q0@«VGwދM {$*K]eKbKZA ThZP ! AkmR+oSa'MjAjș|M'm}HP'eI%""o֫(6CBZPT"A\:9jK˂3@W qtie5Ӗp i[,f:տ'Fq;!Ψs3ǣ$ A@DN`v/q)Oy.M?ˣ{Oٹgv}O6iǽ\qM!bYM#}qˮ"KH'@#Q MY*OJD!(yxJ#6)L)Kr()Z X?M/KN#!O<%0 tcF! bP0$&L fTzD?aVVq/eH)`  uh2uj ![غQyQFMB/ $:G3#7BW-i^/9 WmI[-cZ^q7b^ڏFx/QvTj !S{3phb^٣ƔB XzsQ G2#7h.,z0g ?|U{nKBGZFB!r^÷FvyS3FƴsX(U{B;|뉂 on޾yLD#ԮՉxV|2wy f3D7"+ӈd$XF14D>"d8wc)ԓr=BD/-y"= EEZXen/xF:nC3~]R]IVFEKST H@ Eb đDU R)E6Ì^5rOvhRWfbNڧ> /'wn1lFjEPq#~YҿO}3_tua٨qO,kϿvh͜nB0gG{{Ĵ%"IA晔 of9e^PH0y҈W"9g79=审啟_vHșy]-[La%[|X@7ZO`Td3~xR[3FV=t]#N3&Vn jLzݭ3ANM0KV"91= ֓M[f/h;>&#:[Û垕2E TΌ $ xZF ^J R т#V%7PTń{Xi'l=H$ !'iP~AJ"dޣ\|(q\(+kѫ$01&z Z`zցY-; tA7maPA&@4iOVvD1)gىurO8ָhk|ETQRײe=~\F OLCsZgjcdÉkg=2ez,OBTUWpʣ8 *Lwb+HyۜEkСu 3`+c L (MD3TH* &I3#1FJH1.tzlBL E<m^J;PVc( b"H]U5͋@b}v[O1[B#VlX=|a1DMTxiNS.ձ"t$0x*sjRbZAKK^ŜMi'"A2>KirY =' ~HQ)ʀ82P խd)&ZJU=ܱ"{Y4/!eW# \TO{+;] ]5 ,֠zg +YRne)ZgɈtfP[?ྺ{j"yrM5\3RρZܧ3M1}Vzܱ?w#Xq_gq+ PK7 '?\ѓv!)m  ! axB4o8+FR l ߤI VąP׀ 1$G쓇 hc2u"Hd4T!Ƭ&PdjYj-n3GN ~%D;6:"iDYA 7K5GC¿ee &BpV{ 1  *Fr]["3/ˠ? Y0Ȁ &K-DJQ \LX`bY1sJN6!H ,I@ŝe9)H]$L-7rV @>5IENDB`glances-2.11.1/docs/_static/processlist-wide.png000066400000000000000000006741111315472316100216110ustar00rootroot00000000000000PNG  IHDREm sBITOtEXtSoftwareShutterc IDATx}w`նZsNzM&EP t\ ^+E*`"!Jr3s{΋ɜ={vY~a8?h]'r>G"{ii *VÍ~}C"""M44_zW}6_dnD܈s7O36>2T#f _"|Ȍq,%@Dyx] 䳒ۭٟ36ˑi]gGڂ!+( ̡.{H  ȵ/M%\x yxhs$x_QԹDߙqFًZ0b\249( 9\)7rviGOB 2׵")gs[x!ImQ,_-2to _@ (Ņ ū7&"σ }(9uhiDѺ'.ws:xTAD+zgH GN&21#D {Poaf]`u vPj|P!xJ*4B$4k4jD_څBZ' jg%_ulZC@E 1Ju`!@"B`QtLjL~fXL@r"qT~S hP8XP2J6I3sb1OBĕ7G~iZuw2v%̰3l.wD.0عB zV(< z3Hd#6kYy.ֆ&c1"@0;qxu$  cX9"1KEA %rIa1jG pQb4׊s`? A|\XJ-}`e'/U\r}y& ! yA(gĸ-(BeIJ@KܢX^Ù消W5E Κ@jTDUwMl&HE êEj$FGe~S͏ijj<]ii&ktR_U"/o vݛRFw`݋l?wA4)7"3z} m}6L-dXYZBFց,b/>D#QތU.RCOR.}$3^>yO)1H &MዯP4Ip1LΒI9 L%ZM) "Ex zҕENDb`Cr΅x/kNo6rϪc[u.鐡L4B}77iP0$ .Y.Z_ǘw8{˿ѹLQ\v8cۂbߜ:{oN$wq칣KtcVMUOTUPcN_/3jT"FQ*XW'+~;cN$Ż}՛Vn^yڴu7KRӭOΜw Xyf_aժKުFjn_jW\r底+WiDZ&'Ynu˾_j[8oj*TnMT.ws4դis.uA(:Ž@G,qac-3/Ե۟e9], V<$PP5q[!|tS7f 0TS#>5ik֭swNп'k֘??S?†.zewj?gDtlh%c/?}S?ȒnP^>ywGJŦb:tCzn~G}97]z]ɶD?ڕ+>~>B UW4iz9D뾄t1S 0 o.W6 t,0be(m;:c"4Oe qxf9z}VOgؓu`#nL z)2LkCAଯa4}Gc#H!6GrVMRC{0hܯ Xx3^T9C7_? |! 꿴>!r| *i?w>rUU.GՄy?.}@?2 V~`c,2*ėj|Gyg=)ϠߚmkI{{ң)jχ&iΒ&V9%[ӏ2%빞8Q֊K !f/ j|-񡍱}* v n1`6+h]`&wەRW41v}Ҍnޗuk+[&bܳyVmz±vR=RKMo P|m ܜ{5r>T|NSVy<y{fGݬRk cd'~>w4mMy;%cq̅Q Ru|!sND2w,;?:'^v^e( ᓱ!V^ {蚚Dbm9zv^DŦGLLjw~jV_w﹥P Ϗ_N ^"@P"l1|3[i=mVVS5(с#k](d+ @RTJ0r#F~u@nPNu]Z^:ϵLx}E.o|&Pn.ӣO@{;}ݦb]YzO^[kqFu|׳Gxtak^5C>Ѫ|\:o}y@Hz߿=ٺB/Ǎ,}#&:1&]~σՊ(; 'f^_qFuWaa:-'Ƿד*@=G Qvyia?YWCkVBx3'O,P_Gdtd/,g~ؓ_4<7m)[8߰_>7xWE2g:ū6c¸vdRsk|}j_ߊ=c:ZrZ^I]@ܕ[{)kң>ғ-V?W~\Ed͚zM;4QE<䷋$rK44U2ݗ?Z~Z W7{nzDFyӿ^ %o'|IөL׹s߷hO6wse/}zNPv3^ѣES|iOuxO3܇}m/[e\>ő[+qנWv{蹭 ''"%3GMmPךE-{"JJC=bsoN\ėl6g턊?0s~SV|_"ʡ%cԼEOuٶ粳]D[q|r a xr@y(bF28|"vFX>AEy^.Ä>@Wzʂst]Z2b"! bزFŚ_ _L] em^:LDPm ziof ZΓu}Z U^~ā5Ca5%7y]߇@IiPSHf%(nnX"cJ;"-uQ4A`s@Ρ.h٤by7tU(Tm\|.gw5{t/پ}_y Ctd{8u@-ڽ6o5ڥ+VVd-mtMe Mgaa8Ly?gi}_MՈvL۰_USzɉmX3ZjeDa㴌YoJL t;r߸x=ڹc׾y @zmzOˍ|] v&#l\%y?=nX_ x챾_lܻLA#SlҪu%"iڶifV1VI|~}, Lzɢ_yiztxY{.M>dк{g xoyv35Sl$տũC۵ۨU?o۲UV8`rSF6=^>Z0S0AhWG̿ttLiұDhdT oΨh֔οjeu&ޖ@GnڪM?{|*yk<=nh}3<Ό'@( F>7dϨ%:tJ.;H)k* 77eyw j׿AA5OO候bE_I;kn?=D(ɅfԵkמS+bv-9X t;l \Ul ƌh_PSUa[4~dNcF([xt9a'Z p8+J_۽k@?Wmǔ;w3eUN|aL噏8 D[vWG&fL/mol~6eg5lF{ f%DBKk`~GĬ.in!;.=A)ghRdDBncx.'0F2 0<</+8nˮ%5Ja1( *ah@wۃu_lߠP&>V&;w>R7bKfn!3׬^:sXYϿ6Cj,ɹed k?pɮCV̞{8Zbq<~s|*EץkzAĔ;m~ci˶mQ&np)3W8qxFA@Ѝ}[v=o׳oL\pl'փ|;Oڽ 7xk^B-=-mᆳ_;~N-S$1O_y}/*z&C/ ) )XõO|=ubo>X/ϙvI?g{k^& dI9c۵,Oxnbd/>yCfLXqkFE"'/:V]rqRC&Rkm;r5sߟ7۸i>EO;/sx}("VM@WC?o'nqk۪l"w̢oP['>eOێ:{)e#DO[`вVL5>#|{SmhS2ސfrg D]]F jqίb[?@ޯJO>Ts;}#CG0&33 V6rPխ83oͧ+ 75.x<в/Z, )(!dN+(~%fW41EQ38̆M'O9nP;e-[ݴJVomP&{*iшK@/4Ϳ}qk k@3ڵ W)!9:PN\B\bXv&m$4 W8BTDTU/YEE49 q*9f"~"B{$i_u{uYB_{mB uҜ/;sinm/YԵ(h$ ھփ տ: +p^[νI&r)e9ݳ{605p3u%IWZ^> [vm_짍@>׾q5s;OGQfx͊K}}-##Rl-))z-JD#TkQSPIːb;I|*~1 \ң py̔Z]H˛ }(qD qNQ IDAT^A]-?[;Y?l%yQu !DON; ܵm g SZ]J.[Х?GIg#ggU9 s:;xVJpժTuu*baOƄ\VKl9 5v`9_'Ջ/F (r9 .;H(kɒ\x(W .tpXUt8"21 'ny. H+_fO O4i&##=򍻱!2r+$\L1wEz$RI56N(oή_ 7'!ziwSWǼ)~S 2!;n4b5kwS_#CBgFaJ>h6uB[F4]':U;dl$Ю^3d8kǷkK-qeuvzɷz",Ҵgeϖn=OV%P6q˰oIM7QJ =Ռ+FYd t"Wsu-,b#IQSM#MUU#|~$5 ݗ4VͶ Yk'oMBZQDE,T:x5gUgU~HT`-=7=h*$ I(Yr34c|rbNTJJ7^/t+a(ᐎcYWjg$*VhJ,IONG -T \ɆpRJ eĂ&EI Z6aIe' |; DLФqO;` sJԴ9]-z~fLyklhќ&# i.Td҈ d~.BŊ1&Jddux!A\ Ԝ(%ơtUsOzn)mvxvd /$\F$?PϮ;MՉ,~UÐ.|J%pZeJ,AVK b1$8HD/][y(RΛ)؇9vɨpth2G([7*% {kʑ;{wJ/{%*WZBxL,Vzj #l2ɉPS͚WNPw,U<-&/끵`K9\)C c)U^XqJj5 5z-nS^'x[ʾ ! uo*[x&mo{aoU( \;LfT(Z@ްH*_\7˿ *Eͼ@l&IfJRժT@<&TMe ƱQUTͶݢxeEV3J-ʛ 4[+ZLU54{R%o֟2OJ8Di֏u^zW*eTyW!#{Iܴ(-i;K!\Z$zc-ȱRo-W]E̗||gfM+'R~%Xxm~yފڅ+ߥWnN ;[k7Jl[+Y.Ow@ZcJYha|?T19\=L:6TH|5~aE  xoì?擷 xp)usu† <ά>xGdfzO KU3ݪ1aoRrj7m B|"w5" &vgF6pRJ^Ϸʛ\8+ ݢZٲom}=8C_t[B=ljy.nʝoٻyղ*ac#.&Ň%@Pwbb9\/x!rH_/arJ%y߁KMVA+|#5=΂$HNM4\Y$(M_&>q}Kڣ&g=N[.nU#5=Ǝ3]u(-4噔6~a嘷W.>ûkvW;ʆ!"SCT;: %۾ۖP;txۮ`:7+k. {}q/"Qj}|"/eçߙ}ܴӽY]~;b(gߴA#_;| sv~#Q̯5_Gc~:+u?1RɽE.ZsJz&O<<3jcND)W58O;L ӎDEZ!S]Rsxʇ޿z"Df| diW?К5A/п?"W㻳G8! ddEpI/~@ߚUwftО;Zr rjpOfW gn;͕#`D4abRć~S}pdV_vOzq°O~2:&0)Ws}<Z,''HF(h,c@vOzq°aO~2|}8vy_~|#/E2me(zn#/}vFzwnxE6規Vyyi2.^v8Җ_?Wf.]= CE8W.k W5NJ/3+aȳ&~S .̟'V2S'ۨoծ0r#5;cgu1{.IWYƎ݉B,paۜ_9ݲe-iZc"NZcᢂ.#',[ogT9.a7Ve*e/+ov|DLd? ܚgחхBm&BxDfh̸kt)ٱ\c(=o͗8kC? O0Ds!$B!{cf,`3$}cA(7$/ 6Q3W̥oc2PI^KX9iύ"gZm'˾!n)=ץ+/3*5 0g&3l_DFWY 0Υ&9$9Ǿ5JgozêMNJomqr6ޮ뵉 aJ/s2rܕC^_RbeATՍ'mKEuᥱ/ް"Qxjp_Mo 'sFzim砠Wx;c=q$3ò[+\Ws;a"BPovDlCtQN 14_YW&\0e%|xk ¿J8`١R؉~Jýۄ_iG> IF!?DW98qq= J~p>'/98qF`$4HkwjrbSa`j2DGxC1\{2L9Dr \\`#!B#cy䵥迈C/wJ< 1 r}WzL(h1@V֢) 7CRzID`O )@\7F5`I0AzC6؁<č_f :P9#?|pϕÉay`ʂ`+{^>xx\Ȣ t;zԎCzc  (l0$SC>Xf z I&hd "&'&`:-]25ؼbV]=͒T NX:ڄͻ"`I8xɢ^I%U(K.rm?нJV-cZACב;Jb1~5lWENdĪƯ>E7:ɁJCеLBOu=b97>\Ga .cSZ9~H`8hDz)PfWa( :!VpD* ׃h M3SH?tFeXD>:L_QH[)#.I5Br0M5YJlm6W2R͋p[uBXb7o60Q'D>h[f\B >sxWz]Đ=\r03EK<' oL=z,RrMuYQ:!$†)!|D'+|_j:cfuPBDdgUWJ}/g5Y"$W6(p9FpfN3Z-&r=ڋ*q=넩Q:kF&l]ܣ猍%{2RQ 86h we5[2 [" RrWt#Rt (9)3ZzfFCƲHch}恛%rVq=ёaP^(+1( Nu䄠m dV2(o^&wJAM$"Aɇ"ara"yybn'Ws}Rn%e˔U rdCtpz5)l_lQlΤe$򼁝ÁE<|² UADO?G(튲>Rdl ՋETh29nbXd"?'<Wæ|宾LE>F.]˲ &RB&)MF$2|9'L  5H&V6uI>k  _[-1@xx M'J'OiLr ԅ G@!v3EeYDEi=o\E366,H4a*׬bbԐ#i$/4$7Ʀ[ f= 0fy-]ےe Hw`2ɺdBdL~Ū;W5/$QDQq$ 2=p86}i͜8F$XX||F9hrbPлePsW*A> bfx6 &w& "UTU#G>QERoUJь9L ;†'De@z8ٚ'a/LN1]1nG#<&ec ;/] T䃸8Nj{IRT=APo rȟ9?Q΢!,EHQ$ AL?((BJ(wVp{xv8+3?zQ@yt̵͒:ntv_=Z Ш0 BVidX< ^'#G H H31N؆r|2a?IGyɅf9;* WJ8 g8wIauG.+?iF!4Mrqj 5r &~3jԳ( CT[@=uAl{EGz%t֓5/9%Ӝe(jɢ=~O̅qjz`l?sxDd1,'w@B r\nGvLObSa.mk1e[qGO7Qr|Nzc DED1Rg ,D}^[åk=+젘R JEJ^BLE%#K{=FNk+Zu60L;E%w  zиޓnjVcC~Mq+_?r뤝Zrz[ bc滈Г]M-Y yd }rSK%E {`kJ(2|6*9sP983s\‘HqE0Q$g5|٨ժR +k9""tDt#\˜ π<֒Pes)D& i299h|TIEtך&j)Aϙyj0846 "+%X}r%F ;!E$( y(g_\! m_aZcMbu#COW5%b `2&ķ|.E#, :i r [֗gBp(`KWVE{$Aa\8@4uHri$$|vfva$20 q*|- ;X?Q Rc=,eh((+γ's#HXEPx'x^g%TD/le2M*V qf WR~%<"P1 /[bfmHE. H^QDɿ(08 eî_;dQ^#}Ű<Ƹю_C::=: WX/+_XLyx/pĨX([B;Y/3:C,$p*ZW$=h@jz c`!ȦșX-pڏ|hCF1"DIhr <9g tG(Y,^%|Q{祉g{BΠLUT.[]Q"7_$;&! kي}\] WzlD9L"4mD7wxu3Նrt +x[6U,ળ$CYR7 faPgH JE=L&##.p6.+cJAfR~*ne,2 aϝ2ޑQg#../h0%?0\&/ڃ1Q)V.X1nR$c{uHϦidۃñ!S'WSƳK'i%UGYj+eos.0պZG\XA^K^Xh6 78@0DDE==Շ\_ws- ; v̕҈I~7%&~h8 {@zIKf[:/8_VlZ /X2<^/EBBQwE1blS;뭋0f/9dٸɋ$#O PD7ыLFޑRNiK cMǍLi8F4@>\v3QpZDHVB ޫ4Q?XN&O^^Ty9Ȭ28nZ6}LKPN@8aBǖG^mtLJ]ܝ9oྙe)1שc"k 4ok1_ɋ9A#be#]q騅̻ڔv=2/#P2">̔Ҝ.ZH׹bX:)^̹\~yKX.كy`;\s$VQz~y)7ecFK 2IFx/;5 jv< $XuS#Qf:|V,ShZc6ܕ3~C$e_9~t$z%MӢѨCg?sz3Įy,հ@ײGaEb20cuvQaOMQ: 0yY!B6,Ux G @r$&> p~ȧJC"َQd%B`CP풘$8:S<u8xH ,)qEu߃^DQ&%>m/_9a'zƹ YY.xvگGu,Ht3/((]ޤjy g6ԩB+%#! oPGnܺvqrq@mܶnCJᶳoܺnu۸uƭ/q/ܸu^*}kO}ac-Pėh!5}~Xs0]oغv [nغvW +0}ڍϦ׫qQ7l]iE-/YU4 ~3W" Rޙ֣OFm{_ݰuŲW"(H3D'nR6lIݰ%uտ.ۿI0`fS׭ߒjne!̣3֬K[.mGhU2sx d5̣ۈ6֩Rѓf/ۼf]oK7m8Pjڴ5F,k?=FEN5qh W]vVbi7OHT-hT-+gt,POYV!_]Q5T4}+>~Kl"iZ4jTwUmI4MUh4AUrh %賵7^qMϺ/ o5Vٸzk6^7EA 1{ͦ ĕ uo/­LMݴ:uG틠QÙ7bZcYf4IUͩ6/5Sd$(ዴuiRoz6*8h,^9GŰp%G[R7~ٲ~sMGN_9u}ڒ٣;VOHU>o͝54˾tT9k>V1: `%m5ǵ[n\v~_s.[̭Y9ٱE{Iꇳ@L;<(`3-@J+9'v!a p L',\bZo9rN>ռw33Pe&@a,tvmHDeъq#&Ą\*ӲP\+8%4#bJml"FLP8m/~;BZ%-_mywSk*X֚m|yStcͥ&RcǴ=6ɷ >є>r-MP|6-Mk:MwMzJ[b(۲up7㉻W&?0i3m|eU.Ǒ#Jb69zQGU Ģu8q_Z$m=So}aIGlͺ|28ծsझ\G_06y ?Sc|t{Д}W.@.e'9cw-_MDЧ– Iw¾rzeФ}}Җ7{ʛ|˫ O0b=npikN;UZߝV/,;1]#O:O:~o߫tJ#@ΐstuAwQr;y߸1g:_:<ع#L'`bThX9hQΙݕ%D+eXMr*|;e iZ柣7  M2z{V։ U TDC& \wFT۾kKҸiEKלa#7 !D3[:.]6gT_4h m#zΛ\󕏆&zKOfhFMq6;%#j[ `%7NehtHn]2yoyáIGnӟ \󙉯޵gsCw5 ksc*Z)sGTe! bǡKio7W?Ķ'/&;Ժ 2HgUn)? (-:)=i3GzsG" 5~Ywe{ύs`&/VT(z?@ ΋ GK=ӣr\t{, H52P~ȡW0PlKVf %s`k l(~zPX(0b)Q) w? @hKN.LE؎EQbI& 6};B?dwʼn HCqwE[{Xww(Rܝ$`q(qf뻡}~m޽3̙3<9P`vljdX(Pe~pm`?:lO%h^C ^KXKI8x|*Af hck|L\Ƒh2^<#zt;z$2k B&.e,*?7x<@FӮ *"$)PYZ|,k L+m.tY02->@V#DTg]jh7 @E ;>MN= $~@"է.@*H]\R䷾+q UAWUebߧվvt0J8jmMN;'}$ݥ._An2$WARFOl,yUx87Eas '59FSJ(w=G{ H.-#@_0HWH>q'5$| (u~SkB%d%X'ėQebK zЎ7_0.mƘJ&Q51cK ӿvs4cƴn=~MIR@RFOl"y]ihBPOOV.xBÆP znаw74C7@nРwwB@~rڹg{:Mx_ĈB#cHxVݰg9Q&2s8!wjag]*)RiںL`""2F !c\UU @/0P),I¹OWGB KV4mU_&0KaO; 2UNI]Nzt4 LA\XDRBZPz(ޛHn$Q 㱂0bt1AXcժL9?1%A=mHcs ު&Y?{av4wU ns8N<wnӔQfu5MƒjV}ߖsiC,+3U+nss=jqRg'O~[F c 9*{un`;}.Ƽ Y>2nQƴf`=eq3:6t{-?0)1<ͫGw H NJM'n>OZ8iZaߟK 7"D^3h]|ȋ8̳a߾VAi?IӇAȺ1|m xUD Zh0`*Ͷ_]:׹vhqْƜUĒUzp_gO|J)d)#of(_7M/VgECO}ƈȤ; u_h*@n#@!u""cb]^s臄4lp[ \f'APt~ws'Ǎ_U,JK]<8fQsNWB‘;u$:~oFK…g0iIS55 L5vfsQ{sw/搯tuwN1=),Иe#@ 5cØG $ \؜~Rnlز5@UާǗ,^%FZtaK \-Z582%Ŋ*?-8◦i{@ڰ3zwqό$[?ت胭%Qq1]TmNWc޾xzt@]|z c9⫴KEC4nݩ}v&?)`:52&az2__keZ8;d׊j=f_D o >3 S_Y2IVڶiy^ 7N^5zUZ2b} &#֣.0E)aDDcdZIDF8WeˤJ:l[1$Ċ+KF>kܲcm:hږ~7z `<!$*@4yM*]uZ3ѹ9pdW7w\"?Jh;7 o̸jzU"pey{e#Qt ޒ F_raʉ5 Ń!< Hn+j4pn\Gp1Ŕ&J3* }:%yES2V%~rjk?}~~({s@P*?:LWI4%|*RT BPJʑxR@(lĞl, $^8X+˕`!خ~@+>hT2`R(v[wQ{xdE9 ~/MWe5i+g9̈́;OF6 ۀyx`bXhDz]I0'DOC(2"e!l^"1.ܤ|e_ōB%ɋFzTbPiaCbPWi@MVwB?\l_g5O4Yt>;m-J˖`qrwbxj d[ |zp_?h"ꝷS@ @nb:!ȏX0UEg׬o.NKNO^g_Nen_&栶ݪ䵆vZ㇆kZv;!37=05E1b`uƕ+K2rJFg%C (,VS"0&TDF=R]N| gmkzc7Ed9<6tֹ;1w¹{ 1 Z1b9" +ccR匆Mko$C/.up\MV&WLMS$ų6^9[9hdC u 6x0vLz˃m7ea|M#),7eR}K%WV|_ye #YBVP$~VhIg_I۠魲O\Nϊw{&~ЮK֝z?dMSSW:2]h s-Fh&1Ak׹eo:ǮmV.7peIܾMN?dOZo q=g9JLQ`WO\~R2\1hcj@; )gB,V+Fujd Y@r-PO#*`5BL 0␩)"T͏@Pv"lGD`n?Nd qc6 jMFb` 0̫bCQ3l}L|@1022~p@k4@&Ge1]KhٿEMjxk#KWXع?&V|`E'}mE>р.,Ey34_͇ !:/ "|$Oxe}O=_kB?*-s> ̯ۣU^JCUglOnWk_Dz1(o>] 3lpeNV HkJ .6fYaXa;a*.4=)!)KNoRhj=z`]i cT%ZB]ZRE= \YY"x`+`luL)JlPu9PgT#+8mFZ+Qf<]=uzH4n M<h*ܵР}u&.MIO.YiN9MPqtj5˳%BYˈpoҲU]rBs5\ZW#6j*G wiU.MXҠwl o&(*> }~߷w鿶q-;zvF^aY4p 1F>.n˒?z4i7f<'W"0(sevV_#ʌT ya7%Bȶ~r5[O7}@.ve) t ^lAm7OfZ]8oHs/j x`ܘ_Mqת? dh|?GИHi8t_ I b~z˹Q &̮96n/Xuu,f%.˄M>ېYnD-zb c1يG>yѴ,Fܬ;"b :f.$:is,lnxcsnQsVN %)w,Uƈグ UG vwr69WFWO `Ҧ/[ו '{MYȺikPˢw-b烧BI+*02JHtIW#)m]]IGʶÜ3DQ“ˏ$)h'S|"Ġ7,R`$b+}c8g"k?{"#ܔ,+Zm:lmlIt&@@BlxiZ5?oD,,yYH?Aq-hdX3a ub'wQd0R\:1եd"`Osb92Jj*3⎝ӎŢ˩7j6Qbm=')Fdҧ˫iV|:xZ#X9Malc7:SQM\2=W0Ů46#Xf;\[5b"!M+?S(8*0B4Fd0L9SoPF$=@yIcft]P5lYwy`,^0s<9 `6'Nc J&2n;׿1iĬfZ{1LŠ*2:0Sѝ&c0ƈ)~;LZ r kV27Gc}y$gf0u!Iq ?b~c^M;mİ%s.jbc8gvc~ \x2Yhh6a_3RfIڒ0aeLЦ=x3C>S!qvR(o` aR K|lc2g;zγA晖TdD5}q/Sf@T- lA 焍X=[Û9hS sOw̲.L<`Q 1 *o%V,*l3~C5i*pu12a1\Desܹ3d ۾tB,-8_,尌voqj@t?#nM̶Jٽձ30Ъղ_[ՍY;'1:`ޔ6wo[%Yh0bAa8/6eRDə\&3^9k(T eʣq5iZ{9UM;UܡBHĵpM9-ÌV9DYM;U3Ʈ">TWniP: y0O9ۏuW:^lc =˿6{iw bgFd νc\LK5ێYAɥHj$i6jL,qEC.5Mެ"s90}֓vOq`۬kjjp0ְ𨫿6Ӱɋ!QcH\oKC!jY8E d6.d抢,b %nM۶~n'"K=aciK;l{}mnc1MlE/N񓋈}qO`=+y%͖ޖ]onHh:{!e||نf"^;"9gse6y) j?lo}k֕a 960ߛY4ݗoCn[YlYӸ1`Inˏ~Ήa¥D0;|uj]^G39H=e "B^{Pѐ7 ODpӰw!oZ&^z.9oMuqR:ʡ%ݜ-r{vivw!96w]N9tе9:HNl0x幻8V"!tNIQa 䊩填ء(%ŕ)*4aPXi8j`cc1J=]Uح+rwٟ=WϻЮacsɹۥ*Pu-?r~b,(8eȫGVn`EZBUīЗXIϱḿC"NwJaNӘ5NfMeq+ ~~.bIi/r)1{#q7wEB0]VF$rz1Ƥb4w;CWЦ(%eXǀK mLrsRC1_^|" O4_(@7kJUzdQ^.oסV>9-LZF(zsrC7KEv[wc'i88Wô!ZezLt92@|QW" 5 0$tW l[f4gšOcR<$X $c1Wc@ภ1B(',L.U٨`U0ZzJ"Q2.ʝ **G״DJug+y }@Xd}ٻhZ?ڶawQcJiQsaJᙇ^DL.:nf"&֦l>*ΰ;b`,Ln:]&l4)Nߑ4Wql-ַvÚ>_++ $ 36r8Ww}]3^y¶MC ,8IQ~![Uk#*(K:|7U~|P3e$9ؕї*#3 s\8"]bI7->NP'ǃ CЮfinD]wd#<]Hx[G5FXqWGxq`5WC/Lo8v]fhHxԋqyt*$@0˻kv˨W7v;&*4<*4`jDU`;ᏋBBÃYQzwQ/o\#mbKxy⟣y$kw>V64" bM۟}ڙ˯Fs? ~|y4Q»o ۵GEDE^2V:|NCB]P:~9v/<:u_}}k|=b b|ſF7 ^zuOϐ[~j[bƋ_GE\?vJ-uXdGqyk3J:?zޛW7 '6$NFykѽ7GkB܌V| I0,2ɕmcjW2z?Uċ'tP, Z[RS,sS%YI[,FXYm5r򮐆vgF_gC\W.kft3v,ֽ{ɮM3'ŻX*c_!f`@J UocJ7*LqbbsF )79UۮCa]侍-kXXRoO5/oPQ 2@ip>)H2*[B+HST0h0jƒGBFI!_ LڽCE\}sjسkJ/vDfH¡"ڟF5/GqAX:`oK#q:U&!bwٞM3bOKh"zzS홼.ih/ Ⱦ0Nn8w1Ib3|/_.7B4xlӵ=}/ꇊ_vy(6En_>c*"@y{VI<4ë>.ٯ'fS:g>b؄! ]Ղj3䬮] \Ot[eUcFt~Z,ӵ;|ϾKhIX:po?ߗP< (ܶ@JA^<Ҿo#fX&?3v2`? e>;LX֩}k&>%x" ym#}Z}>#M'gW=N pz#pՆq8N8s[E}t@6n=>y؈a3>W: Ϣ.o"^ — ~ܮ[6'#G#{VeW2P{OqYDfABy.k?D4 7Du  \葶 :j*@X4 jNmP[R&L2Ƅv?NhuwƵs Mqmd@'$\mOkW[ vre x;iJ?MP@H,3Ěݶl鬟1kɮbbs:=9@W UsKFuBp=&_oZ|B4|𫰐RHů7->)wA}!NrY*"I$>E^9<E1~>W|WF޻~gs sR.9~ͧb-|[~RUE滠V1ANe$JҦ#{Z߷Oygc܄yVm`Z!YCy¶އO+k;9w9[@ۍpcr(ݺ!DM@r{k(S>u!vOO{쭡 G40^)UɏI5īXjYa1#}%b5Y5Avc;{pbo`)RUG}:("h?ߥd}~qa*@5N&zf y]+7ZmFWo;:Lvp5;IIO%=_8s]nF;p|-}g贯C=*BxIij ҭǯdB㸴3 h8rcnl>~[9&aO5YP7, ;ǵ,AE&Tʞ1$M4؊ޗr˟ G k^tgePuh۶/>l4,L7,(SQ[S} x&:?}մdagJ|6Y+OuտqJAt\gyBK UZ KgO wCu{5/|3\whқ=LFܵ>mŠқ=LFܹ!m򀜊.߶A i8s5Z*`!p1$skZ4] .VS\%&OҺ~M+ˑ-ljŹx2-k(~UROjwrum/VkRY*1scD+)*VegA0Siw7ViM^%mRz;eYl(UI5k66eMgOT3N&Z^=$?vSi@L1Ɉ2jD9 K24IcD}KL.*%caz%HO*Dp¦' (AU~bNQYT-d@5\].56OҦ~M[BUXPR*RAl)84m(t:p5j'O<05i* \U{YuJe)"j1yk i@{̲{53D1I?~VUdIf9F:k+4}p%GT=ػ"d~b%HJJӔ~B\,05u^ K{_ 7رiCm3ACI^S:}PKxUAj> P H ̚7P`iVAyq}c'Av`NrrZ+^jF?1̭MIԻ,e5v:Ht~ꙵo?=N=ϴgm;젌*"}TyTmD+ɚVK~ ^U*7!  P% ~ld+' t?ys>Wh ۊ KEAnS/"˩> EPyfEdv`纍+λΫ{-5͚C,_Rf^RraѩWC0W ō7;M>sJ9A$cQ2xǷwagw?^˶8W_av)k BRZo `Ѫ5jtorwbxlI93۰HbL.r(FkYvedrw˶bxi#Yu.?GW: vG4wUrrOǠKj#?9c $JM J{v3s`x<>G K2痬=s}6?$PeՈ*T2އ1%c@fYn\L;?B7N g e5Iߣc^%cR43tn(,d IDATRf(~m?J m8#8b601 [8uǔa i΋% n،{M.F<=-6Qʂ幥 RF:-Qϋ'1Z<dv S,Z] %XB6hFk~`]ab+ي9?F<]#bX4}kpJҲa5D)`MS(dtU ^Vk{/]jy=Ҿm> My+YZM:& Aj>WMUrJ^l'U|.s&ndbZniyԞ=ҁҰcGKVD(4jB'~B1$ݩb`A4cލiP'SABFQ3Zg_(B# u?SK(SS/A*2s_]q56 ja\xlHʎ byPZQ Y5u5+N+=|jW6F}nQԖMF uʸ0IIFQ-ʺٰ ^X(wr o&$b^yK rP޺"ꁓ0 ܭSd}ĩ(Pmp7NNrYkK9"cMry#$1m0l7};FdlU@, qa>^ [ In# |# 29G/r1"gl1ZjѱT`‰bK)lh1+Ȳ2#{j,Ah۬,/ UHl=%Ҫ܄l[KVN^v`^tg}m XSf}Dr qQXߤZ9H0m[xY}H(&RԟW^0vAn|)Der]˒IrcXlkʑ,i!;9R?#398WCV7jQǏ8¯?TB0Q!&S\)@Dڥo1QĪ70^=rkġ\)7fSDir7ib1ٵq^ƸDEm2ƇK)lYrl[v-Ƹ˧|kNboKƓOÄV?H2g_$I*7!pvN? dEiWäz9cR=m!-4cYP d069(a#,kBYQbfBzkLϹIEJ HpczixaUdkGqT{ڶ퐖{+Oٝgιh֯LVҦǺ;}3Um,E-úեRcTl\&B {X"@bV#Θ.1o '&[oyipHPĿuv碙sn*m"MZ"KrrJrJJjv0r56.mيig|(ʭ&rTuDg1iKH#ʌ":94w" 禎8;1_ƺ;}󫚚+Y}!;>W;!vVzUoOI:4$А %#]nlrVkY+cE U!Qcd}G7_ϑ[5\䚆}FO`@Ϛ, h;gK!d$*6ƣ vm-@Sŀ, ^ȍ __\>{#]b?]`l#3ώ+Vv\+~'Ajl:u~JwGWB$О Rvod'r՚qԯUu;tϑD׷9Gvpwi!%O,qÆ=\}z6׊KNlM&-9gm bij/sIIDћˡ+fLm2m}?IhK Ȳѐ~N&tUgm]>Ǐ~zX9u 3zx[]'-9UW{'Zf)(Yi]ꊑ^}亡2<;Y^F7(ZtͿC]\\uUuw^0ocF-%_檩NqymҠÔkD ӛH"[5 2G*s8S6ս)kiY[v;Tr$hIdR-PO*J%l1Kϻ35p" z/=&R~{wAEG0[%(|mݢ)JSofl$^sJhH=2lҩJMM#ʼnAm9OIKWѯaO ӽqwpL ^VMϙ[T2-CmVŝY/NenԝusRbf Ʃǜ[8j_u'|@ҡSϦ*^ * ҊXc1vc1XcX#`8  ( {ǹq3^gZkYhɲ֖T>Q5\wyCI}E U_Ooﳣնar`۪ ˊ~xEIw*`eMOn[DۻW?4PbeqϟkV=Ewb"vP sp )@/IC*<̲5^KN&*|uy㟧2+1E x~>F kY=,,I_.9EKVU֙k9=f((4T>k#>uǨ.#!;HnX#Xל gxϲ5^jqɷU?Xd zMK-*|qiⓙU|["u9-gR'x/Yf PqEgf-)[1өfPUt2#^H,ש 0h6)| }߰)//_pzmIenU8{ h%[TexϿcAo~ xo}͊T@ Pn\u{IUwN]y(@8Xo3խm/Tق<-ٶÿ=43(OY>!/ɥ[{k.=^QTHw2.msa,F/ t#WQs֟+lmUA'u8+_\-peey>LDʯww-=Vin&'STaI>>_~ߤB:hܯ>y H) \w@V?|27_h5X/U#Ky֯nb!9͉2ըҤ3,_<탢8~Bkd%v/yօ`9ǮH Ϯ\seI}%d ήZs;Gؠ›&(a @ޡ6 RS5 ?qP W15jSU\;C]-\O[zzfjLE0k @j1"$ {X##Tǀ@`Y&3-J$@CVX:hbFlb .&)f;RLDK|YzMaz¤;3V'N_uS^o~it'|Y 1k&Vk% /!!NH0BԊ бX@*.] VkJu&/79x֣B,@c@(pA:d]EJXׅu5J#v뿎?l`vk4_x&WU_={-\Ln]i r[8z?F+0p Ck&`my0Ee˜mfF0u\5'']!Z WeD'ÀÌ| /zBs">Bml[V)ym֥sdr*2-Wf/¡ vP@)y^: 4g\\^q/ҥ 7ܐq!k O(w0cio63w\.PJ!cOe"gw50Tibsh]MZ WUxf}'cc]Wn86cu*8~$ffUެOK@3}/$C P}]t9BŦoW b_chH~rLI(1.gJ[8֛k@E-惲w"C$EY "ġQ:"rL;.2J*>Dݱpi~̀Xٲ#B$SuxQFL 0/TFLҋ5&B{z!5_ED yJ r0hِ]H,(%?xAm *>D`+"{CVd(D^iQWEBIS঄ta>l<ì!e½Vaۖ>oe,L;1AzqXCPf4CFi ,"^Ԅ$Y@<̢`pkSe @t#jhUU!N!S'h<&WzHke peb] =ZBO!-Dc6ED7̎14\MnȸV0FKsx ̯Lܰ5Wsrq谼O-sA2lĵi['FeC?6 t."n2tJX%$l|sIJgC' }V"̖ĭQiBTLLAjUxMo\gE So|M~0D7\rM-8^A"ˑ[l|+e.΋|"#V0&!"2Ě޵E" g#b"b#b_eF2?b;b##CO][ ;18K\yqyGrx]gz *12&%Uf$zqȧ7g',e򹨧'#-1ߝs.$D\j'a*\lFu,v\dL?SE&>Igԋݾ#b#bboZAτOw6򡬁M?"S,0zo/3Qk2a\]o> zzĪ>2LixOw܍ s`m;:LS#v>wo{'64e=m$3pͰ+GviCīmdnc\AQ%ҥP Vu(i$$'aԾ#AqOO eX;%~ţT7Cs0GoST05 ⪇V[*0Κ\0@6KoNs]@qDYuv|Tl-տK _ p!%H ] 'GLXR֥1_J;0,l2X1BGtw!Ck1Zv'v/36.(Ii<]5  h;`$Wٻr`$2٢aceDT8ݍ+*s_bUϺ,,p x,_S#,UVif`J[MVjptC}*@f\a(QiO8i^\dSJ> L K[!y4ٻGg×vΩv` OwJ`m&gW_zh2f6/\VG-sQ`yA~z}Af%NHjdXs"$aIe<|,<#DmюM3&ɬ Z=.ޘJ+ q,֬ q'{Ww[+?}wU4G'qg"` )m7`BZ|m%UӤqϖ'y+H4h2uϪ.(Ov͘D̟se!Ϩ,Bx IDATVG7N<<\˩W-› ǵKRgt8YYUk0R'Om#[RmMO:YɂN\w4YBfaN ˟gw]ߛr8-GYv|%>tRu<2C OTYȞFa`:{6kӞVRL+_.GQyN?&7uP0nJ7anqǺ-|ΖǞt.@7g]`paY3sY<6yL9}".54VQ2DPKH[6+F ǹ/,X]W~ڔWsh&mEIϷ|Dڞ3VR83Szd3D/WIZthњc!OcCo&)@]JW)_d*c+k?MH~xx@(X٧Dا2aQ0P2ʵ!8+v$61A%?wb,m2.^|&sFsعL5eQo|V "e߾c_b> [ ͯJyA-\XN1UEч]I!ʆ.COO:yU{O% 0у-<D{)2i:f{1 w{ma&R}ݸ譧GD'9=$ f\LgqDLBD?E 4iAX͏L|ԩ qS#gW42aQv4jhcCN nۿɗ@bߤ :l,"$`U۔W)_NyRIJn]Kc \T 'ls9i?rqAX6UW_"T0hvעËמy,"%P;=kbHHnvjO2 8y衍 U.9LSu`H ڙ9XpKaiQ>>3Z0IE{L,wac$LG)bȻ`LĨؤT#MUGoE&d/nҌHb?h텐ؤ بa^&E&EşfQF{~jaW SE4>%J"+,Z-@3}rӿ;Z֭ke,uLoT7!0Zw!$.)^ R!K_ݽ9 (:)*.I%q.\ֳ "N |veìNt2qȶVt$)2n?QqI.Lh]$@Eݛ V OF?:X`LrT :jOmF 0m雪qgL')*._f@d3ܓV]~/Y^vR-1x &d+k(6kY>4pMkN;Eej5zqV~"|>jm]Ȥٯg㒟_LErz~ LR̲ZϬ퐥݉LKP`R֜o3̸yvmGxt\rTAjTdaQsG5)Bˏɚ/|zdV T޻XcU#j$wn!{u:+r򝇒u gGhUav.U }ܨICN~-6qȹogH?E 0oK|m7G߾De̻b15U? <Υ3~RsCHw.zcM`L2i1@ld"U+*3B"b,BF=G=̨ \~4`ȯg4 SzĦj隶{9{"d+ZQlmR;yȥb |ރċ>&+Z(o䬬{w_i15tU YUҰ5w&>j=4dHL͠4ܪ߾PK15Ek?[h\CGs˗͙hm@NY<x\5HM'}wNw߭I/s#k3(Ra={ԭTwhDWO}/@O뚊 FbQ_͒ȧv^~J vۏYs!R#WL;*@TӸG|H >'z+G/e'>W3s-9@FmcE/V73 ֕vDZ]IJ{pףJ^㤑`ҽqߵ4]yNGIn6]]; Q"د_ۻF-€ێhQr~% Z{)&#;3I=TE~fWSsR#O}k3[]-,og/c[bIm'K)6ܬ؛g.T֥z;{}5OhŒJW^ jA9PA/3^>nZJ)-cHG> sM*HNPaGXY1Y>&}Z|xk,wv돉̻כ|N}r2˸61^ݱaVw2oSj 'G%J\ꋬc} Q‘sqXjh|o$1=2Wj}s[X^%. aV;{ݺwع='^]4ek ɽʌį/>չtb̠gʉЇS#bVҼOP\ 9O~l+QBc3e&>T򉱃=>>] r`x:A? *dzֶ̳R`4ȇ+//0g$$HL|>h:_,'aNHKW?}V`9DJQY1Ȳ~һ}Q2pǗ9Эr&ߪ OFiHԌOvH DƖ" #pUѡ,ArL ~}NukOPb/>AO/s{c+ (Zl_\Tq(i2LZZ%&;hF7BmtjCu[QNJ@P"eJ_'(?>Xe"\(xT|SRXb<̮˲?W;[q!29TGVF<0]fتa ?X܇L>5` Pv+!)@fJ?2H~`"R/BNF/N ,neZgqngce D4tk @u~Z^%erl`b bxI"3K.z èPs5KS$&ր`s Uoji|!F$o&o(,/BZDFz@uEzA5dBCS\!s:inЖJՊK CްkW']1T۽AXܰ=Uҙc H(K>0)aAg/cðMsX .ш Vm * k*L) : 0% Dxu[ñ>U,G9خ@N6uf*:1`a.Qߢ}[^E-7'~*V|D|YŇ`_Wfʀ \lLБNKYJ/RXy`be5|0l7w1|-lgzJ֊F{k8 !\ɥ"mOiI}:کG&6~nz|&RD2#nbؤz3Cƫ:|z[B|F'Aq^S0(֌s7<+;oa=慽-9QY"nM|l:7嘏Uj{)olRĈaB&ER53e6-<[<%K E? g5܍D @e'e3Pu]|'-\uH'kϮz_t`fI4Q^VVћI{]=XSb FM(AI.hIsqRcLlQ"岆s4i1Šws^缪/Ber 0iu jcNQ<^Z:WZwʊ &ُXgՠzТyL Yzeۗyb$*}-(+U*6=õJuN_qVG^ԫ/1 ;{KXB\,35B Es=qFOXޟ;uojiQyJj]<>ʡ#d$7q'Zkn"!0l2zm镈OMF(qѻ T1[Ueg~Ul+5F"XH`pztF:Wx%pIzbqT_,Pc g2u}%;Y][ۺfU`ƍlTtҞBknnAH7R*1kk[הCi`J^e (xSy1IQAb lXYNfEJ]U0`"L⩣x;8QVUD&Xؙ SîyW+\46!MZx+"žڵ9oT BPb+WW7V)AV5&ZjaO=_#OXB07q O?b[}B0bAG6weQYLJXڙw "Ĩg7ZvDQ,xqhq}@⺿Fcm J"q[k0%ճvO ;Mueyj͸Ƚ#Fi[R"RĤYƍYK'wiԬ?{'|Q:qAVoΖkb*n$wqT?Ma`i>%݅܆q-4oܬY@9IvKmKZFD~Rwo3}(n}F\>ykجieȨnæ͛:!I4jڌ2楷x԰aKھ|JFmYr'[Ϋ ({y%[98Y}URe/>WE hf 5 K'GS MdK5{(H͕ZO'LͺrMW(&W8gtO w8kȧr8`Q;mӡojz[:^YBXkrYZJ u L悠2ƥT]6b|/5/-A"U7.fԝă4wn gObz|p4,cҷIV?jd$]&uT_=ھc]=w2+xׯz|pIv{&.].d5cݘ $вրe>(ضbQF<ĵ3l&-SÆ',fyƛJ(>\NY:"jxV~|_i׭}]) NU2߀dY_ϾOԐ}{k})ۦ4Bʯ1FJѻmӈXNK-ՐEK*C.'̤{72uIcDY §bLMN 27e 9QKJg[ Y'1n-n^^3jc IDAT4utjئsa]2R-ge̍%:#uihuAqWÿ`T05\0SG=t2'^džmN\;oАv?u+aa 'ڪA^D}JY԰OR- ^78"1s'Դ,a@sJ:Є#44NնJ Yؤ1嗒g[X6snT Q(shfSK\oy*ZU9xW\ Zs?|ś#כ_vױyhljw޴t?D/.mXt2JEYSXE ދ}֭s(y{o_qE?'޺B6=4h<p˥\ TA% |ЃY,[kd?3E//ozY7*;浑u6"(skוK)jFL3E=޿9lj"IϓD闥Y܄[yU]WWH{̇j_||jld|128Kjkr/4>7ek7-{fť OfV 4TN/]]wӲ}gm_WVÈn<i}ιy %śoURYim,;kUiX''3MJ$Z}'GXlM) }PO\?,;̷mi >_nbЂW+0{mwKW[oZ97,:Jc7yPYG72,HXv÷0W_z0+;OVPhيבT&] U@Q׃k[|8q_j膕'\TqM(\J  ׯ]x9d۽`!oi>n^R_*Av{cz"ͼW_ _U998$9nG/^vv>E߳8uv-;R2u K1p w!*:O&^v'#|V{ٶ# g^ rl)2,du2QW0`8:#:@MqG_usg]c~,PS9M{l~͝λՎωwؤ;w=~_1vy%n=XH*5Y|ɿb [ cmLjSbLĆLkXP' ;N< l#,782ta2ygJ4">fr}[B}AS90>M jݵx Nxq f,{;cWAʹ-.!'fЈK0 Xh kΈS zc" D88;L1Y8\̷izđm ku&5 jMDW ۀT?F,FT(9BRTI۝_iBx-s/ke[jneWh>*P?A4+#XrԀ&aC&M~I8zE q-LL쁺!5\bBa^@Q%*E?GeM@\4YCP-[*8c[HZ/Ƙ=S- ψR2-l~gu1(baѐ0m+h7X3E` E) 8-VDD?EҰ2>#UG w40=m,WRȞRn e5]-0BP%itCX~_%p"C1=KKl2tӡp8Ew.Z?tnz0p!t<p"e:^ 2ӥ̩d)ȋ 1Neb-N!3A/PBHAH&;<}zkd?~ Fpi?Dlі*G,v-+8͂Cm%?ㆡQ#BLVwa3ahsvWz'Ccҭ?8B+SEI]6 O]٥U|`Ѻ@dA7]zJ?1 &LUij!,5c TSi=eݯu-y9=`KbTӕr5HgQD]wLwLs$j*yx fc2fl{AL h,[D&.&*'DLO"gY%wMuW#jV. i1QuzMDG&E&]1y֥smWm\xreD?) N$6)*6lORY 'f_'W'?#æv=K H))Qlg-ixJDaqvmଫ'N$渦pI vQ8 Nb%V-&BPi䪮?u)fESɌ]@&cBi.XfgQOoX^}b럦remjd S69{ixTiOGf3΍ZO:r&ixT)$A8||MZ"f?ZL2>e."Ie}V|ɕ}eդrbS)XS:0Pz Cd}Wxju_{)H_h ( $SE\tb(Z޹[o/RMzU"z.g͒yER6kwBMʲР+d0dy!1~^6D P I"\HF_:֮E5r !^J Oi%ER `A rv`W@0\).Rᛋ C~v.ڔR@:u*`s*KS=Ϊy/"yEsR6F-ԥC/{-`9C"2¥\ F"!3@faJ3+W@dp jt_L-d6J*F9xWRҬB37tܦEunȷz&8M)*ګ1b"E2(so`RߵL  aǣaOz\}Êcc/8[B`]efMժ~F4wˈ1]hٯI,>뗯_|:U{.6_ oztv9&Ԕ/Sσ"e_%>}fۺ.ATMy*%E3@2ԽA^sGml9QYV(҅GisF{>;y@٧Xا2axK\'n]b׳>x6nTރJdܠj]aQGml-6\7e".l2{NI j#&Sdv[ 1a-YO4;Ƕ4ڹ ^' ѱlj1 M:~WD{ y֡ .mمKȤ譧GD'9}lKS %(Q2FQbX2dl/;OG=y~0Um7rhP웴!gw{eocReQaoף?"eݺP|>w憖ZtxcOcClh\&ްAá KP[#Cq;|;a_gD,P`'f:J0 ,;&g$F&=~p緦ݸG![]uN|dlbI$iW:G{|nړZ{!$6)>6c$~.&6 W|Dxl5G%Eŝ^WLFLuUG%>2AdvR@bbר'"I3m'E%ݻTE]V{?J&Y߫tjNi8xuZ.zEE-/b0jk}c M%uNa5rUK4N{_j% Wi5e`bGeM i%&ט"NI}MVڒbA+K`d24 i{ 魖@?mLo%չYy8rsz-VrHUuKz-魷7^51ldBq.YdV[]Xpm槷jc}e)9E*B+Hv4,qَR@b౨{43 &~>$_IOB݄T~Glܢ:އb㒣]Hb?xиP"ވ1l(mn<8vȲD&G%Lmi^̃7DR ՘u V~Us }J 1S8u#>E"Lsah3r҄%GVFveg+MD`floH*B@l \ȶ6Rc\K'Ole|[6Դ'+zkү y%gVNF=>̻c1dְMYӜ* 񯋭[72L*߆D~ӽ:wg_0iK/Q,9Í7Յ9 1ƲnQ`W2E. غu#s~g̦̭:i~!z=۹c|Rn|QcB]-qcD7K;*56GBbNY0={S#LHןT##""Pd=1S"kRO/#3b>q#O\Ӑm$"KaeSN=dǓ)xȼaEgܳ5S+$ 4>"ޱM1=ڍ[uQ^ݶ]c/:mRX{cB~ː:c.{=-(}[SeȢaEfcJdf䞙?a{mPȽ>1ati92ml*&{v龕DHYw]?6/80kWaЙ{6T{:zu|T!4g۬6ge+>v9`@EFolMNVƉr Vaf>#u:]>q^*/dqn~F 哧O{wܙ3g|cy-1ksc|e{nOV|ږ^Bx?SڣvGyf}4 ԫҵꞇڣFRad鶵7ˬaABn~Vbԅ_Y ygdTsq]WJ3D6۴ʫ\*{.qk5lxpSHtDS+w>Ȩ4U\*:Lq'f?=n=ro5#M_d3KHȷ]8F9{&msgigې{ 眝-?;2W6@t/2~0|#GjggwW$|^/-6yh]R'r󳒢.>D7*^/Xо{.ĵ."M[LܿR:n?ƤCw}<%7u U'FF{͛/'P'x"Q{ꐔ;Y ղQnb4)I vׁ KV&+DPXzv}ꅺy(syšD=k]WzR"HN!cX?׾ҳhsG/2,oE:p`Y_ :3&wu~D]NFϺEsf[eZڻ(!]fnP*FA%~]gw\WQ{#[&$_><{9#oY+*,IoV-%U҆ErwK^ZIEetd{:?#z$Q8yY^=c=Bؤ,vr - iL84Խ)﹵dwuP^ $bP&m rLq~j];uu#N͌XvpBXtlN;N2fo^>[@9rԇQ"[AI\4aĒƔ)0! cs%k]'\35Yk(=>:3&pYv̯ďWg*rJ7$z{,ŋs(czi_G,qưNIIs1m}ѳ'.^] LA7A] nȩ#k)xNlMȃ8Y/ r\|%ːG};V 8Y|b~?ޣgOn^8?ʼnFJ;UjJCnZ eZ Q ](G,Lx3to1ʽ[ `xq0jJ},e!IPYuHM/(66cO+C ϺӔ~nep'Ʊ4ʹr4Bsڡ:h.}ۛ=AWHNBݜr i۪0 {~r[#@&mY$T{r˒O~nحoV̵5?|:|} kQeLD]37N{±_K-3wDŽڣ!NsFJu5(cqUYm{%vk!?#4~p.#.tzwwF)D KFL~GXϘ JS-$A5lPGîaۇ? Y{7{ys!`X HP-8rS:[q[`=ݟMEwܘ񱲏*b';1,A/`]fc1Fԩ{>ed_L:cmjTR+q+(wVRaZ_s1;Iuj[bZG<"߄ )+›,o8$F;l ']ݡS4Z0o,zugd.az)en[l\Jnm]CO&t;y^,ڌ1}p;u9s>Xbʌ(.d"Ӿ"[':R`Ȃͦm,5nj׾g>f/nN{Fo.Eɬ`|(*DnA~d7KJ0YWHo:{,ʵjà*2^OaI71ߩ>FiR-KXWNK)FG,Ŝ)٭uO^J1"w!G9 `d##D۫=5i쓗SL̳(]rlW Ud {~Mc ]aA%!TrV,ՊZRyCˇkfBʑ iشneZЁLe.wv tX׭&{=H3~DlYU}.(XXG]]zy}2 [x3SvZ9cBQV+ݕ6-[iTF!P4RT |R:&D[N5[ f/Rb5;V=`#K%+v,6ay [Z8ֵ=":󟣼Xb[&PoYtut>]: b4UAUu$ s񫻧_=};{5-'z'Mkk?3)0NUNcc4AiuZA3} BEg[x-g$B"DZ\ikS^); xiκwN00H-">?{<[4AϕUX3\@"f Vݭ_7~@&a,IED$, Kv6,L CeJe4fKݿw:R7,0faJ= l Vka_tz,58~9WU:P{?u}`+1hZD|t: (UFPjl%^,z9;{5)}Bg[/H_9z" -"Y&¥9|be`F8(ZH14rB5kO(5!_632YX%ePceIm6C'eFƔ'SF=Tcd3ێtcJt2 |8PQRnR3ip2@ިߴ/x.J+{tj?ZwnnKsvӞUW,I8*f(#gL>{qߌg#%0voQ/ݛ>$+haCz lԴVQJs TCv,3[ڛT?۽ 6jL[YQbH<>sF$n^ɬw5OW?*ŀ*vF ڄKOa:--GG!H3:p_{-!@MLy9y^FdLg kc3' ͛_?&cO>=ujѱ,_^TaMC9NOzh` gU>롖ǘz}*uMI Զgk^Yo = j '`2RCo苑:4٩w 8G6 8+J#1htVTw+NMP{7*x@L@{[OV Jڌz2E>q![>/fAUZ\I{7ڑJi01n{%wne<ѳF1Z! Gs8^/D۴ɽ'{ŀOC]~Bb̢e2^Ovy\#y"k{O]T/{#;`Dmc3k)+VVlV:{FN%~ػ]˶U);|DY{m0joW;Fcv+`; Ȼ_ϡXs tKYigK5a `zgb_.:Sa%w>7 ʚ͍ݛ`JOO*VTx}bձFIig84wa9O&|d3F/|-ȴZ2~f3o֡> cӿܲ`]̪oV}ǽ2 3W<كL)zsϿ²?u!ޚXp܊wwq$*hޕ߭81ܜre̦;kw ڞ;ket5W4Ƥ]n3|h4o]G/5&}?FGM  oFOٱCz ^{0,boEөܿ?ݘ~)?\̶ Q, |b0g0>?IF]v#`K.QX u #, X2g}]fض8 b9Z+5g `\<۶4!|Tl8LWaÊ^9q>ܟքUjeT+nK2._ )zձ%,;\zbMDsΩI;4r+92\+(C?!X=ƈ̤b N?Ə#dZ]s*cLK| K{ -m.W?'2iˣ*0VlI;bt OwW7#Ś' u*\OR'*6nM>S$b6u5\eϦM7 c Ƙqk376>=|0K)JAՀ0gde?ۧao)W] b|29mY5`-Zpnai\MQ*{so>K ~[<ūϊ24]d2 [4܋%ITŀ]"g4!P!ȸj'4%X}}ks:~]^=ɶ^lK2%Bl*n?Sr|0F ťULk4B)dIfk rM hB S̡r#mpz+4 JW!.tL9$" 9$$htLD<  Hs\Rv2F` ;} f5` LLaTc>r Ҵ#߄1^iė =3R&2aK3D~[%`.׾#(E"Dd۬īQJyY$[䟋;ܜ oCLVfdkf0Io9+[ul͉k%\א85^YK!rg JF,qeSnkM$PtB.TiD|Pdwm_HMR~&V!/YF1fXd]^g`q͎ؔX 5PN+Rcxu0o\xeD6чrOxHJHHxLGo Q٧HtЂ]܊{p%#Zx٢KmgF=zxj^  ?q܃q"?Y' id?#SQwo"NWR՛|q\$yTE'.}鯇:53noO\_(zc#8kGuUzpj|Z>b#F>(ϕԜƟyy[Nܸ(Z`oiڌ^O";{Q m>1upow^|rѓ| %eŒ:- Gإ_y6]_9`Gvץ'?9* ˢV9rJǙSEN|w >ۙˬ!Μ(]\2$r`!&`rJ#+}7hȽX㨱 ;_Mb8v$OBb 99W,Cu$] ya]cINݰ߉_rqSlwNSmF{[acwKwk=ݱ97 hT@uM,9@h 'lg%4Y b ;Bwr?z=ÖɉBNXD$BHs2ap!{z* +V/qT˦Zli9CWv3-R#Ӱe'%ЭK݁!?BDSL+eM6iřU"PuDjcoݜ*W<U:fY6(82|dhv;x(zLё+`-gs=uevhxa)xUƈ;ZQQ?DSL?W>e+n?,ٷ>z8 >A]-,GTbU{TwKbZU ьNXնǞoٜjRXHAo3etvuYƫ2fxti離'C]xn e>~n7ybf/K|ڊK9Vpw m]M^=@v؜?jgGٴh| Bڦ,OZ"?Q IY{k୲(@ҲN_VfҴߎW|7)鏃[|M6?7?J=L!~wn WOܜ` 2v=3$?e"^޽?i|OSq꫄ִO_ *3}ݻ+65tCNiJR_xe`_R^ 2oph`r"ppr!pOؔ`@D؜۷{FNp$u~CNɪ>_NSjuWvuR :9!;3̀zcV[_4͇|pR,.ʌh;mlٺ!_i/+}zⴣfF[1{ül&ZA?6 z:62c Xޏ+Cm+wh&(nc/pW $lf'G>qn%:TQfmfVqs8\擕i»]oOEoxȺd,Bнg.^_wci»]_h-f{;GO~+@Nf06?IM 1q3!{}^0v Os9 m$c|,OrBzev4N-Cʐ֫#~ɸo<<=3wxo d'-*{gu0٠'e+֑Pus[mڒm*gt4lCYy3z9P8=X鶭NȚikw 42DykPOPwڠO{NUVz~N#/HG[l&)QO}ۻb]ա a塵iOOSMcW$֞ |$G'苪{oƶ>"xz>a~PVbE?dT\dTܩ-l gKy8{y@OTbis)-kQ{[o^1E VUSV^Bº*tŴ=<27Kai2'=nt^BxsdP2cؐ~Bi@`9#F aodZԜw~xՠ6l<4+Mz zx[V )/;?Oyuоo) C~0SgΉULtt}ծ^e'_߳񦁙'l<43مMz j;-cL "C@WmhS )K;b ֚iĚM[Lͥ7>6s7 T}g)C f-rk5lxpS  o.=}6ϭ7Y%Zhj)YC1)7yjб Cx4~"Bŗ~,І!:c鿎Kw¾>:3_JPjB(2P(j@,< cѸ탳S(!Znh ۇ:>i}lcʭ"o񺶣39Fb@QKsy$YrlLǝC2v !18!AES$eE#H,+!=6%,x`oX,]B15#˃f+8bH'hCr;SSެqﲟwG?o_JM͑@/U^\`E0/tfB9O Frح%q|lI65pXҿֽjzr|YEsG/2,o =6yQ0>6DO[.2߮37D@5>ř#ѾG@t?[Up0rI&RV@`2Z٭/iZb,!y?M઴EjVR"S!h=t=Z1a{%jG̡ճ| x}@:;YF`ȉ/4@yn*\Hա^% [ 7#P+tĖOfY*AwdHO6~k8lĩR$0*cXo;oĉ;r@ nL|{d+zUS7??U{c[>&qj&&MO;{r> Hb`(7tf \y5'vf Slv%-ìnCI1T pXY QFmu[Eg!̥}ߟϢo^p?<ߑưlR]1rKMKYV6֪͠z*̼UD`d7oãjf^f5aPj7"T `xTHpUh}Cl1Qf3@AZoh6 2(uI}d|qm2Iol-5-)3sh}W4ML"DY>pVZ=Mh;ǰ 9ᦫ|pNH~ I1r*AER框lXtO p1$N#ԑRɱy  «Ld ҐWj-|iN2M-ۮ)iO\ 4ZN]q9Ud8g/-Ø-kxPMEw:]a%e)(N>r(K2R HV#oJB^@KG9!cBjik K2g_ N| IDAT7 \biCGsi@/TJikVσ~[f2CY v1/W"03εULX6Θpؓ BTŢ "ҪeuZՖ/د+n;q?۳mJFqG%hLeLԪd^rXJ^;ޙ٫rIq EАyƷ"E],UAw"TcB|my>]&jZ`Ёw{?uu^g0<X2JݿW֐A7,0fa\7Ҫt2*-0UY1(*ո7R{Rgϝ͇ZConV"O{.-4([ݢ"Es]&b`|BUB,V @Xav2[B&3ΖZ+XI5cs;9NsN) !N+f!nAF$msy9Dn bnsxJaΓ0WcHP̊J[=Z U(ZoiVMe-K:'@zo0T+J)3Γ4}N5ioQZIl2v.#D0s'&?ٌY+SqL"?E{YVL`;P+:ʢi^y`SizJ~5 i?stlϰ;_lNtM{My 3JLN0;"z kcSvu;q%_!3?zrɆ+Ç>7umB+ۊ֧Ŗ^)/5 1}skoPvGE~1+K"%EHЯۄ>Z^>4Gg0rݚRroMiB0>| #aP ZOZ+V6>4r!W=а" ٨+s)GY_0On_ڌzirUct0}Μ(o)J*&,.#4 KUFB8'~!*2E< v9%'E ,TleFO@~I'k$p:"Vq G3˅}ȵ |BM| \#K О[ʘrMIeFdtb~ցztTQv?֞i,7z5FJZLٵ';x=C!mۀQ{.\8۲*E.7th)B挃s,Mjv2Uȧc?1*nӾ2sʡտhߝaEwNO4g^h{gjeTYF>bmʐc:$F`9}C3iǙFnG,# Xlڹv=pFM}ODUȠU-j=n4o+-۽&E^Ȃ839./N/m`V.&lfy7y}K&\PvmAiQ/n=&BI6=6AQEIXx +4H!ܢ6= *n9̣`P\N*Ϛxj^u\ ZrK?ҥxgJNrH/&aj+T-`v[[KFD+Hz8]Nmb߭TI pT glMwJ1A \s8n"EKLg#Ihr)C?#>/&1#X;`FfF5 ɒaRNTm<-БûQe6BGX}sZ9B$ʕpca7a7ݘˢ`&8aĶ"dv3=/;v ,)A`R|Czy6C(9EV>>bz19WMrmr-HO!/Mi.U#ł"ʱgp!+q@Ru)-ᡍ+ȣ)x"l\I_j6-eGPC0]8\_bFbX{h` z#oߢ[SPJ$Z;o~*$PZ(:Sb{XTL Y(3xLi(hr WO(dޑ P鲄vJuC",y Y4{h!(8ˬ[SUX Rĺ^F@!uS"̀K߰XClp-IQv-b/KJRopk 9{/9<&f+ƥ\c]K+ b=xjI}9#6`5SԢ}MJo'ʉ"QUjUJ"ӕVJ<1QNn lK9f"i`A2QK HW,VlyĊ -gA%#.L$3Q*J-2Djʧ'ɆJQm^?@} _JVNHs)Ռӗջ!,TCw %wK-Q d<1z*JȁT|×/66곲!Kq`Bx#txl%thWP Qc voI V"UDFeӁ( ҎVfXmKoAWBQ(]*+H!@PБx BAYGMQ0E++8,B{)}Q@h-p|uku݆$F ʕ.QH -ZzdIOEW\(joD%wi.vQrbG/D)#U)L!>׽oQ2)?aj# GGh+bk"lO8tS -W!obIQ%/7J> ŷ#|WscB~Q8_z,_A<~RWcӕQD{plb5-;&K7#D`I\8oCO8KU|۶\sQ˟T|Dm#gM"[D⪳ z^0 @ʧћ'Gc#M'"VZ Z },#6,!n5Ɲ:KŏsΜ`qQduГǬ(hSw","!b(y!7pN=LdE'x'DE^KM>$`ԥZ.~Y_CچZ[E/~Ygɋ?x ,*{H}@tuל[YY|D|/^GN~Xw.DEj:~)&*:žɄ*fc\v7.*:֟'SqeǢ!\R[킆o@㢢㢢"Ϳ_EgaſEFG2 ;@8u MNދ<1OmQD|h+9_Ř{1wiﯵ*6z~}c" _KHeI` pF8=a*xq͔bb}f[<.NaԌ]@'Bq D]%!/B`H Tɼ#6,..j%pO,,v֨؊4j _h5Y+gǤa׌-]!3aȶ$]`읡bg/joP[kW9fj[6~Qg]i+_qML/hjNZ?MuQB h{*t4{'gujcKh5KbyC)@ =N S.!aȶdʫ#Lw쉱Z+Jy2d7t~qRwRh IDATe_hcvmBDܩbQMزi¦6IeO uDT@~9uhzEo  -=!" #,띻׌-[13a6󯥝IDv<^7nц̗C~OEdUCOO =uzY퓆]7n̄<c,Æz?p.IfzUvcaޏ֟O4EƦE7@L~t :Izfh~j\N?Y½߻?ٲqe^f Q†${zwR[RӬϻK|:mI}Utp@e&=Ϟ%=T~`[ WNԷGU{%AMpadzVBBZ#(nhkBD`Z_;@lo1Wf>=~@ u <t1`DEDžuj7յ0ny}i/gm3&2mCi )n̕YC__^}uv^r/.*:.2W{@T^=7z֞s"NW%LʕΒ{WN_0 @/NxLejמ&V2xfݧm>}9aKW {}=rd,uգPz˱w]6_#R?(.#zb4P"PQWz qEqS|yYDH1o9SqV4/96TNEIH@Ɉ*Zcv_(fyFj1 S)W䌇oyI}dG?O^ƻ:TL0uܬؾ Dv`sPw݆?[E*'1;=J_4vI RRz.h^n̑'p6 "FxO~iױRPǶx-&D,'K^/<[ՕA]۹[UvDơbN~y%* :E EƻN%gvj;MZ:M!r;My}/;A߿~߻oT6lr먁}o~\3pK3e ^0OaHEH}hӦ/LL/9cVO0-qNo";8 tˮ{i:~]}1 nTщrY (/=.۔3* zK7ZDTeգlm⢢o#SZżQb28K@f]PaO,C8@"@-/'ȍ~V^O+`Z}̐yqmWCƶiݺϋx^}l[ȣ~}ۗ߫ǘ~KWt7kws[zwd@4}r:~^wʖiӴ}9|5\Lpl_@c_}I{G=0ȍ=}^;[)x ͩ/nj[t:-Ly=L94i\r* AՒFB̓6pt=#a>q?GhE۷n}~>[V:qޝ&-ߺ 9fNnlfQG>,D4&n[ia'3t?lڨ^ӆ.}0S)[K?iHϞ]ape-gOǏv֧6zp|{5QV}89w%'3~j83>5l>= Ϝ4&٢izM?v)0 o(amzRf~S M/2!(( ؈B>%EHrDJwPVAA \6y^%P죈B Q< u9Ot݇F)^`0 HMspBP:.q:!:GK>U\9V+ dxqt".գ8#\\J - eM򐕔iV<:.*:Ԕjk!lYs# oz@xl) ؃ZxvDeo^ 5v>1ZRhuq;nFj-]̀)7rO!E޾upӁ oe.&6ׯ&P7<*J1,Ĕcי"Ss=2L,(o(x& @/˷I}yrh[,''D{z"rƂg%Ĕo9N5Rh֭oU<4$M&R)VsSr DW;';e|˱$.J`2ꡙL 78\h̾v7ݼ2O~҃\)^!{Fp,PrcZ(~ijWAP1E}F&a-Cdʷ B i+>{N/Uc;jL@2EU5X,9-OLgx'7Srwh~S]Ul,x(} I_'*1苌&ySEш  `B4 6ch`N" m o@$}6XFu+d> ?zgH K U̧UlA<=K|9Pb4e(BM%2Vx|&/dS՚Loe܊sW9^%,%N9 MbpVe:brhaNo,ƌgh890H,[ yy`MBur ۺUQWY4>Yo^&/8+ ._'b .07l*m@/.~Q*`ܖEw>^Y"“u ?smʭɌs[hEB[rrXr+Vi&ջ,ba/q&2Ȅ9fG#P~Bde$ZjS$VLd5v]%F6/b_yʰuhqFc%?0+ڸJmG"osT@p^@^aj7{*cQ{g{*GM5!+K34.^^.v|{kAz|V%ы&D6듺j ֜%ߊkG#CU*ۯ5hg ߪ7C@z~V˲^cKϱֈv~M%qҪ5n~n*'T֩=|;TqpjN2*>k `שW"-ZZ.Al-Qq?ʈPpuU QF `}c2B;@|5Nyox~1"P6}n%cL)ѾZ3@&YjSiI S-ɡI_c4n~* eȊ8go'.\ՉhBMI4@YωAwi")ov5b]gQM&F'X'vUɱyDU `Bh1@GpS}9v|U0 !h|߼)._+E "X.G.H8Qt2B|a?O`3} (2MEZQnlUbjmզܨ2l>FՁ-:Qш2l*}_T|Ϸ|^  ,Vraaq=cէ\ ?:C,tqQi=cדUǞsYs\4ѻJ5*ӢwjV(e?0hiY%95-Tn2xhW'ξ,AYe\VQz*^ `~?~AMjUָc A /ғR>II|w7GK)zJhJ^'VQVUOwcwɉIIIq~x6%TdѾ'!^xj?ݾ@6Z>vdG#lgMO^+)z"-*reV1ݒ#}|Zz|54y`5;B ^`uO3YcU{϶}Ur/e9IK|c`oɹ{4Rn7m+{Wh5rB+lA׋OeIVR8Qrm IDAT"*XЩ#WdQN/c%m iӨvj ~7{{V,%$ϡSGRi|_8=k8yv 'WIIIIIɩgPy1{ tq.ۮZ m`'΄ %\ծQzfϏ]J!ϝH2ux&Ĺ$3a0AHi+i:aF`cI¹ICwzG%OŸtm&qB;W j6n1ng)gYp|DH]_pg3˼jVR@7&,4ϡL5k] ˈ|{)m/tiʔu_ϯ=ԮeDJt}Ge?\<k%24,tk=ƽ՘.k;">-'T5rSŜȤ9YP t1^q Y3;6wiļ{6?LjU\]mBl¦H)mC .2wN6`@G:sPf^!M'4[B@՚cg'sB@֞B ˠwlE6~|l]I:PKs^vb9aA&͚}4$_z27*2+>ҦA\H @zfdz= t8K&b/fӿ;me~>6$ <>~igb04}7 cvGI@#ܮg6r }9bա~?SV]wj c̊ɫ~þcteÏ+> W:ܗ0Ou~.=7b++f 1'Α]7&r3e.sLJ/>z#!$/vOΞ+']0yEGټIWbK3 $?S$oE?v%X$ZL1tw:7o#wOY0nNĐ(lƕ6sϿ~r|ORCQʰ`oBi&.=¼6$w啝PF;#ܗa&ܟп;m?)uDZ/RJIR*SBcvǚ.GAeFe ;7Xh'LʀR4Ƿ8؈bIj<WϿe9Kt'Ęr⯬-A\?,B0=4v۩*vΝ{%݄h_c]86@zAqQ}}qZ,3ݳlѦɊ/tXsH(Etֿӗ58M9 RtI$ž;;1j_r3 jJ-h{l~lD\ϺĽ5Z+:f߯J$-q W$`gN:v]s~nD.7"ƿ-7Kr"ƐKEF]0isRPtՍ!m,Ʈz {B~ՍW|To3%-$܂M`6 Z J@1Hkc ٰvZ; %5sęMˉKD mjOO6\^c+bE",)+N%fI vL3Knk"]s"p*?]cM³=zJ[_%<3,ݎR[ץ,6R ,;9b)7Z(*U/mXۣcV(6G.QVG2cK5|LWm?BQaQY:K8:hC/dԘT"^<6n8˲8~.昸PH2BgB].wʺK=""Q 2[┒y}gYUiC M >E,?KϞ6 >7YDBMmt gRiٱRAU* VeQnke=.s.":j ŭHDהs䕟ڊ;_0v[>Qj Zb.#M܁"7HY ɠ<DyѥF?ki!1!'g2 .BqYE?\AЯTW@}ǺJE-pjp(3RhT+HaT 1Jjw*$"6M雯yK^tsFBIty.̗(vl'Ju) 3?QHע@rx*[pP8,O-8{ n!R3LEz!bNt7zY ESr%VutcQ119`K )Gc2N'4VMNDJ"e.61g ˉqh{nT}P? WŚe :7/ݵPrgE`*2֭9* [P_$Z$V J(YGB'DjGDA +?[J%lr6+!g=::6wPҮ+*!DL1U""G&rheKr֝#6ЖGqYzߒX ROV@Q ˛R̎ȉ" Ƞ%4\Eqk B'wCi5v qSRN/,M0 *VIS @e/pC徠Jl ez#n/8hu'1Lsٸ]\m^.J/nDj(YcT-(<3PB|?REv~R4n-NdQ%߀r?;Ta{eEl|~#HX,= -qnmܪ2||UjAƘrZȧ@<(,: T-'OYa#Zk@]Ei|NzFLDT̵3LAYܕȘ;l򅿽>+Y&e|_`~g0?N湩bsS_ "pz 6Ӷ :2D,$=DM g@[9:S~?u3"Ԏm4ԩEga.* =:=%ܔ]nIjÎ JȬaol,xqRxJyL6¶?ؐJj)MFpڢSe& XR*|HJ$eAq#i sX>\"6NDǚ¼‡˕2$Uס-"` C/|S df "?I[N-M@#!K)DbQ ~n%]#3#@}7Tg" Q@ 4ൗ)hė xOwK2Mv}Gm\Ty8!ڀ%鏉:޽-w3 *)0{'j=,["gS[5{zdݾ 'X4r %b.$j 1+l˲ŵȠńdAy\KDy2mai3[jI=?nl9qµYG6{[9xpמmMНeU$$jNKp>8w'j_-Zp雧c/e#@2cN=oi5jּțk^f\Z8.DE&ʫ⅂.yۋF6_X 8rR͝7_8ЕKzd:+>bǛ)X*Po)]ejIϬSF]3j#v։,QpA=vm N M[|`ӆjb*InnYzt7:)VcO~h "1d( 6P`85~Z c1ND!*(DMd R u*`֣73Lqp}S]5!"5h|{/S_aZnN(Ym igKB>\Rsn61f,r.3/]VrłH/ކej>P2kovm&tDK(8I$::o$)gi'ҬSIӿnyvt{=e|+@2MyH¨jڝ}[~|1/ Ѻd|mET{uuxܳt[^tq՗L}g{3M TovYFSMxgtcƌv._~q{#c&1|"ڳˤhPMkz5+OoN 7[t}}j3׍H\ыgj\^unzbc N5zΘi՝˖~gAkj/ܭo#sD.!w?ҫ{s!Yrt;|lDgu/SZځjlj,d?0Z> ọT9/YEuQ{XF2/=/^q.2T~nmz6n)y]hiʟaقooE OCJHft3|9¹BD E?Yc@,dgGƔ}KtPoK<@{ IDATYe|N~w@Y |Zu8g%fwWQP{׼IoEy ҪjsfѸ!ֺxuq7zŕ=+xGz~  bOlecu9>˯m&v{ؐGN5Ι=k21KN<#ا!+V/.[#8>0Ou~Op=~]!'R@4>m#;^}kPLJ}"D_۵χ7CoD;d 6"y|ݹv]^LQ/B>4Jjr%k‰"("HO(?"1"=|%g(x2T]Vx[ARY6=yZYƏi.=ͺ8LS=Ze<`,I۾e#[u͋ M,t?#63WnE]<7USn\cvXC[z=Ųr!"5AuƵVq<3S"nw4y7y%?{cA_oS2r;β**DzM8p+N\;3d1.㇎:Zpe)rү_]0lmi,crc!Foޔu?uSɐ/vIo00*TDq\߳ ~a tSՕA52yVpVѼ[3ڨ[ۤ$y}} L,av !Vtle 'zkҩqVq~/!ה.1NWA W47A@z-QDTJ }ЍEh8y\gA|gTu)E5GC'@-jTY2:]ψ}ѽNWm<]sH\!*5>Mmt˨z};gyvWwLо}_M,3Q:sְ{B31-B(lBw@1ղAZ ߐi:N<u@of;W`^kS?ʜJ|ΣTEo;5]U,=!Dҷy&rV֑Қ]]l( & ]MIxu8Me*/\:s f[a~Щ=lJ?lU ,kv`Ґ^='nMm;ݠF̙!A9Gݿй3:j`ןی.ŐT7i6Mn8}r=D( I6ql8@D}o[7k۪YV'cH4 2u'oY6a}zO=ݼuԥ] Hboe2XA3{Ѕg ߜآQ Xuvy669 oW]KıB"U#VI,B]SIR*pdT2%=Pψ;AwO&RV%{( ~5{Y=N,gq`hEfY&@%?X}SI1ĮeZiEt_瀽wco8ӥ߭}\@LwL QO:q+i,mٻO168zQ߬Ybhn:v=M/T*J[n6Mg!'S]Ey 75S~9ʘi-R{w#iNx2H+.S@ۍ~|EMVpvwV#xŴBvOs?}l JSv3?(2|M{%׷.T婑_F KW$>ut%@jio->yc]>uTDĒW 4]ڋ{^h7 rCwGQuSPCAA`/* cA *JWPEKW:H{NHm-s̝ OޗLs=ysڱ`Ŵ{yƵWʳXh\zˎ[kH:Z>|xgK_{U" ՝4%FCIvy _j5ѡ>*<+>YsUf|Z!-Dp .Ś1k9~lѓ"Ӣz?u衭;ޝ=jR`Ȁji%yX:"o?|^Dd /\Ӣ{d] -/;%g6͙bjk@٭UYzǻ7JNL51v;M#2VwNX֯ OB)ع],=4DT "_|R«)m0߀Vik_q6ހyf?c06 f뚼[}Vg&>;%+RJfνd@yԶs#{hŢ6ٰܿ涹u#ADa6Ť{Ykuȑ~fĞ{|zHL C|=⥻w+A{ uz=ed|}SсQDfڬOmew%CXb7.^yNuI'FҲi=oGEg%p7#y݁3;w/]);{3慌И(RzŠ`.A /Q뛁$>Hl^(s| HQ} ڬ5[(CR@#毼;m!}kܞ1#D, BQC毼;m!}k~P}Fy-3W}Uա_|ݐ+"O?"dnjaq/&-ˣ9D sV};ts׶U{ѿ6~+8ZK3xP6v:C͎}ZY["(\ѩ"vGX108#![G`eWN9[@ƙM6hDWs>1q NM8gj꠯5_Q@"It+vAJ?+x;;zlcddNZ!>/WWs}"Jr2ҡr7>J>?9{=C@eI{&Ng.{}p޻ig ͐zaxGr9n=v<8*3,rz"HEiE^j's\"_p߿$w&^<ݞxR4\WJE1g!/okbji_WQNU>d)3\' Pv8 ĢU+泡f:~hBC =U[5#;ldHv+8!NpUŢ@(;O3Lt==+,)2UnJ/:0 \y<7֩|p,m"^Z|p,ϵ˾ٵmY]F_.p#/[$9ʬN'meV栀@ vLj:v%EoEyZI/~Wg~ O} 7CvK{9䯽E НbNmTt2TtwUee}쒅T쾟)[`pb6>wr*O5ɉf\ ܻɍ/Dt؇+\įlՃ^~bpX`K͇nmΙ['Hݛ'`j؏_:w2~fY،vM ?%uU9\)/'}Sm'حϑ,~J'ջ "AdOfHXm:V?C k=tԗ{Š;B/QT?DI-RNYK i[= 후l?{]·;4qom3"eAHDY .8?{ySS"Դ3/޸ {p-s,qUlDF q¶޻ (-!^<-uuvc,8 BdAɑ]~رݍڷx{럎3`_%UR+zb{J!) HrۡgLOwKvDRqΝwR zRIBB };,Aw;.Cݮ#>N'og"(x[m\o[?5qxe6C e.qY:%e7¾"\8ut}2= _O'` $dB9NXy-MCiıtdY$$ H5P)/>VS:L*x j#".<,iUrqj߾!"X.N'Ryf, v:$rZu8A9*8RXojW=L$\?rTa: 2ԯm7rXo.I0TU0YJp YنMy 4` 3$4 t;;2ƪ1(;ܳwA`~ "7hnsG|w&KԤ{wLTְ b晫7f(8U Ξwn.3}o%CgyaV9`=2 qs9ĄD<z<gc J6$%i ^h]x'.KY1ܳH͢zP cIDC-v*Lͪ0L3;>lc# \@iIMF5jW$5u]כjbնbdI.պYx"?PyVzԌ08|l~"oY&wȖdg8- OMr3?ֽkbP~nz^2d;9`Hb/ܝ 2[)¯ڨ$ pDdwPƌ9̙;knʕz]SQARur?[ -{ڑ9p1}e%Ơz2 W\Wm"Y*IU+ST)RP()zѝ(HIp,~?_9Ύ #!ݎhler=Wtq[7H(O0a:2o%yEw+G6kf[ < @b|TlE c̻&>7l`{D{4ǻ8Ҍdn,3%I͠=Ήcm|7)oq=AN'F@Kq*ڪA42_.jg @FTީ^=xzxH=G*%RJֆuI޻3Hx#?.4 <+Jp#)0%Â[ RryPoLdcԲ"艋F6H:}-!,Aw^r%ۥF lRNފz.ָ?g)ӗBn̻G| *be.c,=c~׬R7m@Ԥ2 eQqzȇLב5{#@G6I=}39OҦǘ^aKJcUېC R~݈zUL豦!%YIy:N;  :oY2&R? R\ϫ"jYU]?[ozfϙǍlsvoվj[l魝G?/Qc[ُQ+YztvGνB%&$XuԎب]xWᅭ?aSw'|od{3d`]Ǭ?vڦKԺVcco v;d+4x Ȼ*?pȧxn7j쐶Y˱ t:\̖cPӸqO=K^HSwiX3ϯ6$C7}Xo*]xדܲg稸?e8 ޻+֏48;uÏ}:R7>u7f&{pyӋI +Rh,&Iv$:aեǜF i_U[!t`7wۤm{'6aեGFq_;4<6l妒/hucpSPčEOu~&D2ea[ґ]eXnGlzk9C>erOdao9?d$e;:F1e IDAT0@oGfLRb ; w6m`joYoV\+c4Zv̍L b_q~ߗeJ%^5sEDzk۱imc2xFF %#U(1=EhS\="S*G殌mڜ{<3&v{8W뒆 U b*`gwƎvއRNCfY5??ߠikuЂsfKص ̓`˾g֨U#5a镦q['Oi ЛGӽ[t;?Z9Vjջ}; )`z3ې0*?y?CN#L lO+^ wx>\ YE@[q߅~=|`˹1k-x'dI<)#tfn[5 }W +{|1Mr'KT6ڲݽo.8/?ZPϒyC)~{}~𿲊N/}?8Rvaۆ;ϒrOϚnW37u$ڰ+i[S"n,`җh7Dun&Nvf]Vݴ=m/Z?ܐw̉R:&7~, 6}1%zEٯmX^mm3[(wM#ϡM ~o3u>q.wfF=CkË\.t`m3Y[(Geq{cȜ)e8M?ٹvp 1_5@wPkw6k[DV\UMy`n_;C^XPzaR|DޜrYzGDmKoYb3Xi;᭞AP靂 " -'DP3ۙ[8% n=U5Ϗ_U{jȚ >S[]Mog9嘱\\VطIu< !9̘/{bRy֍GPxf7Ֆ#߲s]+㉥_p%\>.ۡ%չNjD@qşpH".SQy ?w!-~-_^>XkG-/ʁ|hZL`nLO vyWHkzuՌ]tȝ\ΰ? h}:ԧC ڤzuvF1yrdA”Zn y<7F(K&8 9I ErFgl}!?ew3\iQ4`3i6"P}}ϻЯ *-V9vwWX#:|LTNeq \;_fz9ObJ&B5D@|"j FJ$PtL*)J_)g *[«*V"qK_6?~qϧ&B-Ԅ7^{́BPֽ#z!OOC%_ i)Dl y]s.5j[HU9H_BX #~ Z|CJ%xP|RO-SY1C(fY4:ޠ6D? /Dw4́FM%c'oT(z!?B9r YIYpQWcCy5 !'z} 4/ !"u%]mTR!Q1;˼f)oK<+L|;g_}Hq-?IlG0~!ꭾˤ0A ~?WuzCZrP@.C)QIhn+2!%;/R3O=v2Z}Lk|,UZZq\Sr }d4&U+Fϖ3el]Hz9!0fln0Del]hɮ_#}6<8z/CЇ>: y oS,&Mfc:CSC:zç4vnw E@C*Vl L^5B(؉ >7;H3P3~L"NHE [ `s. |b2_@xx @;!!~$X <:,t[rqD4*IUHӿq[ 鏑V0L)I|A;Ik y׃i;aZDo fUܘvD! {BnC|*#OjXaꋔ!f\YFTt_3j"vW6ߟK-iz~C301~ZѧlUM 9 x6zV`-ߗÇE GhPP[ " :jw>b|4Is ~H+RYKW+ t%@d? uPG?r)GhaQ^:ugҭض:jZX-0ٚ4=]<*Th|#҃oDW?ĭ2bFm>^ӑs+U<F?13;MǮnYQ*GCBsǑm>z+%7L?]v(S]+7xܕ ϫ,/!}|sO{W*ؿ15oi9s}+ial\i+69{uZ}];]DCu⧽p_|r|1n=}ĖA5> T|3گ|b׹\+1&>IԠS/W 4wNJ/_o}%?NoMnh$c}j0 HFُ>z3'A X=?]HsIo)г-IV^b'Ϝ۹WbL=3GG%U73İ+L_=N{ݤbL1vZ .l)u$Y7D̀h_ Gw7Zmwcoon(~+<@^_Ò-8ܝPK9UII `_(>8nW7@vłx+KI߰{@5W2x7f|,]_@1}PH56 |?92϶:Olwh^c|/$4eBh^1Cl ǕC7y{ 1?-+զsJo_sOFG PTPթLmrm/@5% S>z}U`VM>h[k۴jB'@D^zx࠲םo'U)W .dبYW.Ɗo^ɥ15%ɵ᯿RwxdSD.7Mbp^oάny& 9l7vV씩NoNgMwXn^Q_I{iU!@QwN%aF>8kab $m:(B,Qcϝ=o!8ۏ;s~ASy )X? ub"jߡVxeٕ&cuڷ5c{F}9ksH雷VBʹsoIf_OQJ1^ƮiSD$IA:=ˌDr/91jvet20?=?Λ 7aj1)7fE?A)QD`0ovul?ny W@$&=!UskV(0fM3% \]VЃr_ʘMQ4\ wHly KcҘj#OQOЪ6I#j`pv%!؂@]RRH @z4+*$ b>؄1Q+gi~t8oL9o9(.LMTrM%'ܬ}$fsC$J$ wATK6FBszʀ>V{W=Tǁ-Y}tđBBPWijR[΢ (/0]uL!ve(G,{;g'XQ"FD^}$9z_dTۈHsii_T~/?cCGEr*yV e nذw-*=5bTUfloػW*Nk9fU~s-jYUd{b3/8c╃Mp=8[zՎ?GY/CqVR>{_yy'as~t Ro.7| `gJeK?[^eU/zuMgkmw=έ" I猛{/ςpnge aLOT6Ԩ2%^3{ŤdXI^}A%3/~y ]wvE?D!ڂj'miK8BawK ;ѣhW3[{^ԨKOpRo.M6-mE~J[${߈n9 jɔ% ?쾁%^]ٚ?'$;ή_kq]ַi^-}7  Rslqg `lwjeK>[XFYgykimZD70Sox{{o7ٴvgKnzL/rS@F]z}36H˶nي:U(E`xkœdnԥGߧl8ll}&v;A(:5lIڝ+ է77f/W*ue\DHE֔Y{88g 9nYo+GR7 gl"'RUSTqSxkqnkGϔE2EnQj,(AQ&)pfW%F׋/ OFssHiHY$R L-6Q>Ū 0H y8*V%,%#ԎFylɚ me׾M+ef̱ܼBdGHՖH P9vPYm/+\<›ɾR݇NۿeܷnjsFe+6赤 doPFˁWo k۫rX":ιb펃'N/F=rv=y b5$XCsw[/5l]$RunQtDdjczVq;w]ϴ8A5)Yo}..x1-C '/yt0`n8GxZ#"ÞlmV州lJ@B8nofT{^tZW?fY3:vG\d|i"O{r=kua`å/C\[ [W+i@\[ղIˑ;D]Tlަ^ȑm'ʛp_9 ((gK `v]G_ć z޹g]&԰?rVܰ?8[@&8*_ Ȟ}NQT&cLVį騺"hxJ.g9WE|,9P@<{ؽO a [W/sس-n$o~( Lh hjRRa7XkJb񭲴lcCC乤13FB+?Upr'1o*Li_DTD!{42zoo_"쓐Bl@T/;}kwfv T"03y@ 2;{zͅg{?s;fvwȅK=?sʢ^_rЏGy'/&Pzn_41 aPSqɁCKߨf˱@xƑVGj` BU{|jPc~}?Y͚kaV B)]T;^@հH, Ɔdω[+׮ yu3(r (x;z=>P\5T5E\vE+i `/}j q%#C|jrA D3c4 X&iXĚB-l}+VMxT!@>,M;})ӼԎT8?7X,F~8]VB}Dz$u0ΖwR+v&I 寺;yWzcyܜ8iB$\R" 46Ӱ3RҤK bnL4򌔱4i$rKb a۱Wm={4)!JQSoŬAd$'=#bSrĹCbȪK,̐%9ɐWыjЀ r( $Dpdfd;C\@@- hj^ w+ic^SJ`M:4pS1ChA.,_!l~lb86$SXI(.AA1I, bb+!5=Pg%Ag UZH:D>wQĖj_gPby8X%|W \I=+U:sQ1\i^{ƼF&GY7 c'*@b/_NNK17KX/ᔊNfգUXꐜ f$|gѨۘKer9̃z> |lFoc/떕 CEn) Rqn18r] ;ڢžS_xcOq(=Z[>aH*ɲ@htpo0=9,9ƪ]I8 __~mV]ޝū2=5l鴗.ON$,zPb&@}_{r7KJesC<=G^2g$i"AB纓,<͐Am:% k(^W'Jz2fP׊J% )<󈦧:%42<@Isխ(PyIBC v@D*:^?&kef#ns:֟7Hl >qt}'Vѐ%Z4-!2eX9:hK듊S.|Y(s(ZiܶGKU5 ___N)R%/ZDh% ER^xt&)X{uv\oBRNChG?&u-wKI ȽS#ذWN D FRhҴ,}q\(1'1P9VedIJc@*/ΈF:6p`k旕/ki(XTR|6h` kJ ,AJzWsV-:,YŮt ɒt;;Of8UkW̔@`ȯ,,S,ҡƊ{vI$uOѿ,"nM.ɻkh9gwC ++n4Y5l?ouo%ZfH6Սm`zYxΉ"̴=esmZCx^sw&GBgsÑQ R7~%%Tw!=53)MH C& |6 ){~[HMJxP~;F>ↄ`B'Uԋğ#݄RJ8*W/*3 ,ڿPQ,Rn_6C:{y2U(ޝR4-U er 0&Ϯ*EL260GȏIer?|@OGvJysHrf&'z";YRӋ%K+yKq1/c躪;2ToPR>)LLɳ <٫sTƃd\yܞ?3|8q@:Hj_wQW5C`[ۓ0꒣vcLݸ7ފ)I-v(&061}SjDfd/HM*Br0Y/lI[{GMk;\e[ۏ7kKzOُn񼗲+Y{w -v 9?64|{LP"VC3}?q_LAw-_>vT.Q끟>e?6f * $xx?+8AkMpu1gQkmoEm m΅^0{bӫq1DSjD#ȞU?s#!\] ͜-5cliX38;e$o')-@D_c^64X;Vc \O(3o Sn8ܖ4pWu;Fʆ?cHb -؊Dq6z$i3娳A56+!|/#ZH8t|?u5Mʁ (i>u$paF q[V!\f)[gKj_5յ,1 )'ٮ*+<@D$jd^v `2ɱl *告%ȩ 7qQasnEOqa(_gA+͢U &RH6sTM|j"~uELq= J]έQS0A =. }:uΏRu: bpd>&ƬRN!O>cl`=43?m2ЈZlѠ>d*?YMWcyw&YC ָN4}OG2.唽B?p8lކIFʏ=u[g{+W^V_6 JO}GJZWM1m̲M2.մ}XS1 CsՁ^N朎ԍ_Lْ oo16,@H>uUww~urm&W1Hdl:j׺5\gzůwkq g^J5%Rѵ9MzԯD@q%ιb2)-lj3g(w],<ó'gEi緬lb%)䷓}?ٓڰ+g &#ߋ'̽VDf@ W\)[qݐklrjnȿcS g@?t/dSV 6@I]Ʈ `'"H!| }J=5??O)"ڳoZ8f]\x'TƏ]b"U*Ϗ7pae:`cYBl|r̉K7~hȿmƄm LY#S_`OŔe ZZ,gܘ~N6!e=mSOXn!mH3g־r{>[8gT[snfrܸ\J[Eh"$nO4V1΄;l.'i˰B-ҤK&^nϖ dh tjc՘%Eԕn<5 (EOvZD" ˝G"^Zx(E n "Ԋ>FwaLbJ>*$.fS؉^kuA5G]6/ђ=0+Қ>+])-}6&ۋl%L';N+YqOl!E y!jnCJ׃|"1Bp/VsQ"+ F(Am26tft>iUdGD0{XぢF:+Tѹʹ3C4sDٝ^~i1}jڏ4`9J p&Ʈ <ˌ]X'5 `ZZ] >F;S_C.yN"ӦE|i:udED/^}REr R!V$܀}dgX}B>cKB^zĘp?DA(Bt-N@S'P)nzW)$n|:ޡL6rA\(texĞcmPO*Ѻ|#E!*v>dAj92xZ8m\䝔NAлO,nG!p02 xj O1?*^K~s!7. mޓ>fB e?}\?#? F,U/**" 7홼۳.G^u, plV,W("$ɧu"# W>n6^(,*"~/ReWߪ[%&UݪʹG{+ 겎&?ѭeD—;9#uKX(bjtFHl]<&$7i+!R  1_< b8daJ0#ir}!#'.6jHLL = J5 }h[,:Q;&G+ Yx$PJ*n T,z:*wTUWwk[!2~un7gT#R0mhf3'5!&|e'O?/,z$dx {L+M ?9 L;*Z*S߽*b^!e ȫ%GyseHH${ BnAe$TlS#FXFWnA*[՚hC1!Tɕ2k;ǾG=E$QLԈDr= Q2K{O[n~{Pp~ƫj"S_[`I;E u:R=)wm9 x 3Oź^񋢀i65c1M؝9ޟVF[qPMSi G yY$>]AUXM>MIyA_Z)゙Xt=I|j왭 ٥@͡ >J&UB # 0W$CzUb v)*FQQݢj 7c~PwM&*A$"?DuFi3ס0 m)'"Z}H>~0G|%l9R4Lfxb,-Q95@7jy$5qyA]_dN~U)1UR4w ` j:/@2n(uo<:Z7gކQ vt hqWj8~;Swa<3TWzzڒO*?(]9@& fY1tziJ-"|fR( 4Jf"zE[˓Ta4oj[% ~ZTM IoCB-XBV3xނp&F@OyIjg)C1A/:K4/xT4(h"-,6{;dEP.gIbJDjHiWbD1+=RY 1# jn:#жG//u3$iRܯUu`g@߆ D~-sh%}vQT]R W UTH T@J#HUB( H #=Bz6cܙ3˻?_s˹=9Q8zqPCݑɚt@@6ʻD`# {-[ l*{/Ž"?+G^VJۗpV)gi<6ٯ'Y8$^Tm?KTjOdYR,V0*HW& .'}6J⤬đxPPro{ Q#"_QC:W%GeH<}jDV4jw IDATJrFm[q=*} Jާ+(e'ӿCt@ 9ʏNB^X+*wS ^U%O#Қ:D"''+ G"<EztϨJcZXgdBh3Ubmr wѱ'fY.2Nqk<0/%ޡomkzF#9:RI̚؎O0ゴ,g ]ɿ8nWi"2#LՓ(囲ݢKt&{E!vUY|ŏɨ>ơ?`Ԗ}>6^2uHUWɒ"+>#U_6J@6&TiqC|i/,i8mEgPkugne/~j!Y8Ac~{Ƌ5k77 ֥&b_sI5g8ƅh]H'݉9wOn%'m@i#?N67hޖE^;‘ +h =Ȩׅm,>~t[q1mf quay[7]o޽~:-{ *wicWEDiTzDZ#܈{d0F<]@؝{Vئ't­ގwLu Ba׶ש$'i@ iۖ Wc==46ȥG@ͤG0rk-zCYl9yZ͓;v9.iz["ouȊ9 nrc xP_ 6:w5jD_ft vE:ZAά_]t-*ÛVr 4{Ӊou`m6]q [ƕ īͦ7F [E5AD'`EӼ=먰%;tFxčt rR h$Uzc\}Ms6y-2t mGG,%:R Gd7A~V걑,Kb]SFmR',=q|T-R)T`{[n47Hޓr4:A=y<}H%Kur8Jص$=(XeYMuF:pXE5s6{"j97[Xc/Q<3J{XvTI,0"OZKVP-e҂ GP+@N-;ǒ#\ Yk0-yj[d)T:ku;{Ӟ.ͷ9B̴Qw!J`ģgȔU^hL*{6jey7&CtOj=up^Z/LeƐkiFmM0jz.[2aǟtْIƟN6k ^5'q jܮM?BQ.J.4sk= hiݭɹQ?V>e*lz@Sah̩{^B.+"_5Hk =4,;x>:diko Z'a~?ݭi؎6SU'b zDzsεM?]w̱{# Eʐٟ(hE&(e4 UhkbN[ yq=_ln?煫sBlO2x8mk7y꥘ Mw @Q"&Ex*JҾḵ^dB>l ^HkN/:7HxeL)F_/O_1cw$(@iʲ$7& !=0$+DK)AKq`tA#/M>_IF.5_ OAO~ ~9 Wgٞhp&xL,ޏ•*Nx'5xd}̔}%W"G#?oUE#tMNfBJɃx䨪֝74QnCxPAnz49 Y<,GQ8 F"E 0_ P3`DRR-EJgQ [PcB @gҜxzYH5lRyx/1}LR2xb.ZaYf9:s}_}'] &e("cO32z`_WOdh ?vEv8KowS^7_Ūo# {{g[h%I(5?͇Aon3s߉3X{ٽ噦Z$n˱k/x:z8vܬF.5-'Oou zxe*@"B$J1漎ySF7`+oq8"vm94\ҵxҕһe1/)],{e&YG>@Wkqj欭gQ[lPFo] ƁV!"DjӁ}d󝑵jybs<uU ϧvN lú5+Iy%n<;wRڕHA;-?Hrv:׹y .W[BK<[=Sޒ>}n#i*m-7uc܅ѿǛxԧeE9h^2H ^9?kރk~DYс}T/@D*^/3lOLU1w HJﭟzzآlo6`s\!').s4gDmm؂Fwj䧍IT#w{o$͚} ]'e&+<!u̳e!usJ4NFz/&=fH0@m\6?-#Au&7D &VDٔ! k{`U{ԧOQHn\o\3TȤmO6 5;myl8o&X1濎>1g_,_㩃rCjUl?7wAhz~shD\yަfpf{S1gwQ̗{a)f n&@pڏ]@o fgNyI"@xcvu_p'7/ p5?S-1UwFWԚ,ykɌn 6M4Zr sѾc-Bmfܝ3! u*c~\orh|gC%k ?6/{o釒헫a|op">]]>< wn>g-85U?wt7 ̗ ea)r񽹋G!̋>;^X򑊭&a|\ϗK1#Wcx[Iϸ;ؠɇOL+ѢcԜ|ϖ/9|":Ovư{d|{g㹟)xF\ݕS>?ƨ% ml뛠C >LJ{eƉ H,exHM P V\aX?P`wBP s,O•+!I.,~O#(4,kfRqHXPz7DvA|f*UI9dۋ^6Znr@my5>iIɋŪD 㣌-C pZ &+4jMjy}fA@u qѾ[PQWz٩w+z֪am[܍ ߿־!@B8x;o^ٷVkho\>VVNܥIF#HW,ۥ}mh-(+=_-7rh- D,*L( Qtݛ$-ѽصΚ ʮMж۰ TrӤO76|g^3TEy7zN˘GQYg5&*cyV2=۷#M%U{>_/{|c#eGMgJ]&1| ip9 ܿ8n! |U94LfFjxrVH8VDĄZ[Y56RcOnZS(6Cm{iWűw |(EMEG\ڳjJK?i N"+9H%T]q4ysc w8cLY=CzωMs~Xl H%p٭:vhP{ |Q]tHLOݿf9GSlg].]S7dO=5@]^nN]votXF>^Ը6f9GSB*Wض9ḳ֥֯o!{O\[Wn^ऄ~8d}n=XCD, k DmHIszX~Ü/6y;)ݎeG?ܹSt!}&5>ra0.pPî 7dɲ^`ig4dS?}a6/yф]mޖ[a?i{;v ߿oGZpB{<JbئmC;_wxMZL?{r  l:cO]1i?qZ%LW}JN|w$,!I~ ɏAB(k *Fa JSA=S>ϋ^:k}oF-EM'bM>~$l/] jEhQoq蚵v8z睤"cikJmzؔ]7h4ۓx$lz{Yt7;"R,;a lLc>Xvn]W?}V!xyqr:Q6ܫ4m/#Kuξ]};KIUu]4} ře]֞=YV!x 헥S֕f'N3q՚с:BYWv)Oٯ \68su]va}7s uBlL]̴bb']ןK7B$(\ um<|D]EfIL4B*C[R߼wF8b[tb$~5a?5M76n*jyM#Z'|q?^>íAwwzcY'cf*lD4 }5Er?q7G&}J\?'Ĕ]M&G i6"ZڳdF$b4h+TԻQOSӓ^9 #ECHƉ[ %2ѭAwwL2 iD`녘7v:t~4V]u:\~&ޥ~#?$xȠ;O&YG觩I/T-g=`KF~ZP,MҋUh;aUzϟk<ݵֆlSd(NN%CAI'3Hr<[NPLJLIɯL*qN2f4O~Ou´2 2Ϫ^jψ%ȞBj;}o6&tI/{0Ujy(eH %E5`h WE'>mhj;[F?# 5KlP͟Wi\HUAU@^k&{%Fs9. d\/<Q!P)*Bb.H7.(vGR nYy X"S׬FE.^ l-γ/g ʖ,B.+g沘'f իFRO%  eϲLu e=K(F,EYMߠDV_}^e,JK"kz4!kٮM6톯> ? ^֝&Vn7}H_.wc܁! 6ݸG+4zš/?Zo=JӡeMt郧)Uأ1&}-=|R}#Q&UAV3M*H()F8+- vtΫ5 )"L. 3REj罉\y5q#^>zzݸ7SJ7xn|ޟWIf|\ԧi^]_-E2eHRov;|ߟL[ 2=Mĭ{El2jk;㛂7.h6I"Ougg򒁱P`Saw?vgGR )Ui7pD0f>ySƔ'i~] i:hO7b?}Χn33\9[;߻zRvWz, ]=]5&R@3uUm;7,fsGiFVdZJ<G݉(b y}bB2C-␲r.-&"QX(StشV%f0GgbʛM@*j/4&wgQ޽C0웜`׃0"+f^BkYxOdNsXPEf=ffhyyMlJ6'< 񖮒7@.{oGj.Q>鲭oE./?G !ɶ hkծḾ6+k hIzQ"btU((yE|sR4W`%-FTxBX-[ 2ܚSJ:T4IK8SOq)[3yi}ުth\Q3>ř+] t&Wq6іث.k2 *>@)4 #D-MHz|:+:>ߨ\K̘J 4L<EKL‘NT8Rѳ݂~ |jUWt q^3x^@h$ 5s_vU:mekc5+]1:jKSxyi%"w^G(A]#C4zrƄ;A:TձDd 0uryy&E$]o)橓7" S Єy-m[zcǃG |᫇u[Uu<R s>$*p Lhf{ Qf%{?u*,Y^_"h+xs891E=g:u=($h=`vL0DG_@w@] b3M /XݰΥnG-ė.) -N#c yp8cĂ:Xͣa0=X:O@@[1ASWϚחÅ$U~sGi9)#-kʐ8X UXGrSt.#,Jȴދ}iSE|6<#RJ Y"Kv`h)Q=b ][K0E,ZJQywХ2@$;]˽ɘ*AP+u.3TeCn:jV"'76G9m,ۛeOޛx)<[14kW<R␫|Sr * ]d;4B8jkTtUمש8=.!`ɰ1tϸnv+q t?ʬ߾‹u ģj5+wx%yRtw̺ BWI>3\O6ז:fI?v3ė'YŻB{Z~ZAϢ*(#.)LjoO{:78ǎ<2eɬZ]ϠSd~Ӵ)l{="O_g0N},RﴏȐK_ޭc3q>k iT~Ӵ>JꗏHr^Aa,-{v"!tQ7\M r ,L*dvΊ}^ԁ3%-LYneUyI3K- 61~RSBo^R[_L7cԃ W̢t y>FJ{O|Vn5xϗ.G9|VzbAEEd{>K*irbJˎ'C`sic%?ROĺGB [Q[MAt«uBﯿbn7}Lgb_C0ʬ Pr};v-;qOI܈klޫW2q>ZէĞK3"3ROO>:뫞-Oh@8ߎz򗾌4';ߪB(.7exRGiU}ƻUoG='IEQi1Qdcl%'=?A^x;jHuzvʍϛz焧Utԋ[x^J~u ַW*[W.aRO/#2LصޘO;\MWmsSgfDIX9:-;#W稯4f}~z`3߯~rlyȿT΅?N7{iRmϞ/,A)1Lt-mV88LC2EyQVX| L?LaYݕLa~ }D@9l1Qk^ozľm&- uWs[eΔ~*2=YGW=v`4˾(7(P~():mM1/N.c,Se;nl(+E"".oOݺ7 ]}(o#ެԅt3ezEbHv-L}̎i<Á1`|۞㛃jsuseÒ=1&YBLG E_^+. Ym6plm,pXi}AdpbD!mC=Aya\,57y;. 7˨4V?.?=cLU o^m4iޜtȌ?VIgx|,|joNq`6%\ZʇtC[.]{j/0Bz~%}¼7ѿyv,C7ώ\:y 0_{*~GG笚Kgz;ƁҺ( л$aL>8w߂kvr_\8{o?FYc&~7ߝ;~^Šp[q͖rON^*z 語353`L>0wwrX՞DBBe^~42#\u8SLD,B;H(x=hx?Zkď_I#d:QΪv\KD`yǐww Zg"3w'{@@oLcc"q{WlY׏yi:zw?[>1Гb/zEE) ?M%79u]s if=Fߞ-ۓ4c[󰔡Sv̭ç.]|s^\XvcB~W\O;220e2_f!:hRqk8zឈ13Ϻ y1R6]ܿDL4$ƔWpmB- }S.BE]yڊɶvR,<0ܻP녻E3ZO]YѢc,d̸v?->._pՔY%sXog3ĢqlQ.Zb0y|_d,bꂲyq7PLDXzRiĦj'D ʉ)%&+-5Ȍք :Qb +|E8*@@@ǐy4!4EV* s$cXPrgvRH2¥ QyW2=@T,`uKjjHԡJ;7Eu/S@~raa`gw}Eu;ʱcO5X5P˿X}!g"MT4 g˯Onȴyfe̓El!L@e |ϖsOvԳ<pÍóż?V\;x-*'FAzRty=TV&Ee$<[|k,A'rxORN9b<[|k&M(-8""kqw"-,W];8 ).g1R ˾r.HCD+1DfT @ad崡U漺XR\Wb,!pȦ4K %]jr_" =dGP/]%^ J81TjuZB ɱD4gBzb|@^͇qi!֑6 .#8'MY$4%bp.=o16S̔YFR;FL*R+JZUERD k:v)WJ-IWU5.vҏEr Ke QUn,]iH@GcTջQ2đPSW54,MEEo4سB&fcxD<[*c;2,SA -q)e 陁+{DI@\(V "9Bs8?ٴvПx$7݁O1ԧEF,MX,U&J]VRSCܯΊ 8NFZ`qÉG|GCgDdTQywܭ9O̙D (McMT=(eJD @CvW8DKҎ* ̮*D\o[ cZG @mu 9ϫPu;,w8Ӳ 2A[#Px%ꖁW*I (t?6@ý^pIiEW2vDnjB5<|=A@1~JDӈ sKexY܅ut$FW2Dݙ1ԔP7qraYuF5QE++&ŒClGVS ҅ghbӐHN[ZC׀V5)4A DmV0%g.K5(Uy~:!b*=JHWߥ]Drq?@Gdgu!^?Bt֤cK@)W kC#bE(09V=m>(*N ]M"/<~hBq( 6Dm6DMVB2/-2}/]F#Ca|"U(xD!jkx!J ޼&KbN[Yֵ3o7^☆_ڤ:8>n֛͗☆VT!nswm4R5%2v=j+iWM\z[wm`epQ-;"K1xKPy;"]t vB`t[uw`X8q=\u9pܹ~n^7UƵ7hso:voD_qgpBU"Lm<xAQuPTNV'w'T,GD9"Gfu-cT Ft yjۿC^/ݟk;|7Nl)Hg]nM|iףw &F w޺iyݾyZ͟;{#W_ o>d 1qxATv{۳xεH-ފuz._6] ƼJ(/MFB{ss^Y>fYrHDvQrd JoVxLK{Gi-煃*!^25aH-uupȸC+Է^ekF4!R"= يqgHͬCM1o=WD>ѿ\۩h3 IDAT xS@Zw^m zub*Hy<7ֶj~@ƭO+~9ǭRIPPv5?G:yxxhWحk7=lP#o+! ,uֵg4AD愃]WjkEǩ3f/?#U}9dD;[dP@#=F5nuds`feeq^쫧w^x2ÐFF:>zߍ׷ޗ2O]W-^`0еv!5-3Ъi늈|Ao+9GtJ)AGC"tc^x1o.wziɇ}m;a TSoE9@%̍<8kƇk=ꥥFrT07wq{x.OV|*Њ=)5T m)U_}qǵ3}嫛WN9zGe/T}u.eYŘ @ lJę@#)w24fI:h)"1s(Q]!y#"r*C?f9ěQ(T @8?JH 33_'*,AL*F6[TKJ<+"I.|B{gٛۯmKlRTeC봨Zvcƽg~MU@;JI$h9JX wUKbo5[U`phl4[3R3ָ$yqؓjfΫb[* |WF 4B30=e,Kƻv%1hw!>('b6m^Djs)YGn:mÊMYw=%>:NW4y=!ޫyiǃFo| s[xsvpNWcJN{w8z+;?\4yte]|1r@i?q::>m#1eK\BLn}ֶgcy-NTjOn/hǗ;ĊȀ&'&%*RĝHuj5@r |b*o󈩜e%G$DQ)T`Xv'@PrǸJB0D7 o %e3b ?X΁9ݐh[tT$T[/憷nmAjińQH?Z+R7\YV!x[\Q]`gQL-Q#F/?o(,6~_iiq}yQ[=a'ݪ=z6' .@qG<8Էڰ D*on.Xhv_'2>{ Ye~]ׅ]Xo^9.|;wa}7}f!x{sD#B<"2.o]3oI?Vw5X  $U:#D4\aT6cKG:Td,4Aљ]gPNIDaWYQ-LO׮j/zy+˧E p1#kGV~ٷbq$%=>~]ny |*qb֨"CI+ͶxMÉ~r@*0@{~oNNϵ=5D+>\c512ގIFJ}{z6{3{usBid^-N="T*BX2Q _ UAQQ;(d܁"ﲽ(QKA@c2/g <XqAՉIT<-,hUQ2Jfvj åXxs>оZN7ƗH8/L|Z+;?(|^ZJdBXы83- BXXA5Ic8ҠȈN.F)}eZWi.ԪCs\^Sl O3E'vy/撘GiFJM;8="3"$yKH98="KgZ֨EQ9 +.غWp?TQs DcT9'iB"Hi\Pttl׶uv#qj感X}3zJ1~|6? ]8*K!=-=xZz:-HёW&eggW)24FDZT\(1=슀Cx-I' =p~ƢT>PIy;eY]B^G2"Ӻtp^ ͆%3EMć4cݳ 1˥M͊\D!o]6[XSeu y*dF]Ƶ=|'"7[#[Χ33g4-j{w ;VzͩPtx[sYr 6A>'Q+:Ro9!0$mJ(Oܱ [?/g$"!n;ua(i҄k[.FLiy eݑpwE6 "2# iU$Y!qc%ڳ3ޱ? 6F" QoO$ 1gR&JK0|QF!xzG. ڲ7fNFBK $ህP߭qϋ\4k{ ͨ.ۉQ?뺽oE.??\5~5Xk4l|:|N_gxTb-BX'Zq;CySٮ*1mb3+t(+!ثO#B :t!+`BDJq EwsѸz .73֟_ ?!ݱD8řtB4K^PYc=/j(z^5Շ9E,CGɏ^FI"]OSJ& AUb]HEpL[PQhvAA/Sb<#'B_맟b WF[ O5~O۴ݬr҅2ZB@c,L kl?AcANjvlbhC[Gwnyxۮ 3]ZSP,$-}b MQ)2W"J JTT%2&"T>)*z}-[OdY>#լ8']v_A[ Z6z[2S !{k]@ۢw֣?w<#bmt7࣪){eE/`ǡ:v~D!$>a"~HI&)mXwϐCa24@pn5y yFQ0m o.@iK8AFԏ$%Y=L2: 4GyKKWZ\Y"!1 /|0óNK"fk%W3<򷶳ETG6׷li]WRL)5%UHt9[f֣ί>(`_!|a=1 k.5qѤFn/v]{v{I.$$4  | ɯAhs+Evc8cޮ,{z:, f{Y6t`ϙD6լmG12/YNHI@ƍq 1W[NfGVu7S:PE"b*K#Cgd¨ 1D(Ƚ0u (bg^ũ3SUvˆ@dgRR3BNg'dLc*zYNSwߍ~Wƹ i %P4c53=E1tNJK,yg̀ai}Ld{{lg^J@sZ[kVv!u4Rمh|:n|㣨dPP@HEA@xE"*B`HG*B U:)4B3)O>&;{)yΞ;3Fzq֛ѕ^v*u2 @jy$!H#QYGLFRÈ: Ծ;T!J׻4xšÚvv%Tz;# _ R rq}I8? zEMfM 4r7&=G~K4OT xƿٵc40Q9ɇ8%%f m\)1#Ⱦ-ck=sd|k7]*q5_5 _e%rtSP56zxlz5R}-5b}8m7Kݗ-UZdPhܸso|kVnG$)03=בx/YQ}ZauzxQO׮ݢկah-]t8/Obc[tR r˭9Sگ?z=c2&]ޣUp%gt{/5jim;O^]vg%k 8qPGj7nCkNaփ_pl_710JRVO׮ӢkdYDKn\;ǭ\_޹^grpn Ҳts'+\$T'TXS=t %5&bbn< bI|JOLhyR"G ;Dބ~C EBm}K^DضI\ E(3e=d)\8ئm;r N hܷJ][&喚7 #5xO#@YfBf\3Aw6hĠE.@++|6iߴY=qĒRR:B@$,|6iTŠk&\~`<|k!,l f.u$ȻfQR Y7O=w=Z?tfyd>qed,>`2JPFP#g|FN?~ ̑3ǹ_ޞ0ur]ܔ?m ^Mƶ?c$NqQ{WBET"o $j%!%(H{~ #,d;8qԊ+vPRABev\@oΒm/ey繲 6|'(Hۖ0#w :A=9n?xwyNzsdMYf0nټ$T(u@_ǩY_^1z\1|ےׯ/IiJ/=.u_' _ni Tf*U QcLIfV0j{+~C*|GM+.0O  ̗L+KPTA$麪#wIcU+^+pm+ 47GpƄZ" 0P4 RtO&]5;RnL%QyN*Q#: N@nIq]a&L]96yRjc@q fUOBS(% 3G+%ϟ忙U,<0+zNn0`" #6,~r[<Se+D!E^{oE-fK 4v5:GQb~7p\xы-4giPჷDQt zf@f #J ڌfH3]4"y1E63JXL/DE6UƬSƅHCgEו \u$=Α|Ӌ*b22W6 J:]Ha 2|y0L]D5j8jlK6nfGr'Г`yKu8R]C-SPhk"~UF[z ,M8_ЬB&PuS rA {BQ\a`"ڲyT2<+rb꒩b$2v V,JLz}N BUWz纁z\+@#r>hBd+Fm#@!ŅL෶0BLH=[&^RɔGk{m=mhpܔ+ҦjU3= UlVQ""?WXeϋL&cVsd>#9 h:?;ʿ&gkR N(3b >1HJ{X5f싡43>xˍ6XU=2"^Z!{y G}d 0NCDcIDѹP{h{u Ż=MGzQa~}IҵDf!ѣ`ׄk`bzV/rOuR\f v2$:)@VKU1 $Gm?y}ҭQ(lbAq LYZ " %H T A]< WE" ^SV@,9[!(}\EɌX(LjN(U4:Q&Aүom>0k} =E-,mD4:Qμq3? Dǃ x~ *7+t4frPh &A P2"gAkJH(pxƢ LTÍ4ȮV`Du* GC,Ⅴ8̡s z:*b= ;% @w?#2p[ &MJ^"}>m|6yKו$sCҁ}",h"e Iވē߿}, ?ά1^*b@%3G@BNq_.>(7Hآ bn6q`UUFh.rWbpֈӦtk;ʞy3o_|ƝḊzGwӆP\)3mj{A6{`|y{O,mI3o_|զ]n3mK왡&ͺ }O}Qv>3tٷ])Q*D|kn# r{wM q*ʑEŻfϺhXF̚p+ςt8,"PT(bWsK5ߌϺ轾;J9{r­ 2l9H*lc;FS=EP|4ӷک9/leFwxogߖſpDl_ ~E,J~wCY%|E#ns ++ R\t$TL5q=E"9QR'rrGǬLjڅ=e rx l#U;A瀊 `HXM[[B-_m|7Rf+ԧ/|ńH+mՐ "`kq*eM' J\p ^85eGNUƻʯ_: /XpY q]'/tϤW~ʣ4H`W,thoM+? ^:e/<鮽IL^0dx#lծ*\TDR9^]BlG6B?~ZUό|:'!9g/Xj٣% c}j=~}fdNu|{<;}{̭UVOK?jQ];%}RZU3W܌zS?&?jvZ=?~9uނSh˻|ٳϝ9 ʎ:SFU=8HrVnGTeK`NZlΏ3KMM^5}ndwP#fcrSKg.ۗr1ݻFz6nÝicτ'^>i5O1ߝ.=caC->\o6U,>ێ6{_:C}_`cmq='*WohٶhONꅂeyYz#rwuoҦ |_8# \[Bwڷk/;0?~q^=WQsF7 FzY^[.זs<ݼuvIJ™$%Q"&0] ~Isק_6 /eC?w7K܈(&j{ʣ͢-*ԩ4ޏED m^xH4 X`n%]z-SlqZ\׏drڰNG8Jd.y_}{on׸- ~GkHHu8|{el]Ź-x<ImZ%DDaX8lr e;գR:/nmߴ#"U*A]Οw4kl>dX499O\z}uɨy4 C^譶>.sH%;MAF|Yw܄9=c9|Λm}G?](U5&~^yPeyelc}$^OALo+T\򧰽 p3NlX3"^ ]-}9'KKIAFbwcI1b̙W(ˆ"dO)((x\+@=O2y!!EFYܛYm! Jv0`Tkc- " 6xV er9LR)R.d5Z㉙G RHҍ{^*I=8r -OKPx0 0ێ:CpxEM_q=Qd'5}CpxEЎE7ZtҪ%oXWaP2@?P>oZ}YUaУ_{c\^TXBդlW5F:N|۽w.oнɹ֝zy ukH~տ6K8ۮ{ RG݈N[*rm[e\`38Ot{nqss6|Ւ[dIz~Jwqќox:"vP[#6 D`(-}nΦ-_/qɿ8.q me; B œ_mKr31`nkT]MV}w>zm:p!ۯ!)FQUr!޷Wv}1ܥ)G*CjMr1/諭; @$͙rA*ʿt(J@~}'}?[.{%]wS>׾{cY?[0;qwWmE7:r匙ؖYF@]~?skOn_5_l6,wU궔;"eqUjuLE=!R*=C5a3rrJӐEa=TIʪԅ,NwK^QJ._2'ߜeCF C$bc:-$PícQz&T.H- &c]A ʉIAQ9"Z2- qUuL՛αKv[{3³y?Sߒ*~͌BcR $?xv[;s<9Ǐg(~ڜ6 t\5u sofB]]~*hIb78T^ [V)X3.í{38,@/} -Ѧ.OT}]6I'`Żo3Zw則_zEK{6#|)ߴ©RDEJ/t8]>,%Wz)v]Jw! +u"6tJՍH9r^ vM⫿ym{fO?zkAӎ Ek/+d/v^=J q2pj{QnM(;1Ly}|߂;JJluW1\f†TP=6C\+EMymTƄj\(T07A+刼yK`>z^f֩Mc~̴4u<@gs}DPVtT]sKSAl@3v$"z%/2(+:w*Tm mY ߓ*F&~?t4q]Z.3v8 Q7!cj#"Q n{7RVhP8ȕb>RD熑c׊(o>`:bVڇ( D7D2сDmm\RC N5E,#^F̑@b[rg ,@,!\qw_N҉jU4`$$cK+8[&OeꂴCY!2y! ;$Mx`qM.^ 1=\wO=uf n:xG' lE)]ۥS<dlA&9:aзg = o@=v)"o_̓ZU,;-.k&"; H 4+ӄ3WנCI$y# "rT: Orȳe-jJo_<⡍Vlˌm] WVRӁ-*b8>\9I:O[ U<ڭ{cv?y?yyІ< OT6O=oSXa@fN(@뒝wN ׼s?B~ N0R(qg}w|pėr$)Sg{%TI/'պ[ӊܤ³w|{6Ra8w֙>e}Еns/?k3|+ nWZ|n~Wlq6krjͤ4 T#zr!X&Ųlun4SvU:h)tE 32IJ=ꫫk#xoG(;"Zջ}II.R+ s&D-Cјl"Ox,$ܮ@#0֋!/*_Ubr_T+Y9 &f0;fNʽO8{<E |/}RVeJϑA r5gD5dzi^ ` kZ?8ԅ|R{X$ԷX*H;PyUDi<:d*e{~94i LWxL%/ \2)(0,)}姝 EV9ӝv}[JD"(TPpZqhZA^0ۍ;ʿr843@KB !H@r\E~ԫZ_w䧞,ܹU瞺oԓ]cVs.p[D@(H;XYwsO]@VZXuq~q]r䧝x;I\pwxW~{ާg>=џp!>}׵~uu~mTH$`r xy5kk?z&W$F7.}U @xfdpeW>kĝ&n ;ܮѦcÛ7oױMTޱy{jq-~x?w=gΠA5[4{SRɪ%*ӿ~Ǘ\lX@\߹]}e 2kPxwV PdKI}aU | -9J`&PQc ,~")ϗ~q >,`b$5̒HysIX DI*dx#'͖J2~Jz"ōwxYX¦GoV`ݭ+.?4 bE$u^#=ۢרծ&nT"t~[^9hsW^[/~z-7l̪9xT&CQ]fs_^\#8/qcvUamOn:|5fzon (@>ނX%h|s(ˢ6kbЈ6vJ}[֪#Une:kfiqݢr:t.D<nN̨sDbx}D|k7],v[L֚]eWkyMMk2ѧELt#]m"KפѧeLv5q{n[;տ-cuDe7SSSSSҮޱSIwK;mk6 %s IDATÛOLJRVϨVk5f`˫_,̑lc4t*I[:jQ]E1k\^# ;{gO#4~G.7=u= NMnC,:f罦#{QTdNF6L5__aiZVfpUՋWW?.aˍYvŇS%GNOK Os~" Ym^lKʋ2jٳB%f6ƒJzNxE?$ջ;یhk̳d>:2Gu|!Kiڛ3mT,4j[.ݞֶyw[2`Od t'km%$zk9 kB:v bX,~1O=7-ygVO,{Q;$n- ԓ +߿qQ_%̚#e({3_:C:~QWVYNjKR91w}-q\w 'owu$u !;yʏ&lV 4yqlLhݓ3F7K #Kr|ӏu~1oi~:NO9~U]GBu-}`,fP/,13 B˵#f-`;ۤ+k~|@A @#k?}oٹF`#"]O&l%\+]M`Ø& K5F.\B`bGG%G6w)6w*ԬwJQ 4]ek%j~V.$eW>y̼޶u6w|'d¶.=.ly?e;z(_l_;e=}^>p R繲.1EǦɸ+~ m þ8j6-?wNzsTC'/{3lSl^S i8Z#hkbn?BIKe}5Nj5uC[/gcso[Q@SZF&O3F"^ANGYҠ2r [h,k Wy2R;** 4? R'Ey6(^AZpMPTèD*|;(;tWԡ+Ҋ!;JLHq6ʶ%HW&A46Af\5 b8An.\ҨG4 Sd\Inb"*(ǂRjґV_VPПd{(QRpdk5M{>'MP?dN lW`3I#jTJof#t0c(؃9Ʀ>jrȈzkaeҦ' ZPPh< S萹sK("D)۰jiiTz&<0>$r{QR74嗵n>XWFcH`VPSߏ/X E }A%w,5eq@1}UU=w--1Eoоp "{*B2'DYR1"iǃcz) Il:4dUF 2EzUC\n4ȸ- YB QWjF-)[sl5cj ҡD*dT<K T 0όL1C ʥ2A Lc3(4\3Ǭمogz(DZǯ# hm}?^0*0YTVd> ^ph@G2N̦AǤzY4d!=bHԜhÃ3%HL]~ֈF≾G$\X8FPMR~5b%W7'dଦ,ҍj'4cV/{jI5 S:KzJJ=DF?ő  @Bq&ܞ2k:RU$2=>I&^y Pqlj*(D8[tJz"C|$eEQg>!zMШZs!$IHwiPi?brGd[^(@B~ Ui}OK%k$4,L@PyT`°\B _'u{hF]U͆ 0` 9SPX #R:b|ɀ"VYa!7 ;/Pp'18 ZhfVnjkPq{yAmGy*Ycum %BS!5(}#@9 f\SA=_O p6OsG @ߪN3=EZޙz2LWT]Vv0%h6tf|ԧ替l=]R_V<%\1$J3@A'8Ft䏃r#W.wp$ocI݅dnFi9I-]޸@%:$#_['و,Dn=@U- %g{C@.]#%2bgSkA}3-.13SV*ay߷u?qCWZ޾=P|. kӨM4gǎ?ɜ $hK~9`6BzOD 7Ȇڐ\SpM҃g' 7NJ>nɇ"/b?F> hhR2}pF "F'.qQ^{?LJ#z2ٗ|4)̶AyrUEҔ4-\` [9{9H%ێ,Ǹy@psTBd܇˕BbmvIk6ªtCDЧaˡ?:{9pOp8?r]p@]؅SNٸl\+Ɍlf}nnhG,|`-4?yS>C(//1Q)Wn=z dG}5mI9p$eq#}~A#N~wSNٰl\H|Bq3)mWQ MG̒0N^5oMZVNO^G>">6  :t,,{j "S_6]ɚF,?\ ll. dWu8T2I 5n0enԳo`ϒ0~*wdpnrRE]@l: O=>FZ_-0eӱD{QC9 sjOD9L:zB_!lZF$,Ն/^ɭjD[(e.U&וCɔBmyءRux ;~>㦩?T@r*~#k;3>}پvX^4i΀2{ȚHziPF>e񽇮q:K>5[?wY9G+eo8@IM ~Eg6/Pw} 6-| gKn}O}ɶad]!V5͞6ʾī~5$SiߺM^nLi7㳮w~-49a`Rq|ׂΓrw͋>XT+0@?H3UG`A@-Eiog]k|wuAs/:",LŒ*S;"C~*&+ԛ}T=xeE*n'% Y7{hW#bרvA%Pn W40/*j>Jcy,#Lc Si4 ߞLMh\$AԜl6pwZm3IdT˖5؋-^.W_R3P{l~\/;H+ uo*4BZ:7 m}=WD9|pƵsG\Z9+g.OJMM^9cn7+̟7Y l'ӫrWZj抛5_\ǗX2ͱs~ܺkMRPս _pΜ?ʎtw.7s"9V;W.?w¹] x1ǑRn5_1{~)azݧ.zt-h{zݦ.ߚt},r4iߊa>Ϳس?h,"feA!ɨWUjQ v=&wլRSWXYk> MHm:|_w8g ߈|;we̷v?\/5ntRO+(4jht#6Ǚ]JMv_u}^/c(qa8T'%LAWkrVZj1:N"&3^˟Fh2vǶYOsY6'l3IW?]DZW[l9ow-G>iAovu?@> 2qcn^޿"rSGu|虁/Z-ڝ]VYH+t.iqป F;ꅷ툏<|ݛ6+Jxxh1շvg~>u!:OULz)%%rF7,4d@DhFb? )S5U_nF(t|E5*^&.<78GtywWՈ;Y{%{&ƕKk<9q'2L1K&GvpT )$&m6~cJ k7ZtM=+L~X:!`e "n唍b1=FuB,R҇tzy_vV~{[BZ~=/^TTr>'%_*uFvC^>.; _vu7 Fl<*旾zj<*&@ei߽V~˱-z"wg;bzħ"YGG{!2;uv,bHj`lE,&r-虻ajz[z'(w @p r(Ah-%og qc1=߼wk06{~ "spIaVE]T.!u}3]r6?Q`QwR N0sJ^?x:V ( &t *&rh`E?=fcŵBueA2UO Ykwg*˓9j-PVRNzXAgvPcNg EV?(y -" b̩WHʲlWo(xм15y >ZOf%Gpm+Vn1ix*0, sumKr!8y1PN-AaPs/m;T  7Ee%ص;߶%9arNe~ln]7@zuuWʠޘKO۞@*L=[it D^5}! [/{U~vM8H*rW lnuVyr`Wf>~ɍsU `vⴅWmE׏:|̽kv1M+C~_OK =79ri/< %amUp% W()n: nIB @C-jjN  oC^"ϓ]XRuZ%J+jc8SAB܏P]րX@05izke;s2AαKv[{wx4;KHjW7n^.p:"e+ T1QIgwViP#]PRYIZF#]u޻q)"8& 0,^ A~CZxy|hTrc" Q\|?k[ TGxl#@J .WA㫑kY4` kV?8ԅ| ?i*8M98Sgm^5sO]K#sgv>Oߺ^~m s0~y]}e'? ĠP )uf+WfsO]wP~zOTE@t_K$5jUHE jT&C\!_uqf:K/VlJ5NNP-KcLƤA=v6 :esr@F;79iZAs;$dYԜ{3I~=t=ZX #.iO}+Fy姝Sɛ w M^zxĩsKn|."S@0It<!"}hBIa@*1?%|Tš :m1&b ;m'`"vx8B/fƐ,ha(0 ,x3ɣOU>- )xv6PAE:? ވku9.A~ n_F;eY1Bp2b(V_@ WYwJ4x_-4'HV#qe ^$u>⟮]e1j\YR!+DP`WOm36N=ӱ[=5.3F.DuU&\^\zj[>44~Ћ~Ά֮_^C>_N\}Q]g}|NHݸ C@;]AA5l Oy/7|{#v%,D(:RH:ȶQAV_o h؍čJdLA)${QFhsaVk5f`˫_,Qͥu |r܂IlG8տU:-{XJmi>jk̀l$Z>5__qiھr;:qj^Vtg\Zxzͩ'0‘-n4ƥҙ~ٹAIV&k#+Zވf nX{dj>kt~ vv;gn\k3޴K{ IKVPx&qgqC_jѰ{Ûv%,ЌN}?OpҵEOM0#QQ=s̴4UZXcQRNP*8ڦmkٻ{ٖju9jq5(~CV>Uf\7F<pr\k}{,Za뱾Upۑbk9f@+k6\*Q5ٚ@Қ ӎ+'ǘ C(ZJCڹy> FJ-jsD,ߘopTdeunG oq0X؆HĒ>=e!LdDPU)"NK_}3!muH^{Rlj(GN=V `ܒmR߂"d& Ofbnf Lr'+T~eŘqa-K/(1 JЃ2|6i\xF,ͰcPS]'.Uo_~|;no! +^5ky/8|(P[G2`|i#ѻ+~ ?}rAwM1:UG>ht0i2@݅˔iLXawaޞxl<:dz Wg\n/[U|Á l[0߿Qs];\4lbzwgUeTo@Dvpq T3³L^T~ 镆\!E<1쀴PvTf"kV =8YHsFJ ~Ȇopfc5z UMQCQ!H]@;p3Q /ԀV8F@4*qѬd6kx&]ѮLh'#UD $%1W!n9 z! kCM}`]k9T!?\PC~qL+%)8c_SfʼXF jxdFbDȐgbDuK#"1oJԁMǮQkΫC6XS%w~mRCyM$c=wՈz;B 8",0Z619QEMKowJ#*Fg,AѲIK=iD=P}̕󺗗NNw*8gQеQlG(a< kZ5Qe!kݠ Jw$1NIҴDa&Id K> n96u`*kF IEёDf+Ĺ]wD">na%'ƺyBsuĎ AtC[ŵ/+ҋ6Cm^Q -UGeiyIDD'jc a/8'\G5^Qm ''2 kaO6T*+ޗ:+~VE y)"܈Mh[<Tm1ARfS4co1Ǻ0ar%+_ :QSLf;-.hz%6M$\e$hd [7 +.\$ٕ7:EH(K#H ].hRRA/SCLwv,0s,\+g$98":]β2W?\w>U8ќfÌ@:&AQsVcH5\. L7A jݤzg@`TvbܭBP͋I?(e й2d8 DPșBMȳB*R ]DO $ paŨ)I.p׵.2HjMilWE#ad(eM$IY,sPtENt|&^s7"'2,ˬ)V",i GE2ū HI`kaT;dba9R@ǩєa"*pr@!p#?V=Y*d8{ܾŵ__qʸ Lw6!lt !X NEEЁ@'}^`0(N+RL>Ȝ*KD }u꣍]F<،"j6d#cr }e>ې{q}I-:]ؤ~> _LC6-.elݔj|,eOz3Ob$U),$cɹYzJ"J-SqPUh(2ɩVFG=Lo)zUd$PTbíMuE "͠I_mkV̛8S-:)y,{DcS{h2{}?~"v Ft:ƣtJ7Wi4cn^:w:pOI7=OGW>x./6e[JZN쒼Uo>=@!PɹE@ŧ޾^+:+L_d1o͆*j.I4F5Rw<\hUc<9{O7:s7Vw)dw5Cm0Ș;M!9Q,H0oBϚ)S/mM g&wbrtXe_W6H0ӞIY]v軣'E zL?tΛ;R+ݔT)2!))K}wt}> t^8.mcPQWzmzd_:dK8/^5>e/bC@;_4hӑ{ڕ_K}V6YN̕o}S*N*)њ"@o}cWy֒˯%+ }3u$|D}7\;e0#b[<ا柩K*.-X ]_1 qf[3+􉠨oCK:hr1I@L;b'i+HHShH˞FF9uh5K ʀPB N/da $3eq̀!w*Q! lIU:,3"dd~Yxc[e@G~][z<"66t}YW~j'ݗ+2iﯻO=euԜ M {g_ӢF_^o loE퇞||m']?eٛgM}W:ѧ:ZwiW^ܩI+Ԕ;"z8=s$q(8}Ơn<֓&_*9{x[pCJ@k'~ڴmyv ?G.G+MPk;swh=g Y]ߥzyDv`'֞_4Y/?zG*X|_9}wqIwMΗD۷RW"gכS~7,/_|wteuρeoy{Rn`' $_iU뫟48| ۦ1^ů> PzkU/Ő=LDK=ĊbǪjTWIQ`᪮lh8XV%T ^` #,1"H ;h>,^AR+ r `ؐWb1&[*(/x횙Q٫x`xX[ IDATHSPPVC ukax ^@a"o {*\0 O\]orrΜK%Ҷ6# Ql"toiI}ꦯU5jt[{\b;W|KVmڲbT`cSQv|E%s?tFp?dz)cשO\('# 4Rq4T'JK#P$gSw7o0Ջ#Q oV?+=B..x ᪾˳KϰQhj#j ;^DE6z+ƭjߓ~8k.Mڄ\PLE[7@+֢g]V50?񊦕XL_tfFy4㴤S麞`÷~LTW;mkm|jΜyB a+_4+x۟xE*h~UT9zdz;8 ";CaNz<9g/AJ.w?;Dunqa-u }'ggL~[^i;wGusqr\En7#o'e|{?hϹ6'tQBe bQ%2w/M8hqibBC qg0h35e!4O Q"t/Rh>$ dkauY@DB8J˝ťg'm3=f,&;Qhw~뜡)) fsxo4Q/Y,JI0ogqDM730~ǣD7x\]c}<OBѵ;=b!MMx&W8O~AK߿ Vtl)*]x}|nK I|zT>9ѻkΔr_OKOܿ74ޢ֖ޙҵg'#LInbp)f-xMGEyǶI?Y{ybM$ѷePLn}t@GJ[c|yo 8ưZ~ٱ\uϵPAYۙ}{G%=:%;GVΈիO*4yEnJĬF=G˛R`39cǎj'1S8  C$K#eT^]r@Cr|uV`n;ʀxBE <kЪ]BN y r2OdIpY&zgi7^o}嚋< ehr2Odk]PF{bXA(-&QG$ڻ}Dҁ q<ғ?Ի'F~aohQj.xQ*s,dff2i*'*ss2Os*sQAzWX0ݼoHXdI_@2FꑶoPzْAT\)j7շrƯ9BV}4D:!9 QW.2PӄqEp[t,BqMqMb&Y(PZ+$MŢpX(HfK-Ⱥ@}kǤ|7Z4Qʈ,."/ [\+iޚ@]\}F vb6wxrɦƤ֣DBsG= -|_K; %,AS&5# Dnk~ tS%B3QtxћuZ륀(x.܌bk~Q7v/l1HG;T}#Σryu`s)@m/jDŽL /Υ㒐ܦ4E h$& x. LʚHLAQ C\F[g疊Gz-=7m޴_\>Ii,rY~{f >7 2$OCHQB".|l@RdṞPWD'cȉ7 6Q@(3Ԅ{gOK6r\W}zrUe@OY"UhǸ?VojҽYq|{}qQ++f*@୚Te*32F:5"E[8Ӽ̱3/޴`yʎհJ$kXyj֩S#k<,o}wߗÑُe7QuZ2ÒM/ؔS%%Y엥(Ǔ?՚5 bc6^t@L< =YE,X/W]Ⱥ^Va㊃&—tS}tTB`ǿ_S3 [U?#{X򳎟JQz eOP2{u-7U?v LED\ڵjGTFc^]KD~?iTn]k[| E׬]f|0%E(y3A_\tdn)x.ʂ @-/McϹ{ցb"z܃;u-@h+>>Pw̅KgڳaI/ ~ja7 =-eub=ڗՂ̽%B /%mַG3?\BzS^"U:8+%QhfX2;o+H.W+$h!Uu<.ǐb Ѹd+ͥ8U&#T$& q$@b^Dh*/#B |E0U Ey!큌ܻ "l4lrS_ڻ@MeS_yi{\ON35>E ?gܩyiz8~#y6Vkp~⣍fxGZNn2S.8o J#jnرD~t)./ʮ{-9k){?\u=ϵmZ55}i~ W\!͎qTZe ;TE3{ ~1eߔէ\&l9id|6qϴ^~7^k'+“ZۡC^Zxg'-?PsLnP%E>fq.rvZ!oU>=GgPˇps`U)(>u(sm7۴:8s{J&ݖ,n.ܿdOٖjdo>6|fiz=fMB}.e[ qy<0=o"4ou^A= /Lm&p׼ܰcfAt}^hVyX^i7rP/8?{!qodvTDQ9_]rTKv~̾5 yQN{>ZןSE[xu鱀Yq Q+(m{G~0/ȁpFQɩoKR=>wڡRiotnCym_|W rL}͌sm }Uп?M7[xsGd;4QRLTy^ŇgJbyq &wd,<~ڿfmYv%!bG=w5tơB1럝y(Or^7Uk]b5V1/Sz{-%w|kKf qHk*ZcvV1YEDw4+$T^1g?9?սw5Y-9 ۃygL)>G>Y$9" 'N_+8d g7+y7q1S5^JWEZZq`_eX]b.>D_YD+?DUyj]F+V1 ,/&52M幣C]Êc4k #9 uq3NtLC`lE<ޤLJiՠ/1|"6YFMycJ(eB]j?{y59-U"czdC~P( IDUA1g'!:.*HLLc%sRK'!ķ>c<^%@a`9u+dܕgP8A+v9. WUX-C -mh"%~C\nMe@BN¸FΡZ"{FO;FBJoLl# PFxzk/)*"6~9tzU=$dqp5BUAtw9ќ0EJO7ґ('zڐ^,AT-B.Jww6idC?:LK2!Biwpt45zl71>g~>Subtuf!%IN"CQǞ "eP^Ghhkb:F3gG(?ppy,U~\y݌170bK0sk A U`dH7SH5^q5NBGjfFxƕTbX0++D$ 51+݇hks& 2)CJm1dIR"QCP휭pˌ5}3M\PIf]oJvGaBs@N'vd*PDQh,)emNT.ZY2ӏ*aͰGGea+RȅAHʁb66Q/$"GL$y%/-Dtdbm1/AUT/ Q=Gl)dU,0lu zģX*V5a.J48Hj2L7 EOW!N5w'$LAnP/"t0QSd;X9EH ֥5B'-OqX[&D)IP/_I&C|c3+N01ƈJ YXd4$a6Pǚ [Qkՠ{L2WLCpMx ܦ.!G5+ ľ Ya<l$2< ױ U%`-(R! aYߑPDrS/nMD@/\0 26sk@ʛTX6\S•~Vp:~+<1lm2%cK^i d,l+τ&L>ʎʰRlf2V9l_i%XaT#0VX !rlceC;E> 0J(|GnM*AiUI6@w6.C1vEx:("DVIZ{D6 +(h~8)2R) >$ jZG+5'li 7m"{~~ "FKDa ~ʍZ=K*i?ϞrQ;D LX[ ]fi'J9s71EA6orw \´)"bJNٶ3E>lx klG.W)kZ4Ek,сP@x㲡4CXV[k:bw{=9j OĘo6=͞PV.Ddc4{r|Zjl +x"A/G94Dyn}Ҷna˷&kNЬ-p `Q Rݾx6el]:ueDfDtØg:jB9x#36~FʀADv͌f7Q{[ ΐmĊ֘Ly IDATw2S} e(j: [2|C]yEh3(uO6lپzżucԲytz:;H Z>뷤/9}]/ٿ{d[x/7lپjgOVg0i8Gyp0ӥ7/R$/9B]C[ZVr:/9: %R'~*hDURV?)qFGmZ9SҵQEږ;I3er%R`,n;kԓ]M^ RѶUBvf%r72mB~7K_`=cH\ D} zbNr7Y-!p\/30$ߏ2ɘSF/<Y[/D@շ1Fݙד L)\[O ?磽FC ADg!xU!Pȃ+0gY@L]-NC/m7-YtߞO|eLF>BcC e›tJ'<&u`CoE?!I@ t]__ '~okQ #VHi#J@lƃ6W`C^ztn){ؕEK8{~/گΣ' l-@ˮlp;4x`a?['!3QEH0x0C~j^nѩd94΅C~jI6;~Q뮷z}z{S :ZLh2]mW?e¸E=dIYmb(=MDwjπ-!FO ʲ`B-C9+\aRB f廅vD\WkN%uc)r]Cl»pS柎QⳞӷn~ѵhP(nC>CgHcm ӔPud䈻NS͝`wRhf8Dg M@O!&.0/ 2uY.Ȧ=#D3&uٓnuX>6U"%I?ϬYedzRHHb9N8>_{HݙKiUa"`F5;8o3~HVI`ן[12vlsk|}m{ Un<ӷI^?mߘǹt<ɏ۱q%Z_1}ƭ_Y##([4˅JңQΜf`Ӝ N4KPeGx.jy9K,c:u}lyd3w({{ߟY'tD\5ZUǹX;Gtvwƹ1٠K<" Mw Wvo3YHzun%9ъk5Da<t,#>t *RsJhBOv9RkP .O{>:W$mD]-n|f!h~@"e1bE@5y/g$ Edʠ?|1S`B47!\DO|.HkOk?+0 5Lpˀ8lW#9e嚏Q퇄zm_6dS7 8#Ƿ8Yۼ1S_?tm2 y[cv Bf!]hn(+8wT>#5= {?՞j>٫]XL!s?\j~HqfTc;>\z5 s2']8ys#|a]/ܘMgPlv?cP -bICj{'>=^ƺIqy~Ώ1Ă<{XFr]2ԻL|dOYA#fMl|A%%zI`ւo'OTv@WQ:~&G:֋(<ocb߾+5X螟>kQ譫^sukޝzѽ?}:bH8RlFEft(&JA $\~l$V!OIˉm`!6ҝVX) 7NjӨ˹6デِVѓ(dՈ5bQ hXPT&OP׹>@U6<lY\ؑOa9i]Ϻur0Ъ5Qy^<eg5+"OKJQ,0說ﱎeƃq?}=oqZW!\M~" !ElGpQ'BD$U4~9d -'g PT\et׾Z͓cי"(jQGCޤ6f?V@] 2}!#A_ɑw^R&z͓xq,ɋVl(k q&2,YM$YcC' 5VY<nx0P89|!~طho^PJ "%$0-*-+s-1 P-6?27\WTL_ b#UKE灼,?%ƞ]7*e`t;Ș?4vxF_GOVn8E޲FINF EtQfBGiu Ix=@jP/Ҥ*$?B9,(Q\clDNSU2bŧn^w93`C7}uaiY%4JѢq6RnPl=`@sճ0ƹà @Hn7fm=$ |"n7y]}1eYu@rW]RϽ5]+ǀKzYT܈P탧'=jCLٟ"_'@|ƹU8ٶP{=f;3g&?rȁC6:S JK=xS%2+ZeBnzXfYWWNLM"ND48LI~%`=8yS9. &DŽm\ݲe/VԬQHycqp2QY*^ɐ9"%%4JDOK͢н*'y-kU ;I3Wdr$PZN3x A帶ZFUBnd.O.RE;u-"Ff 9='.&DWUR:2ш=*&!W mf0YvlKʚ?OAf=E G btfCzIe51$XjI䂉\ olSC'ل  @~։s[9 8wq{u`sX(32F5#-+:4(~">Q}L>2f5Jx|q1F -J @S2ݢ_*׉3˓?y$O.eߺt'䆼<ӢEUoEѷvu -d,$b=W%~6Fz,5Pdq׎k}YrӫzҳK$RQFLP^%%>\_,X`x|{|>oѴ}2ycrBWXt`C>rck{#6w >ҬuǪ܀ֽ^ߍ@%&~.8-z~M_Oʍ"[ Z NQS!&\<~ߍ38>uω}{Ytŧeyon|DEg.:k=tKӺu[[CG n* !=kw&}^F\xW·n a32;}?0#n&WIІw[c,XîVƶ{,?BVJɅ}Ufxxj[0B11LYiWZ <Œ(#upZHi_3?NPU=% 3O((Uv &kcvd8Am5|p~%nֶsDoo;gx=!iƍvs]WdmR >FUYsj*\ņ1@ah/LُxN5Գ3@c[My~5cvpވ_>9 (_Ims3S%pQ~Qo١<*Ώ :nddսL9eͿ*jj8?5_R>ڟY?O~o~?b9[p* Zs1;6w䫹*L סK sqmƩ|vlCKh]F Hz>f\U%U`;;Q&ލҼOgMx}jeL)TL0E =ƩgB]~2?H׬KU]RF)mt2|lѝ*#i$p)]MoA1٤v$>D[V_y0 Rjqb0vjc!*u&j OT!3`_r@;v! r隘/H /bz(O $lZpdeXftB`jYdNp@QGh&(ODM%_>D̨T~)M=fv /ם(>4#Pi!V?]+u4HʘSP&j'Sy!(odC oti&Q@AE3Wܗ*k `;3Pۓ, 5ZD6[A#ЁD\Uui l&wM *y[s+twK,j43@.6M*i]` k.ˉEn,h{ €,N<٨ H$@dV] dFœNU\jSʢ^b^LV@ӏxN *%$H‹A%4@sB90\Pyn/rUܾ%OGAd)LQDZ+ *E\RI3Zd܉Ն2-D.'7U˞ꠧLrvh[8A@-n1 "kk@Ǿ3y@r# 3Ցol. HA1琨\T\#G2X6;E\'En4;hR*JG+=+뱭\*m~YkšfQ? BZj[]';f);$~ 9ڋp% (p5h&ҵfd4KD߄13 U+@GVu!'WoD. 9+$z0뫚bd(ʺ?? We]aSfO{DNY!WdM$t C*SI'AsHrlc=Dؾ F/>e-j` j3 -qRl4(?mBj YV؀L,`Y&u[7nٺdFCa1D1PVH;FP@Dvæ[.}S_#9F "a+_^QGo|_Xy- ꎅ\G0[Yu0+"S28=>-}u:tifԾ#*IaDOꧭ7o[wuu2x#ԘK0%[֧mY4}D𹶓a'KK۲pu}q^og_e]֙y>'bo|o~^)c]چ>{DHv.^a뺴uLyQ|ptc'i i YIh$wZE$}Ě!7 `hκARaQi?%[mڲpڈI>9&c"|bp>qƚ蝬ANuyw[~"dSj ]h]1=X PA%u${5҃i$+ 2=!#:q P6 .'GwP$f.(d$MZnbe 0I+3 ,bQK~㡗 yf~IA٠{;4x`IWZK,au~D;~lעpQ4͌^c׏ؿ#ccw.Iz4C~/ӃxrܚίOy@ڨ]s>gRW5$қf' 3`T&d RݡϽIg,0Oj:xxUd>x&.+9%I/ RnMwçRq~65^! MvWA1{?X ^O/w=i@(DkaH>Ӓb+4 ]IŒ]JUu呅B.L|%DRIh\F 0 |I'2i v-1Pva\" (Ԛ a77E"&.{R8ЭZx_{L׋w6FtޓY>(6:yq`r;2aaq,sƗ|wF_;si_uaDѵ1 3V8 q7kCh< uiYlwo"@i)}˦M^|梫[$FʯHdu!?ϖelH߶wIqVnېǹ_ K7k嶍[8{!#vl}mL߾!;÷A#˃&#Jߙ˔ًdQ|-oqr7k}L;Wz{X,vf:PcđBT|=qֆ6ywvf42WFj^sQ]7:{78wghp_Qotsl9 J^x+4kӌ߭L'/9[#o{o+s~Z >|ǼZ7][ǫƐd5CA~CUƞ%w(fm8p`iU2&8D54P[zkE7gn+!W]zؙ3֥m뷻]ˍi< ^ ~)+!G6mR.k[i"P!7Bv,8P L"x^WB>BTtLEnu퓜͇<7nU3oOzf @Iֶ-T2nk fDB5dd"do}.EʞЫ#34Ol6tj_\EzKO/U8bc\CtQy M+yʯu  dd go734ETjo1ן&opS?е/\H&|~~Ѓ=S_4kYo%޺ne\F>NuM/)-nuWfy;'w=ޡC{^0?sq)ROeMFPǑz |I^Վib,c~,giд[g=Sb?_ %vRb[ 4" ʞ "#3(Osm%r>޳s8VF",z]"8h ^N+.#  5=A"[oo\A^ ;4턈 $2wl?5z޲}ݚc:7]@dZ0GEo{IfRD^@P 6U(V]u \+bE(ETT@AzzHB$$3=?斧2 ~?y.y><,x*]^)[X2-=s:镲u;t%_ߜ3c:mz7%Rf =y\ LƁ 5:` DLBiqy7gTawz͌i=O $')t4)[oo\QQ`FЇ2tcC-~FX`nhJK`?c>]Y'5v Któ[H: HPbеӿ]ƵJ`[VJ`䩷~ߤUbbw-Iq (uۑOCV~j: ȇW3?v[Ž _žK/hZaJQaɈ摷 8 G|ӁS[{D+4D}?q@rz3.)RZtha8ʹA0 )}w)ZR\p$B^f4b!! gJ`ZOp?znOgXd?){Ay|&MR/Łk@P҆i 6;UiL݁%3rTKY(ZZTPC;/9{>b}L:>uVmPn-,gb$ۯY#B@8ZZ\PÈEnk.ު=3y᳽yyHv k}}Aɟ< j!P攊vEʦoUGee[8/sJǿE7{6Ɲ+~9_L{^ V);Vhe; E8:{)k5mr|ׁR@Xl ۋ*GսޞI8Ld\fG [F!*qs'>FJ:8JuB,E%˪q,e&=(YAzetr桊օmg1v $8/S_@{jϺ򣅣pso#3al?Rw/@@ޢdϵԿU}K%_}T)}56u0 iRO2v/]B(R8_!'0RN;d@r.,1l׳>$s70=sv̅Nk`Ǯ/sPeYDuNQơBggnjjm Rf޲Ôӫ ]Ec,@kY_0垿B5X5(_ lT"bCL c=TQ\<}8aص3:-yj`Oƭ?Ktό{YB&ȗvzS݃t^*-űu_./k9ŗ$3'ɇ|S7Ǝrgc֩CU^Gfu+Ҋd*=Q3l- u1*MwIR֝Hlz˽S+`XϤi*_2YRV/"Vy3SBLQ(Vvt}cnHܶ{ ֘Ib^=@RSQ3FI~NhW@h ܒ Z#ӊ{eR*S_?&ɕ֋?|@ç[J9APqZW8OE#gbU_q{vl?C4?uY|_( Jc~R8o  3: o}F`R>>kbASIcf9X4m}s8\>ҒQm"=їܬmӚ~=˸޼mSnkϟ Yde. o% Nd^ckasX ѽ X£g vڝ\qPI޶cif&! un,޾ A ٰAf0p0Q8o[aZ.Iz TNLl #=QmI %)mOsx҃ dD)D >NE"n;֪KFl?gzAIR UPp?~"7a\eŴ+R€ݫh:ru٩>p^:& yz#Nk.n;ЗP9|`yM|30cU@௛]o(~*3m;ֲKfLJP!ğ4b=ɛU69.U !:Eggf(d>{C5yY!%e9Ո8.m\qhfQ& x#"7::tg!:yFā[eekFRoQK4u`-S: =5L7}WxRh꼯tf' 6ùJs1G4˼\}ـ1pOY{ f]8w_Cξta [3Y01܁T2Y9|=1vܾe?mպ;ʼQ?wH鱑#l/E#l/7Xx~/+'>Ve 8a1NbFЫm\F5&U TV4V\h^~Q/ʺlxooXQ%z٭.g6.\Av@$oЀQ/!.X$/ۯ4"b?je[\r!.X,df]кu:L ensA:~rޙ#ysmN;\qOZtYƽ'Mw?;lզM dg&Ty !խğYv^%0ǧEV;@F$\D6 5nGmpp=Li,Ϸ^=uA]BI-=z͝[7ɨYP,X^{oԸ͏]1{K<^W4&ժ]_1hĭuƴC7zY{Uw__b+r'688r+E0sbi 60Ɗ CTwLtwU,f5\*kϖ w\,K2tˁBW\ @H: Wqިe6d4eh]#5knaĚR%hSjzc:ʂΝt6b_`A;:uZMW}@e3ODBOIE m6Wtc7fN1Ϗd^>5ְF|8KO~?~~DVp;:Z0~"|WU1̨3[&3[6W6A>W6! *a? 4"=DxC(=5|aW+8Ȕ %gC/:^Ǝ`Dh̳2DKd͙n俗3UX;Q~dg#FX6~.Bu%{O.x)*'OlDC;ц !lp2C`ĭx\Tu(Kݲу=?c?@z#r*vrk;yerwTvj)Odѓ}Ԃ|uk2%C5PN>X2Y$$;[qqVb`Q8|o@7ŷWoNi*ALpΡD"1/0JVo*mg |e &cHmAi0.iRK)$rPTI"ETl6TJ| È솈TtƓfk'gI=~=ALSFM9th}%7'YF[nK{y[,O^U^"s!)cH`X1SFm,TKD6YErNjR^"qJ=E =$&@ '^Σ"VO@J?"+X}AXFC\~jX=Y "}a82d(:\!\Zکj'/K&5d|%p]TG,C !w7GJAj%#X'V3d,u"ϨBʓP5rpIh_I` ̅( 'WmU.AܦJh 7P!8~'WśD }:ߴP~#$'h=c%i1HR-D@ ׫#C֦Fn%$qHq -"u:G^Jp:!_*ق P:JCAAw'WoXn+T0_P-v[8 Ykqb㱮,,'њuT9o۲0 A_wt{\qk^1 'RaBK>2ESle''< S7ˆ ,P/kLUIK񈣸BP+} @>=:9H!lm-lNsP*䶭\NwCuEjk'|eb+EFicyb窤 9D>Cz2ubL $;=qHo$,-M:fмxxSϐ'ΛޮZ(sy(7<߷G%7:E/z"Fhdxcf&|{LJdn/M<<4lqfMreOxЁ Gd?EeKRPi qUis$ӄ@)fIMh:Xg(ԲgoHj}֎Tjz',VeKl3uWO}ACpj`̱YJ/,5lЈ^z}h$^poi v}ė{GԯO4< r">͒Mj\!e/)%* {Ez}X fLM:wtȡ 7Aǥ2(2'r?UcdR +YW"ɠ/ߦoIl=8MNp[tȡw=6?|8cЛ$a ^enֈ+@9 5 yz-VDV7{X'"a =WMކQ'_\u6Mҗ V Fsg%|̏BD_g -^CvD:FVX>إԴʖ޲{-}6MZA ٪oFg1ʵǒ\i5iALX_R[e}Uk?8h;ni'E,9|aR-Z}:yܼM}GbZuqaطkǮ;vܙ{7`˘~ɌweEo h6wLUk7+9}c6Z9\@B{ؼjՇ]_YjU>.S_dY)\V`#1Eܞ+Bߚ9BH\g>צ~ڋ|SԤc}??W?>d@v=[;]׺hK7cϦ4soxrfj&oۼx[٤ ~3fdMM4Ⱥ%y[7gGnU2A ş_oĎ/'ek:oVIYЯ쵏 U8kۊ,DZ,O~(4Z7Ur%@-}[̜8%չW{Ncfɬ :$ >?X񗵛|;.LGcҺN_7>ݸP晑Xӟ\0ou o#[jKf>z]#һM_l|ϛc$}MgJ&cfdM#d>}*Yr(1Dh˽ZJ9#**ld(J0B!V2ILr׬"/ZY&* FV9F|O8)mMlt5kX4ʂ.h4v4UꂋP1S'1h̪_Ԇ+dW>B0qHYA4Mx8_TTk(w<&N..{Bk͵/d/08A e1I H<ٹ}Ιe6D 7:嫦Q"B  ҳ;g6slpCOS]˜>z' >jy{UV~2偮ݤ/[|5=UןyD`^`^Po?.}WEOw6b9]#aPUiOV ٪jN~c/6+ TD,ڲLjq6E7I1䫕{hL>S^|=yl8x,9 "|jWu9~_E %I^*e}!pV !ORj1M2HT_kuz3.z +ѯ ?q!wtdSɄ'0א2By ޼>TQ`fzb+G!ɝBKBi3ׅʋH1Z!3!'E?zw'=w|ӂ>uHcQΟ8spOT陲mڌ})[z1o_njrq+4Z"4Vd!L0f$~# ]ӳgׯZwLL:/tm3͹> 53o?~߽Ij Ir0(fA iA(-.kgʨ`\!fTmqyK 8=ҍqPϩ|?~`^uazT.drc|bP!Wl1_z(&tٌ^!c%qLk=|[7* wn׳&Aj.Nns:]ߞ)Mc~_#[Vl] tz׉̺*򾘝{?rV Y)_uv1ަV&)W ;]*\<#FMjSTZP5㇯\|c%h0}}^3~IpQX#M8>EaNJ ÐV/T}J4MS_~s`Ԍ|8K{ b7J:PE^el(( iS#dmpo1ba7|Do8~k//vOvspY^|hmgF7ʲ"j״9@>a{̜Ra?Ԛq$u!! "wD8pHOyDdswN!io5+5kVK~: ٽ (b$۹+nF p0XHaIIEBlVw8D4M*N$b ߨyI^SL9>;BhUa->{4R` e_М \vPj_B^Uhji Bfa:^??JF=_/UPDU0>xni>Ln֦^pimۜ~$qk!&&"k|aaтrbYKZbőU$ĀTs'3d=C&;dҿM`ӡRS)WT6i>_Zu4؟ki3N T^x bQ}VJ ORVֲKF&X}wX334'ZZW޶cidEoOZInz`n<џѠAFZujwu 3h2m)XJ+E(e \U?5Vt4(8 AeL@6X}OL¯:r֕&L> @gvm<ѰuW7-]. J*6+=0C#h. z}Ѧ_L`m(O6Wz30T& d>>D՞RRڒ}39VdeX#dA<dkQLZҿ2ƒEd4Jg)okAMA@ŃlZG-UUi0G-fǙ 3Ba@ eN{b9ibZXPg{ekV޸K2|}@I~HCj7H76iY~K9P eVްK7(RSbinl27,ne菂IJ g"8 @E¹2reve kޢ=v3%h)D@9S *F4]\ui1hO:'ka^B*V4x~皮:^_GpE$2P`$>;xwƍ㝣VX_}FŮXϕ' }ٽ.oL'Ţ2|и1?wcGr`c{}Hb#,s.z1φ^zGuv= m;Wob3L ђLnle}x:޻#^p#6ZL{&uIsjAIFN/:r3)\6m^e>iFx-'׺‚EHBm/Pv=uS*n=5 a[_n#ް3u LA ^zd֎rJlq@O>;zN?vPjbBcG?B/Q Y6zs)zctXAHtgQD$c#J>3WJدlp(pMD3{}'w;zOI5N`%I\)2-ܾRfpUTorw'QhGD %CHwrtI\OT+@8])!+NUfeO;86\V˞&SBf'qΣ'{|sJ#t}^Io_qX=qm8(?ONe9>7sW{V.}VԐi<_7gr8/ śxJoHoKNA<jelE Q懚o<%2A^~4UZ6.E}T&puv)m t6f1Lz/|/|)? 'ꕄA1{ QmH%sJNH8Α,;GH$ Txh{d|'BSN&+H< U0r͕`M2_y?:$3$T/UOVcMl>/|GCqVe'F/fs7 H=Vw;0\)AI#WZ 4$G":iR ̎x?mq !At{3#WgŏHNg|.ԭyxVM ܣf0O ^|j^X :/Gr\x]h룤OB\Ɨܣ4t\oxuvQ$=~E!#IPM'ujaDr/1^Y j@CHӯpn_5>2:/HK=A/4b=Vg24(R7]Vޖ!^P^ Ub2HPPx)N1Wd׫?I<tM<2aZ;$FWǡ+}8Ewo_ҹoTde$?Pa"d`ު11r8Uc_xuKOTCr! #H4,xrA^3X 2 A*TT(0Z]f$wO<<1{rĉwWI\E`m;'3LC˽IXIMϦT\KQǴ?)BĨR:>Hygϫ4q>$j'lo7m#䮌H0k.{̒ZtYJ1fcMb+!o:*D6g(%. Rew+B nORhVpx̳kCޮ ct8eI5pcC# ʋ[y_*N0{5V bXUQͧh)dqh7dSp]%HsJAEjpm4@]^r-lWzW#ذHd@`$k3<-7l}j\Ý"TyS/rs]K< 6"* u]:lB+kѭhG@O}zsP~O_;M _kԕr,d[BZȮ"wB!~XI%'x^$";-.S$&0l ,ˉKB׶ +G>Y}|>h+O3WʶGQmArĕO߉/ß#],w=YN %蝉l"\ }O̰$wx9IXYcO9Ir} DbcGǶ[;%sM;O\sc=u̫Ym,f.hkڅ<;QP,D.[S-⨾>7mQ$)%|^pkI嚧{Yv~њ+1 f6|a'mLGD j0"4,H2 zXǠQϏ̹(w̟cvr#!tЧoMkaɼ-ߟ|xPuea_xE"@upiAN-:A U(R!dgnMG-5WZRVSvd,_ˁlXMRU4K$x1z H0$h? nk\&f$r1S+h(8%hp!|\ƃWD*rUO|G`?$\>5 85dt:l~j?U^9rs0N( }"A_LJX^rCCA.6\^GC`W}`Orf{Q]7˽O5+GL|y3 Fyb) uv(3:fT|)~mEZ/f]GqkdJIЮرwnR-Z}:Uk?4h;ni5Q*wܱk]viWqΦ8*{if,a|zwɆ6-z{@C?ə0Mmf+9}uW2P++WݴjÇׅ}:~H =&[+J.8@-9-?ܼus^7J&$^N׶*Z ("4R36|Ԟ}~7ygڟ]|zÅ?oy9o^? !󦏖Ͽ׽& R'`Z;&|d_7nm:z|Nw+7ugue}ey+7\S7641/?wa?oXgno8~Ve U>s4 %d"~@Gg-@e͔0yB#Xx{L^Dq|-X;rٝ4i~Jlo P>OPxESXjH&&I(jT;%$YicX/am"]F!\,}վZ#JO͝|X}Ei0f-YkCAYUiG8ԡe-폔 l"q}ΙeluhDK fz2պW/7`33[_|Ox{>~8jژNAP\D7.ݯuQd~ݻ ]VYqE; -3$1TU/)tƂ Bp3->N@8s]"g("\-xY 7KOmq&/sZ?z.,Ks2長vurˎ㕈N{6 Tmy^V|SօgC^]A_0SfMǢѢ-;τڷ,ZG1lHz4r~_C fּU[3իmcSA M?1~w+#k' /rpxD~ϏwsQb( M|{ƈԯk|찡'ģ타i>6cG>5F}dzfBW0~yK_8giW]dJq.d!(gr-B ?J y'W }>qbaٸ>N=ٟ/d֗Ңz׿Oo^( C03=66IbB$AXֻ~03>0Sv k3M]qWʟm {|X8‘#[o+hɯjwX uÊcMQfPiK+( P:rF#".1iqIDATd:y9eӯͨX: !բ"gtz1Py1 O@IOTBEe \vWpwR~49 6oYPt8wOC$5wg>?eٶ#;W}yu}bݛo/ݕcs/ ku7?37G<;=_l-6Edyʟ!'EFDNTdpF!Tav nӷ4Vg4AWl'w4R؄)fT9? m]FY*IZڸ9gkh1&c[h ʼfqw5ȱhhB^yC?AS+O@fr͹$#֒=km9M.6UH;?D (Ja$$PDxQ7m}A[bl6UWz*4Ugw^Vj$oJ5*YҼvꪦc}K4V,4g^A2D|H^p,H@ID}?2IV>Zuޭk+NpׂCa/VN87OQK*-GeEǾu Y:3>CF0d}3scxz"G!Qǐ U" % Vg^P(!'PHro kZ^qeFX%#0EuJ~ZPj=GC Xۼwt΍n}K-8K:m+ =[\Ud$f^"nw`=Z@X6KeG~/lj>79yoiTTQ0+3f?$R\ldwDv<(h--|3>ҙ ڐ"LyU5"@ K:lb\1"b ,GICF-)fZZIfDL##n&$9(WW&eG|1CZ;5ZU *vorϫRk_"hq| *.nF[ԟXmX?^_遬v|JJ9jU]BJ<I!ƹ 0 iӫ ]E K4wЋL? 4 }=oUN-5^"5$ϣ! )HY ?E%NŪ`|~jkpq)!i_=Yߎ7gn\y3mPIQ꥜Z3~7!\T凷nlx^"`iDN=sv̅N'7c㇯1(؅~$&Np@XC7@Kj3j.zW9(8gH 1`Q*>("ٗ2kvi[2$1PN@.E=L2tKsCǜI)rL(9pB)j ;"p3L6f/ ={k B^\eKGN#5 6f]М \vV7|uHh"fCEJDkCa۠۟u]m?eVBFkHkmsKm}If0mx3dkb|*JXjs?ѭr`+v*ܜмRܪmmnVor3m"ŔmE;ig,ּެMӚ4B?@<`N ُBDq˰OPwTXZ.@s`%d8H5JEG@j$WQ^{DPbzfF-Ϯ>Nj.wJ d'2ҒJ ԋ0پ ;=Pax@cn+Lk%37ْ'.:NNIf(em WJy2C EU@bk7pT*OYO?hkJy2Cį1u*^֖r!bUcZ(n,C.P7&<#gSY>l )J)[CwbH'b }>/%0 {Dy( 3D+$V tJz|qfSO0|~HCj7LC%h.@LYo?KAӟ=Jˬ/1.AbF!-/Cnyi1h/oSA0 &GS]4o_]\}i'580oў ͇Өt岔^gܩڡߍ,Hڎ?Ti#7jG]`{)bٟwH)v' }ٽ.oL >Qu;f&6~m&>wLFنP! d[KzfGFs] W 9u|Ǿت(Ssz>^$|ǚ o{dDgnygE%8ѹ-xTۼ`A0h2RM䀑@㟩 q'c7m\ўW+C, ^;CӒږ7blO.r*3c;L@]u"ӷeY={8Ƙϭ\t yC׫iCC,^wۚuS2tuoQ0mxuQځms߮gxS|r.7 6BU{?{NtdJO5:g]gaPrCO8Kg?\]O#}r{KhLqqY´i?Q "|߹rUw2F|˽cƌ~Ƕ=pj7N TCKRXu!ý#8Ӧ;7!;By $QuzgZNmH(/KIYToq"u\5mi<шdìU6+MFV(DA;"2*Q\WOZz&n?NE3;սl;wz-46̔%Khz@gfSzZ?#+>͐ړO'oceI1HY1k=HOC.Jh<G2vn&; 5\Cd:=B&8rYGl'qj2EtrBiYk uߣTV 7@3|kbb;CRk<'`2?#+2('F2%5 m):?W+i#[vJ; qy-!Ɔ&˝J^DZ!R%C> o>5ȵ`5p{kV0[(T݁."dX$A5RAߡ$73n"A>tjzlXׄJ݁ V ͚YL59"C2KA;w:xJyR2!zA9ǒC"isIPi6А&.d ٲtfF}=Li*4W,|{H;{.ܒuDX5)L 7JX0Aulj&r@d PBIȊL{J-U.׻0Y$&Ѧr{i~AȆFB!0$*(!(שdSФ11$3 kb!d)I ] %2 0Ep^o k6OP$B1}|952aHtjıT1`LFBo0+g: TOS<@\N_PH C=Q3ӹξH%bH\$;/dMG ).֛_ïAUDxH;d%SV!QU8 xa xTʵ.Jȁ/WۥIENDB`glances-2.11.1/docs/_static/processlist.png000066400000000000000000004500461315472316100206620ustar00rootroot00000000000000PNG  IHDRVJP;5sBITOtEXtSoftwareShutterc IDATx}wT9{KQ@)A RD P@*(]zawaaLr?Mn2|y샻Lrs﹧|O\ٲ8??w%O7qzB۳w!0s9E\0e?D.zA3,'o"" Ȥ40A@@*A! "#)a,M?Khl4nlP4wDih;E^E*asx?مvkD >;Ar4J1UˆcXf%( tH?ޗRd-;<qcVW^1mKNv9Q&  >}輱X8>Ev.d&!&o$Qh5Ve qʻw#ļ2ZYg~n<dcZt m+(" ^1Gd%x!퍈!rx=K{(Hq/u$"_Mwꦂg2\{XB &YgfdZbْR)B  20ol»x'*6욁eݨi8Ȑ|eS կ0a˙%"$ο\+N|:܄\5 $U2{-NljJ8ņ/+&Br3AbG֤s4YNH uY;f;(`Bu a=]CP.wL ܰ !a<2oںrz*kg9Lfr9!]EKH1-JrhݕTtkXc2\AяC9 3 CcE*Lf s] =d [Gl0 -BZ^`h0H!:ٔtcLaHqe~ta:Q8kGڊb Titx6I 1Rȿ/BW޾($>e!R+A^Pž ( O1dt$4DC!kP-G˔(x8\8 ]"XnA OQX[B3 u $P4u(N"+qfA*eK!.7Kbb Kوb$"@f*d$isNU|*@fj1s\HM] ˠw=>[n~ Jd8f-Fr5 QSO6lt/Eo0s& y[M8$2,nUN#/Yشf@FRE()XVA!BEӖ$ %SlcHalAF"1@*dM9" BEѭV"XV{B0d\LM.m0.x<L#D2) 1B;lJh~TAȪVQgxs^KU[[bt_8(ȇW{h 1bw;^J X_ F3aM,ٌ2r%M5^Im(|e' `6V (6A53:}vȹSIQH!RLQ)5%S7R"BꗒPWKXN{0"3CwbBT %3hVAeXIVgtvc bgјtp-PQR'bޡ Oތ< bgb>Q޳1om'Qkq"·{xc.Q L@O}^?кu.hi0ԕD`9KDwِ9 4gkl|8:o^>fnOCbb-8Lb誽")pE!E~ !")◶ Re%BX 8;]z" f$1IvK3Xԙ%U> 2!(fh[aVU@0i,40K0t/( /&!zQ3bZD3[#dY&^߂XϮs ^]֪ xW9Y Ec/V~GdYϘC"C q9,.c.DS $za#H#I ,I!zx̵|#"H"T -f +۴)@"ˊ,rPewEQ'AF{~P:@5eE @  Cf~CQEE֞)˲"+Bn(h:o\%>_" oD}#zذv_b_7SuX`Q;R! %$ $IO;]n|]/H, }dl\]BS@.bĪ PUZzKFGCJ_X%_fǮJ96rNb{7>C :$d mCm7c%؃B v]nV/9-Z6nܴs㦝{Wkvޥ}`dF{#>35l(?v Ga[@?(N .oBݷ_OJ$'SOO.<|=꒧Qe; k]3󓶅#"j}sfߛP]x͛ߩCQ8tM!*;TrP rrV]qꕳFy ըD!53;yO !: %@/OWL\|65 E/ϣ}2?7ڸe ok<8i'dVvjn.s<+cs8 o-Xm~ D_WaF?gOzFrغΧe ::uo|9XY˝w<(f3No#x*fS }Ʃ CDRN̾CFًOeEQ ~4:΢ 6AdS=tH!J440!"D#sM v ǜH׷)Մ21ZW\N^$d$ %-REPƮ(j :GH#SEk׈MR:w<${ȹ.V ސItS]+IC$K{xc49LtڡwT{6yG g$ ?~ 0iN'> Z h3 ݘ!t_l$ o+&d52D7T hKY;έE4 P 1U#dʵ;(񬓋V[RI<l>VN[NG ޣffI_+-EVPQ'H;tG3^~eΉtoи0y01>cwLhήQvihJF,0Gw߭]XJe| #zf Ya\gfpqCGKExԎPE>]_uߥc)NWOTܟk7oO5uYu?cyԲ>_~Q@G'>zFL2nP;L3n u իY`SFإ]R4^f\ P˙?|&([0|}I}zO>y\q-r|F E_8㙛og`1wv|;vH wF-A6)o[ݗ_z0缤Wqph^뮩Z;̅g4feŭBlҨXv >}'}\-A]ώέ~_1Ó|grK)x>\CC\{M_۠>>R(:wa߮(PNEnw`zgoZ3{_5:dž}rʒ[ݑN3dz%|kP|*5G-$j{ͺYG"Ǧw?M \J͓gt I_?[>kQwxx.ˮKq_|,==K'|6~`dwmHl+gxm-dWz̙W8-סy>ko-.9;as:)-ťX2$e ."[eIPvN54_OD+PUe@}xi.v%`&r%J<өEBV(כf41[br2PA&HNY{sGۧr@^Vn)vצY#vܰyق]%n($KJ&S߾PvKg|ڏUh?jZN/+ǙS 7oVn{=eGa RfEf\p2zNR}D~ϖ߼޴qv-<&+i}:$!"DnT-vd@q?Ԉu$S6:$L\x%EA6/&/'^I*ݪN]<y]kۦ3bLE~&I~w >! \٫c=ƗWGӻiԸ]C7znz=]ը$2wanгBWђ{oѳխj޲x>kְQF`\Bֽ./K lI?/O?m.z}QMYC8:o[/wxč~f,,Q:3պ0k|9:W'f>|7_|CS ] #s>{_zuFz8A9=S'Wu^]u$DLOG>?R*}aԔL\='?>suDT΂.fX̊ghTP3a;n^ hȲ0  @dßBCھkaO$Hd'Vع@V5swks7~EhfyK< ;oghEgޞ g7~EhfUImtg{NY9} [2:A=eשHEs.lRy1 <5SGݧLc: ]kOJ[ J\(Գ09]pn<6>i[Ƀkp*"b ^]4ۭgogܽg>Wgo`yrW hA(3jcL`:K^]4m'SXZZ @D@ Ȋ[+2~ciJڙMTcqB=v@ֽ ;l,/l)ߞpqN];em7gnתE6<<טwr4ӟHkۡK҃rPPRҖ뒪We9OX88؊Dzo/\ .y굋'cA ԏ<a_}E7([WO4~Nv¦Þs '}|3W.]`qj#:'gG<.Z6u?m*e!P.u}7Nl=xb+Y D8`ww:s fTp$!g3a(ISADO%OϽP7cߙKoX8鈐~j޸i8x~w8r‘Q kTbR|6ե-Kvr#:s,U!' iOֶ'分+X]<)Z$uCWhU5nqJí+*II=Q%Oҳ[ח{|v%ToIZ;6e B]ZT^ݻ\?xw63Ox1e Ɯ5[R&@==-~j̓uRΟfm^r7G2E}PDL$d2!™POm^b7])_m99-F8rmY;Eg7O\MPҒR)*.ʰ3Q{+!"/9 QX/';-wBdDe×)( 9r YQIOɀPdP_3׬#r>{KszGW/G?jKjˉ+{laa-;ײe[/AQ`TMFj|UR*7.ҊpoF9E G_?r\T,+nJqItӕ&[7ٶm\+}.;z-bYq\9؁+"ǟb\^fN\[g96bQjȗ&78u89ޒ6a_1j &ɦ Zi16[yX/~mC5jTՄoBT_,prM^)WC7S,߯eՄ߄TڏDCF-GMޮOVk?;|vJnKJj]%Y6Z}lL7q."0e8QD:b|QDA6 &[4&ޕ8===B(kKP 5P rG"NG-BR,kFr szU2'v4`ʡۊiJY:z?0K' '!RX+jBDҤ뇳v_Y9,+h7:$TdӃQZ\t@gtFj+Tcb5 (}^{2oߕ^yv%FArڮQ:Oa@ ˊf,Ubq?[UT&ulޡ a*]$-M&IcdϪmٴq=f~lS4^IGIK+2R~8(j1}[u}r JA[$ 4~:I9Ɔ|Q2Xpq IDATAQy d5(I[R`mZvڍnФD/^'HuTʌa]:PO[qPhH1nƍ|—=m&o& C AǕB?:]:Ďe>IAPRNW<*U9 e[T1 F$gA ESGfƻD-/x HQ9" L0 9ZrtF /kx[κQ+#O~ѝu1ڍޟo&3o[#^pşqQ>`qw 4x楳ƿݳK(*Q~MEQ rI!7 I#E̛3S?8>lB(I9w>=wqU4!O[( 23CH:c*W6xH[\9"A$ Skٗ^RS6$ky^6Q`ܒ z?M ʤ6 F ƗJH(WV/].|Y5~n6~tO/?t*lhQ%_׵#eɗPy,IG. y굮Yv% 綬X@K#=jP1ȨDcUߥ^…KV|}O_cѮ+ĸ[J+0S=_k- RG۵Zm<wKXXV[9W$`dz}Ϳ -Zwn޸RѼ>֮seHI>}6c ,tR65K͝+kf0M=_dܹ%iϻ?ݽVʺNH!D#G4|{ٜ ?W(U@|Q;Vy2 7~3ճmĨ*}?QF?؁$Su?*=o_ܧkC-?8xmsFl٦ hzk[;lǢZah9jo -XEg^ɂ@9#b oW6xj~ R{>@~7>:9|W{oܛpuո ~p0ڲ׬H`d:rX *M"dy>9h 4+)sE̢:xh7vpzjN3NE<, qj v 7mで3 ezLwL(2MeԊxo1_RϷ`9=7-11Ŏt̗EŒ{Ժk2*Z!%==W_t-')IW}gj '~lN/Ն|?oe"_2?>xݕ^`cFt|R!vc&UI-ݿ?7AN=Rί0x~#zzCޛdA6CXII:f3Φ>4уu2K?B"Zdzrľ料o:d@}+g] ׷|9m;Z띓7OGoe[/{f{u2C=xbӒ͙o][5yv!^G}h;25[֋tK\UB&w̫BY-x/{Ϙ#2d!yV`[oqG_b2'lN/Fy|첬OT1b;4ˮv-Pߏ\ξgMV^tfARN9=q1jXع`"גCp]kj)]pʈ_ko&0p{? @ugܹ4e JNJ(kY̏*W+ޕ>~$kB7Cg H{HXlX#1l2{1(b5,t+;֏J-uuє5xo<}+$HFSKy.b QPXVy{ /XkK YN 5bd0?Rŋإf|x1 dd,ȝ{XE\u{%KO~ tș^9V%]# iܖV ^Χvz0XD^n3謅Z<)i ZB 0"ʧ'Dn@|uks%aC!d 0 ~-)YIq/;{~~v~{+f "V Ջv^갊gCLDNy٫#up]q6_(rPVCY4Ck2+?  Sʎ ޝu$ vm'`9CChyޘʾ=t¸w<md. 2eǻrxYaCG\a-]ᵝڷ7.EOn45DS,E<* `ͦX5"-"1,W|p$"0uS |$r&j)2W&z=Z +H A6јʅe9"4ثoe|zWMvܺv*w5Wn歅 @򇮝dzS{8*/8$2Њoei$+ $4L6 k?"9m&Ӥ tG B|t[DL"kZa{\/SiHđRfGGw|TEFDZ@P\5N4VT75UwP*kGAMv5-{L胣Z4rܶPQXlÓ1ZA\^Z0(=X,Cэl~)p)S _ޏoժfgzSm}8-8D0vRrVu93 1prxp0m/t2wkiv*quLc=h/9S' ZZzkwUȦx)2hO%&q,?''(*A!_,bJHjBB.0p"T*(RlkQ[IEzx S[defrV2AU29/C "hD$/E:gzxq"2IKͺbrdK.Țx@ݡ$t|%@D+07&f&!M!͎AėIP%3F͗Y_(4-r}0 2_jLr|L8M-d( қ( i:-makvXzxh T@A= ] %8뤒5TP_;1R2dՊc.e;O*J17rư(S&Qafq2%V\G{IFDPvijT̀3fs` >apA"[isIl:.B* n ;1Q.$2m_$L6D 3 y_^jFlzS'/h}oq͉; RHYUP;hn]"tAV 6Km&>3ejeUBK r4 $GnK[B,7FDŽ!YsuFEa^18}Ö ;MN(xUGb`Yrb,]O$ fV=bK8j$#B*>Ͻ vuLMf gq_fxkМ+T{5sumP酵s"KB:`=+ kDDh8@0hwi`oV5}̼gP3V7P;K4Ch<֗ϥ;RPBdD͘HkL K%GFrCNQ`͌cJs'Y [I "gv)#ԥj \'E{B,0ߖA"(' aQ,S7~zlZz)^drizR /2(P! eFyVZ]@M1q\@+46]{ ,ϒTE$tKy!u3eBDpd)ٷzICgbKqEUqD P(ێ\@ׂ /@ha@NðE4'!rHD|F∐ل*L F5$TR={pF 3a>JLBFxSיݣê¡RB\3-<=jD "6|$>Lw,!*D1P-G B4joKhMy 腐xϹör% C:VJFx ߢ 96͖%K$?,li%#~J(p{27R[$BⰨ<)g3iȦknBOYKRk@|gaD$"O #fe~AȊ ʲ|ĵif,( O ?TX^؀d|Kh?ҎDŽ9{ unu(\@ZWᖀ %Wq(@D&#T6Kqz?L E]:J|13)nXa]x̵2߇zHZT[Co^Q)(&۶rnBd+ Wvʱ xtK+[Gp0<.h5oWW9"8tChkE!=Z+gzKo8C6UE!ňFh6{eysahD;+DNpCsN2#wB\Qʆ\ GT»_$ 4A4:K C4HM՝g!bg-!L'q6,0HQF23jNg; lVo^Et 5LR Mmnp Z EB9g PG!^-d$l % ~dap~K=9@`Cm"*bTCRAVC25,02Y|3Geҍ$ IDAT՞qFqLXd܏(ڂg:"J~Nw(t3_#E[hLh^‘z|$ZC"לXG0ǐ2*^Lc2'6KD O"tLĂ"'S}ж"V^풭t2bgmg9M1f@hYTϕVD/"+Nm:SQv8t, ̋"[4>  @Qr0(+dbo~K!sh#{H#ͩN{qDQ\FI\MsKU#%)I))o߼uC!mە[g>OWcII˚F&Oҍ;~x-- 0b?l߳yIϢ@bm{ϯIٺ}ϖoپg=*Ww=D=R(d/߰yw虩H@wfSYfoݶg=ٸ/{l6~vj A*ql޶g?|BQ=r?5_ՊQUU=Wjm{֮i#?S[B)oƙܒv:}mڣb)YY̤3l [/ p|Nۼeͻ6nٵqˮMۿko(<;6n޵zُ)V/4;7l޴Z4:G#{@Nd&Q< `]aP4r  dYM^Kf7XRd%"LtN+їHQdUɊ,+,AY{.T*XtY6Z30ϐkNbV%d,NTF)j?ZV7:m>Z9)䨶$$P(.dKTFN{\a*lek}eJ%(k?PRn+Y7nR:i'HɑPb^ߗ 1BH=r71١]?1/iBN>VlMq(ڨq֛s􁭟4MKs1(p3{Ŧ}w4lf@YNYg亸ǎPm{R/g ?wBx-6}}ь,E~=u%dOʝɚ̸+a~#gz+n(qNXq#_ ёԬE+׭W(.(㏦oܽD R~{%K^W_\ice٦鵃zk_A^ `2:-Z- nLEyk'dc{}wJd.E}Ş=y=?>H: eѕr&Ny޷A㍋ kd#8<ٜfL(-oȰdE(*{ 毦]$AQQ2H.9[ jfWmL-T@yfi6ߔXNd#lPH& Ht7RDgI\DXHAbvF1*U_oe=jJ>{БZ4lTdihHYB+Zn}1٣3Ȗ軐8QOʥ'Oޅ'>򽦕,8|Ð%GsG>(r䑽{.}۔Z3XFw*M^7kOg:r޾pԉ48qzRV :V-rɋVhv)g_L}z |r#1}L,F U[iā/s_~QFc6Ww5+o^9}o+я#)=kuz7+ttz^wOBG"W |}J>۬R.ee"XO\-|j弝~d jK *F"b "B"FaQ# Gg/mbdhnN'/7 7Bc7lI(Q&e9Qtv͇^1A#XNhY;OM%RRpo 9y +T?ZENmrx݉Kx杹+Yd:Kl\_Z\kar5ؠquJ↑sSZf\ӓu:}6wO@Nf2m) yRe}Ry cs}fq+)pғ a'np&W@ Z@d\#{-fHC#X< ճzKƭ`ΊՋi& &JS˷] 2"߮v웮/q+-Ц]Bp.>iBOo.!C>4듾۷ѶP'X t15կ(_OKE#XzKvQ b؁h# &K$ݐ8lKN^W-M8X 2 h  %à~xC! -eRT.8\ \- ɑPD/ 1# }AR"d,k[݊[7─ Q? 2di8yИ_>֊ʃSݼ77‡^mZS}>s2$p:# g~bD2l8S|qkj?O,yT0֚V/%WҚwNk=_VH$(H ȬDve-KmY:eC}ԝKke "`?9p;ktG|)&"|2L< -@Ag0-o}VTtfnǶrl/sg.Wfג sմHp$+]DZ8z2@D(A@j}nN D>1i{hDhmqP.Yquude_(3Ȅh&ҞBh\i M,M:ǎ(PS<i}av#`#s419ZEL?(Dbw:A((uH2UC#s6$bJj\?y#ukwR='S^z,):`|`[/r#Ύ)M׷,Yd^Oww|o(WVՃ62'{ ~h#r7`G<}E6Y5ua7ɉ)r+"o[H)[5J"';?MYy`l%"YSB8mG%6NUʞkb+#b koAl(UQ>s>-WYTi]\ "/wŇR|м0ir7p(e#ab( 'dTmkq&GwP9-m N^R7 E^ttKZI+}6bYZ~ƕ˷c 1J?pE"W\qʪ7\et iRqYbc"l:)8يPN)W"OS 5H)@Z>NBL]!e)R\2EH_lr E5nY LF| 7NZt,HDs'ҥ+7ַFġGxwǽWB՚x}[v\'e'$OH(P\Ѽkmʓy|D&~/diƨu6nzɕfY+\6\q˖OH(G䖕]׸Lgz+*SYhL)c M4h䠖5ʕXv{$Ek*…jw#KAPN:}6`GDFzQG[B' kpLy22&ĶfsXMvf] oQZD;㷖;0JCYړj+qV |> en^x*9NǹP#4d\ٹ`D70ѱ}ՙm}i| !rMFzZ>aa(=)_|ʺ7".杵WFG'Byj :'7HY}̸pLnt+;|wơ4` VI?0oo{LlGVO_${G9z} +^5oxɛFzt~O3>]L xm& {gκiW]{%X]RfzIus+VLI-ؘ Q;}B!ӄ9xKC1'Fn56OK[lir0)D'̩]mbtDGEBġ|K.贊΅7:'jvXL -^պ>2Tfgyu&ulP0wvwBn%;{sؙG&{ am]DV"!'yk@a˰9f"&{Ƕ*"3(md-`{QǝɝD!2u$.`4$L*ŨiQЦd1m\Z]ka1pKaqOqੑ$d5FG6an9$]4 ͂7 E]: =b`OI9PB<(e=f3!(ӀgیDn_|ChL;@29 K PX34HU:t.ITcE='""Ќaq `+8!cܩf< bLҲ^CNN]A^FT#kY7MMe0LI4e A)O'Y2@ً6Fj!YmHcâJ߿L3JJX((k*b+ݮݮk(v H)R!(=33'gܽ8<穻SN/U ^`@׃*LKNY s0Cm p ěSL*1n6 bk.l(q?+…a]gBփ0$px|3 tbV- o*FfBiQLEal};9?m"nsjx|}xdbs$ӝӅQmAXwz Vq+)>ExeG^([Cv~_gĈ{yVQdeȮ2m`F0`;*Tv+v+rtC 3bt"^ӇFW\ϘVx])Hx F}[. X}z? 3vXu8!aǞ}+u#Sny`5f<-p)i euv0j`<_1\ZHѯ/2Ipv*tyH{o`56z$Td.rF&e"eU`Bf34L/4ĿnfbQ.Bj>_1_)"X̛LF,G fQnX(Tea ;F#CJ/4 j|}z+c& LZl*ᤏBKn4VPDǦtBa!1_gDCHwH!0Qf!LH1%%{ wDĂ06q>Ȱ]#xxkMG1|Kkk_DGÚVpQXE1&[b^24k4@uFiV>)ѧ|Em[CO%ƌ ̽{F ,9?1W3#B}sMB=,= >'"##GD>>=2D:uK]ǝ8(.ٖIbY˵Q$2)| sj@LO1-粗.o.D0 ZKbR0#++XN7$0p Q!OFWc.yh L± )-+ L\9!+A+Xm䍺S<R<4A Wg>L~X{9:6Tp>dMU7+Y ;}+]0\c Qbtb7 rj7i Q1.YBB݉ܽ{NTY0F=sa߼.#h1)zz֘-[5*I, {H%)f4\r1 Kǿ^|ʡ]%\㺡'ue-]g/'(<ԃê rs#슮<"JD1`aT3t>)J ĴR r֭[w]Dx[\v l*0iĉ`ztt?uћ[%ؠKE9JtP{KH/[)l[B7!d IDAT% }"j SQ!% Z0,h٪Yǀ$;_ g gDt71Ipshy4:6.,/ ˁ.naL]$D5:{Y$yngSXU}c]7c%fT'o3#KVp(HfޠL 9ٴ tc<ǀfU67{ufӱןUUM[vzַ%o.(!wsDן9:R]ϚurOD>_wvߵ}|1rΨ xmV[_20/u qsuPM7eu%: ʐa'KeZd p Tf*6{hgl\ۻ+Ds܌H~w^V;&o=.=(!.TWb[6nnptUR1{[svBԣ[GI%5G|ff=TzjѨwOo:Uo-s˹i|zZN^ՁT{ Gw4bD|ԃ; )wћq17Niy-wq%<&tKNDeKZOz."2:.i]%L3}q< `9t?vq.{{ey۝#"qO{Yrj;gq"K'؈OWalF8t%zh\dԣ+GW,o5v@n]~.1lK#]ߕGяw6ww:>v&kâb#jO{0Xuq}H :=<>2&ʱ,Nmfl;(!]]$] t_/'DE,q&cnjK1k/ϮW5;!֖00J&hqba?|nws9lB59yIxoߠa# MhH U >H^{xcш/|MȲ7r5$*b9Y:}kF~F wkƮ56ߴ=o!eHtwB{έu3%`P>u~{P6huo1o;:Z0 7N?Ш2 0%:ӿG+^[9e#O^( Uɽ~ڹcξ)ѠJm{wA"<G@z(ϫĆ@XóOqz0S:ukٔe[y"nQ[6nl/GWL0-4l:3vuz~}lˠTLKص~AZ 2o%\W Ie} HQH\k}x^=.84_5xJq =\m:znɵޗMRVo1?@\upྉuh|Z@ܽCC;-%eЊyM ;fD֎pkؽED`ONҧݟ:,\Cb,kqiQi-( q`t o & #Cn6Mj<@E 2,,TTϷŒ;?u탏i;Hu?$0h~Į}P(v"22&<˓s5NH}ps')m ^ N. ` )=|9XS!ZX{g_vRz֧WK.E`5,)h?>mKyޖtw']y"53uC6uMsaGEq4T߰^wn +9wH v ,˖̂wd$,K]þK>X9XX(l45q|׭%|y/^E{{q?|%w*e3i:$d;Y<ݶA5Xի'ߊRb<͖IuQ+C3?<^RXcgaj7ܿx̌WgwSXտmۯ<Af5\ҴS[\}:dwWNE('d؏o Z(7Rjh OPc5ϥw]@^==J#o%pirʹA{o⾩{X$Rzj+23_?Zڰ : -b] ̭{G71u^G-є^R^4NxA^E^%@RJ%Ȋ}ӻ'%3DKAP߰OoѣpZA{S`lt?NHz-p*>U*BV?v<8Ya`߉M4WxOo Wh+F"~|(GIE"K3dAE>_>}5yIoJE'ӒRu{4doKtO1J n~bƘ|v>ɿ~?[^Sʷś.{+j[iǡm%.{-`3(iS6l#t|i~B%ɥe*^~>IR2HٸY|{V_}6fCDk7篡xGlk@ @ضYzwfWS@,T̀bn*u>ڋ1@U( LU`U@i^8Ҕ%9nxlAZjO,Ey>k,HRk _7,>i1\²ᄝm㗍=|c7`zdW"|¾ {66~`DgӪ6#aL(xgCFtr ;p+Y?x柛S׫)p|FPh* .[[c,o2KJ}7#:-Oi~׭EecNN9x%SZ/P|Pe7e>Y@$-_z.mGQS#"k<}T;LNUu{ BlF6:9ט3Y"iDEonEomiYLp()hx۶hں˴C?188|5>?e!-ns mţR~w)-ݛ>gb7>>Ġnh۲i.wvv)OF"!1` nO`_p̃|/~8Uqo?3 kK]z/^KZ&55 h~W4ߊ3 bUN5 E_d-}sv ܇ٗzhKq\d4@Yx پ_Ɔ#0%ؼvNn+@#DH,-DZX XҌ sPcdf)2uI%V^}XE&bm4D|򐁷Gҫn$fĶnuKVN&QVB{zS=xTԞl*UNJƩ`0L:p{dmju(Y ,˜@T^̰ 3-ȥjĶn5K2c^^aٺچXEҭe]+DG2]ދ dZ' ~|kݨD|TbQMNWU *rUB7z)G#}=dk껒.6uuj2Ӿ! 3t#߫77^=6mcn,DhxF44Rˤ bg Sd%O >.eLIG2>W"Uֲ5n6I'߈TմIF/ i@ߓ#/ ;az]kjSdurM:|>CFGHH7O-{yS{6W}=-D|23ƨ~tkUϚW t4p΄)J<(}jjZjjZzɡAmݎ]b[Vd?*c?nWwz;yLBni(ڵQ κL Z^;kϺ_ӯ am_$^_X @Zם^@a5R6+%n=~g]YXA޼sV<<֩S\ۥ\9qݩG~Tr"2*t3S]WWv#PvmGѢQf>3ׯ料n h/[돍[lIj.]ѹNAjcT2~qÙz5pucj ]?&8tעs>:Aȼfi iyc;pf6C {뻺zi[oQB$lewyHz>~Ȝר.\M)xy*K+WuPldfzZ`Ԟ]]|lP&~>:|crusaМuZ m=vy~<~͜?:Vb0ZRԞ^..:_*?$8ZJPоv=}17 ~(m7wLNUZZeA zLB cLs(>c·>*zrMQ4'婾&jtnje.` Orڵ!C"R˼-2s`GRv!ۢm%)AcQǶޠitH]뱥j{æ[m7'6ݛZ.nZzlOGݡעn/dVt ԇ`(ywg:i9x:>:t:qs -4_@=XyTg V66}g,}篟me=y nҊPjcT 1ykZk 6" !"C.RJ 1ѡFXV[K }VCK7$"@6r?V|pJ|'GKҕU?/SdK',?E=y)^˼Smsⵥ4&r3t"\t-~=GV?={;Kť^gmXx`k(H4wgWkaxkDmZyE~}z|Ea'ruK>?Dzȅu53%zd4 h!yVz|<ه&^}UɳvXԚY.,?YʥȦ9F=)y6޸xdJY~b0\~sO]qx(Ky$G ^#87n%zLph\]nO>j͞;u{HEI秗=P!@ :1"5xՉ֭?^9WfA?s}z|EtGOA@o{Ci^TZe3WcJ;_hլ}bgbgW=FQxჿD\{ ~Dmva=z[ +7ްTLZ;gu-͟8+P|\1]|Ժ*l[N^?YNhR~>7"Ea+Zd!G.|\LH ? 3ӣnÙYy4>϶LS״#@]܍C9JRVS6';pr{Yl’Vե3>_|P9]~X 'ZvWEƵdt|Q5g;RwS?#rٖ(*#t_mYtcy6 r$ |0m:6҆A5`d c hW.}F𑺛{O" IJF =FcuŨKHf,wʄ)y.o8`uvF`v_fWHrQ<=",9㝧vk& wزLzɛNݏ1f07d;ln&&+Ǡ'C~LRPCe~TXpCFvHݷ16|iAV+f2ֿRXP#QqCi8r+!_w(,LtAG&ɍr5h%`3d|?S@2?Q݄ j9)뫮㔼 /x$¶ -_an$z<;ަ!%hX,qћ"k^A?B00eY@~G a2$MwVqquaO4+yo2]d[؈dBͪt{D)E+Cg A"A^/VL1g{1kH²q޶h42hs`P &Izg2CDF[oڏtMQ$xFi:s^&9? GU01f&*{31gS?_Tanƥ7A`},L3;#zGlLflBGG,LɬhR] al)}7Y5ЯZd2(~LR&I(̻ixA 1w7ӫGNr (12A*'@Q k s5f/(x`8w3[yKX"L** W*GP+ɸ_P8]o 2\{ׅnq ;#WE&'l#萗<ظ' d1˙ě1+ڇJE|>.v r3G9ݟc?y!PCubjL~ ^DHFz $Pc)9Ub ]$P[NAoKxazdʥJZkA7UkHQ>"ֺqQWVGtH՘cAUBlG)^Ok_[E/%f Xbҁ&xL苸pk ȕNތM<>ҍMȕOތM:>ҕw:wZz|LlË:H.'bbbm`xƔg$;X ̋Ln,zma漘_G Oϥ.w-.Q ;H`u?[ <}7!Qb[89#vq*0w1l#OF .1:M<и:c|Tije͚'cLXތ 0܊1`s^}uL2UYrYg7^nerdad!c:xB,sӁuȊo.c sU*Q\h8g)5Y53ڿ%n-d%/J:`/By~2ٗw RcdFLW>DhcB\ck%$/nhI$27-`Ҫ7飼4c) z&\4h!F =b1%ʄkdYE0!|X?"M(B\SRqy0O0j8DxWuh GD0tY!C {e^Cƀ巇wƨܠvt%~$7d5r*\*vC+cb ۸CYE 1z LOEd㲕5 l4 <+Cy&`o,*6bYlѶ v7e?f3,FZ9?C]iMV\`qv״I;ej;3g9ς~jrͬm̈́cYzIv׶M~>#dʹo/ aBcj pM]}G=EJmȥ3&D:<#0!*V rq2ґ_K~X}azq`x+R=g;T㏛r@ƸHn`+$d1b Le/sxk{ˆC0"x6b@TKVB1lž1 疎{6:dpU1IIfY}G=Jg!-t4Z{nDޜT׌trYD%Vj+1!$,Ҋj#S,I1wwwc'>aG\]6jѫI1T֎K+bL㤈gvuЈTc=}gϣ$/Tn7sŇ1qO"nYB&| ܊Kw( Įݗߏ{')&zj>ߺ$=yEz@~X;^OTwWۣ#TzPmZHgwEqگ2DT9UC5|-)R 5Z6j|=jdݿ:| Q(!0@~Zj4r,J~Lv*s_7hJشLBjZaqrϟ&o׮3o5ȲἠM5/W#+@{NBn5uꁁ [>E6-6ldح/P_3 s |UƄ{#Ǣ7$dn-+{ yJ^M>ּZ1_RglgOSеeB|n9vᡧ?/!:N;.9X{glZ(TI' 01`n"',e uRA[ 2w:Q3an':St3+Bխ/">߸JKDCFNCwogl4?hAӷFo@:h[ĉ:]D`D r7 3E\%?+~Tcmft-Qֹd1f-89-m>$SOxea>Kr{+(Zbǎvus(JBSHy|R)3V%B>ٵ[I\`>Abn"t>C x29aʤXsBVPwBY0Mfnw\3upk7afA$ٟ?<% C(+)4J{_*zǮ;o>|3AV<^t'Oi C\I)є|x@Biȹ^.Ҡwr]j\a=VPؾá+;SUwR(M=uߕiYCz%mU1H{g_I =8Y׌+mwՀUlNB2aqT: h~=]WޖhJרB7 M. KgGBaWIZ2O/=[;t-vRO i{k٦2?G9k-@ͫ$vX~ +`ݻnqZ\lڧtZ@9(H }LA+=]M7n@9,1p'?,"WAR> zwRpQ,V`)Gc{-9ZZ1*ese)c^rd$ynVS`{J唘'X})h\qr=UJ (-J F6- OB"%=DncgQ0 zfIzm2e!}2K쫅~N-07~Nrd0?^oAs.h7HxV:nҙcߦ$~۴5 Dc7ê"%3!0Wul+F1 jZCNRRc}BFk1`ZD!ABs^@ +'şs*}s+xSOoeʘ%;Ogb "ʬxEC:hѮe6]f} gT 11cy7!/bu`0(k5UUsmFjs+jSqDZZc7~V~>`cvL Wk(,S!tLCMϲMZ}}"ռv>?]TF?Xb[% iC"Aih4Q dxvTW݃]5oT:ɩs sg@ @Kr2ƌ;dEa$T) - lhYN؟= X r 1ܙl}CŠmkJ&jCy5,b\S>]Z껴B~G(nڬo/ (?HUW&ء3y MJM1*'G^#ohۗ-]v{s4:@ܗ:f2)3b_[lŒ؋+&xUJwױWI1mo9$dqȊYGL,cth} ʬa0M:x,> ҙڪgLDsMuK[U̫a݋V #z>UkZc 'aڹG qZ'ɨs/_Rg 6ʃt! Idc笡 N }ٖsptҖsky϶嵘Ү>ϋ| L_ z> {/4MhK۱@Hj2d;bSr4iep7m }ui;Ѝ: kGEA rd4E,d5bNI1_7Sh&&;Ɔ1ʸ妓D bl4Lx"6҈|N#qd\4 :@c` N d} urh6 ;{gY*;ܦn*WRNNp OȦ}EfH)鮸f] |QIdӡwK3qfɏƾ"F 5 O@/7}pLK^ 0_f aj;yi'r KLgɾxnk<^c2`쪣ѧ|Eyu1я%O)fюY3e-s!&/.SqMu2Q8]2|GG=Jzp~^Z'eC @KAjYw5aB%M,hHHI:2jx>@KbjjDo8wkXU9"Q'a c 60)YвUI #`=ʴ~lL4GqW/*o5 +1Mb瑧"CW;~ w(b'#C1=\V΋)]5\\>@$/n2}B7;w)1Mk1M+/]!4gqՁ[7VZ;ayrumںX [iaY!C]{4Hĝ-Zx |+ k([L[<9_˟_ ‰]P٤Ym=w : E"y6M;~|W8^%.˹l[y3';0V܈̠eX9#ND.kXjeyH:Yt%C&F=2* {HnqGѝLpԊNPN:!N1Au5 (35Fc7&ܩJJU3p Hpj`ͽ'TZo[ѭzYq\5ٸ7E ;jۼ9h;HIS!Xo-@./훦}$SCF)ƣ0V~nc#Qs^ JHd hx? 4n[^ZPm슔qLj29+\gݦUhL [r/ڠdhvӷB5,2EA>-F W}wɍ/Z60FbbIٽ0Ol5&FGlFl|؆Xk>ia٣Jn~ѪIGɋձߏ;~kR2֛uG)oOI-\;4D5܈Vd-:,{X0ri8k7M4vQ[^Sp- Tb*ZM@_\_V6qFc"& [hx[TS;7R~LЩR`u὜b%#sfoX(wc4rMՃU/5]*0lڭ981^wO-{kh΋Td^'`+~s*y]Aq>\{i0h\K74MW_*Ww#ReVˉa䢉 Ocb  xNGѓCr;}+gڷ>pT)UMe/#!W^ϩ$J=׎}>JT2L@Upƺ)wՕ=aONa[LAٵFWJ =<v1bCfѶ)A&}{6Updζ17rmuv6z1\*BQtOͻ~5jVtQA<6BqM 7}5nEBC2xXäCcE)^C#Vl<,čku]<' dl `e}4s!ef6 =~T-דy~:ڔFB䮍7l!0 Ƿ Р2\u1ή*ȰK}C=3g$S2S֞0@)PL dgsdɦuݺ.p͓ۅѦ~ٴrgo[H!g`[NL}WVMꦼUP]ͣq0F{{e$V8᲏?߼RΞԮg3+JzN5=3 R،տps펽V+ Zdu50JN#=2tǍ|=Ct{VL N91Y!Q.k .`a+[lfUV%༳)g1ݙt%i)'WogS/3iG֩.qvu>1F4{ d˩ SIoѸ^%SHB'W|@X  'lRP;AŗJ_{PsSȜc%9vxU3nķ" 5S'F ##L灋<:}ѰƋ_س~"y~k )u!B wf`Cf:>K}.yp{#V RdQ2,xb{[]u r?oHRK"bʪԛ B b6}9&0+0N|FqG\,2wf9 d.P}fzsʻ ~BU,L' 9 Uu Y!K) e0%N}'w5ԑ ;-)qo2uM o^zĖӾ|GT^aVA,Q2\?"dg7U..e.Kz&F6}]7{U Z(1]"k۰45F U^m&~KWms7:-31GpbQ}z;;MdƩ 7fʝ\SǭW [ͤR×SQrUMB"sArᐹ{/.;nB{ 2WErA7)XB2wGS9d">idnᯊu{doQqH"@Bbm3,,rޮ5A"עye}}Р^ۧAvM *{=dDSDeN_L)m7hL6g} t(U>}pjcө hzM0WE@?BB ۊ$[9!ω@\FKi`z936/I@>N^T]G `Ζ=8PUӮ\J󐯿kՊ)6c* 38'&y*{Ӈ-bc7!PgĦ'vX,3:o]^Whn5GG6ߋ3֧I[_t9XcT(Ekƕ5c糨7O:a3[YKĽ3F=gt.Wbl&Y3R JH(/w_Z4_J#s6ǹq? oIzr>U6Hۀ[#s9ytǮ.:sƣyr+ 7rp ۾6k : F20>P|fh"2cD^ d9eO܎Q [*H8?_R4j _>YS_]z+trnujƼUo%0*P9ظ `T;iCϙIִл7vԛR}\ja 1&JTMf2[87yjTUJ0&gw3JxJ_ WV>@Mxiz#z|vCQιrX29tnkrʹ}YdD_ Xw꽕^/N% 1}*cWk 㑔&D >&85. ylʊK)ǰN!| 6e%P;:~Vumm{F2kLPXWL+ySCOrvʃ÷,~yZS{'y|}36?Iؿ˓YsKs̶xVM|'6G]ݪ;~{Kxd8O%Q-M sߘrtAڎzZ*<@i s鿘L^v"k^{4̕ː9ȒY}p(jjI sc;oThGH^ehO -O]L̻źI_3eɞ `Ύ~|qOU5.X3s̓c8w`ZxK?9f3+;%QDY9;I}zzoF_=@i/Q٦g3o kVJ}/?F(19cCj\ofWn#08 `TcWd KӔٌt+q=gWot3Z¿uί}WC زd6?7Ӣ`~rL`^ε;-?jSN˴#ku&}ɵ~xAtsQ|=>l `eCAKyk-ߔz>'*K=7('{}4M;Q,9jzKyoz!иkgoacIS?,<r('De#Q5Xd +I1-=3!P+S.#vˮOT%-tgrrcd3!eco|O#s)#qtNaR~tG2dٛ2瘘fJdǁ^8>|O==󫒙SzB H&+cUpe׾׃j築ZM.F)r.HvM=04ۏ|q.;/伩$VT= ƃtqol HFrrH uEtYR=,9!wr'(#i{ qB cȝ/>Q(,l *@ʙe;Y-i{#޻l1F{h;iQW$9cs V;,r[ t82rj }Q1 v5&lz~ pZ#&XUݪc GUi `/@.M!XǢTd@%G埣 J!YLx>Y+YŸTrI#y;^>*/pY1X,&E^ RQ-@aB.gm\G(Ux)YP])o=r1[KM|DI|9Xa!L;kCU23v|_w~τ*&+-V鯒wv_K<Hz$Af ^_?o Nx#2c8=i782ADLT\73:!"amMm',^/Lpvc~A֡pR!X;N &$?1Q eFrNRqWvO;r_&9Y~lBn2Tc%(xE Aڡm\-4C cYGb@A^E?dB 0qbވ:IG9ED2B<3Zwx;_u ć /K&D ɹE!8Z2Brgg.(ϜSHAebe J^Rӎc9p;LLq9o"#U))甘MsX!'IoXHk t R/\̺e[JS֞VIVV R%x&{Z< FSBC 6PTa\6@qJPGeh BĒ_h)fJAqS"eXM,S%oR˘[i(V@܏Ht)v3'[NE f?(1f~0(LQƀ)La sqĘnB1'AQݘ{rwĂ)Le3٠q+֦L3?lWvޡ޾jIrf lU>՚>)5dI+"ϘGt xRP0Ѷr2=AU?OS+0h&cʬeH."КK".$Q?9I.,0MދPx%ҒVn1Ͼ0ma8$5O?Ƙ<2fi #Ƽ.uއna5?~f#Y&0YC@H-)vQd 9m S4{xKuF7]AM>q8Fw/`nHBt\Z0j,{Qo}ZfitVUw]/+8u[O=zz܎i C==qvɽGO AFu.ړ#sYb8v/h)ef-0L:R&I/;;S; 2427~?nNZ ܛ}ΉQ!Z<%)brL=Ns*| 3s]?BJ5Y:ޑoBdD2R?Н!Z:@o*.GwNh@L-Z_@j:ʕHF0G}REVK$0h>Gfg"eŷH Ab±PidC w_8$z|n*TLch &s˒bwCyhމc5#cI?zV-zZ V%^F֙ϐm&V OcQӣ߂ nCWU!HTέ 18sI'Rt& d˺e!Y*G|Ht&5-H  ZYa ]pZNO6xaV!bE}im~u>rS VA_Yr`6 ޹-xf?|]bԎf˺eOO("Jn\-H4_GVFJ_ZzMkMgVNJ@9nd * $_kXQŮsqY}Z"-r.VCvs ̟^ǘ.^P$0_܂{Ġ`?K,=C'Z]s%?[Q>Ix J>y'ƀ3ܜ>yed>oW*(q|Yͽ߭GWlRT_E=z3*--CJlF]c7l{V*O+8s.pmywqױ!5}>h}n?{5t ÈO$akKp7;ޗd=pŁ+wF~d*Yc,+w<>ˊA]U7]z~/lZ|o#:pca'i.=tx\@D\-;pYG_砪w'&YClܥfo(2/e@ewdN'j ׮;\\GOu<7X3cM7XIow\xmc;/q% n~x؃G{>+괛uKH,o6lH 09dˢ/USK ~vrY*n֞{?\deFb)L1W:fPPpSJ2xi߬[4n #t],ܾŰ]LoD;98&YGF2pvӷGsܷ]>}*;rLoBac`mBOeiתYA-voڷn޸uK dl0cۊR>_)ے>Zvh5-F,\Q%J^)Uei; ܣv9G,?a\v 哽iU{9U :fLQ d0S:[ܪsxKnKO˙O rԴ}7cf꡻acuƒ90ܭ?\ϱb;H#qX ^6UM7j׭%I̟!$5c_ypѷ&C 7y܆:hbg^Ƥ$~`}f:. s ,%)7eS-2__jdb]o0SΆn\ĩӀB9/}qHF2#A#s3Kn|mK׊p3 Bwwӆ]/ 4K!\0ǻO'Zˀ1S=9˱f¡ s 7eGO'Za}wrk-эZTgߕbSsﵵV6 Y|߾?yW.E:^m`cDщ1bѮV/79)>ٳj%<79:0`ywJ㙖_Fߠ LI7e[à?ň%ƀw6omBt.6צ""R'D 9UBzÆ? ~&|kfk-Ͽyy1Zv$O,r`B SnU_ZqέX@:zn&s֢+3rm[4o6t'gZ0nZXŦXi c·%98d.CG4 kˤb@`eZy DnlW ?]|b_ݬѝ}֮gz|~r?;/3l6%H姈|DOe&fV5\dqkKWI+T$=+ mA TQF} w"s39dB#{gue֍s\9+{ $2wC'[k٬-1 ZlaF Ei7"̌}rU 0 oƭŧzflb1Z~ !Uaa¯T1. _7[5oeږV t4ʚ bz&S{Ui'n`so<  {|ثbn \~d -ڷlޖ'10$'V%DkMxVV׸#x)r 2N4Gr1hOP!w . rc U*-"E >Cd"K8UFHff\;p7TTii$<YoOfHW-o~6r?0yy8u%0mظ0␤!g]G1߶Xk <̵P 2W~ ݲfDP `UPUQ P1)3N+P" :"PC_ֻqXI|0s!SC#6jLZ)Y>oןM9mۥQI_\{O \BX3X[R#-NȄa0`=͵v z; @ Kу5^Zzew6y| *! uBD9o_f.j.:-Pnpa ؒyu_Һ]k ( jqeVRF*J") #V͹9e%uW.F f;xFJZ4O 'OD^S[Nkj'[K*q 2׹hO(`ag<]9iX[U,;*,2J@(-yrjۉu1~.L2wgzHS-ѭfH\OҎMҴz|[Hr v7T!Jk1g[5H:!q1=%$ܯ3Vt ii@Ķo_V*Fr5JW߿ɬW$2uǓ{3\9ӭ=N\B핰10(2UZzcњ0ǜ;:Q[L]9oQ&e]??vϹ|ۤ|L#s1I[ [1(z4ۻG}clI#sBNGNsg$2!% 򦑹HX@VɪLi)i]'mN}5F9 3^yto`S@mþ"t>\ы"p5Q_`y%]D¼eB77v[4ۇOCU̦:cmn*#;R8/T$!nt{fm`ogӯD,xWhWWm}d *"p@k8r'j.,>ml2DH[G`'ƳQ&$EmW,""aFػdf_"52V b,C9gY?󹔝[wC Vgh2}Qy Y2&%)BYvdu~<˹"jDcH1CEȕ) H0;0![}Rˮ$N,AWZ Q$)W>skΰoA dhQx!!t.?Oe?1 a<0JU&.-L0dnXx9^g?b 5 9AU\A@nNrt)i+w"~6r \]RxAb !W sůM̶?XyTf8HRHS\JᅊnLm\xj%>%4dDn0 `Uo~lً+sFۙ^/%R ~Fe H)Ls:LP)f[: o=ǘ)yS(ٗB]dƿDYFKPI|=hd_~ sA갸$yJ~8. vQYau#.V@ bɺEkv@lr` aT ʸm"0yXE},vcv9HL caw`9Y\c%nQ)0RtYҩ! uV/eP#it6ceC]7y\[B[IXII 3*XrKd'*$Y#4ӴrLM٪'L ۖw>CUJ{HXV&& Hmsj422W$"dOHD.\$1EQve>W0?N-Ug 8:qLȕ9DM16q;Œpk?鵣<'hH8]]g'M H1̇f=Mvy7[@s kdqws$0`jmte/{`ٻFiUF]}i/3 ^"= %V<&$ ,a-HԔ!@XįBn "/0rf'hX%P~,P XmbsNkkkjXy}(9-:YSO_VRAD\ 3^|Fԇ OE#ƼSڧոoT'>c-#\%F?3xW/[%rERU:Fj ^n7hOW,~*,;D4X'&U W>l(XSH22,,#r.:8)k<.sax GUn+TAP:y$FsW2` MY޷肒ߕn`1#^V65sU-,Qf- j<|UPj5[o lIw>oOЁL mu뜁^jXzWO&_p3mlE aEܝF^jY÷ǚoy6Ɨrk<|%=>qڛV̛yP~;~we%V1}ބNMB*lo߳jʼn-\\|])yr?qʯ6Z0oujȠCנּ͛?{ (?K;HI0?HʸZ!w'Ƅ߯Ā^m|eBz=;fx5{6n\wod޿w}-ܻ8>[_ ?n* Kn̽[l"wSV<-L`u#bsi>wtXZNGW~Z ;nCKOh*>p|]atobί|X Bv֍ws!8tFLc%WDH1^wq~\qߣy^߾΀l/Ȋ)gL6zT)|Si/= N~U^m39t" 'G=v/l!VfR}B.+A)/u@Ͱ~uL``"[M;,[rI4GCVUaSF{@UcQRA\:PEo*I{Q !i KUt$\II!X&TjuрbJ1T)tjZ[vZ! +sFts: qV!*? ȿ{]XJrh;|̢\>H1X*iP~so11Ydf ؒdZbNpT]\f[G?rF6~ s|Ϣ;⇻!6m {/zC~[B:.^5n88)Ӎ\mw}_6&. ݈ە`a\3SYidnMw1z9d.RHR(0ܬ#ɤeFȢn ߳ow?+n蝿:w$V6FYG>+Fɼ{r._pKh$3̟.ȕ,p 1QhPohrdK0AJ-EĹE3+fva/ F֐n꜓>]*[4h)srn2aAm[֩UtQ/oZͼWݎ!MKuΥ; A5U j:%ujjnzQHQVPCP#m] *#B*@g Y4 &-SHZq tĊ'uP q*HsiXY[<+dA@.Z'(U6םÀ@Bv%IVz?c*y[bY@ `u_!Q<ĺl[ti,Gؖww]=p/3ɡHvDc˵XkFw-WoǔY@ T5y\v]_ ~ɉELrkw7n㦆 \݄KqrGأŐVw61ڮ4w݆3O^#bIF]]箛\ͧ4F沮I!}ǁ-+ kdP -e2:6S9(!^S=>˱"s eSTv?l]',Dk;^LVTIt\2˥89`pB㏌+ƞ[XRs/R )@ b#s#RpuU,@0`ljqAX_9r@Oc$,{IȠ58!&j#Tnxab$ W氨2؅!]i8uH$8a{UZ@#so$1_ `U+oȕc9e[֢̔(b? 5 JbufӶ-l7j'Z0)*p\IPCSY%|j(3Ĵ3#>Ԗ*.mM} myky߲ږg-,r KZ?gwӃb%D%# J8T@'A~Z1\y8XXV3e)l*B IoWU>1׊~k0l~snSu&E_̾-/m> &K~J@Wi} (, P Ϣ0(aD WBXG $P^ F+2ZL@rY6]XT*KC8Ӓ؋W?R .RPްSyҏqr]l,Y)`}7Cj dU>]G l~QHJXtF^b 㨭u3sk =VڅL U^FCޭš> 6V\9cc{h%נL޹Ù54wԗcs-mc\N`dpn ʐ02{{;vuB $T%+{g~sa:lt: g19DjoW~d -۷ji[Ft[9lb$\.E*AqI\KX%*bݟ@vc &-+` a,SXیJp]3X&nRa>F!$Qee7RN &ɐԁV>rHp9|8Xc|pc *|O;S`L.iF.T\ёBL ?fފ̧pIzr>U6"F;E se.6֠Snh͎}:cWޥhj!ki,+7]mGcz]pq_55]_,٣L 0+w6TZokv68 ȃt+V8."ۻCj?Ǽ OGOit Ȼn6!KS>$wfusN&k #?=BamT6Ndz#^+|YziVqy$iƃ(E$ԛW]?rw>)a+wfLo7mq~kӥ hSD/:#Uo.%Ejg@Xj, )yWJ IDAT&_v )flXEAcHV*-4 LHhdt~W%@z<'\ tPYSOlߪ[h[X)x +b+UhP^0 K~0Aߥ{295p]-S?]Qcbâϗ͡t_26i_Lt_?WY=c͂Ss˜맭|!s9~@Ȼf9'?'ޑ9d.닿ݳzᚓ#1҆'S)}/"^E8-JnLNPZFכսcLSÿuί}WC زd[eE4B˿U@ӽq0b+.(3]/.ڨJUչ9RnGQ}}9M64$BA"*JG)VAADEHbDH&'HH/;;sgvy~'3s=9\ s"d/>Z.*WQ 1h67ɀMOB>R."xdL_(6a h w+_p &P72S}aUy@X'@AB{\} fw{eo9'7,̷S*"ZӅ2i5a㬚s{ܔ'm"‹sFyrVHK*OD {Jl^S>JJ0_Qzu=nc*:OߩRGH}=IOtE)Xĕ.ዘXjypOGujV#X#̫[fq/ .unVX9LtIi~ (@(N$˰X Sa1aH]"l@)C.U&m6d My/jjk'OhJkP"%ۈ(,Gܭ5s7 uXK|jZf=2Cd>42qѐSqD҂/@[s?Zu@|gO} {-(g jH3 jKͥ!S]W,#&Yn^i&# 'xw_*B3 9A^ DBgNJ]&Přl~7k= $C5s 4ރ{-zzV^lkg '?KF1!2Hŵ(6uQ [- ])pkCmx-=!G}u]0QT-$ФHِ_{{EN5m<\&I'ZӼ;YjR @А|9Ʊy^;/l%_a~+ւ/L=E~m"ڊ[޼bYVYw0+З #Cb\ sн5n6' pæ.5s&dg1 E1|LX'iCM\Y3]d4B d`"z1` %t9ʗKWW$pQFz(mTDV\uceeR鐍̓O޵wP(:3~nI^C{P (QL1Fxd_MrwZ`H!~Iіk {LpҶeRڢ/|w>,ܓ^Ms죤&\ٳՒVLUعSzBKQ~C3yeu6c'TtjȒ*ZSn w.bʜ6Kȅ%Ð 81ܳ|[3bG-70 Hp9  H|^DCG$sYǔbɏ4-b$^%\KOǏ|Mіk~ie9!W4^cz5;ϟŞt +d%U?9nwVfKeN$(ä׵rAM^gŗ9LJ5lX%l~י|3+G&nG 8kAD>VދPaݶv+"A.{(ީp"F3AUH2DЮoԑ[M?(NJ! })'_Y+pQ5lj]$!\]26w?xM2>fk<.PTtP?zo9^FuY.]|_Tr:nxo4r̜^wk>wN>4TEDI 4qOD3rg c;q. 0Ϝ[CYWGs^>wX䀤^sg 9C^0kC=> ┈;1wQIb S{t&N28*y`R0Ym%}{{_M$) ^v/t́q ੩&J3M( aa"6 }l+NXsLvs"(D8JA^|e/ϜX>1kF4?G H&8=ڎ2THItvh\A $́C<}3bogIwK 6nk`1avg'S%K49P{H>VĹyz P0/=ܾ«)W3S@^fn+!ia<,='<.+%-:/}]&m/_\vV'H[>{c[.zdѮ9r/lT)h7ెJnmGd<3aOԮ);~2}"b =2)ʽc36-"Bm=w-Z1R?s^mgT&6qU7AϯMu /1{HV/inm9v ttJw_lz+*{Zv奥[:{ʄ,4I8M;KP͒somCy+~G.`uGE|mǔ^j\`xaѱ;_ZdIuY* mHhDDKGe΢[)+zʒ:;>"޶=T_527Bw) DP(ɠOƴ,47hORȨ!Bb" S \=|%^6a+qn4`o$ɧ!tjIࢨJW6E㏏n(]ԡ=8Q2D kA!VWnf,Nzm4Ӂǿ, ޡM~KnWq5q%/58`L}_r_EJRxqsm}aoAyYB"V}4~/+iwIgN#{.c]j9Yb<}x |'5{k;|y7 T&7[ZOR ߖCWiKY*1!6{˅ XtuTu#fOt j:6#;< Ylf0,wG=8˷`ܓNb_lĖbuz4uԭ m#6L>KZ A!"H7:#Oљ%a (/{t%7$VDe_!MkD$6Kn&}eW%pQ n AMSθ,]XN!f#0|Ĉ* tYhv$)o?L9֥=W\hH^BGS{ɕ۾be^w"I_.t6=Nv"L J\=Bcà8,[{ryN!U-xU^?pQ_!!XTuY@ť9o$#bVSѴX7![ΦJ^S~dBܹ9!82ꇑ{ʒAJse~EXКq$Տl9usŰ #o|$GEvh>{ϲ_Hi>)H'5]սVN}CE\wMͽ9^ɦX> ԝt(aD !s-.P Q'(f; ?|"vʾd 0S{;R iͽ"ٵy)s^gmH?]Da&#-Ȭ:ccџT5<_tD}BO]:*:*tKIBɶ>4]٠}ܺ|R|_Q_`=нɐjr'v!{C=Pu . U SfHƑŧOe8Qxs)Eԋ-kFHܤtj̽˸J/tzKl*x $*}> s>X@Z~/fWk!QEhkNia75|q[%vW~zJR=uQF켾\nakD8ߊr@!*G@\R$Ym @9J.HUZx @ k=բk'=Wa5(9+ (DZŒb(v:& wđCp#!Vcqg@:5wd%)q/tƍ"!)qr̀"EjlÍW^W xM3Z^ޛ=D:dʩ'>'nҭsr<fXz1 }v-,O&e .޳#<.~[6`C%Qҷ# yODI z$p󖥮I.G >YEesNO vᄈ2}81-Or7vx{M@\#=ԃ\R#E&f! ?za'y^M<|˩`ĒE" 顂"I+ =*Q4 eXJRjԜZwGnA!!3L&&yj) "(BbOv0()&]Q$29s\{d Y$$ Wgl5VÃԽpTyLe^w{2MQ@?<YY6@߼hi^ٗl!P~y7%RJ" [zQ!= OM4.f)쨨d) 4(*#ӆ|-}+-8vt.V:YsVx|{ϓ&Xv㉝}kGrs'>4Ȏ@wfdg*\0ף_orvuhWl&J=T8U4^o*?62'_ Td3F҆K/JMJ;%Ò*#VHgyj=&G'E((KF `68sȤTgǷhnUN{<5+v<arkEz=>rld{v 5z|哃9.=\zFBv+5p{|$/ipa *y./Yi1 jH@XA"+ʝlSAQKt㦡Wl1 *P$d gΕ ,ކ c17{g9;g^Q|<   }TPk7S4fJJJJrJjFlt$0݁F[jPB~+[49stv*F$d&$'f*˄R|zvY)ɩ䈐@G<λEJ:4FJJjjJ2b0G +/G=;]hJ!Dbu?)R*X@TyI>Ȁr j$.~R,dpE|ZB姤/N'6J"@o7 7fHjޓ\kۖ0%52?,8쫤x0dHd!UCosȻew ̬/GGobuJx կ_'.! Jq֯eC{O*oiC{\ $F7Fx oPrĖ"_%D%Wϧ_6BpQ IDAT5տ}TzaGhQcZ8?-қ'*?}⢣#lrZG32ZNѵm#?8=MFޤZOFs{ٓq@xs)!$!K"\~mԘonv[C7lZfL}|/'V :^ճSd,wHFynbY/;Enur]ِ䮋{r躐w]M0&A1ɥr6]B{0<'_sUί/IǶ|Jޡj1QN}EŝHWaA=VkDxfkerTV\߲>5zOJjuv٠ɕ:d '澃V. cJ:'0f0;<:sEgI Zmo=IF~.e5K؊)h`MQ/ƠD uRX襙}3%DHə!c, \ϹkmOlDŧlέr3|rW(葴f`[ƺYeC*1BWQ.Xj/~L]J1ȯ}]ag7} g,Ou{7|kҼ]xfʷy^>r4F lʯs=4׽^\&nk8vܨk+Tdmᄇ쇷(y?Gu\eV?[,Y.~̰?2 Ν}\ݴ#8@SdMs`&~@gu2=~w_Y*^AEhѳ`s__ߝ;9ˇIy}8~ mN9IEKϿޠv o0.! k%ҋ;qJn8wJ#{ݲ/MW>>Ts6*I4|>kj=_0'7ZTބwb?RɅY_W39Ό4r.pygۇE9 &j-%U{D¹JEj3K@D[X廮`)Q[:sS6n8>}ȕ[vuo?5B?9=y;+*Am7h&PƾʜZmn>mcX-1R[?)`0U"3&NEԕwdTM j=W>0n$$ rP\Wh\.l[-ya<7Fz Je-je O)Ebb bxo!]V zj2D&?` ģSE'ѤFyiOTJ 2i{^ #kVN6Am;~rkߙ#t,@~-1i^䆠YlW"Ju}*볯F"^ u}$|Τ(YiΈY6%^xޞhG$.B=` v<@p$:F4nR@2HZBNz@?1H)8bMQ70!N-Hݫ?V"Q z |h'[S]ajukY'bn [3]Rpifv $,O*o=sC̠H9~V(6II5$9%7ʒJSĿJDp.NFTf@STx'~H+}BJ`X=_oWB N&ŸW@|ah1MdVe>!jfEFbJgl~lf zT}pdn7U^&>4Mhp}uD!Vܔu[(m'Wi1}|ڦ-] bQ!ڀ~UЄwz7YM+i$[VixyE`G|I|$ş-ܛ^O˥W!݃ Y,9A65L8 7}?)7 8vލb΅>;ݡꘪB>0xy%s=?:.]k iVq}/A3)kyOUodzx/EOPÓJ IhM:$2$6&-ӹ2t"7%d@D`GPd"*4Cs+"ʈ:G"h}v{͟׊L ctF8O \|8DRo°Њ9cJJZZq\.t#Ip?a#=#gnyo`OC9o[6-fN뙷l]|>ukIL?jxY.e:5ᓅ]+9pgGf>ޅA?&jfW=yn9 ‘TAP#KAͲo&uc$}onTgg6gTQكW (| &c Qo7^|]WBgPCeL/LFybU8R5Ih7L8"wҘl@HLjmلT~(5׋a D :XbO2Ȏ'$eE$R .&c $IseB`^n ﱚ%v}۞~H7.٨so]+B0R(#t֎M9$MOe_'R뛣cچ(Yg_s,H6<:zY縛zaܮk)Nty*ݾS$s-3ޘ DG9#4#$6ָ5P|; itm򎥟|\k{;%sXgx(CIEFn#坚?rF7bam+h=?p '@*՛J>SMKCfQ:խw͜[y0Ձ7gzjZ~.|)Ezٛ;t|ָ6ks&8*@AWЭw./(3MmjoSSqDŽ׮!QAy̍J>d]1ذz.TBDQʐ1?K}_+@Z&=':wAD, $k|VcuD>H<,^TfP' &Q#.)-&7xTi*(A1)$j̓g bBQ<^$DDwk$#9rV"92T~‚֖1U}n/7'}(;Vf(IFJ9@!I3.{/vh/\,a@Rx5 @ 2߷+*_(mV'lI}>咿H{i-pzekܥI.hDD%{F>кcŷˁT%/587Tᄑ_Y<.B!MߚN+_ ws}y>=B t[>}{W9;ߎܩS)?_.saCS>c#>'>6{kλ|=|`?o<|஗9UH:d~b)ƽ:3on<';jL{BeVG^vaתem$XeDZ7#7 KO:#G׾bow^N{=-޸Wvͳ|q"S!Ĉ8Oi4| _rKftuǂ."i-Hy.w-,vn[;$K˄Sx$'Ո& $KWgگd}ve~u2{p~9{Ѣ2]]߾j 7d 9~},?5PEU^U5^迈[fb{:Dׯ̈́%*JN#(ӞSZլ8<*vnH.#qyhG_x[ `޲e"QALm\B8{'P#}e!XϨխ|{~L(lpnmvc.v7|X8,:lc֥"/\Qs6VȞQZ0h?3Z d$AcwI_p|\Q\!6dw*6qT?'n;Ԫw^(PIʅ[ҁ"Y 8I mo;un̽=$W饳Lu%^U)cZ9:3n䒔95#5ߊs-H. f)υE9!s?*Mi3~]v>?os鱻2K׷9AʑWl|}lCE=yc"tR{.6yZ&cW.mo~um1y4&"-%qγ!֗jILyxge BQs133B2G|Pnl}ʺ@Oy&OPd73K)^T 5 c=;"[31#Q]J!LcJtR7?SP̭`# =Ñ~C7l""`` [8zp`JQ1Id|bz [̀ZXHhy6\v[/\)ץNI3WCB=HT@ћawf=Ī#Eg\#6  El*B O&& H*;RU$HڥdA-K:/˄H{pq_F?^{EvFdz{!QPzgĺ: 䞺Jw̨,ͫ@!_{ Yee{<9rXW_'̼_^b:м'%y'cؚP^!'vu;ZꊍWP̔H]$s6u~JX "/zV\H0#Q}?Tv`~jϗϭUdiˏQlU{"\vDV^_wݲ d*eUiػ5m=щ&W= @v-3GwǨб-8SS$֧R+5d+o5e𷆜aЪ7WmRZ%eon;aSwbz^}~>TF6^`YٹCЮ{& gmb دRiA+k_R彺{*w욝T#Y?m^DJM=XSl' [!GUVjAC,BK?M zDU @,%ِĿkņ)dnpT74O q 4,Ls R5JdqտkB^ rɿUG2*S1ЄS;ɹU{0-o(W  qD $m1rEpss8RWT|wnc'W IDAT@Dߎ̇UO8Uq@RD`7,Z=IpmQa+n\74ыEZ3O @'g9IV _*][qW9$]}̂?9}oM;fv+L;{??]#ywoo N}Mz}Pcޛ3OѺ@wt@y~8~N}뻔 `bay /M,A>|}2P{ϙ=((msy),:PVÝXq }U 48qsM ~m3,z|W!R&A&QLAm=(t&kLQ'o!uծ>:  h5T$mܡi:kCqRdm nbI6 6S=Nq׀V8˰?d| X!@[ȼȓL'r_`@kN?/1[SqQ/2TDCfGKWDFw}Ih1H@Դ@c׬h0k wѳ-!p{Q4n ޣ-9\GF K!}Z6!RE"Upo *Tė/ᦍw2^zL31A߇p]-@wyl 5札3.Ӫhf=Uo_L_iBngB?C@2B5<*ҥ7} cD>JXIbQij )<Ϣmh!GZ7>^fuAEݨ](6|z[clXvdʤŔPXq. Qo)P䤾Po=m.=m4f ]C&2(R~%x9m(C#MSIƦ֝n gJEFgddQ Ԭ2w)#x˄'lYۀO)9,&<*y"DMhkH(  Ch )hPZY4d]C%[{4p(H+_(G}<^h I"r}z| _O]ۢWd/C nhO@GVsVĚg&=-0r1S#Ip |aUV[^9OT!>~ \4 BqrTZv5C KCdsb6&2)F,2@`̞곿=`4"Wioū"dluJ3'gS!Gf ЩT{0TȌf i3LpN&^'Lo IC3F}C`U Fv&P݌?O Xq|ߞO՟AB+Qi]aY#ӆ-5 JTSf̱xžILM2 sfA8T1oQCa'r&)qN+ܡ`۝!ƖݜBlCԻ(|O7$]Hj9_?FjZ7EU%e& F_Z$Q3c-0@@gD 7 4|W#F+}(yg< a$,e&C &zpuo9ߥ` 5zS47Kj3\3Fc*$"=QFf6ZsSX7xCp v|j.7S^! *ԽdXqW}Q\_r[ ip#\ {Xu]#~޻*V{O!U@͜zMm_}!gm /SUZjd Pϡ@jslѽwMl,׵jEkuh^գ;Ws-ݵh}SbZ&3Ϛԩ)-#_sV̺U8To>QLZg|!"T8v / IhH;{(1^?gd9sQ Zc#N}L]%cq}A?%T鉅(}pK(qmcʐ?u<I0ըm/O4hv9=XH.4z_M#ZqO8(-KBRPg`qm?^w @xoFYir˳e@4[TG }(榢;٥t d9DK*ywwx"E+0."$+X f Wn"Tͤ^ CJ/vBPdnYh`lSEPHDr v 04v[u&VkM.+gm}o`{fm|!(.4{եLGb/v ;jH[iQMj H"ǒe:|ugO dbAN?!BMP4:Zu,Ms Aq ~<"[ Hx~洞ߍ{a3?}ooT5n̬O_p0ce՛=P0 d9ܴ 8ȕq*GM9Txbfg]t jĞrkk, q?7dnȮ}>ݧɟ3ruF.k.Q%h\7?[Sυ¬ ݼ}J~mgЋPі̾QyP!Otpi42BA,/Bz^BWK)s)JmОƻZĔyCP`Q JhXƑ]+C(o=IXZ ;thPʲg.RT̈i1eɷ?iK?G>mȼwXxl:O~oJd#ƥ_xś~:+򄹫8vȺ3W}]5+ /1oƣ饤 zG]rPAlywo{ˤYYtSqXxU?{ apg?noލBQmC`P7ݖ'{Oz7 S`qn~Gd` @j8g#|5ҠNSCw͊#ץi: n񣛹z$s+B%T?{K -ݧ_W+7W6gN R+(F2[ι^+e1y@ uțn+K =xѹ;^&F=Үˀ28ec_F|ȭ5[&SJcCu2?ٕ:#}gJ0nuyKfo~I(a/*%<;鵨?W/kN#ӕ! :ˮn,8SINP鑻'%.6գw甃A-&tbӅZS'Ƃ?"XO|qk֨24 t2XCy%1T|f' P7$F X97p4LBM>R}(=Ͳn$ xSfm$xUkC~)̭񰀌%` TEU274fӰ |_aRT i%,UG'QaA?nVw -k5d֑\Yu'x؞^s,E˕|2RnFNʸhv뛁%;O I>]]n.۵}~`ԓ&(z5ϛW-?pl*`Yf~st'5ꛝ{z, @@{?f+C]~л Ѡ^vE:a@)+Y1aPZo9#.ʡ8 UC N,箞8z6J/2 FxjǿhJ#G/ed ;)4fS2T]aގKy v/_C03 FII¬u@(:/(Ү1S,}rÀN k%˂ 7)E-֢]߫5O|DntgyYcboaaV')ڒVkI5﹊}nHA"4~l9u \R{u_١;/˼>׍|K♼r;6i[p9wEn5:<[ü  l5W2q >E`$@z:hWB 8:іځt[Ud.tCŤV댾 OA\aɷzmż lsΥbu{TǮkFrD޶zlۨrFNOh߉7g=f_ fſJjhZu](̠D= ->Z:ّ/FMkhLP3bSn'jDʹY}cJe1ȐwqΨ7E"(.A-ُ|e޺pkkn/w"eLz%=FXr1nbW|ɀ΋ߑaf4P$&w"eE BA <)ѦQݰBD-Rv ss2bNAESI,3nK*8(-QJA*RQ}m~PÒTagkOѢ,X|G[b߼x4.[4gOf+xi!N(6"+BڎUW ),D aOr$Hq9e JQ@X)s*J[%@fQnҜ~m( 'KS/'iE*( sAgz+4y24z\Ͱv`W<}y79d '0dJuEw}4Q,X蠮uP&䊶YS:n c~qnAC売ISzL$=4փ[( ^'YA}pt\r$ Tw3XE;}`3+e.*TA,H;QAJ9{D:F\;"-Ee3 n>>nzDs {_1Ïui$ /zK ys$ xZ ͨ7ƷRX?(XC!5&I] ]' Bv7R}o?ò0Ă'OU3 ֮ȺAg y""Gwfgڤm~X!m'QBHpӓR^tc 2-80.ZPY`yZ 'YE(U*u]WT\@'t=\HIHhUh캊 W$9{iaɳE!38{.nQH6s~関M.L: P'+n4o*mW%7v w;e_L7;Zͽ[X IDATO?9^{5'k({HWxl7hX¼mkt9i[~+ohvEe+R!ߛ;]cvN.w̼.+&lZկ[f+F:uWr'^5֫G8I|B\\B||Be=oQH "*&,n˟7iBһu< <^ =WmmnQIv}^. Xr^nGQ!ԪEZ@R^po7jV{mW=m*xi'8B')J[k5 -`Q&ڬvxPpݶ[s"AːmGv2ZjW1-Iܶ 5+W[5XFx1kT:Ts> _{!X\a$Uj%W6-m=Q׉Ѹ]Is6>Qegw,k8 VmmGM'w.$@<~5w緿\j_aߌerۑ']Ȱ(n>֟t*u-@>&z:8=˃̋,uβwԘz$y-*ACvE FHne^y sUp-w1em:xWU6ea9!2hj`V<(dbEy'E2zQwǥՌ!, !YFIXHh րԥ;|#(sP@La)s|Ql*e`Y)1JPg=<.#D%m wk>5{?0^u;IYk% ܱ,%?^~? &B#!:Txԥ)s^DK))NyW%]YڭN 2w 2wM-,27?cq%e.:5N]Iu_  '/i̵7"{Va|S3%mlf?%< ~3L0x(J{JA aY*=N6 d?Z\yl@;ƚ+Z7ox [:cu|)"r}C[os9S쎹;ۨ{0SٶzXU|ݘGWM~3z kmRXѶK-LQ="Iᴒ)~po,ώ>1 2zvۋ?]<}{k6O-|#~xp{723c޲Tnϱ UoXܳ "eXʯX+ łyic<;'y n+9(-Ѯ!`-֜ LZ?CDPbz{"pcyt 7,GA) 'X#Z%ć- 5lYZ8z%lC*$$]p9@dB"'[)s{~p&1ڳ["XF9D7AGCOϫc D*F>jd_hh>iۼ:L`;~5YM0Ddع]W視{ԮeHA jTBw ~$D+ŕ <-&P0v2L)OCQ"x&ĕy.POB(+BP"yKJd8E%&ᙪ#P+H#6Р{JGvxk|d/ 2 #\H+kmb4a LcL۾d\F.I+Kȵ x=SӦ2uw*TDmh ";:n>ƴKȕXp]DT6; Te?VԫV8*<\4D́L3\ <@ABe) 8Oir7J^K:Ҝy2U(xFU\p) l22'j;(n<5הSP)tkO/m_fZԭmNP u3UAK36Jo@@ hv#Tp%?r'pXK4UV) 蒈p;#ޑTՍOE+n*5jA>϶m"D'w8T{?ЦD\Ԉ!6 $gSSՀI@e3aBSà#UA( bswT*xAEek+ e\BQ%dOB wp,BMH1;DkNi>"4;̓ wQ ",$g{ƯDs"qBD{]Q29E|z& Rq$2a'^_g 41:WtꄊGs4c\uW/5C#)M!R+t/Gsך#tp4cŧÙ[aɎKg`<Yy> HUj#}sc W=9z*R=kwr?БZC`=՝JO{3';3f Pp`S"2!nnȩu xnƗ?wK׷Lma\rI}QqiDYM*]He-Yum$ J:2a dj.tcº|Ԣ:XxԞy{fޫ7~6C  NȝTGWf%;,5Q4==l*#\9X-hQxw-"ؾ6#KA# ]UٵG@9#! AmQ6e{+Dq9k蔹nmuWxy42J;uǬb~ "ޣ7{VLb<}ۉn eׁgәsRජUUA{E#Ei5tʼv7wkR JSn]5oɑRԇuwAֽKg~& B`)+A6 )sy,\;_i <8thgՕyXȵHͨ^0?r Scs~җ6(sUW!"2t_%e9q7N_E,/yָH$ k|2í?fMo 67cui?*/&%,C}MV c3A6FedjY%1'%SM^䩣&=v麜 +K foYy0i\R¾{ QDqJYgi;5%:!*.22J%Kf:}D[/CYY]GzS&]AyI ’UD:(|˼=t%<u}q虳~/}};gͤm'}͒ʉˋLVTX,YV9bԃV=[H$W^ӽ9( EZg;QDTE ^8uG7h7bN,W\6v]?|7ǂ727ͤ-5LRMCͥA˯eF'6KP%&\`#L%͈#)zIRQGQ7g^143l]v)U?>pKFpmgu3= J" q":Փ!iGIt#*-y ƗvcOWDž*pkZ!+<[fA`' x >; dxd<}e.85Bt=gg]v0Qa[5Ot㝨?p6m豽oWqnZ۲)l}cc=WOB&~w^nql|7LбA%]Q=?^v6Ռ`{uO㏬3wBnyuC}7G[cnXݮۅVlllܼ9K o@!'zTsglP{x#_9d'fBuߞ>}l$?ڹw+c*\dw2 =jQ{}'e=Qoұvѿk{Ndm/c#^ ,Ih0÷Ҥ䣗A4(0j<̿<; >}VmMyD]{էiV,_y-:cZom3hN M ?y9r R+/{ӛ %DkmP=`YRyA69"g܂k܃gk$@?pCDж;-zwGN3/>S/:f׽] J~kB9XtʞU=Bc!fY=nō ۃFJKx.T~yiC[XnKPgvO;o]S{=BA[޳s.=-TDzKԨb'ii㸩IEpx#ȸ+=EuY-*u0-1~dS")sFfA~?:Uoƹ5K|Z'ZnxQ a~H AO!- FFNU{EM>{쳁VtgR<`W4<ekAMj։'@co˺q7ӢZA2W,8ބ!%ƿl̕i.rww?tY5jti||$Tfdy%&05 o|3okV+eWF5x Qc)?Lkz#Vi:yɔ&>霠AP6*aBA|j4 .ZHq~~Pھ4t9/34li aTG֭J,_]Yɷkʡ_e#1b_ۖwɿ3/Ϣ2K97vX)^A#{}ͽ*/@d_IGDm 7B&iqD~ _K:Mć~bNg[&}ߤ_-|r%ޣz`w+7mHP&8DWݣ{HiT]@:K e|we"ܱq_$Ӕ -ݬojK Fxi-3ȕwNY2v_LШɥ2fQ& +O.@ ])[B<&)-kLj^I sϨXE uSV-Kcq i"|}8V0WW/8{b}wev^~.e# nA7\~}bh)B1%X' u(ٰ)w4}zG'<z5׭﹕tў6Fq0\l+S=8yCf#=I߹h夂g7N^[bѳk*]Ш^{ӻ~Zz>M-V52Y fUocevXz;fOQ`&ݟW+O\~ؿmA`I‹]4̌3`U}Ve~$`wTL(ZⲎ|M;Eʾye K?3#&70I1ts {el[5D *e]& \? Lm}a[f/yɳۇvdUKfVnM#ޙŀ0Dȹ8OE:,UY5#q7}F1HU)>.KHmCߪ e~X2&_1 {yJJ߶> W2+74w>b@;"[d_}gA9bJ#\-މ3ƾ+9eM'G&Odߕ ԲNT+fzP.~Sς\^NӹPr 3173sV7mе~1=iP,]Tz܄Ԧƣ- 6 ߿ŝM7X|Jyt]Utd K֡kycƬ)r2SS.Kk9mڼ1cW=.,K<l C:fvGxeݎ/% 3[V*4 N:}v܇z?frR=>w{@Fz7ʐ%Of[PQ%/TCWVp"h*LI쁔>2Z-ۼ666j&"t.tPyJhd(i l/"2a K`xukݗsTeZ{ D3ٶs^Yi;N;r~r4!}H(GHϐ'fD?,] I[\mZr6+/hahv߰on-秗F.ϒ4l![`*$³r,Nn យw ED,IxoQ|Ò-Iu&)drIT(QyEzX A-2Bbbٌ75 O@I45; 8 6 ߔL%^aPcJ28B?}ޏf?dW mveg((S`OOGbI7n!E+d{j@(LQ By)%6=:ssM8j{V\[XtdAxJ '/Den#ѢXzGzW{c.ݼ;zm=銂/2XUa+rbI*/FA dB@,rm/0$tXZGǂ 9y7*jPgV DLh޵/ 1i9|ȿ!^`IzHm9{ײ<\罭|^IQZKe;UmZ)x5Wp}bIz.\IQ79Q3$fcc-\N~nKwl[7ݴRұ2 vJܖ*fwY96jVCt*3]|"Wċzj_JZ)smMϻWU{}h ~m}g G9WmPqb+o A9X)|+WKQ웕G IDAT}n4Û Rf*Dj^'|I "wh5-ck?*LӴynD 14^uV<ѦT-acc̶攋hU_TJZ?HgħJJ4q{"3K逈#fzA4c햡5y;e#I/{A,IOГ]@rå%Rh2zzp E~na\.9d&!Û;o1moƁ|BpkE&,>Vl- _[T,!O|>tF"rIBk*%,-?$wA''+j!^t*)F96/U~*3bv&).b끺/{%e]=\J2fpO~yN<|uHnĤ JШ.*::$ڭyu!؊\2"!|.:63!6\9v G#$n!|pfljGַ\yX+Y-վ|gܼj׈+<*Dʏ'|*6>G<)Iܻ;䕋y e_n#9]sb`!^z}ԑf ;'!Eww,eO7^f>nn:1Vq2Ʉre:%NsLOyCGNzcIK ê<ݴqQhh]󎜸(9ϳN }#ҷ^IH;jJ%y u缌FmmypRfJJ"MmhJA]T^^!UU.-/$/]o|c w[{]8b,SRFw M~o~oCB*։ΣڨEq啽x++4DHUT(9Clf1=ſ}Hq߱Z;v;7Kxz'xKl~%OD ׭OHH0džk;_M+ۯL|x _̬ed#B<ʡ~Mp1e>,+-&rP9l^KKnq)wFtYI0Nݹ\}pbfS&<jL)4\Y b*3xܬk!Ǹm>JɥoH 8Aÿ-@yݿ[x< O6N"hOȹO'ACj;H7#ad]׶ ᮵=Wfk$9)M{BD/ ume)se lnq(-oΝS r^ں Svɒu/͛1g Sw'y""\4eь [:yat>:qh0Ѝk}Oߧ z c;б_ ٕݳ'}PHO*blӷ/R˹w=E+UGvJaRWCw:S^ѫū-LY-,7SnxkG^2cJjr>dYh1(.|ۧI+"=53϶ ;k]j~PE}iɧgٱ7o0@IҥgMe&<ҽRBG$~~x恥{ Aޘ"U0GKƩٳtNH3׳֢)Ϙ %Ig'Qi-TQq -%:j,:T1*ի$R+J׎GRG#4YANBTPb*a  <F翸2&MYk 7I}@eP/J̛,5>޲ox.9J] ຝ|8s.'E1j6L$%Wz :s(߹pʈDvyC -q#*59L Ī.P)ʹ )T^ylZxڈPqfSTt ..A\͖tD #@M_ #eD@E ¿ Eu މQ'*rWZ ˓ J$(dvjjЭc{SMF0Yr/5bSNdAs-ScSXM4aJfU4Ɯ@ +q9:ᐤ`UԸ FT *90$<:&81 "VD?e9/hІv1lqY6aMlHb#N3.@9HuP!BW5jh8DWG"1QQQOJGd63PD+·xGQNN,l=<=Н&_ŬsDW63fgL;BW{LmZE7N$;!6]$-&D_V߈lھGTȻ U#IvGȢTRE( l? eh܊TvWra]ߡ;fXuK&.]: !:`g*UjW}p/ϛl WTOW-"&vTtGq׹"h8OE"5%u][< wՙ;Td*8J 6f8P^:>YTݹ&7Ux=uv8\1MvL_8o]i|-NP`+R|[W\"#NGr^(Q# /cOLh"9ERQ_+_HKK*vo~6&c_[k9rk$gpu.׮2_(mz',_'T'O iuP&B&pxXUM)E%TgǯJ5F VxݥouPXaXvU/ȁ%qCiMapt,!9ryVA12dEt`U O l*zYyH8d/^.G㹴eQɉA^+?թ/ DG  aUnu%T/݀ivw%DaBq 嫠՘ 3ug'X!3?DaK(ژ}^b]; ߢD"Ly)bg@2+EPdQٲ/:zY:Ǎ{ށ]`d^Ŭg\=X*0pNReIV(8ᔗ]ҕ Y7yqK|8A+\*XUxH}pQCHyto!T@cҿZ:,wS0 ~: ?wpޝ/)Wj$/ݟO)MFtBg cy۠.KD MזR[rϱso8@^4Ut ʻ QWۢmWTjW 7wU7DGoPK&%Iۥwj<ܦ^6C=b/cNWSԪ|kYF sPV銠f}<4en5y.b7"%yWοFJ5lԸ!qцa2>n9Gol8Hw?Ѭ1-;gI5 rn|?nfC3fZ˟9;Y)p u|>N۷sw+ݢ}D59> Q;T]jR];ͯLgm.5cs ݷQ*w&A@RY:Fv l]2Fk3pd<$n!]5Ԑk;zPF^ϧOL}9k#[7\wnܥߧ~sk&yچJ {}hu.rֺuϸU:uӀnom[<iڊ#݃GfFkp٨]~C)$ &y&ODB3u{CbDF$e=ݪΒ2?ͨ{%|ߨʦ2z6*YM';|_kBRYm: 5䬴ytZr9\hӪLhun|mZOAx+,UZd)@;_<6f5+A^vZ EWD W}z3΅Y)sK*P} *pDv`AQ(: &bz7)&}CKCo˺~7ì̝ FoyvoWLHN]:#N)˦5!Ļ%Y9r@a?i:e٧|XVo3ʯNK-۾8H21$&4ࢡ%1 .4Yu&,UeqAk{6F۠e.r7ͱ.mrX{Qņu=|ԩC_o)Z*G6߾f:3'}?sډ' 8coa:KJ+݃:4z`PG,D#;jcb)J& Ĉ Pf47*MŎ̓<[@ÅcVB7R'a{}iHE*uj)#Q{9Z*}x,_§Q?׬&-~i#=[Y/̿w*5}DyOTO&cJqO4t=<\ P!TE^R SG|[MP3d)'ӽ8a wIh+ Tjѣ2[A;JzFQRYW+8\$ҭ! '\M;>ok7(cbc (- |4a3 NfBty->6wmr[|+q"JQp$3/us{n牐|Iγ6Ytz|<$/_ҥ>M]?W W3b/y([πBT]By2kac3e-01J;,[=Maʌ-@'waWW|.]9}瓊RĒhWI6) XͭDR_ynh&%^N2(>B%4Xo{lEVR_y!ڮ#Y<|DzVJ8}`bɩ cJdp`BmN  fo*:v._T Xa~Ig :*AgSU#tv@f׆_;m0Y1ezYp*ȬQS塚A%fI,,yt5wTvӔc~VͰk~bGכ@mCS@[{uJ1FckżhiA/@YfX7f@ 驳d|`_o6mGcԸ`:~9mڼ1cVŔB,oXp ʺ_dMުp!GxH{qPplj 1@`eP֮D[T4eBIT-Szݲ2w'#_ܻ,+4ONe*`y)MwܪrӇ^L)N'J]/ODí 3TϏMdf+bDQ+;(j힓Wa Q Ijψn̤2WN!QMf >d5e[_8(|) ˷"" +|FuQ2"Qz DśQAbRi@(+էU^`yrBh?nQڎ[lłD ȩw m:]䌿TȔu[Ю?nUB8+e!6|' 6 4Y>嶤^7. IDAT~$Y$ !Πta>nُ.}g|~FUZf nwQFO_~TCMmu7C!qŹ(%Jam3_{,59oh˓Le V*N?cjnjI(Tܮ\}0jF\ 0]I9S^Jd)MY3è' Ttia9)]Ed)&q5u eܘfCɠFVK`d3 gӹ6+XE(*b^-Q )se&$Gu6.2~z*| Q Q݉WHziq9qVjܡזxDX}ˈi݌M-zuTiQ[.|P R wEww/]ķl-T]'((jM B_8^n1Q5 >4s%P3ĊGvxIb_gБhRJ u;zgy^;LJE6p'ΖS.dXJq⭜W_K{Wl1hlܳgn'wi{:њ)t}QקGԠrΞ^1tj}WƏ}s;|ԡRY8H@ۑ̧^ȰP1!tcBf+'"r?Qa5_ _L<^X="EZB 4 `/R=a݃2 ^_ǰi[G*eo^dy Q ǖ~:LYHK]?i[G*eCX^Nܱ3~K(䦴GG?XнmԲ}[1BC{ mm,\U׷3{֙(mY N1x s+^#yԞMr68k31/}2|..{'ɳYC9:m{P)3nڶ%̧RD摌B`除Փ_ѷ_9eFƉ3Ct1֭ 1p%eB҇DI8] 4(x#U&< ~ 4)k9Ъϭ]&򀼜RA s%FDr9$P4W{':@U.^\WAEѮN&ܺ!rvxOUSpa_ -&_Nl Bx CGl_{yDp]EB_4m^L<+jd]\0;&Og*)>(G<+XFXPG = jƌRQpUg:jO5.g`E3oɼ'jKMl^Qk!ZN:˰&F /U+*E}"kE$hH|r ? py"؆LkD6Rb>b$ W$.ˠLFE1mے'r,a 6/A\&f{{m_DEӌDG̀C(6o_D82YZX|gǝ$]8CT2:UD COHȴW+"\:05{#J[cDH@\ h 6"p)1pa){n %SQmI|bT{HF eku y^ѹ& /%3 ?Pi 7L\ݥRm,BB\w.z,Z-\DUoThpRm7E )'+ҿU%&KJQIlk>o?(/ڶ[?EYit^ֿU/5$'z"͉C'k{sd7W]P)MQ-? "T`!끮?-EKM/{SND,zJ9(EG6%.\tjG1BLj9Mmt&7T7.> s`⊒9։[svT&lQb2E {VBm)#Gi6͍rBUFn ;9Bq)]I&#CT|;ُRMqb)w,-rc}lS!sVpwX FQMC08Cѯ[.pLޑ<&AVJM ݮk3 QzAT['+ Ī0 =( Eј^oB(+9kх; kTdxQDrQhRj@y((ؘIMH{LOHԥV^Ι*<ӁR,fȚ;s|b*nmUƮA(T "@dfPE-(("w  cl1QEz"(P͸"lf|!+-d Vӹ"*&?<7/\=U+F\FDcVz}>on._q{WM/qC^W:y|_%zo+!N\+J@ ^-KK@pҢӭG}W]~/rRY+~| wpS(2p8 VeS[EU0KCJQR֥TeSGyŰX3OK;:ѭM 9ЦDI٦Ȧ?I֟'S<4! #-BBw.A .N,VД74_pڦA\.¤qy}7.QLn)5މ'ឣ:s;[JԽ .|+/].i E>{Hq%fZe.E c.)*ԅ:]t>a%_3ﵘo?^Y èwƈJlNgb5lŇ{#:oV@T4^aD>읖#]\9{.%_q?nxVOZm[OŤŝGXaAu++?bDߺr2`wƿt F|j៭s3;&+??N_:þҹӿjlt 9,qV{%@PXP[۹@]b& Tqw{2X\l?mHֻG-T{RԬS} WݫXGS_ۑ݄#-;T>W90; ճ8vml#;tje`N mGt9k 篞8QG{GUlKi@ $ޤJ7J/P)H $@@H(! ofΙ%yL6gΙrÁU{tTœ>jzt^{9*}+ qR&掛08 VvB+ZNB/:]aޑ&=g/ѫB*}khڃ O6 P1~%1ao|Ug&KEE2v  &O4jJ䪇ȍPy7߸{WL[z wO!FV~u56nϧuv3:6Fy^QS4xʍK NPkFGܸxr˴z7՟UpW V[*u t#*~Z up= _|R"sUVphrcר7Y\m+@5 V+?'ScS>X vs!!5>:W媵̥˲SKr)d!*Ln aAR>VԄ(K2ƋYy >ZT.IIY35S٨!oVۨx30o²Zvt䕓{LQ8_l!LB)^fܳåowi?zU~ϦQQԼV?m=5<2hh}` XFov8烖-C&c݉Ϲy"R,G8#Һ`sua]I-e3?ϷVjܪQ $VS.ϤWY,FT!ߣh)Ԡ[vS {4}F͌nkNz%wE1`ъ4Dm/xXQ. jw\1RӫL Z!_LwN,;R"߾? [o|bqc= {{m֎ܯ;9B@'Ts61<\/߃ȩ>f=;؝$T=#3K$v$UZdEFFATLKaryȗC9x!r"<638LqFˎ?;(PG$_x|UqpD_zZˠuE&qh`IBqVi`u;,|+jW7>y5z;/̳ƧJEϐ>_5u”5a|OU;'tUwӟޏ;qۋv8^±Gt܋]O?W3ag7}`[.l9UzЫJK)3CxɅs$6tM!wi;K{יMYQR׮ m|80/d 'R.l^ Ix{="5jݏ܏f:q\ɐvoJm{8Pk3MF tW[8|"{W/=yHhn`ɼZd16ɀ:]*+[0. `5#zOm>)LY4{ș~ZX21Xťz͂-j4FaJSgVMpW80ۄ,#I07_Mѱ7coFny B,{pDJ{]6ݡBs 2}i̋2uѱ!yJiH񣹢iTCDw-H>Nʸf%OnWnR8p˹Q1QWo({p"I| hV|R1€4}K'O[)=4X!X  Hpkk6wk1RY]f2H[PSH\J+A $q[b *(&( Y_r%ֽ|0Ў;M97MZަqݫU[ֲ>ɃU|eVfǯDN^sѽ'JKAXRSVVu!5#ѐJ$ \.A: $%+±ɨH¯IчrrɡU]~;.ۉ$IZI2S,7фjHnɍc{h۩]N=>^7#Ͱ [J,vu#ZeyKqoo׹}N=ޞt<$v& ћԅhwĿŶNj6\hϧn'z׭gݢB{4@]nh6P,VԐ^;b43߉HGqmv1ѽxow:`Ymv,H!T/)6wpp|\.)Hq_E7bJU IDATd% Gʹ)K+mŽ2i -} 2yjRKr;{ڼo5e34οDCBة|P/? B\X@jhxK-`s[6.1iyU<!0pl6<|<4(Nr ͢Z J7KNC[1Ce{VCZ;H ꂛqV ؉f"t #~3qPaEl h*c}pF<1s~ ǥi`3 j*0ycrU4zo=X%_nWxCF=:"J"5avc62 ˇUWҨ d$eYU1h[>ũώ@/ȋ2 mTP˨M%,̲_QpIƣ))e`$Ɣˇ~?5U5~-vkɄI,G)))E^Ɔc8Z ;MwhQ2-f` {%y73󔹇r Qfo(j5a#h\(s'u)Qo)s0R&ǑX@\~Ccѳy#{Fw}}>q3޹h"wFg{ӬPtHƈw?l~v1Z6'uƼ%R [mw> E:#]vrox}u5;H*!R`Iu7L!ZMB8:2;E}c'hۑ$]O}Sgc=-s1V8HvvH2W a(~t37s:39$LզֱOebck4"vvGS]xE SSzdgFDfcFy@fMvm?3rX(ou^+)jSAY?aU`;b(.ms 2?^0YI`!iX??UGϵuN{?e퍙1{b߾8];=| q()FcH)^e_xX~#⼘13LuF-K6-\b6zU8pÍR(M:~ʹnt-ӄb>޶3#)gF|w |K_Rێ,g@PzfAg}n*{n3nw n~YAs]?ԹK_sX2Z. e* Вm(s,5)]L{V!I~2Ԣ\5fR**SFq`Ea@E[}qSO2wMOo(s/Q)s [k,20%m;>Ԛ35X [dh{~ҩUox`YI"9Y=ty;;is5N"(źRވ,q@dh5XSRm3-2塙n# O (~zzB6p|g{,wowrIK M37/SIsm{sBg{(6:|b2wV@nkI;xx9g_6m|[`݀[hT$6rY-\q`m4wm20 #rN49ѳ!1d n$,qL^+bKl !1o![/Ξ{fm]&(5yޛ'#;f) _ί/UŭߛQNjLs[Dy[zxG_tzRcQ6`\g{(falN޾-;{V+5w{gw/]|T$ RkN޶rg/0W2 \q|-|p8):WuCe U%Ui#GH,|P@ܒNY׭Q&?v;2|VPsWl7cW,&[p0:1gwYGj쪟qOxrecGPdIACZwG%W_KpīRIW۳'j hŠBU@u #FyPR#'X80-gYYsI',e6H 2w%E䋠0uI6 hORd@HBƊ'Q #W0Kr" ۑ\1,NRa+R9nDlG|Zu}O45_JtyB,Y=\Y6!rE U e: GTUj ]RÕ^ ܐD+n&jŠIK@c )DZ  uES9Eve)1}~ݍ8e&A bP{cuˇ9+r%^BB"?1ǂZF)3jzIA/[YpsG"W;Rh&FH[%T/ŶAE02PEX=בrw)uKOY`S +rv*Ϭ!pcOrğղRs܎Z0ӵU! ۖRGv%ȁtQj#*n/)%iu[qh7M_b=J2pV+r`5(pxpvavځs>)No?[t,QCwEPYE"/IuUXz 9ù_;e탈I.CN,?9s%qQƂd"A$k^F!/h6y_qr*Q.^},J_BS@ gm)pTx2b rڐ/2nb}wWG֓"PoICm麛++Ĭ}7jgZ |@&w+R o4vE*9Pbwd> Ee?~um_9@0kwr 0vI*;|f-R&䓚C)gC髽e43-)uS~xzB4K-n>mJi݀a2& QWcSc䲔F&,淰@IR@_}eoY Tƫ'0!H_W}o ~g.?j ѾkDjS+SCșcoF|]֦cH&-%n>P&ujS,,v.GQ|aˬg/aV8Pjq-͏㘒-WW2?}ra~d%C\tP7\X:J ߫`f"1Pf;LI q="\ݵj%~nQΞ蟸UG[Zt?K^KX7OmU،]~y%數]rx+7FUtw˶}#:_{V kZ~;x2ft;Wv/Yڳ^qbPT6z3?s:wa|݈V0) ;-30V֎o^ʮEeãJ-z>I=c՗$%bwjNQj+uлO1y7Qn\8}`ŤOn݅3K{D\ԵFVG{UHg3/mj7!姫Qb@(O=ztYuyܾUt[KݿRw/Z:_$6^|F.Z %6C0 ƟNyv9/ga o+ >h|w/ѻm}گEBE >^_V%@'ĚלqѢk{E%@S4~л4Qu,ƓqQ1WQt}>sxFT̍8.ʭME{~Z x#HZ; m{" 2^~1Z|d^A!'?i /'bbydUopR̅>7˿Oj>Ǎ m;/?~o/G^(v1Gw,fľHn+.E܈w; .vzԵ,/_NF^~l5/P鑣[TA^U+p R lqb!5^h0724~YVj)bf\fW 4rI"1;n(V}u%.X{[w`J)hXEK_[}o6kb7>Pi;GB]So 8=gЉwGmsƬ|_9LF+D[E{1& Ϯ- jVOTz8&A|+ӿTҀ7ϱ>_+9w,Fyз%ٛ)Iu`@Sv2)`QޔXUw3oyj.OU-moܳiʒ_o'Rp8J۶ewO,_~E{TU<=gOF 㿯XEs? H,&ڥR$M#P\x@9㸄)(sn.C1`**PZd/xTnpӪ[6mU߮CN'VN6`Lߞ#AOGg? *.`-?^&\sO^ε5z|~hBHfԸ>U^tvR)  )*Y{ĨfOb;vٝPdhk>X~>|vrӻgn٢MA ekPo~~Rh)Iq.6^-go;֜+xC{W9|ɓ[|}w\B* yTƽן:'Ph$*w:ă׬ dۅ3\NՌy\bz#Fd4(34<;O}OeX撧brDcϦu?JLMf:)8&0E_M{h8X']IQV#qhpFAL7~Mk`MrޭG`Ok^-Pp:ȜK3$lUs\ăo'U4*ulcGi[6׆s7ξtVyًv$ =>Qp15?v;%=z4oNJdhwG|!|Drn<)r|xLTVOdy㋒-&2W50s7+ɪ*սAMe҃27E1u}$_:H#-3lY\ Ǝh_u aWrvvҬ%/Y"F=-_,Y%aY08F|4~½rq$fjkUh}\x+7[Ch߻"}>^&T (KD~rAuVtcPMr⬌g,e}T"j:~_qv4'П|!K%#I 2w5_ϙ$2kA1^Ѕ+c 3bCx ʒjwuB,_H8ρ#zp" -[!qVpMB/n1k杧%X::e!QQb~=4@ο0~j\8`YZy-=HE[ORfvj.2+H'L$o/Ș3+zxj ҇ a55"rt+K2A^d)g7=mzUk~nb\ʺ|3p+>5+ɲAdD4F~Uڠ:kNmDao6h ){nY|Q ,YFɯ6)KU6oB'q'e kp"F@ӇS_J j;i֋,v05 1yd%۫4 !9^IY@> 4%5CBa學( j7Vb(t9ƥ !xC Vil2c ZSRn([p5AQ@0Eض ;pa7zl5A"^Bj횄O$)DfO+h}R ƷcOCɘò8;@/G)G6)Yb3@Q"U_-Ym[{25Y! /7ę`1IED>^ GVRZxT#^EWE"2b+AɁ=/=ȷ԰1F=1&7ɧvKr" e\"QWVcP-@,$TR|ex'BqVj:RJ0 ןgZ 9(r9X#c*~`쳿u]`yd/x܂Mُʣ?סv#?X#I&=B&uo^A x z}Zl+tU&eR0icMO|޻y*;v}O;ϖ>ͦaMM+}r=3+{h)MU; 3p*Ns޵7>ԵNٓigJ[L:YXX~|t"סI"Dc2ʣgPRF_C_ˢަqz?wxXftL&Ih:Eqܠ׻1"]`QC43;5zAUv7^ch:u,܍ҿєuj?Y|mg~ShxuGի nshg Wk(&7M>cÆ}f~)=ȽpGkF٭:YWr#*"5tvWnES16PZu|ѯE* ^'/!SukMQ'Vq3z_?- Jn |`djjwo75?pI/Z/<+F\~s/Z΁_=Oylڡe!:L435{t4x5y?[>uz yGLd#|fsj9+{:(_W(j,33X"27Ԣl@lwFDЃJ*k,`}~/_'PqQ|_g \ * +G[?xkn)f0'BS# |9ejd~t{?vj h 9~?~'Op57W̟~Prjԯ u4?صp[+vŚ;=,?rS{'Wwovd9pmN뵵1.|snEɧVO:EN" `)1.tT^5S~[)m?zoGf'^w42PcS@O(s(A*K Y3N`;q볨q'lMrl}s|g{(@̉wbg S|eV\ bsJK4~HX^{M6?æex~Us/c8rNgOQbU.$}7~~~1rW&ddPOI! QJxa,i{Q󏰡GϿK{ӫ7u[xYhn/3,{|VGDpԸ'%j\3 <|xh8Σss| #]sYzuϖێ!.:fS%wljntż9mE)|B@ dm;O|E[R ,rA!҂ +/pHUespmUn pFYN%]^t@yژ[kޭ <Ɔ("i(ǟ*Hfu@rok|?}2W!F/n-d$cÓ:S?FSVȓu{T z;s-Nh"'w|^$%,fzcWS+m'UW[e~XMUn1D݇%4$S@w1j8r))& Hq7,@ hĀ\˜ hTrBTcen#Dxrپ()1ZxLuxٛZݸ_Jw#Y{E sCBO|! 2D;H!z\=2cjJ[Qe nG]KWAN'30nRKL`#PcUwUv$2L|_e,5zE?]˶ (Д|>ЋNΡe~E!.%0MBj~5H! UΕYe>.$UPRU"e%/}a8e?}\I0 &)tU1l @VcX` 6;=SʭUvE-"U v nVCؽ  ȉ;ϥܗqfIՈ 6/WXGNfI: v ®+eB!@ڒÃ}rh$ns# d̒ Y {.A-b#bn?:Tl$4UP>zL1Q $'{6PV[yQ]2Ն }qP-0A0Rs*҆Q]HnhE[TWH@r* !kVm 0 rdyKSm!cbc4䈬 P!dǥC-ٕkd ɈH)$/M-$I D0OtߵB#OEmRWT⥐7J< gQ37[^-)sWTb*OQlA%k*PIEKuoJn ~IOfڴWn#;wɘ0&3O^UxFErY-Mp5s1IڕXSgI: R gmqI;sI&:Kh)Tx흾S^%wá_o?u=ZԬHg_|귏Ug߫ˏW#G<”@uiB6Z70"k8zv.m0WoP 5&41O~֛; |Dɠ(!/_YA.1d/qv=3bt%+{# \uDoU "Cȡ@%lƠWSDPؔf)ʃkMe"$aS1B,צHUB8ܥS{xEmΝ# #ߖ4/Z"v5!o?@9ڵ~}1'nLaa]4[T.I0X25G'\oԤu os=Ny@__+wS}3[a"fmU(}NQnJK4rϦ)KBQ7 &+H.`ڎ^mۘhu]͓Ԟ^WM*y|31!. B rf'g Js鹘1 Fq%a% "0_N*V;e2)%dzL|b<c5}#Z%4̥Ԉ;W]`[P[H4+2KE!MYzL_jdy)j,%ibsC{+h1Cj\wd?" _(* { VJHIvuLഭNo]½4X+%9͇RUVIf=Q/jDj*Hj??qdn$koRtIs&wc0 ac}ۍԲ01f֐Cd#⼪ &Zܕ@7뵮l@HԢod:(G43oۀ&Fڶ>Y*VSw#6"UD3!S8VZdJ%]GBb73}H]#?=*߀bC7up Au=*Jg,?鏊C @3 @.Jh2r]I3sJ)&M0-0(/bJJ쳴ds^;lPt8Ip6= ٛSPqHiwJѾc%·eqC9gx{5W)J7$`o4B05]_Z{Nc,&P.}*{լd@^4h],qYU-y7S7?me:?E |ܭ%aGg36jgZaEJB5!ΘבQӃ#RN1.~9kiBm;dH g/[ IDATll3yK}Uaaclˤi@޶^Ojw>m|.HԸ>#gޟ<2FeoA3Mkz~e65?ȠX調2 bΜi}}M @tޭ? LײL&6RYU3$Pt4 @0nح u`Pg(0gy`y_*$7 ʢ߈*Sӂ/3 @z^NFg> NKS: Aɮ?dq@@|3l 0}⨁y.4-*@Y6u,VWFlԃ7nzhuTSN:+)qEa31>tRj2bpy[=rϟVѳ - l6،?Y'4dP fëֽJ\pʳ XQ"!VyM%3+\#(R!T+PPe"mQ"S*ZTzS2!a ,|\PtAE%w"K@E f949]k~ ;d'Ub $2W_faVױF?%ԓcDTiibDG2;\xqE$33 DM,̱8ޘFktiC,6{Q:*%ɼa`c/ GsTýȱ'r!D8W3r+-NQԝ0x%@x!Ü+wHnzQ`D!٫ Y[#D };>7#74# *~QnF\nLPus*rg09C@-&##]/H*dGΒ=ܡ3Y- ”! G ` UIQ䐄@T=AW]X^ϴ#ukqeʙU}8p5^0!ACrȼY̺KOv 1.|+{i]|A<`CE"ɩ#HDM#]]}PLG·/GBt0QQ/@',KBƬf4gZR"ʜ8d%LX0)uy@gjrPuqzb/bCJ OKJl$u0^\eVfs˳9G?f"O&Ky_`X0 G,tQQ{5C^ڀ Yeh:ĵ]}#pE)H@@!1kzcV$i$DXH_r".*&oʇDq;W3ه4]AMH`Ff6vҷ,Ѿ~WMa<]R@_}ؚ/Qcf.?%KRZmґmڗv!Nz2SS@sK!2(j 9;_LZ>L!HCJhP F1Di&S!_F+( U=XDߎw])5BF*U싩@ڮD4ٓN= PPr K_n 3mq<WSG.v(B ˯)*Ɵ(s,Gt&>(zť5_s_S]g0 =)-czJbʣER*VR0JdF3Yz_?Y9xyc9?\~I0C=DP<\(nZ6j)Ag}盏ȍ,_( 4Fe27Б?S,1eH^_aKІMݼƇa)_ѳZ92+I9'z`_ˑ3G(>qV[Ujm[ߪ+hAģ$=DKܮL(%k`6l]=3eǷ!^e(s/Dc!Z7}kh!ƿXO<9裼IǐNjOXY BJkPYQ`1ĐvŸ*{ʸ0yY].#?ЛEoA7x&Etڙ^C MqH&H"3k(vS+8j(soQ梒l3U=`\X)sicY_-1mz<gΪO] mNf(sK/*5iO]<}wd-c*]N+3/9.-KO2^5OŦ[-r?k>x0\6UT j_:39̍6|OMOMOSW-Qg+۷vi7jSAc)o?Sxt꺔%oKn2nLho;%"[;9u`"ZIܮmklᓇWwƆBL6*~936#l>S CLBܟ<-j}FPưX Ci5t!Eo"iQFt#_ċ EiB uD6͘mP;սGE\IDS5\>뻔}${țOP۱Fu *w?SF-3DPw`oF1,u~M{\xz%뛲}HMܡl{8o8i}*RP]q+pO|R_󶶷u?O%My4f1mۑEJi&KEd^ʧb"\=b{ê7m]5Ox@jNM.0 cƦtYuՄät.p 8t[ DH.9NZL6uPRnuB-mps X-r']Rj PiI +z^iR rԒ fe(p/|z_= J6Gʺ'Lނd=軻@+?o|t+9*A^7Z?S@7 )R uOcI%yPʘ#\VfkcS և ;++my?MZ:c=Zi-D{b%(+P&@k6b":yHC9|µEG^~rt.}ʬt+qi:Wr' eMxpany8vpw>EQR@enP}MԋG+ưdQZ +Wݤz6x, vO[/zMJT>aSF)s/#4BCE9bCE O"EߺqܹAڮEy DWG6SLw}U RΘ6FضuX$eS%o'cC69 G/ .&&?ľ@@4p%G|>)۽9v D4KmPHTXW<{\XM UA`Rā^f& ~l%ٶJli.F7xL9y۾+M/t}eOIبk;RM3o߿2pIiiBm󵈹s<1hݯA#V9qnjҤqEV;-e-2>w5W[ڭEͺ qK%{ss/^sp?i4}B\dxD(bi)@MŒ5!Si'HR {ק/H]GaOE}m гo>Z1p|tj R5kpR|4H )hj~se}DÚagfU(kkVq}$*N0یI e$nQ~nTxe'?v w&)3Ů✠Qar=Z~t (@WGQ}).G0씝:奩o:/_lGҋB[.Py¢5mx]_*WöȔrK0}+<ُWq܈y' >&s?v౳#_6n.l*' j߾?=d߶4"fAyOӺ hhvK S%"KaI/Y p_QH.I!o*PIO~;{<4]Cr`AOeWo v ~CGlQ/&FPBaԈHH= MdbC'qQHopQ01" H?V _^adjYD`%rk\BNz ]\ =@Ɓ߇4Oڥݠt$:]k#*'M6P%R*kᴃ wC/iNR|^y,z?z!s )s]c"UoGj{(<$~Z+P:赒)7}(px'&} ,o,Q;^x#o3凵voڶ~th:Q%<{jRW6 !O~yBAFeMML'DA. WPIxJ#.^/"^o0:?pvDN [F `#nYavPP.ĨVouw8ۨ$r4'jJգ%"])9gl^uwْm'oh tʀ$LsBX268nRuNԽ ]yqh^ISlJz6_FM]wE MVD3*Ԯ?~!;;;DqsLeقMbfT}9wEߏ%ٝOX7B8ɇ" @v7)s".Ǡ˚( j/Sꨘ^R0[U@X!.Ň6V u)ut1RU~ RA"p 8U25lG%?h:ڀsa~?شz}~WE]E&>!2,0Ǧ$sӧse瞽)+?IZ~[LJ:oc2sSSC?ݞ-[L\?kyґSA =J ,0ѰKzۿ6?Σ]E[=p~2})kJ|)' 9m_[nوIWlڶk߽xL41iު]wzg em; k˶޴}1E7m=>;7m߽iCpMwoڹKPK@LY~x_Qܹiۻf 66n\6!o^5HDrsm޵qwT4*vHl>hH~om_OLG!RL6m%,K Q5͢En :dpRgH:tsI$7TuFB(dޫ7 eVqtA ޘ6"@@B>b<Í~ڴ,e3!Fլ1Fdك>NZcěg] Tr%d#ljވ{gwuJ t{˘ e&-_J~e,ήh'9g<(I[;tSȯ_\u5!:v#>m9rS{Pw7i`Uc|9W}V :jqq7" ZU=Q@DP@v|FK V59m8K[|V|e GOҔԤٴȣKW)INÍT8wәBT('S᪲`)0E4J 8 YI$e'DbI(0C'ҹ U\̺ެ?b)sQ_9"dIY~_{o_kO{֦\SSbIKQM8yϕ-bɋw(t(V%wbeV6e.#lRyk~{s(XO)niӟ(sC+թ gvm&#W.Xt YNQ'Zɓ5#5S洣#zH %S?ޞ]wzϺQ7g期JeTj󶂵[{_P$LID޽kϪ\W? q|$ O"<aI\BP"sSuǍeTT!jCe2"'p8qhSy6\ärA[ +Dl.±31PC>k (]N9:`ޟ}$պ_@Y(B1D$仼'Hj13DYϞv<ܔQJb.C)bgVs9f?F-/wI:d4*&g*ÆxHm)@-P5#C4 Z%k*v:LՔZϬ2Y l$un0~)g6@, }9&EmŒM9 8o2wnفs3Df f1#i51]/1DSGOY1{ E4gvk(+">k/V~P=41T T[&.KRbh3 tM(}9}i}oU5r|h۾_0k̐GutwU ; f ~ '$`1'O;]Crc5@7kr,ybēj!O`ؗ1B1$ӷd,\ks]s>K[ОPY#t]xʪNUirG&B3T$V"e *6TDAH^TM!D|yeX(r|ʎ/gCtn9볝Ӳt \ZrTU P6l޾Ű !<|^C;>jJ(4QfPʌrheG40<&"D. ,db̯Ҹ~=~ҭQ e.M @ A?\귓 gK-DOr[-u9ntkp)su3\N֊B{%M\A7GX 6/s/,/hz 1qօ%K|j0lAN%d@v*7g_߬Z(?r$API(kjٲteSα4z@EALL‡OQ6- T.'G&Sf4|*ɕTNvb3r2 θ0z PsT($ft0Kj%IDj3@(͸_fx-p20y۾+~xōWVBzWnӿ ˵Vm 7_Y@ 's_<5cM"/0V4oGQ.qQZ`2~pnkݢ=&+OR(6׼>{ͺ8µK[&ݚb>X|!@jSZP) *'ս6Us>IBMe]x|o'_P#}Ɋ OLfܣܠ- ~Wm)Y%lNiDM3&oRߦQ@ѰЧ1Zn{`Uݷdm~a/tk^V.C.Zto7k[|!-hxc#륚I0s Z}&;kVK)ߦtpg0Kx0{9n*a]K~ {bd'̒D!˷ۑh`"Qu4ZQ,ea̤bd  zD upk𡫥iROD$A۴Ph!T (.Av0Yc/|B0qCU`3h ^vAHJ[W^2O+(R[ ˔Bz_n~ayҢ2WHxg|&_\56]GgUJVŒ;4(_gkP6D[Ur"JSǾ 'muҰLm^_d_ήNy?'<(49ͲalV܄#uŢ`XBw/@Q72y3ǏDK$Ԏӿzw.0v f+ MYdA}^PX~gPw/I9Vgi_ SR/ :A5{'_d0%C~:חxݟd@fywԬ c_[鍟uE7@D,Z?~嫵gf6M?yATtWGǿ52iſ{iމB:  hҨ'ɼE6-q8lR<]h@=A1Yި!vK0b#BK79$Wx2lFj@҃P|KLAlQr`%h\gCzU֭ڢTx^HPgI=Ph~xUT8Rw JTM{ Q+EeR@i= [$չ~.PtVܣ/+ڭgw&?}BYAbTPZPS=j)͎CQTسqU#1dMF qcR_7j1rٱ.gZ7wXmC1yYB7[r]e+&Qca!yh@iq(:AxuY@ٷ~d jw2q!tFkV"I@jc1K"(e20ʠ֞d`ƞv5|FY!58T RʻH\؄4tkG%Wiȇx~ 3 rDwI6fP ->DmۡFwD9ڬA]>ZˠP/̺^Y`|%(P,[71 80mZrS:Ȍ;18 ܃~e+C 6HKdVLvhH1R{"xwvOTVgu)y0Qy{7Q{GN A@֛3@^%y!i!X.2FF\ I &}-h:n,oT:neJ>$XK$D sěf"=$jC q!G%͂Ex rX9(x1x\B]"8RA`NezNA,a!&+4:Op/'{S4jA{$:4 t_S۠ 2A59= d+s:Izx1_h%:<+4(/I#ŐhC[]H"3>N@7y|YfR6'|D7Pk*rJLAmV#`9zKƣF,y.Z] /˕$ &Է3eTVlyYTF&͂'s* UO,]^;ȎcS!E]0uJz%6Y([xFY}zr[(s"I& gfY:*/. zHF x *@"lk,z!*C@AS ?$ u{AaLٷnIyP1Lq<LygXnYأv,_k:dw=n)V7 'S2]M ':^ӆMKqsSsFtU6.ao5P)d*n/6j%=ȧϣGuFdMgΣUcj?3"3]2RFӲg,w)#Q0(;)ė VWoưz=P>ZgSbލfFaa<˱Eg"Mqoدwb'K[+-XcO&]_f\\ >id.M c@I6t:{xTG?xs@D#kYbafFA\U/R/"0nϤ)U6a"XТ<D5b.Bd]mO`XB)}<_ORwnE?4ﰥ]OP' U"SG gIʽR3N,@XCFqfd({F5 6u8A#R{K.f,/,lV3O*  0TȤ# oH~oǶu٥Q$1$JjUCN]z;{;wgy $(0^YsZv.|^6p^ KtQ%rsuPW8玈3P-x (Px *Yxm#`6f+j)p5$G[ F'J^ՓhiY˴(KgFZל{UҿƇ8~(pŨqHW2>mJkmLܖ&e.Ƶz9ɤp_ˑɯC(>fS掺eo5<ɍNN?/^ a.A#AH{|v_DJ(so5)szq͇̜rIxĎ-36>= n=<ޏ gI/:FܽC^tHNp~]!q̜͆zמxc{|=o/Խc{Avc\wtHǎP~ o# P"e>p% qF@:?}~x@GalVr PgJ#)O)?DmîQ$"PˌYDrb,C?)͒N "߫wdjƵX$=v4Ϣc-"hà8ZWLVxQGPb`μ9FTкT!Ekͼ9gS/M)ĸ=Egh+/?8l37=;#y@B}420t:2O,e2CfU)\3VIDAT!!aRHh펝:Ug#*E`}G=n6 R8 $cDm]U^ϟ?';$D#'ԨsSӓ1xꯙ>;Ui]'B<5]K' CVzE!tT{WQuφW*AS׸47}/C7(v Kߟ#tmHl2|]h"_x{Kh?\R(@!NȢ"UF*I4ݥKG}O׆6{۔w_q< 1{z3]*,Q" }ht?ڵ,9%uwzԺ~TxbGzlN#B_.|״|0 d8dO3þq}L #}53)pNL ~Cq}.9 ؃!&>I["nyO Tx .R=q`Ϲ) Tz?<<;!͑O[v.+uNS"pZH$w4u3qK E,bڏmlI~<ڔYAis;x*ߟgǤ=U_cSZdfՍK.[ܵ`q#는=e. ¦5ݯSAaA&&zESۧLx$tInZZ>RfMbƷT&(8~$ۧ^O)?n8ϒM8r(B맟G] S_N;j1~Ⱥ O#glX'IT@,:?N L [ĝ{$9 ~bC͝H9~όitkǝ{8bjB16C;51+NDoqGw@QU⭄E\3r4u6Ĥ*4?h]OgFO<hBovӣc֭noЛSppѪ"\is/Yj ][Ԯݬˋ#Z]G@>nͭK027!."<"pO^#8fIr;KL^E<~;|6|; ~gZ C VPO;4"i췞qW6?V;sN? q5eoJk|}o",uO nIN"]&.Z(/SҕG^o~XpSs[xef)=bm 4?Bz^-ԺKq]ZKܝ9N M]$*-Q!Lc iA#r PLDwT>=Z:Fj&|O`FCYwpРԩ#y} ;uKSǼnR&'dN6?'<<,b%NzuR`ThFU4 }9OnVܷxGԎQ6e㟟{ _Pn [ޝz OmmSk6(y`\eҴѯu9k҈){.K=et [M]x ><^{ GwUd$O\ ,G FZ2nB}ԗT ?{(1hP0*nFJ1Eb3Lʲ"n ʝ)>:jWP#zE~H7BG>ٕ(l.{ʶC^#&kGFFKɨ6IwoV X 1i;d{zT@_KlCElBKIl)'PUq]Y>DØC(4=*?l"Og+i|1c+ĘNtFC^1po"/$KG`*Iq쳉Hg(w!J5]Ln{T4"Grۋ}S4 O ڂd,DdRT"dz%I,)mR4a+L|!S,A^xc8櫗syP \#:RVs -KOZ"w?ooBϲaйNc"VuJ٧O٣D$jI ŁO??foIENDB`glances-2.11.1/docs/_static/prometheus_exporter.png000066400000000000000000000607711315472316100224350ustar00rootroot00000000000000PNG  IHDR{UsBITOtEXtSoftwareShutterc IDATxol֙ L&CN[qzf!ͅ{0wffVZmaxVr;*hZ4 {aUb.Zli+NFt2y?%%{<=K&2ysݻw1  v )  )AyL{l/NMMMOO_|ҥKPA?tVu޽+W\x(`{{uݝw^|ڵkSSxq )>aWR~SO=Ų,AM!{{{wܙ~駧GvwwC^ <)dggΝ; 0 sr xw1rd>Ow8 g,׿~駯\r޽G"A9xpBoQFy\ReYӣ_Q|a=41 ?}GO?(np"yܹ~?яANYZ-aj'_oߦ(j{{`zի.e~?5M{wg$_O> r6BݻwQǯ맞z':^oΝ;KKKktΝ˿|7iQJ - A\_ןJ'|… ;;;(… |o{޳>gMRw]?ӑZL*OBlKs8'EV~Z7~ LX;3wO]/ tOm],4rAUmOayp8] ʕ+~/ܟ?jiiH?Ez?~̾\2?L_ynOroAa ݽxcoogmj/^=''П7E^}sw߮ѯ}Y {o}v߫'sd?no;ykNFQY߮T*/]/ݿsMLR?~WUMӎ8OH&ie89]?D!:md:Y^@PS+u`LKyҫuCnCu_K|B`=  ޶,wut]o]gyw9p!rwygenҼy2LMZͫtP6!ZV)2|=ev3ҟ$uvɴ?'u*ܵ,fi1 rjYSSSV?ڵ+ `oo瞓GGոO .Iҡ+?~K4H粂6jnn"GX+FNVr$Y ˱7CW lŰ4}QLjΨIL8yN4+W>' ii;,ڵk`ww7 MMMaAƲ> X/nmm}O=Ѯ]AsBڗ#VZܧz-Ll/裏vww/_|5@r{ٶ6-mZ/^l8iO  )AA'AS )A9~n@6#] Փhѱ}}p}z"\y2=pt~O8 6V/{r}\A<{p'哈1!=wo ~_DP4 U r~ ` AA0  BAL! )A ` AA&.s?h}m/x5jwO<׋{yw.ugkPQkP oLs=S5E{wQ}I+Nwޅ {pߢixq%ڷV<]{ήGGuazEߣپ%SmhiBoJкh78No O{A' A4*w S6tRz 8E{k a5R{nQ/`ԅ OL?1B q~tm 0?vݳ:;Khz셽+Ԟ5׻Mu?hw Γ~}gOOw|;O^>Z `oo$/N?%ߒ٫\~ڷ6oug#ymtk|Gn7wiߓׇۿ`O=uSTϋ頯T` o.] ק.?O6BAn{TAѸd_3ௗ?흠NO%=p4Y CS )A ` AA0  AS )A9P q~}r'wMu`+wv#}'_K,ܵl3ݻx_np)pP;{[OC X7GM=+P+ݽ)wo:Z^x{STu)ާ(*XqX SS/~"H`SS4vvvz ҁ|l :*j_|*h-ac6B& ka~Љ{#9uīA!)A ` AA0  BAS )A MW# XL˿ FASᩧ裏0g*#A  BAL! AS ` AA0  BAL!YT8%%MǼ;p0 d(qͱ* VMz@ yzJY)!gؿoKN8-2K1;HiWq#r)+`T Vɸj]4 rvk#WftA3BzH"k5G'5+ s[-"-+sEb")3(",% YYՎUͪY1QlπX!^НNB-{4M"IvL-Vh O'VBlXIUD8A~S"ˊ߿±,˩%k*[z>2[; {}9mxirc1r/4\{c)Ծ觹ƁlCu]gnnnr47mVVʛ-uk!:v9Pfr]{c9L:uvvp]wF/5l޸c"76]mR庮ݨ7lеnБZfB*gZk1fV_07#Zu =l.u{:\klmUwwLh߫"|*EZk|~¥͌goxs٩7_/bƻG/9R* fdRX-I "S7,4!KpR\BސrY'@dZ2 ˨d>ŠI< eZeoQ+QrBXf @|I9I^/TnTJNI,f׬1| NvADSQYoµk/֫/^RflԖß6F%%Gtnլ7cf co,r+w;ƒccpR;;qq|`B) 8bx!իpҳ"N:ZUK_3pd?La1dp cp#RQJ]nju\tF#77 DZlF,Os}w1jRS eYYg*L^ڰ]{c1̭ >4WttqM0kg͆ʳ43Rkhݚaf˶t[k1fl{齥WEQ E6Z v~3k f!'󃉡q3BG;)0C)īSH@oztP ݻyIJMްR\CS;Mݛ#鵻yB6w$/zϓ׳7}?NzO7'k0 c zA#2DzX' AR A8E-U*<"JJb)",-: jNXh)z/(wV%-sTCfVkJ-Bd2RrFq#^mn(V^R ŸZ -SgylneKU'zY9-2YDru`7oa^-BMp&Tk3E9{!hBEA 2<' ȱAS/ rDξ# mCAUsIKm Yz֚GL 2CN=0r%aT̂H|5 ˃G4rBPP* ގ7}ɺDŽۆ(]YaBK,ZkLfl[^ Lm܌0eYf>]ѯG`L>#8]tfUMXo+7B_TWWK_J\_s%JGWis9L.,pVyfVj~xV]fwc4nFB 5U E6Z7#t,{c1D^s L@~ yx|4Vl467BZٝaZհR˛g˛1:4y7H<0ڸc -~/tonihk\0y\8/+/\«o5!$l6Fm98^h2?=U_.U]oT)fiEydOdN$XZH;^zq^`߯T`BA֒yH)RUNm8ћiV%M7-KDNX9)\|Sz~}O N_{c1tD [mt<0Έ9z3#u;Lt~w͵CE@G?Pz~=>J`ϛaY]vmyChlaqٟ]DMy"&4\bFuw#i]f q]DntyJyhESdA;T oi"K O)HN_4|bGϠm:ANvئqd^RޑhESzdyTGGBwIhES0zdyU{@!i p/ĵ1#Mh=Ϧ^"~ hFS/2a{̑_dR'&4"cd" zMe0c" 1hEAȘYZܑA-.<)g8Q;bBXȡ!  ) g@X9-2/ jqQ{=3c{GzQZvg^;:AY^,9r&)`T:tI2JɬutY"("1uRN2@'@/ )UyDL%P1n:@xIvUSԊݱ**'ꎥk fd pj&iiqZʤe׵ZZV\SsS*@8;T2m3HB j&+gjZ]׊)pYIj,)7Ռ8Kz1_(K«TETb&.r1sFN),j > l:9A9"gߑ$hE-XEkUQxwI4r% p)G*YfAq`-91>4ٗO$'a=5S/ Bbp F`}մhjҊڭ,_ѱcNꞚAI!fN$#IGXKekV+l(&"9x=3aZX(Iɒٹ\Y9E%]Xլޘ RJH[Jؑ#B$Ep"O(VN&%"Bgۡ2ݟX 9óZc%U5:,9c EI'=29c)ĩ,E=|p_ypOܬ[!ǸwljZ(뎟UcˡQط)l[eݣ*AB\f#V<[k 73[="fg|#Pjΐ<I< eZeoQQ4sdtȏLAT q**KQ_zW^vWzkB5Htul6rxfӨJպaZkV3$It =gEFa֯*lC~e"rRQJ]nju\tFnir=odX|<¾]a{=29[YI$V'xD絳gX*GEFaf=VabKPx+&G;K]zOz^JcL_)[@s(.e*Bōu"RRxAENdJJ %dr@HW )8%ݾX_(z҈rxA,,U/d,/63 * K]B?U%xezUXScݣ82PάpT"rW! ʃA&3vs|5ԋ 4"UA㧐MfABy"V䈔7wt/H@. N!z{*^OVj*[wJ:m@ESo7O׫Ktnث;r|S/'!L1S&`)1Ěz8G't:nMY:P?k/0O퍥4 -zv76}jX 1vY(U+Mj҆!fnv]׵ȍMu+Q:es9LǺ-˳Lfu[Y[5Hn0eX Gnl3[ҫHhfs҆Z1.ofmL L`6ýB\ЍG{}>^ݻ;9}緸z~MV#zA#2DjqO"8G:zN8BQE%[m0rBX 8(NjX;z!!(ԜR6+)(JVwSrUK89]V &*fjk݊B-)'R~j֋Icl<5͂\,o--eeT% SF,Lta1PHժ-F:4XLlq! 3t(vcyn̵7f ڥ4זb!jGeo ]B*: g#m`Evm!^w@sLfó337Cf?˳E7gB @C3+/ hz>3بv隣IUk-FڇlhffGA3G,hq*,/g6^s,fUrm>k+&#~bjp2SKܖ\<~Y^,9r&)`T:tIE`SR2kh_#'eHLӄL.!Iq yCeUi,T ,^^X^88L˷-=*bE3*cUTNHKLAO3 #x5ӣ+tWظLrvubK/IDZf͒}StrH'T*}W;Kz1_(Kz+A{!ŝ|-nZ㙄Rr:JϋJYT:ɩTĬTqvowU=+J8!,U,ra9s)=Gz018@xɑwoN+J^,VRPAă)14iyRjq'_ F1 ˲J&ʖjz)z +'E#"cF!.gl5/2e#/s|Y))Lp=5)U_Fy"kfais͵ ̭L(DZy'YYa,6\m/΄7`B3KkWw^prm2}Ȯ30s麛aB-̆i:DWEvm!0L0 jn[ "pli~|s犉ίj-΄Hwo܌ ba7(6K3 @xF 9f4 :S}a&F 29YTA$ S/jqq"4" G;P>đXN=qɺQEs!K 2jϔ(!oSOqT?R0 "u[rb<_k}yPrCN"*t]B=;áCv q)<UhVAKfZk6|jFǎ91gv{U[ 1QօX 26qcsM!fN$#IGXeLekVk泴U:+&"9x=3aZX(Iɒٝ=`dByprv_5XͪY1QlȎpBWhܯ2zJdY^Q8e9dj O楄W;'JfFqvJ)(of|QR2d=E^dE*Dz:U͔HSIn/gEYxe9Ȗn*iTOE:Cw! _3ܐ+>bb];xf"+ X 8s]mFD[6ˋ!-bir ?Rl\ѱ[΁2a:֩s5FV7m׵[뺛7"txqaZڍzwwEen.꽵cfnms9Zٛa:\kZܯ.\׵M۵Fvc./k nʳC8UV6mU^u1An>Nza߼a&^[B*϶j3{*χ ,Yc:|5/ZZ+9@/CGolBe}=0Ϸb鼖^|Û+Q:2xH u,pVyfVjþyq~i܌jv<,mح[k5nFjsŃg {}abQ 'V'L8K g˭mp<{{ԅn5lr j6nyCjKL8DoCw!BR^]{շ^} ]l6f4*)!b(Z7VvjVf}yόs: Wy0+^yzyElNR`V-d-}&bRq TSۧ1Ӆb[ȑGcG/zFͲRXJWP>V; c>~v*φm{}.ܝu };}F^3k-gX[GP/Fi:4J7wNw[yL{c)DϬ6N "Òc׷{Hw`vm)V),GAKez'#LD$`Aa]{<'AhEAzo4"2)pSYm=%9" O)wd;IljY%=%mhyf[mk_jdRmۧQHH*G;dP7 B.1F2TdˉTXtPSɐw4/z;!Y7}N5\5d9g:pffi͑whESĘzϨ^E轻o;]ݬPu}Gt{pNދ^4dz#YfUk[DAMB\;]-.'`v w b*cm ȉ&C Bd8T9~-9'PDjqmfg6oa% 'h" c A( H84" G;Pl͊t_e~;+&"9x=3aZX(Iɒٹ\Y9E%]Xլޘ RJEQ/t&hLYVWeYN-Z9ԩ3jT⹴s,!2>"+=:lJ" < j^w"'td^ %Kk\"*4ıOƉ|\N5nc@ '8Ugo.]7o. 6ZnD|jIoڮ ՜r]x>:[u+^02-̂ ٮkyu@m׮&͔$Riki957GEe1Wre%TNFE'%YW+-mb<ޗ+ c9G*JE.UɟU"U0>+&#OLN|*]2y}$LD~ǀ)%yk62_ns9߹p}3o/^OON"GE]$,38zș@Rh4+%d:&FN, f) \B ˪<"&ӒY@XF]7 $VC1erFEw c)Y)B:%IpZ~ڂ2iu,W+ka&yP1OhDUdQrXbP4c[dȏy߀ ȑSSQYoµk/֫/^AflԖß6F%%GtnլIUYTIc2TIVRG]c tljX 5dٵpVX Ϭ6]WOg9}n,+q{UYw<QQkLCcDu C"L}?9> C1N (~8ZWIȟoc@䰉I @y8c*1 d^A䈠"ES/ B7: 9Z#Rz;}GM"R^.Qm۶[YYXoٶm;}ojBeR'xE&jŴ)$xVc$SoOK*XMeUI 5@CRќhESiXo|z%9)^.OB>N%+b6L@R^cBS/zORL7<Ҩ{%9/;SR\C2p)鋦^4{vMdm%鋦^4s%鋦^4ky%ϊƧ_#zO 4>JC11O䱟ȚDԋLez᨜QrBXf `VJNI,fߟLZfp]ee99eĊZE9I^/T3|*Q9gr%V/ %ƈ9cAG~/=Q-)-BѧDcϱ[ #N!E-jq{/Sy=n91Fy" = -nceMOmày!2^Ԏ>JC-. ^jGA@L='9Z\A:hEAwdM<ة(3XߓlL=+sEQ|kqӍ'2)*|\s«{(G#'PB~`D8ؒCs&}yfju]#/ehx"I q)<UfVAK+fZk6|jFǎb< ^'Zu͑#&5+ s[YZʟI\[ZZX(Iɒٹ\Y9E%]Xլޘ RJEQ/th;Rύ;'JY7!bm;ĵtVIeO[[[:|U|0UXiU• [ OZ)tVj xgx՟DQ4>ϱٓI\|]x \ƛ-iV)6vEQ8cgQ.n޶\~ ˱83eW:mRPrd۞DkLy.SY{pK}Z%o{xUV. s>؀,3& i3_Nk86≼`x-^yIpDJOqyN[^CD/`^$;(d3Mɡ[<}6qfl@VI HrFc㹍x"oq:5-7GD( U"&RE%f{k>-'K}~ùhMp?7t+iC3T#j@3Z24S/7~sIr'D[/"X+~w>k@F]uq#E"[au$]k(r+\Rb0th* HTt*2 j} } |ٕl@j9[=ݭI$U !;+0ZrO0kU>ZJǦBLm(%  ZJ$jϏp{з^~[Vp` AvE.` Av? ʃZ$C"hEAz7}ͲC^#3ː?o"Ь DiT)/4n 4"+TGA/A/okvC7|wޮ#ME^oA, !Ls//Z@oBߨm]0Hy9}ԋ6DN;K8b݊oj#.|StXf3ÅY+gL/HҝhESޙzc\7G8&FmBȻ9r AKwM{hde_hzJEf3~7Mh}^ԛAk.dmSPhESor7&RD'71tKzӓދ^4hM܉im{lbٱ!%L:}W>hES};g.h-oH$k=AyM z'6F_d"Gнxbs o4>4m+yAy"kB-+Z\AZܭZn$ ÐdCSffMU$wOj@a6~BFԃQDT[[bn ]i6M?țB !Žj{Yj-|ykؕENW6>i; Jr<1uhjթToT+mga][n.)~EIt#{=;jU+I+ \N+t80Vd@(U5ݐ~xH e zE"˵\m Ն&^5T#A5M$!Žѫjq7-hhh"!?ulNyB;v6FѨ]R%B(;2-QV5zMgv$敚v=; v ZMƧdӣ3O\X` WNENds|eNb6kMx8.|5wZzQlr2-d/72krf3\px+g08f)_t:}?^mAz(BG I4i%4gO,)Ϧ@h6En>{8r}Z)xq'WwO' .r\(RLFdNtj|>=;L`ys!(}:AI^>HE=^A#kȆc #6ݒX1CPEcWMݒmC8fYm=8S+@(~Ϥc #5a aR/\9NpEQ6EZ†A}FDyd򄥲4grrL+^f`JYxESeIIk[HBuR8m/f̙j>O]L rQ8'3^/ 2p ǿxϿD}iw|"} ͺ EezQmWtR}Wz#5vCv4u3j|VTIm+AյQEQ--L4횺[5c4-(դdz\?V_6I˝H[s\?jZn ):WQx=mp{yfbG{jdɲ,@xxo4ܹ̳ '~ VҤIűJ`w-O' VSohh<|?}o_ ;8Yv؆.%dˑm{^f]־ȃc ~ <:;n"M:j>W]L/|7'x`d]"jGܞd NYI N /!L?"yp7홑ַ}Ep$]&Ҍ;sTS F$Esj Vw2Qd#ONЎEoF 7[-K "oͧXu&LJ5.>u{BݗzՂ!ķ _RE WTŧMO}K4{ hp@U(]@U&,W%*V Cr0T!HAG1"0֧$o4Ua5iZi(*|(uVO@Z:ߐIzv9&Lj5YJh}`_/[bo'{g ͪnoZ6&AFxAdwÞ={y yAy"hE%C^#3ː?o" Ь DiT)/TgP" <0 QA,w|ABewUb靾0DAvxIgꝫxyՒzsFnkhEʛ鋦^nT"K`q}RC o{yWkЮ!7[,套 M(ݤD6Ŗ3 C޹;n98HҝhE% җV2_PxASo2RL*MES/Jd7*wr>~9pw"kmSPhEF%SNJF)<1qM(ݨDeD١C=B^ԛw#^nR"K`r2Av4n 4wA^E.^d;O佁<2[A6zA',kP sg^Xk?z'v ]!4WJ?ABw=+92T2}h= 8 Tcyt:;::|>_{{;!$$$D @ cLsss+|8N0z谰0Fc6 !.󵶶;vjN0AѠ]WkkkXXp_][[HO+|#G;K.A 'OFDD igϷ{n0yd-z޽;!!K/v<_~40EFFpR)SDFFe߾}%0NjI&l^z`8t 7ܠjtĉm۶]{.꫇q8L/++ꪫPݱ50yQFmݺ ?Y#F$E$! 9;s}>|`τ 0 CYK/aϞ=h eYEϙ7|>_]]ݕW^')..8n6y;vL8Qׯ/&zp@BBe楗^ڲe !rzjјP^^>w\={W^^^[[K;vlJJ 7`N!!u/ㄐ. :th jY}>yCffٲe8"qV^=gaE' 3gY?ߟUz}wW ^g׽9:>{}a$}>޽{vzW̝;c %Igʟ,2ḡ>/̝;wѢE98@EF n70ĉ1CqP,ˮYf\oz3t:{}FS^ڱcǘ1c$Il~!e۷]g?}7vXBHmm{w]w}w-9 W yin ~]|R݌H)S'iv޽$IRcccccԩS/rT507n&?>eG}4zhBG}D;.L~;~ơ=SO--->N n_X,z>WQW_}uܹ/|z1|`m>{ntۻxH_>QȘ70`Hnh̙h}$ӧ)]]]rdzZ XCKJJ/,,dY&lڴvO|90rqKƝ,tthZ .<?xNgm۶>4 ~JR111 Wh Cmmm ׿>Sݗ;6//G!7-VXaNʹ A[˳BWY0T'\]ZRZȟ3YQ\GےR3f~ >-6eA/g YsicWqI%D=15##%J…]!{YM"eՎ&1F&df͉#*VWU} L5EyTYV&ئ_ЅQ0}K^m;^TAçS=P{3b-3<}>z޽{FyVk?޻woTTT#EgyIQY%"ɩ)! g5bΊ 8;xQ9x#GƎ;%˲}Y~~~{{;111,[VVJ7k֬'Fݘ!=c8q7 0k֬y|I4qǠZvOM=л)RTm/RsdWe+#bX=~\ 01)S0 &kӨ[neΝjoKᦛnj{njjGCs{{ n>4zoYvms?Sg֯ø]˲ZXo|2Ohr/BG>uJ'[NIQXH+l(/>Z/Tbbb}Wigg={&N1v$I;w"%Ku]i,EQ$Is=^wttP:4SF.\0==]e:ߞ͛7_uU=?zͷvۏ);DܕbNȪ/(I[jwd %mNžz7dz!\8x}۽XSR$!~$flD W!{9BqC~XNo׸RN4(gk';:qd:z2L'N~YYM칙6B!͞vp 744444@8==eҚ{eؙ3gΝ;| waa+䈢xQW_~OZoǎ#444ڗ3=Rρ*ذaË/(b4e9!!W_=\xyyy^^^Z:7pC~~@Ϯ5y+uU=%s5y)fB (,;Dd))ȴ3s m%a./(\zN6[[^]ܼ¢UzߋX]_GDTz 5}jMKYxBᅳ[l|UUdqx#SlHQS;6t~:,:+JOfD,wQ&b6Wib_c(,oj]Xœ̬96Ay"b374ʺؤ|⚆V3Ƨde}7RsUEΚvxA™ gꪩi?lyzݯxWMcӿ;OǚVeX{ߑZEI5o$<ǓY˳xT&䝧xp !5WU9Z<8nR U&16%;':R- yʦ{Ľk_Yk8 ܙyى¹+[j zvȧ쬮oS쮊]U91=;32Da&V,gi9K!rMњg-Yh0Wz,Y~Og,}>CafY,/+wfX UtU;]lK< gIAa`fg(\QHj'e妘]%E%əv": 8.Q0SmZJF!7++k޽^Ws=;rgggʓe9(Ct1s͘1#333??Y,BHSSӪU͛7?cjjj>eĉ=ʕ+ə˗/ d"ˌڰBfڟ01ً6l쳢(޻G I;::z_<89)i;n͛7oܸ2rȅ |͡AlteSiaN$:F c܆9)_2fSlܸqԨQ|M.VZZ=90hTTT,ʲl2KKK&MpYX7>oloo>/O?۷55}q,ՔX+9/͢z쮊 ʄNGɚ7 ˬi~zΉ-{_X e٣{~<<θHBH!s3O=4˲ቯw%>?+Ç{_7|7:;:,Xj7wygJJJƃ'eIyvæO-g3B/*rӦM{9ӦM JwvvyLa 0j(pIBB A4mݺu3::H!bHH g/t:uEiiiA([׬mET+!Ě`ŚKW)Xuet!XOO̶@ٞ!g=7/;U XsSިtRfյVU:)g|nf,9#?LIY9M=B& uw}B5=l./;jN:=rn,vE Bx5ЉS_9]BtfE 1R23NYMFY$xBiMxs3N瞩ee,IIVlU9]T\vt@Dڕ6œ#BR]IVU4IO$gyQQhZGiWզELt& kʫqA4j9WTP 9%C[j#O`1ݗt2R6;DKܙ]Oo[FxsKJʝiqT_^MxۚI <N=j '[ջ$+?a%&E 1Y33XH̡4;:E 5~HC2ŤIo>o޼@i턐^_=f{zTgeYYYjq9Ś{ҕjv?5SNHjBJm[9%n#sM(wˡ?^*++Seɒ%g|>Y_O>D-[K/oE wă馛n7q!!!=0 YhQ{{,o vmK,e9+++::h4P֮]iӦ>oC###%I2 ^wŊ+V?~?h'|222`0ȲZ zh_Rx\gtZ2SBȡsS,>g~s $ !_u{(˲fu7.+$$ܿ3ޑ3fyזکu{dz-٦s9.gSgwq/_QPVYlz Y_y^DszQ+RGn\fM^j#y)D%^Śu͂b""9\.Qg6翾QQ/-gq&S?~vU:n,K-#qEzh5)KҿK?`ɟ~%~%wlYǒ3LDiywV*W[yb_tf KL d-UoOZ]UTT,n[ %dvٙxK4)^ԝp{5C~yb_Tٹ<>-#ig>kIL)6^ʲ:k3,!XwUȟЅNVvXF/ܞSmaCSݻw&I?Z}3krzvrz(͚"ۊlqD,_q.|zWQ^RV^p(bANVsGH>7ILtҗ_~_`A 0̻ᄏe˖{gҤIUfϧ6Fb?U  ݇*BF(D IDATѣEQ~Y ̲V5L,JA1 <ϛLSN|o„ _~h '<ƏO9z6y-c!|>V=)))۷og{t@l3{K*$tQӭju{`a~jz~jAQy*8/-55j{!3Wdpe_\۱&_3™S-n}Zp$!D'q' ̂\pI \o2&ZLt^jÙ-!nڦLIC2}*gL444=*Oys L"%ݕ59 i܎fٜg"K׽B. G܃hZչK+ܑe&j K ;nb3x=m=]_U5weNs줰J=.!HCf8%K$I#wI;>麫#I`?Q_~#F:~8!$&&fر(gddk<`KI6Ae/J]W2[vN^U\%+Wr?At8]Ԟ $I_~}vvɦٳg_ve~X7sg3fL2~ڴi>K/hC&F$G7n\pi0L ֶn:B]wq6gk>3A83~'/Yy0dYnook2Ӵwȝ˖ս/&rfsoL"$[;~!O?W\qWݻ_/))!̜9; v}&ݟZBaQFy<v]w|uS~^occܷo_xxxBB!DENndh:ļ`hmmU[U=<,ˊ^80 ~@WWWQjoqg2f̘#kkko JKV̱.5-pWM(*:dJI ;ݎz!i| oMIu%w9D(f$- !hXJZ_M}%2BW9{+~yKJhSiM("] 譢x$WԸDtTU:gSaq83f^0TDW[U.*)GƧĩ7oNJ4645%tarKlJչ*69.]|WaC<RymwD|cNtKiaIu(It%ʡI.GXLZK5ť-ԕx;0zҸ!䢳LL \0)g2 p&iyMťǛOBmj~mthwg222;3##c„  *_vrVT@%k3w%lr;\m՚juT-"8;}7551 cسg0Fbi0I4߿rʕ+Wʲcǎ۱cG3tURRҲenw]]]w_Suv3ۏ={v xZhhO?Z,p~={vllv)Sb!GLٻh; 0 iѢQa_ z-O@/Sϻw1c5\aÆɓ'Zj˖-o1w-[,\pƌ7n"E8Sjk 7qaÆ+VL8ܥ֭10#t),IRcccqq={j@"󣃜&fٗ_~9==}~?/꣣>HO@F@5k(r5ѣNb4Gy䩧 U}ѻh4/Y}!Yr5./V.uEI3r2FVb2ޔ1}T]SW]݋jtZ(..V-%f=9;/hgsjnPTT_jOɴ Ě,_Q"dU譳dN%gd--@P9NEQ\|yUU!$))keYt&%ן7$i„ o_xx`WW(1c.LM$Ezlɒ%ǏLn2!Z60깣#:::0!?Bfmg`.S^q&?6<OP$**jƌ[n}衇srr~_^ !W^y@&Ok4-a1 gY6a0Lcccƾ曁WEO6Ovƌ={lQ5mHHHDq#CnaK޺uk|||:x&~^@8.6 mmm>>nMm۷9s 9w}yz_F]U|{ᅲ%8RȝޟTMB΃YqLϜ_~vzߟI.jփ_3?C83큥ɦb~>Y?=*72zKϾ]\}˖-9yd =cƌd4x1Leyҥmmm]]]6Vr^{2}ġÇǏ,{&wNwԩ G-I+A<9r"<0zH ,{w=rر_/A<:a8[~ݻ #,f9s/ ]]mjjj87o^JJ͛!cƌIIIYn]G=9ibs3 ; ٯ`. Qh<2!%?j ko۶mmmq]}V5XSiZm`ZzSτ1c{曝o%>>~H˱,!dGks !oEza3 ~-JOO߶m[eed&:::99y޼yA;=1 !_8;j\(ei7y| ä2Ř#Ix !d„ ѣi@w8n…Nx<#G?h4vm䛁,fAtV4MpB8vqǹm˸Вh5A["q\`[n%4440]%Knᆿeee.S+5aHdV^M3!d˖-g?0ȹ .xb57@I@_糢rss_)ҟ/P3MY?m gb3ȍ{nIs)BvE?.\gаDQab]]]I(gF3f̘Ϝ9IY_ѯS! n xWC[rRaz*Åp Ĭ .V ,`5L|6e2rss_{ށn%II$[z1XS?XeZ/p40AeаQ(}}HyvC?>>l6hBCC###qvLeb٩k,Ga;?N>d NVgWPCTP>>A -=J[I[:|߁0 3xPK'˲$IrG8P;uV]]N - ЎhpY G'Zui4DoT]DГ/˪m%[ r&-uEW!}dY}!@! 3|>@! ǟ_%w>,rIlaEdNT1Fj(rBB,RAGAtR(~?R29jTcOtyN׆VT=FR>v ð˲>SXЖzi=NA 﫮T+D"Dݢ~M('g2G{8U^~z߃aYʓ>Ch)m'JvJez皏`G{z$\=6Jv7M43鵔NI[aU%wXNWMD ^Qëz-~QE=(zn d%="-h Zh'eq ei{D=PXN|kW9CT{3PIGFҞ?;1%КXҖvvuJfyDeez75"*'7N}L[V bPO?GɷiW}6z}him52lTVh6Ҿa QϗBGJ?8~N55i0 fsK_~{z~J;2<|L頴yͪ5D]s O}VOM/u҂GҞ-].Z0V5G|yjfIU+.Ly]StUbHFhMU6vLG,kxggk-r/jh  eLkKSê_@rTψPojZoЅG{&~ɧ D$IR>SϷj4Q=9:xrWDkXͣZ=-G,h=J=֫v˲_w 5  PLR_F#ʬ[Ry]?%*˲8ZZvMuѾ',mEGh[CL&ktj;Zۜ)UhNtVNÛ#|hıN;u je:Nz](yJ2n-<5 $_F3o@! 3|>@! 3|>@(+itlh( 50,aT3jUiF-h5eNRԖ5|+WhR^,xTʴ񔥆IOY?J_2yiTKiFC8Ղimh"TcY-x:q P-3Nx0Ӫ:Bt h56 IDATj9ڽJH[l4z7~#"","DcPo&Bi&e5*Ya|SA l^-V^%)WBC}i q{i2i!Ю-aӲjxDX"Ի[ZIe8C! E9N~I9Nך'$/2 (3^eY&-JHB"2yzeZW=(Ef%Q@(r C{!ZO Kxk k:݀ԄКI(KC [L <H(i q<&R}iU4W[ի8LXFY= @kK}F QO[̆"eA477h}ꍖ!1]]](g4VG$J~OF?(ZR,CM>-4-!0̰ğBPJKa $OT a)[u$5]WW[[s@}>j ˲DyQzK]bQZcF7 wD,j_& - 8< .rĉ:)r VY%K7LQhoުLg`T",?N1w۾[LJecq(&asF˄rcY YI'#\nbW{{-7BZ@WdֆZ~}rWW KBo>BZeY%vuS>n$ yAy`Qt>@! 3|>@! 3|oZaގz^DDɓ'QbƎZ|>@! 3|>@! 3|>@! 3|>@! 3Mypa&Glۺ;:~@>>@؂12&!aU}{ͦÜ捜ܫ<>[p6>|ѶZ?u1W/cgDтJbYy:opײ8ݭ>"1Lꪙb-&^]M>x:w/! ;+g$XM<] G>x[pS:諗-͍zw-8 y+\3ﳷO㣍ҡB^ۦYWLݱ`9ַ7lxb5X9b .暜[kk_]b\?yX`+%^BNB.ղZ7 կ|J.LKpx֏{'ߕcrr$69f,?#jEWۊnl(63[ͼn8遦Ʃw]g%>^/:=4򫯚k$=;?gMB"u +:;;_}zL.fUW͚o$6ݳcí?U]Ϥ%f6NX`k;=6#nG6^|YMέkڢX쪙;q eqфVv,/:k1N]8^3.z ^[L1꜅ґ=}\;m.|wWM-r,oZڳбɓf,v7>Saz5R}a'ub~mMC< $w#uݴx=˪|Y VnطsֽM2! 9y3lbퟐ=Lz~qyWN5螭nʌqrwQQwߖAa+SSQ"CLbY1.[!{s#DiHQlmKlgV7:B1 v  ` |~9k>|?4x[.rKSv~Цg}[!ݭuÇO59# qsoN:Õuz>Dݭ5M-" /^[6Ev~KƹI1DG|o*+^W)fm.y9_?6Fܐ>%ӍדGj߽Tsx<0ԳfҋSƗ +z=˛zE*-kiZm֤/ >搩v[Ǘ~.|ԅ/66H&@mn{."k׼9fʩ!hw\1'FYZi݆ՁS*,mRkc47S_={sfEdG0*0tyz÷<_ZZ%oz.%C^|Yy6񢠆w=bN~fQhc{~YYZv?t$$$,{2folOVsl텆f%i~8G¡:rjpӇ'mQ(F1&`9hϳo9iEA_O]yE71Oi-z^v R;hH|;zįBhoPB15ḑEV\Ya̙3c ߆w uwijk{DD]z4\˥jTtv\c֏$h95RzInn⇇O= ow߭+ة]{aSk+ED?8\y.yϨq齷v_=/lNHնg#7ќ9sn9x̙#G>ϟXH72}pm 57^`iiŢ& t74wzv&ҟ>غoZn}#C-_E~2˝{|wj+kq~}wkÅu5y):Om֚ 1skkG=]9tOK:o|br:K]mMmݥqݽGފԵݞ"Tr܍[pm{Dz,Sk |c\3籩"ܿLOOoD͖SG,D<mkkV;ڛED3S߲MzƸ$ٳ+NG9ϡo6\OL2twp^eЗȠbhp=1ѳ؛m9ffؚq{j"N >[.]ԾiEVUo{s+ҥizzcc}(R\A=[Zlm|lИ<7.oguAs_ԏ R[t77w{On{(GSw+GwB3'_xTm+Y>ͤݩTc|'f.A̧ 'zSpWD>+`̐}wg{<컇1/9!f=:V+i lT Txz瞋\<φζ݋P.x["qY3gy?ͽy\/#=~1ߛ3w OޣgyԳq0&{/}ޅ.YWs]==lcZ|؟.f>|:y / lWΙi_UOOyO<.5ڦ/RS?W% sM"p>\-}j4t>6wK? :{]4g>'_:~6==U <ʱ RީSoV-xݷ˚jQrv[WbNXdBz:k^8/>m?[=_8ϻiޭ"lS~t1=Ƴt'„v}x=""~cr~Sf͚5aa}jM|ϱ_48HRϜ@gO {O5s~(۶/A|Au{ J*i/=}g*>gaݶ:sYGM?uNqzNy'hIAGFw„ *=~Ml)8D<|C{jNBz[k+ƩoK%\bn"Ɯ>_D|}!kg>܏~#}3HG p?g>܏~#}3HG p)\vQ;o܏~#}3HG p?g>܏~1bEEE1}O1oL2]v_x9}V ]aĘsdBA [rEkQJjKqJ@G:'ETe`Wҡzk_Ngo2 \\~JVG;:_&Ŧ6gߓӦ_Zv7o8i9GMY:Ƴbj5ot)>go|Y׿IԾ3'HM45oܦoʚ5l5e˷DԹ6pegޯ87koU]S[RLk-N3"NQT} 4mHZrMDq.7eKffpCrf}F? }w0o`wtЖ٧6l2w8eoKytP~ԹH&3;Lrqv@RΚAIyy |u5)>~hOYi~;C9~;n8?d2ڹĹ+@.i;[ 72b.*Jۚj/EZo%kܸph*?sd>%ZV5Ҭ}7rXdDE$tI2SwaSUYNr2AQ_?cÈ5t8f)pZNYNe8;6ܶ>Yryxժr{}3vx ݕg_dKn!}q]ۦ7&'9e1aK0DD:Zrk/GZ7x?wr*#LNY^BQ|h9SYY۶&,بZgV|CQmv|N k$"//;ui=l:[Eu//?!"MM7SԖ#LM"3uq[Mfd2Z2㙝.?!i[Ì)Ʋki+[y~[g M٨u/9`n!J6Oٙ\7">>䦽2|t!x˪2$ee=os$lX驃䭩]`[Bs6|1U貌W2ATf2rk׮tUUܹsͬm'ץľQ88E@c===gΜb(;o|٪[] I~ﳳd"s}W^T~㦇!ڭeK*]zubF^D.Zr\ߢ ׭wJEю`թ}G햣; K]SLNMשDh*ܱ\Rť##R65uTzN#r,勶o׊֥ 60/ZRԱ$ƀ[KK~zEvl߈..=$uR\߮ x25+-MN YSf6qk9iz[s,Ek%y-'31xs20972 bQXi0{I^Jޑ.r,oC=25ײkwgo>iqZvTz-^ZVj:dj9>~YNNbeo_c!ZE*-}MU7do2x0FCodƺoggx}uDap/g[eYZ8\%:ve"qCFDtJs醖 q`rZbV$019X&R]lrEK_ IMo*8v,i K߾4R#":ڦWbm6e2CLVDjx;mI{c!ZE*1[Ey>]A X(#XFtʏT(lWh=PD.0Պ( R*Žz{vY9`3.;[5RTޖ S"Sr J3MDo/4m(.^[.v]i%o<͐-Q¥dm +oƥ_r3|ǾϪiX9ZtK {M 9g&"uʮc\6lڠ 5ii- ΫjL룵=isz_ai&_8(82/JzgkHqe}q|v%[v`'/Xe]Y3EvؘrxxwctGU󫎴[7tnMXev$5y H-ہ^9ҙ,vhayWpbkj*K=ߠq:; U;NYNe8;6(]YyKqoJFZDB$./:Fs=WP'$":8DD|g\3{>x9BUWaWUDfqy'WVerK#e6ػanrjPTz(oo4+MONhΖc;TWkyW>;LgmM8 2n=`ԉt6>Ň3mk΢%T3ԣ/1,vXM}Ɉxbkwjݓe,I77wc>˴cnKrU!܍c*^T4nRTޏHe99 QEgr>u/Rx)cHɈ9aݶg^m3tyDZ:֘Z47y (]S]RJXO>9C7UzUө#gZninP0mTb5Y: Q[׷9}Br}B2"^Saȏa}NUvC&l9eK|^I1ׅΏ78'"> jěYJ19^??Kؘc\C:-IN3nzސP%/Izk#܏~#}ϯ]8gL|+SLa-`-y A 8CַFXXXOO< X җ5LJ6x@LcFΝPbcGQQQ pc3˹sDի.\hjjdX3ڵk}poZEʕ+"r^x@ܬ"裏>#>>>m>skjjDdϞ=}n?~\V;vo< X [9sQ(5)}F p?g>܏~#}3HG p?ŘJA TUU1u0L"ɡZ{ޯeo|cʔ)L |AjeZZZ+L.S]6_:O߿GF9<<\P0\7ŋY eiu8FYP>Kۇ+Qd4};0cN?޳>w0aX& ka;0}~zP`Œg k?s?{g{g_Tцo'>.qo>-M/2NkJM }h0se%-|;}|owΖ~zW7k:â8fjU,UQ2 0Ɯ>g(#ZGkZ_&dҐdBO}L~?].|XDD|#Zyz9]k?޳bO"y=O{VJD|#JR7D#+6S"O?yT5Bٻd3Va^hu촥/`L/؀hڞ^X[Tm?n9y]^x!5{{duSA1}Ҵlqտܸr7}ת(ݘn|czƓ}0o?y}!.xS7]F_DJEQnfoj+ K-*+Rt]xvK@[u_/78z8<֏trS|k'f.TaFRu/(M|wќMX(K-+~ip1^So*޹20972 bQXiqZvTz-^ZVjvRkY7O]M%;J`4f'ƳൻBT]ѐ.?Y7^_i;QXҗy[q9;-[N*zV6絜%V핏[{wUCR.ܥOy='5X޺{7+-- 8wx滃-?ۺJwMqyKZbklQ}i3+#ǫ"Һ?叏>ߪxU3Z.s>s[O`rZbV$019X&F2x!&\+mWz1,}Htk^=VcUkQVijUu)eӈnQ\@J6 w -ue&WőcW"7D&3B4"SK7EDTC7x FrV1SWuKc"b\_Yx~ٺpr]bbZם;w&֧H۹c)<:|JlVK{WCoKVDk&6_sR m_TkK.lmt/x&ܘ~I8tKGh0^rM.E GLVkQĻt=&z}`>Agx(gz*"i??_t]/&JWcīۏS{7V79EDTRT&XJsц"Sr JX&bQJw$]6q9נ{Hyf\!6θ(hnA׈c"N5d@t//t&z}`}bU'>G""]jl_WGS[GS[GԈܔ?Eo~&3f <0#Ju ͇o0NDvZfz_ai&HՍ1\L7-Qս. Uqu-?;6+L]NxD'No.mػՃ]^a6.>2ڵk/{DCG.SUU5w\Bp8D}o,^8**$r}2{f}a;0}~zP`°L>?@ w0ac==k=kuL L>q}n>mOq_Ϙ`D_MvK? ?9yUUULL(gF+ HG p?g>܏~#}3HS/N~Κ5 F1&c;yCsy~#}3HG p?g>O1.-Ҋv_(ep[j^7퉁9*Wm?>IGCکzj}Vt\NaZ!}ܜf%jJugnNN!Ɨ;?\]S_a5FE95}G"cb# KE29 ҬP̘wD̂00*Nmg$:+y zMdjnVsdҸՅEKֲ% . N\:1D#NKAڛdS}WPtbź:me%vqjC2֢zyrg ï@K=NOo,_%~,R׫*G3~!k=]{Uگ&=;7#D=l%][֣7?;sp{OtZ+Dd]dd?$v5(h(wwʹĵ9d&o.:J{sM,''sֲ7{I PX4VNJyGa}wwU47g= 60GeVu?|֯\Wc+IpJ>;WEcs#VꁽDg٬OjT0yRj5᭳:y(9{ED\^Oqj"W !)ͥZ^U"!ږWKN^] ^8R+x&qW{:E9HWs.EO61ަf̛#Q3\C%"|qWW2C!?WVuXt0i9}Vj\"*U_u륦<PԚWWvIbh]ji.Z4U8kDdjΫrJwP(-rS-Wv6(b =u)"V^_50gFp ܊˶W^A x-&7Ϫ)6c#5""i}5۬]](+UZNͶyf\!6θ(hnAא+ED\njbJ?_]p4*ǭjO\bhŶ6 c#\"_ՊY7+>0WL&nY& ތ^o_}v|3{M 9g&"u.נR-i5[]pո߲ˉ jGYk$|M;C]9͗Pa+kh5#eqdQOwgޝy>C܏~#}3HG p?g>܏~#}b26;b8b{mUU7)S0WFpڵ/yS!4a&f(ڗs u jB@4nb!P)$/`0&%}u|J^ro'Yg._4!_=u˗Xp||WZuǮ,)UÝb iD-Q6=X[8\Û_ƲS#*M`pttd9ij @ IDAT1\Qfb!u8""V_ɉ}XlYޝq\"uSO=SO4}IQUwuVS~~߇Zo*M 但PU~|=_Tq[_!LRc2z+ծ0p/kuZ侵MU ow`&g7q֗^g ]4ewg .\pvTWmy[g-ore=*mHdVś }Khgy*cU4mizج-n"Xۤ mхk5W& )3!yNzut0J:7OƄs$1a p6ktƁDm񪭱7[md f pͦjj[/4X}MD7``[umC]hCNc)-JJ'Gڎ ^8VԱqOiؿ*=Yz/ITJOXRyfwjbbB>J֊ -vJGgEy;!U{k['W5e<5x Gu.>+bm8:UTvq.eQ[خ ֕V6tyE'v;u+\UlǎܘɵaoUU˗~9toQbXîSEDT!k'|]u)wy-| #cӉ{0NsS>nVo2]ǮD?M۴N̏_Yܲ'phH__lQU"bϨqseI!Pe.?٠*,'O5 ?;[^ׇ;WYm8mNG"3|}oվ>"[;FQ53@]So] 6厬ЭepO-[RBխٛu8|"yyƈ뗬+~%lP]6O@Ԓ)2ijm06yh;ĉ!g.vWe: wgn_ӷ/xiHH`r&Jnnu4Xn9`C">f~ᗫ6ݻqфET$m60'6:qHR}y"vZK~U"bmپXhM30isDb ^:fIbm*J]݇HkY&8kשII9rxy$_k/CeCuJV U/VD*'q2hrhhݧj?GyU+U"Ё{;U0hΗ-Yp;|c `h3ْu/DD$dΝˎ{`/Z&ZZomt]}?zt|@YXײb~ O NK)Ӂ3YIfZzܔuMɤmxduV4d i<4w]ro$<6FXr -8:ϑt_lK?Ȓm}bH}Bfw;i\[ !7zm6םcx}' /Ǿũi:/txB(L}l!ay6p};O'P(ؓBaP.5PUo>y~f`7-=Љ9eccc'+"M|O]}ekmj 7'iБb)cyhye 6z>?0Z ei]~p6sh]!wSWmWcL⃺LhmJfN[V;vo/v_k_xw͝Xbo?Q76o{ Bʏ]}Bkel׾Cc/ P}~φx2'Ýԇx=O~kn/O}/>пՇ:?퐽͛4>ϗO_筏ᑰ;Oc] s\UUUKK[r\}7蓖os3شλwӞۺ.Ӵt_^ dh[g}^e,{O<Ϲ=]7A2MнH̺; oLw.t;)Prg2KWytvuW€m Wg!G5z/w_{]ɻu_xNd/~w/< !=Sot?_S_87oSO|Sۢ]_{7N&&&f߿z6m`׍7XSSqc~^ڼy߻m۶~wuWcccʅLwBz% /{Z,gB~]s4ެFFfYKKKss󫯾z677h nuw9Rl9]_hqHgnhll={kkk׬Yc v+sLϜYmm[`n,g 3}`๽+B/`V:}`צMCgB~R AMy;s@]4111߽իW[5 4>0L?g3g 3}`>0L?g3WǽuT]tErN]tQT̋&](@lٲ%u9Mm۶E8p>?ڎM6Gmllsm||X,VUUYyi h R$OMy/}?s~3zf梹sP @ A +ϸtttLqgfjUu nhh4*s\Ay4x{z}[AA>nGc'A A 0qHo'A A 0q JfmA A @dq JfmA A @d5 &sm=ӹg~,%W\u5Wd^}iMD`ǫkk+k_;r'g}w0:s[Gu}E, 9:BfɚM!Bޝ{ڋWzIۓ;O\W6Lo|3?i?$ٽ@P*/V\\}W5\lյ׮hvUoyewNy>|lVi h /q;\wG[Cag{2ϥuv-4\= tv쯺ͭ a]/+AU5#o_uaizZC5գ7hef|pK:nR{ٰ֏~Y85_p_=3Ug|}Hm΃ 7޶v%s}n}cS}u}=;wo^1ݪַBiw|cSA@A@ @`F\n|tt!SWBMnpMkmW=z>'C(vd۶w >ţdeKCu =EvExwK! F."{ {m{qOģz'?zf+ST}5׶ԇBCӒR~l<=nfղLuM+W=NrțWnX{D9R:ʏytLp=0sU͵!nް|=on:j/}㵗Wε$A@A@ @`}e.W_v~}瞞6Ost뭷rM{FjtKNzSݒl8z/_ at)Uݴ%/  +.IQzKnK o~-,ٰ76O^9zFuޞ. cSk 3?Fͷip[o3g|~Hibum'~^;X9q}eHW_bSκ$A@A@ @`F\VY+FG=6{[7}K\:PԎB.Pܾiuga%5UmCTeW8+]_wp{x78o</Go|0*{`׎pM- 8{} ssEumCCalGx/=p77Uzq.2{;:o}t<Ck[UYv  A @H)}vF}ePrŪ6z7v,x)^xtkKw7/Ue+j>7X}ykjQ,9jOF|̴߲iEߺE5pb`F U 퀌7l9{=N!յٚM!Tg;' k3- o;?aJB4W\V[_;{B)PxpEUյUXihQ)ҞgDCˊ={V,F.4vՊLw'+RwX{ma|BՇZVftV\BiCWmxTU5d//!s^/vBZrZ미wvض3Wohǥ±ULy|Jyc|/nXr{GX5͇аrWo{\_vu|_C4W;$׵bBh4R^z>{wzG}|z'};-Z{￳mQZW;(K'A A 07 y}/ ]ej{7ׄ[nZԻ6  h T>/Zs'Ozxm,jZ<64tғy;sB/BcyBi|hUgxttԠiM㕟T,BHK.潽 i?N̏oO 6mttԠczttL1.޿ի~[]w埽p˿l}o0phWv;vK/{Xg(׹?z V.dAa֭[lْG2q77^~ j{o44,aWX~=WGyϞxcͽ^(+.A A @d5 'wS=o Vnhh4*Y%6({*8  3}6(KU'A A 0sqe`)?d%I4h̍s\A4j$49.v@ @@A@PLb 449.v@ @@A@PLb 449.v@ @@A@PLb 449.v@ @@A@PLb 449.v۠,凬*8  3}6({*8  3}6  h T2m2h0׵#]z h -m  B%3}6  h T2m  B%3}6  h T2m  B%3}6  h T2m  B%3}6  h T2m  B%3}6(ֆ{*8  3}6(k2B)$4f9.v۠ Bh\z h -m2h4<B,$4f9.v@ @@A@PLb 449.v@ @@A@PLb 449.v@ @@A@PLb 449.v@ @@A@PLb 449.v@ @@A@PLb ʦlBkU'A A 0sqioυ3AA>nB㪵AA>nhh4*s\춁AA>nhh4*s\춁AA>nhh4*s\춁AA>nhh4*s\춁AA/( IDAT>nhh4*s\A95XB'A A 0Cq`}Kk` NA@ @`Lb `sg!n'A A 0q JfmA A 2}|mց90}6  h T2m  B%3}6  h`[9.v@ @@A@iW0}<>nhh4*s\춁AApOE`Lb 44X6JE`Lb 449.v۠lh[AAl>nB㪵!L6PYXp 3dm ZUg[Lp s`mA A uL{^63}6  h *IfmA A @bU0}N6m  B%Kyl`o<ȣ>7~98ޕ ,=٪Iڵ遛>O{>۾8+k 44X6J!l%55ccǏP䯬6  h TM{??;Zw488믇|fӼw߾} i?NL=o!?7uiT/yرc^zi|f{;?}ׇ~7]<9!;r_____WW={V\yJK.$ɏ1g߉GZ?/W<.6ut<米:8:jQIЎG{^Mm9!jPwg\Y }[. Y/իWjBck?Mg};Hs/nk5_y,۾_o{}2TO!<\Bc{%|"nݺe˖$nhh40 }93}6  h`>3wq JfmA A @b5ЉfmA A @bU,B>nS-I4h̆s\Au!d׭58  0}6  h`H }FR9.v@ @@A@e#Q/.1}Nm  )ץ2}6  h T2m  B%3}6  h -B>nhh4Xv[$3}6  h T2m  B%3}6  h qu`mA A T+Bՙluc&P bm C mkޒ]>amI4hX!{CmkWO9mT7X !dVAAܘ>nhh4*s\춁AA>nhh44 Flq $>5!R>g)9.v@ @@A@̻h\ݘgmA A @]tUk-E>nhh40Ն{Cu-,scmA A TqQ:CքY1}6  h`yȮ&/y3gmA A @dqnp, ￲UB'A A 0qnp;te_-8  IL6u>nhh44 Flq dE憶"Lb 44ȼ.QZ3}6  h`v-scmA A @dq JfmA A mBůs\춁AA>nhh4*s\춁AAO㪵!nKX5 &v@ @@A@̻ѥC|Κ$>n\׮B}[l h 393}6(3 Up VB0d,m  B%3}6  h T2m  B%3}6  h`ye)m  L"05 &v@ @@A@̻B_$<9.v@ @@A@̻⑾B]Kk]KLq LBCZK>nhh40JB+>sLb 449.v ֜c'A A 0qm8PY|W !v[[p 3amA A @dq ,*{&Y0}6  h`و.PYaDSDb>nhh40z|F{^MuC>_dmA A !d7X 9.v@ @@A@PLb 449.v@ @@A@P7}><裏7veAz,BuK[-#8  IgLRBcjw{G/~clQII`!ǫj; i?NÝg.9/4߽ ;:NܴiuptԠwB梷-mdž{QE?.b-X|FL<#}?aLb 44X6A[ZbmA A`܊98 ^ֆG5kiMbs\춁AAq+> $s\춁AA>nrQK'A Ku'AHm6].*Zm'A t[gpL[ucRs\A5XV$4dDo^"q I0//aE0g5 &v@ @@Pr;r]g7&R~ /9m  Bunhh4bu']>2q}+ y98 B>nhh_f~8$emA A @Qtя"-Lb 44e ׵K$HBC!LRs\AJ^SYrkNA F[jI0>[}|>nU<-'A |>9 FO-+8 B>n_ֆ{Y^p B.Xu-B>p2}6(3Bix h*D,d6=x+]t$s\춁A!0 8 ݄0is\춁AAIvY̆s\춁AAqu w%!Lb 44$׹#Q Fw%+Kq׎B}H m  B'5acqpdCՍKy2}6  ]/ d`7W>nhh4*s\춁AAYdp0}6  $4=>#$H:80fs.Lb R`sg!n5'A 0&oW%Lv )WGz-E>ne AP!ofus `c0'e p>neцI4hXs];B->iamA A rR=ׂġx/Pgq]^yBᩇ8 $zoCZKy2}6  ]kW_Dn& 8 $i.Λs\춁AA:qW^w%'AH(m  c]4K 9.v@ @@A@PLb 446kN\gH m  B tg7;.xUZ L6P dmA A་]jID mk,E>nB0I4$Y=)̍C {h&'(ELb R`0ypI4hXFzC 5.-mlnik|~4$VQIml0^ h^tƶa2[4N >nhhFtY.z!>%$`mA A`LRBѥI9.v@ @@EscppՍ0Wp>nhhR-ֵ, 8 glt=\ 9.v@ @@j#䓋aG)?Apd:wɛq ;fXrp0 }ar ·s\춁AA+g׭$⑾BݙN]2}6  h0n m.u NTh/`Lb RX>A@=䝬`͌/H NgmGzY^^8 5N$t o9TȤ|>{ByoWWWcڏ78{AGǴ;_!l=N8$hNmM~.E_*Tg=ï?_W~_̽ʼnzT?~G2>n~泽W;^՛῱V}|{NjՇ>֡~}T??tttt_^՛|⿔D2jD|G_zo$g};HXc{;vK/{X}>7?={s;^_"ühoF4x{:Z^ *8 ^/'b/}k_\׮kX}9<[nٲ% dV#*E;  W)?{Y8 ^e9%uti.A AHBvD5XzgO8 Bys\춁AAqki !<8 B>nhhIuc&L>X$̄s\Au!d׭$NѸjm"I / /JIcmA AH|.PYAp4mW3=_eĽ>'s\AY6 NA(w#ai0׵kn Em0Lb ʲ$S]8."@>nhh4*YZϯ}Adm !:wj+YtA|c:}uL#nC$Ȕ  6  WtOk >nhh48{=O݄ЫIE;pՍK.q ^mkC>Ne,ځAx}]mA A('u-fI0{E}c!׵˧/iR<}N6  T 5'19oApLs*Ε7b `L6/'A ThRYAp·s\A^TQZ@p Ik0zDoVI#\׎$?nhh(zyt4^$is}co2m  BE:.|܂(+Ew:ȞNHmA A(33IbmA A @d)>G.ȕ@v@ @@A@̋|>H$YѿBRv@ @@FjIGuiqm:$Uj=aL FO:w3"8 23فN̄s\Au 7A)i Bgv$LdsO6om  raDpsb 44ȅ]D cmP ֵ, )8 Bȶo 8 )hاmrm5PG>nhhOCų.^EO:݉ I"@F\춁ADO:l15=*OWɆJC>A8 Z4Bhh[c)R':'m  BE?fF?rj+k`/3dN F\  ̟GN `e~ WmA A vX 9.v@ @@P~N\a9?Ap௄}ފstIc 44姱m?`kWz uCNOEIJVtOky5tm[肓 h*[=a˓Np卸m5X?BAP٢ [Z5NK99HmA A @Q} |lv@ @@A@\09 $]\y#.v۠\̶o w}APiZv\gr!/')9.v@ @@:=ar{FMH F*n4'%$"#}!:gI a=d 44S{ҟIq ,?p>K9>nhh4D( %5 W+"!=}vZ 6  sApddݩ &h%zm  B vWϡq4X?Bd=c?8  qL_\oS}ߵ4=c:8Q Bmk=՞N+ڄkYf)RL dᤧ%ݶ~t~$48]RB[zEJ'O$~ynN*ϗ~s1VIV2Wވݶ9ia>}ƑBG7|.OjŻ3nW,jx~!-jȽ|?:80׿m;/S7( .蒾u룗s QuCv tynNYzʬ^"@p(e4Nf3{3\>W=ޒc{{{OB=OLUW7^.ۻۚ8&03BDoiolvϸP5j,ň ;LqBW:qvӦMV/ǃPj5~Ԡy'B`L NLL\gbϦg~<ᡚ%͍| ̟O9Ei߿zx'σ~n]'}g};ϗ-iVc{;vK/'Cm]n_n^o}[W+~/_O;_v]S'!֡-?m&S}_U'Ϛ&wHl;Ypѯo\}L< ǯ47.o/\gx".oSI0Rb^gB}>֭[lْG2qž<Թ/ w~g=(`}C3l- 6]7)?ѭGmfs7oƃok'wV7tL3=i1Bx7a>sFQ0n1okY~tup;@Hb" H$ b IFN;ng쌅#mڝc[Q[wھf~3tW& <@ $/)7M5/'%|yy:F!$ZgOd6|spi4I'B9a42!:.|">8d{ ۯä%{di@e8z.>vo;8[엥o{,G{U'9#01Lc郝/J/X$lyE,bC0M_Y R7Y9a% 710Bcl/7s; }DtTV2_ {d~2BnjHXl">8aGP9`H}^#6ߴ"ijyN}UB(x/¿t5O!Vs_w쐩FST+e#x2+HE(>8l2S]5 !ky Р:ji fBU|P#l܂ YrB72%a1"13@ÍSbvs $G2뺼=t #~]m+.C{#8 47mP+ڂC<#gs#Ucum/ƯYZIX"v8WU 6 d9gUvCai>T|!}ho%:DrŪqZt"?[̄ XmNg 4thGܚTr #zF [[~24= }R'h KKOjX"6Fm?F$M\yxu¶n@Hy\l P'D#9"N1)Â1 %BeΎ{=\9ΈGR^.N޴}J9osوފ8߀[DV8W;#c"hLjVsC HkgNl^}e#@Z5;JV<ғ[#t"F\9Py`7O DGPbvR}A|[wR&/OkEQUo*w+rf碰iNP|{D, (CY&hout !wKMD v-KKw٭O9H&!гK2_!H櫑Ge4xIE eJ^P_EPǮA>>"e7n*GůɏHH"s̏j[0ev]WD3@]x|@$­c`f}nKwNрS@ _?!Ȅ# $?V>]Y]/O#R)PH$y 6F0Qn45,_  ӟ*5 @*7}ML޴ = Xcq6yX!< zgy+ j}! r'$U*r\v+."F 9 ;sC-BhaF8Fn}$-:pҫն?x,Ma1xEb#Vfγ[W8w!f흶l4g0>!gS"g߶a(6m-}^)v]Wok"[}GBI_H,IJchMu> p| D{+0gK`9Q0}eT9T4Ӹ A;䂌A!dXi 0ol!?Xcw;>.sϚ$ހ4Ԇ .  Y)vfbfwBtlB._uʪ9/0w9ou87#H@EJU "B4am|A\M g 4ӗd~2B.-#.suWo5@igj<!*8_~™5[Qio0E:h_Pfj֙_J:Z2K'HD{k >eo ̘{Zş#)b,Mu;vyXoQfmj^sCh^v lV_7 kK l}6BngsdL*gzc~M} Vr.xOk|wehz,ݚ܁,m7xЮW+g/\62sTH^@ϐ Ae\6>s-1' q?3j76{BI)KO o\6Z}=LAP$W.8(WAdVe|^H)^3@G&]x"L9Pg܋m!6;rB %xO XkKs:xªuDr3;uqp"2)`aSݝ/mϥ~!s%R %ms!7 }hg 4TمBfAy04C1a#|@@f/GFFW㱙^2:׺B{ezFCn2.G?uhզ&Ɲ~&%Vo|:CU6\5s}-G{88E,<&>Z[O֮rوP`3ZlD6{hs3(KK_~x?tgP|QX"ay^]TW u~swҮ|Zg0K𱖭C4d2(jFKyS}m$ pGB =|;{i%vm57.QD,MCM>y*5Ż"<;ztާ)* C,- -ӌ`-sGb~#mKKTtD}%6y3M8F))1s3kB!IDO 8F6>9&^c'dc1ztK_Z6'2&CeU1*fHdT;Ā)4էVA@ƿK e q[Ac Bu @VegP2_qB I9Sƨ y w \ lJz9U !-+<.IJZMṀqn>ZJ 8Ÿ#ARPBI/`kl<r_uUP܊2w@%ܲr~,%= in;˘ef$S IDATه%5Pi6Q̝Ry5DB[=^HQUP &%FxPҮ]H(TDȄsl% 򺎋!hj`g C2G1H٤LH %Z?Ba[h!_ Vp%|RmV>(Zjcݣ~O1φCG#)E.H ꖼF5k3GP++|b)sq=(YQH(iR33X k=1FE/Gxlc|>L; ;v~,w%(+Oa1TeVORc/z}8GI{꛰+/=LZ|@RIRf{q+_;)zBa?Kc }UE7i`r{+~fδY>sHn e1[=JĜ3_::"dp L&tz]PHR6Azv>L).0\|^>7S0 3"N* 'Iґ\lطףǮ !tLLR΢?îȿ@a R|8:;ZpCM#ӻ`#x9\ N)p4v!.H Q w ?S@cd!]vT9c[q4"VǧFnkavΧ/yG^~S2LG<i;?hkb,,D׫g/B;&[$^AR͎}96Ԓ_9P4kB HsJ>)|R 6Kg--1@6V2P&a;!05?4'y!Bh P3 $I"Bq3Ux$ld{pgNӀvn~\7><$V% QV݇vsSB>](%Uy&>4T#bn!Xd7p19ݣ.At1H'-#yy*G2+GB4?)EF1+f(УW@2LB^v}zvw∌]6"H4'f<XF}prmde轜 9kN~pLm7["O>ƭ 2  Z S.34p2+gٜh?p#3Iic  y.G|_0j?\[voxUFb@OdnĊޢGӃRaa g0V$dG?.RUP^()*~̃'ͮ1 OҝoD(~ |q]lt cnΧO0߅)vi7/ ?968|Bn'CybxP llfjYO1q %˼PSc݌?]CoqX| NR z?aex RʾA΃m0H>,Fe;p 4 J< ApUDho<v?G"q@< c UUxzgɲ/t)@3跬y7,㪼B~dS3lpg+p[ޑ]\4H(;J4E%W,V\`1t]ڵg}>[s}' I-d.a Auފ2`2+pbW8N=zWM@R?h4ʜLRKK ^Ql#E?(%H EHl/k3UuL'9S]M_QbyRfG I{H^uACXVR-~ sOFUPu-b\=BB߭]v!l|z#)) qY>q٬p1%Վ."_+ݨSSS.krrS6BCD %_QTMf!cg/ϔİ!37% vَ5CXϓo}d!\"Z,vl,:eS{>]*5B(v Yvr|qи!M^DIOZNKOnW{]˪B>,KKWfj|zTПbbMH;E e";s(shw&88)l ГU4p N(Lؐ`BRlt Dnndps}r荁 ~9#̞ tQpe- ]O1QO$Hc0 jۗ܊A_a>>:.L)FnPl WSO)7\ȃ=:huMр`^ɼr# d!]?pƀɵ& MHw.Yťz|xκk\@}P֫T\cX&Dz94;JV>>666::p8R915޺sjjSȐ+Y!$]@sPL\H.2 9h:>feԸ|~r|\{wKgAG5=Xu[?37ܥhi=lp}5 ':%5bL>}g Wq{f%:ڸ2gy+ YSjg|K)ߚ{pG 3"ZΆPPPz>$[ah6Y nUCk铑UhRK^8,)y_Yyn.VrG"U? R BZYYNL!H4(FpI/O;AY?or,uD49>NLG׆ۚBq$*DN\!nUH.q7+[4<49>.V'nkvS~ &D8>X-PO:̰dx, ev.3mþ@/l{)էq׉1~)<88ӟ*' M(<=Q4(ǸE :I\![%^@)"zsQ a5Ȋ DGۥ][; <}aG)0h/Pr!m(> Pv2_wYf!SDW-bXLpXokMstK-ދ UAaKKjrd__~y͓? C͓HZQQQ"!sXu\BsWcoX"8MF8}V׮tc{M@4m iӛtF 7l_uzwn#CόgJ`jx~3>q kfd94)Yz !3ᓂR`JciݶX􉒷Pbg5ږe!і pρU@DGNB__UWQ&.\i&H~.n $raPf1}dKK%V*5hj+]i4pa O[y~f:zѩMɵ0/DlȻ:-YhݪFx` ;o|p/YqmpUg+A)q݆;Jߝ F^Q8,J ---6Q6pʏU6&2{Y|ujS̃ǹW\bl .0TS΍_|(lg+(IEjh3755䑕WsCSLuՔCÀ 2" ԥ6¾EXPy픏쟤Ӌ S}fG \~:&v1Qg|t灟mܚZZVԪBs} qƩr hoWV*YS]5rY1;g85@AySӰx9' `e#z+`sf5%JXV‘ *Wj6sQ}2yZۮhp#vs} FPN+x@9Z-Hpoa"mN)*q٬8 ovSSS::fz9ꮕcSc98>8#B;~?9}}e)KƇ[G )6-ǐ.ɋR_p N7^ȗdF%%k^Ƈb,>VK̶v5%d[:^W|b2>D%+桋UTW 9&%H#BI\s0X[ϫ7m}g#uz3ƶ`sv)T0ۋX6WͧOUPHj?5gc0N; H?|MAɑf{1` {яďROL (3x)Zs72. !pB"3;/%\ciOM Q`y(Y/suWsdW;Ө.R( OUMBՄ|K{HE|6=>-T1Wv-_X3Iqg1/%aBHC{; D-8dj*H&ncseV.Lç?0<8i!bFSTLf8<ŜJ_!…;J څ;JFX.\ޫ4"3;WkUFS} #`:°[15cᎧ;-}$vgbÂE7N/diiJ+.I0膇d7 eH&C6*, ;Wo*'){{WQ.R Q0WgDԖEgX~ [:͕NmSSS.+?~m\;zGO&Yk5ꈹ9sbbb>J,E}a99>}f }1u9 a6(ې{`<)o6^J-Q%9MQuFD =;zubî4M1LGߵ!{ rĒ+Y\u%v ?o,N[~EÅԒpG6cPRH[bH1+_ B@čuimXڛL<}Ǹ>})AbrLjPWvtCJ/bYzjM2_́A'8GS$)ء'x_rd)bPB2k Z).ݨ"Xru86dh#:0L%rOL_'/0)IRr~Um`ސ9hKScokUfmpf rmt-?xL_YkQՒ-Td0[.àr& tă l pEQE&qqsPzܾψi q ^;)_d EP <\=sh~'Uq4We]tbVn+KH\lDa[@}Zmaaarrd[[g("#l2UO7ό>O;7޳.W|r\TΊ;p@oooY٭ڏs 7v{qD#R%Q?:EܪQŒLhllhh!lڴɍFEM {c4y˖--D%sW5OS;+D9wy݂wE9׿9ߡŋhL66:4ݼI}b IDATM}}}iZTTt[n]lB(&& :t @KS#kl -I;d;˵{/Q;k㢾TWYq!AIRg3>GA[?xL~~Y}ek.<媄Jixb<<).JA3t91n&ׂJGa9bsU l}eŀqژh01-}#cGPs[{O#BʄU^ڵU$y)bjIn۷}?ܻ1Vf/JTbx= A27hyyjT;_(u!9vS}퟾ Hd":" d~#coM|iO6>Hec>wٓ{E\>^;Dyv@jE^'1;naa=D-BLct }*b,:[k.$rouWXKK Ũ !](*FBSaL4]W,_paկ/Flh4 *t}qs["-e㏆>w.]_Wo.+..Sj6zkMSlѢE?/M!TkAɋiwYz{}'y??2<4гJя~t=܊hPyڥrכe.7.\O~B=N36 mwW.O}O\KwC#[G}ٳg_⋟~}ϫkwU"hZwEEž}7<<__o6e׻'W@G;`%pT/Sf8)cxmؚ|O+r:0l1apIZGlZr6f4͓_ ʘdxLsf캮ܻss Ft`(h][!e@B|5b-}a #_vX\$G9.qXBHS02m{|S}mxz'PX)vNMۥZ[+|' 6%->/_[{ˏr]1(3eA'p(5Ô/9pғ['YpPѡ_׹İSQFK1N]ckW&R UqBPʓg` w=8>v~Xʬphob2[|d/;#k*(\y ̸0{b!;Vv4Sב-_.NOF:Jsk+lU J&E~2j|rΝvwP xa6Ɛ.L^Of1P<-1i-׸ rN*ܶ>[ k 1T X?R!kO6J-::Z,GkR'uWm]_'.]n~!DGG#^?RX;/E"D"1 SSSr։[+C%Kv_RRRl2000wؿ/C+bMg; !Ս-M˗/?bx||p=C.l(bYkxx?<+K,Ĉcޭ<;x|rrRP7r8VU$W|UwT"H(^O~_9sfjj[%AШ-YN+-4;9w_[[dx!_7(W닋ׯJT/ќVҔ{+0)n7޼?#l_]b5ׯ?rhs_\F+V[路2<ߏ_M$6^bٹ'C }4dyEP˥#}tmAЉ "| sfnͰ!$O)rE e3fy qQvS~ ?TNka߳LĦS }Hg^w=Qʯ1Mi)3Oy%M[ҮZUFstو1?N܇}<yZㆃ}Rw_&k\)dFAg+ɣ.( Ӭ#o[(3s=j3rL]cUnJ"|\llX1lߑ 5E%r>!YCH^4]6XU7w * g'nKg;p=8[e b6X}[hJp8, i}lUj>=`1P c7 {OMrkcEleCSYgR#pqк'9(VAݔ;3Ro>a#l.\NT"賟 ;J׬ zFӕD"L&Y&Z;jYΙ\&V&D0r@''H9sf׮]fk/MM:dD$''0sϣ>sN }Vg]XSs2jݵL9fΉ]fMTTBX,sSmk/|e$*//{=ǎCi4W_}d2MLL'fٌ'~o6~96:6dȈD"dvÿ]4~%KaSCyEqwU?wB(%%PYYڵkѼyQm_.¨¿o y߂HTUν{h*1qW-Zd4~RX b5B(55uxxgwl4b *ϫW_7!QNH14g\GB*o\6<(i:m3 7m4=~`O4O?V/'yP=lCɘQjJ!#^UFb`;nx[hmwA"}\}|lI d;553 x4>sXɓ]ci7f? ٿ u]IF q/IJEފ#oR>1Ė&87WST2q0Q˯:ε4io(S+OjjčXwVG+ɣ$IɤJSA]<OP.@[׹nח6XTݑR74d/H=[%Iv7tgA:Ydޚڌ2<Ś/T:'c]Zq2i4PyH5͎S]Ӆ%%Iʽrԛ32E#v3,F&%1ny("l1jMWZuDOe }>Wx0ASe.a  D{koQGO7fj"ov}T'; wD_8n͛?[ Չ mJ%C=Y ASTl;5j?gz1%& ڐt}/w3 ht͔ks|/~K"J6WLPf; 슾7P`J)CG`-K@q%ފ25gRw* pP3n8J!~}lq4bW}F6=n4}ZlVd$G"sY&-!x7[iUM(o(ؤ㢼I  X, l999rK,)((~~o/ȸ;kF;ň% *eOyS_auEŪBqB-88)Y egTo~~a+z]N[vnU2RSSKJJryoo~+yo0f9T9njŲZCfS]ʜ/ ϢƐ.Ʒ~oZQZ[[3T*BtSmc/]bŊ+W^t)/rl^ #0 E%ȣ˳pJ~ AHlu}(:< 3 i_evGƣUizo84/Ue4Fs_$W0%a>ey+ ܂wq}~Rc(D()vRl٘ುurmde\5iJBCO*up#e.6cH}e֯ <, \v+s 8n<] ,)9R ;vy+O[<IK z_i">rîb(`E0b>iݙ*(LybBw°Bo : xlukR$aKU~ȓBbSc{1e97{{C8.LNѝXU!4Ɂn܊;v,]T$E -̼1Žjoow<~M>E0 *H>θSð5GO|@F¶HP/o|;a]57 Qt!)cFBJP2ymp٭vS˺4"d:SB 2RN^i, Yw6H%p8-"l/dy˧*tѹ{PJ<c SfB) (j\X ^G⧸K f-MIR2 xS@NAhoD Ą}24ۋx+lG~ʠ*" b% H1G mG#6'b)sW|'ms<Ԓ>_-x;@l;6|Nڌ'0(lBn@2ݹ!gi>PVn=n_w(. -2}x_ xs'J  zNt\-?Hl%,ӓ4111RtΜ98qg3֯_aÆ?&b${'~ט=4}qɩj~.2.\PRR"Xu&J,v.Ef,mMXn:.\b/^ܺu~#uuR)H/&//oܹ=c=6]K bb|W1Ͼ "pP_Uq|">lWmOcYm:ev.R}[1&EOZt[7Y#ț8c;H.C/2yH)`?9P=Tq~[2m[\sd+w 0n(S܂`zA8@#&] iOO'1Akn%[{EN%I<]@PlP8{_2٫PխJM2_-\TX}<~TWY yMFz{.r'ȵ/?k>-"~`"S}[#/PR-&ޛja)Wg4] jB  ϘY`}GyGδ(2ӫ]vmɒ%3~_o_w vmEexQ]zrs?L;?OyjZ;Gښ,Jt:y=[%ޱ)G]3;Nj9FAƓ Y;9?5(tg`|T#>}z۶mp%>Aѳs:Mٻ24$-F ;cp؜XӀQ=#D eB^zv(8!/_@WEŷ yzsL;E ES5?47+H&R(AT?0HG;I׉s =ó2){,t`ҁaܢ5-M!xg!|sC-V੠{G IDAT@QvW3eVŕrA|i4V\ҖY:% tnd_d꘾\_KɵN}?9HC7qBbܪ'>pg%{/h]@\lԸ!4W>[}_r~MHlwYl~]Qe,y*199-~'*RCvFkv)#O*&,#MJ8[91n}z87Z"MWߨZƮY_<-# [7u}2L˵;qF6z$';||^-\}-9rb>yS.k 59Y9_ﴍNh֖il֑M#BAkIf`JY9HN oɲ9mF̫3 beg^5^yZnn(\XT<#&MJ~"_KCGq1§_ZiLtiI(NHWV5^$W!GXs5EŚ}YYYp%>Aѳ1c^]͡Ag]qrkrKOe!4a_bڋhqmIB!"V ${[_@[UPsp 'E~atCt3}e-;[VZL47L;Ğ19\Atή:,[FAm~9 Mv]7߁U >qn^{U\.kh/@q@6C$W84A*2TW nU|qF9ܠg2;7 =O!KOn8WA`T&nCt\Ag/n!GOt}/Mm! 3VM)!N;K$m FKg?e?;`MoQ7tdB |FmFT;XOoKQ}RL9 pN(W}_ =-*g+BME,Lӷ\&{dY7ף1Us B(F(MX&Q:E DiĹ٫fY8J,u!3|0BIRrtO#-"$]Ӥ!L(f )BRՊeRC1ʓg@\_3;=]0t1r.y \v]4@3& g 4%J_Nq %qB"T_k{،=3_SP |4BrjI,/qߒz4LWfUvF cV`O@PsXE Дٹ+O #6,xdFKH?9__Y׬ AIP?nCaQ \Ҕ!&dgl D#&T rI}GA)sq9Lj+Wo?}hx(Y[?BXqlb09`.r[ c%J r:]\c.$ T\/MpqEu:zk<A*my4SzpX4MUPJYTq|IBbBH~2mEl 倒}՛diϢk`gY6߈x;W |:wћܛg;|S|^~V蘩r'CR, D#-QcKB0G \1S9W&J%+!=9 5[#7b sY9W;TfD mSHUl$'+耡Er٭!"NMA-?wܹs?ܟ(YiL>Y~#԰:pMW?5(x*UAkvgui^PY4_+_{wu306" n (⒀5b``4{clb4{m[۴EY4 f+D-(*) QD͘hz||91o;Աjw^h}}'M޻˰߲#Gz}@nS\~C&M~/(]{TJTPSnkۿ*Gyd˖----嗿euu͛;|4zG;v07xϲ ѻ~wԏ7#uuôAy2Ox q|?}O@mX$E࿈?ȿm6K}Ș8q͔4CVN={޸̒%KڛӪ-}?NNN+Vx>{{{={Ct/?>ymnK>oPgϻ+v߮͝ih|W p 鳃G3, Ƣ?-la2#|6%̗OxoT~lსnb?wBOn)"Lvw?~ȑ#fsqqСC׭[ɓ'8PRT]v9s_~񕕕w.,,ѣGl>h4;VPL]vUTTh4Yfكsܹ^uMΜ9JPxxxڵ… SO6m]ֹ3f444ٳGDCBB>eDGݼy;\K~f̘QUUo߾OO .l߾]D.]9sZc?~G{XVV׿NZ֛Ce}!"j~y7Ak a~o/=c8S{ uU?g& pQ}e]PPȑ#xz{{FDDس>}l۶*<<|ĉ~~~&MZ~h?~=:a„7L&__ٳgO lׯWT:`0tUڎ;SSS/]kevnÉ{ZF/:پ}{DD[o;_}|>K.͚5+::zƍNNNO=ԁxg&''_xqҥ{ZYY9tٳgƌ:/Dҳgώ=ãt3ΞwM[፷nhhpwwq 5577?EEE,,,{lyyr77O:˷+qOO;v sgϞuuuss ය+%oYYYZmVWUU+/^6lX u=X,#FDFFz"ү_KJJ֬Yc '|jO: /lO4lذ/~ngj z{ܼ}vUUU?֓κk#002ׯ7;_Kk4hJj;u=ի#<_ٳԩSSL?޽{CCCda;߯__wꤤ;vxth4+n[.S]]=nܸ'xBD ۿ{5mڴvq+8pӧ:)** |Gc|sw^z͞=R>swRT~VVy dX9y'|RDGFF*_o߾+ &:.??ƍӧO|իWZտcdžDDDZjժU^^^ Pk֬y5Mhhh>ۣGεEGG^ӧNʪX,"r%`06l0|Ak(O>ZZZz!Bh/o߾:thVVVKK#GfYfTVV644L4O>ګ---߿/^흛k׮߿?SNyxx(l6[2ɬj'NXfMTTСCϟqO>޽{<fٺNTH~Jl~ꩧl6VM RZmG<== 4{Cٳ)ε?~ŊÇ2eʪU:%##?3gVUU577ܣGexbiӦ=䓹[lZnnn<788gȐ!O?V觞z?uF^}U^^^k8uTttR7n\~~~~~~DDJZhQ>}BCC>YSSCعiӦw}_}ջRVJuQ]y' N>q} Ǐw.8kW233|Ivȑ?9//{)))/ zg^|ǧs%iӢ?>}G?ruuݻw_~)"/R?J277733ӾŲe˜wܹy 2jwy9ksww? /`ZnP]]rʕ+WڻTTTtԩw6m۶m/^O?7R/\ "p E 70((NwppTWW`]0%ڻwo7A7"bM>.3x 6ta6l0p[6<<|…w wLee֭[+**\\\8wCpw={ jkkfΜٳg{… 2ƍ[pl~1ٰaÒ%K C[=>`DDhήB1gV[^^٪3 IDATuСwlѣGMM͛oiX㣣Vw)"wرc E~~֭[ϟnZ?ü.Y'O|Wzӧ744(ʚ-[Xӧ=f=z?6lԩS{})OO* m+; ٶmی3~_ <==ׯ_?sy=MMM?hl;7222 _tqqYbEvvj5k O?jZ/_ܼdɒj*3>|344_X,? juIIɶm esW={leeesCBB:dX=vaҤI}h4MMMΝ.]rww۷#GfYFDƍl2qvv6LXxwnn]HHHD䭷Zr޽{ N:eo!!!MMMYYY---"𬬬744ܸ򚚚>?IK!bS\Mgxj=5ʎ_,VgGDDR}kX>|ٳg:tgϞ2 -llltrr/o."6yŊÇ2eʪU^z555߻*C R˙;W̪gy렓=KKaJ9zҩkf<]бcl6?9sʒGݐD˫}n{ɨ(R[>|833&88ɩϏpvvVT-ӧϩ3UIKsxO7B1iӦw}_}ջmO;8uTttǰvy텟}{_fIBBBt:R3f̉'g9;;+q Vju]xxqbD@?7=Yʫ(S΍+ZQ30l>x0c+G?8hkꪤxڌ <ݾI ',(`yO;gvjoiƃ'n|ȗa\ppntu"b1XKS(Dflܸ1>>><,_^p=Fi)E+ٝSaVϟvMmL()QYY^VZ.%UƲwtՊ[@4{5R'mOacK;f\?/7ekenG%kV1L/7G͞fؐ9ۓ3"RV:1Z-3:1 yqYĜŐP:4:T.PrQ;fqWU랹=CNA9Y)]07vuYvHTf[{yf]3[vĐx<:oY)qkmȘʿTf]tG7Qn>9miإY*-9h]ܼ)ANWjoBuu1C"5~~̉vl]E2f] JFg}+aU ۵GϢ^X4vLQ6-Es]H9cE'oЬ9}y|Jܦʈ)ի(S,HM^ؔKdE<-yu^nmuӞ3 4(<<?*{Β^Slؽ2}c[BD?`Uy nq }.?oWӐhio{hgO\ ~'ҩoՍO[*l_4^dgmP#1i4b:$-y]`U"'L}z{gEYvoyQ4mά))^Z/^qo<9̬ #1䘺A(4+K7jm2A 5 x餲wCYK쬓ԡKuĘk3<YDVC:eyi*ui) cfht~e},;oi)KsbVd>ܹk}-fbQѾ;u?#Vt>7k⥱V?V,V&!ʚ>Ϭ^niVn/+6Bhcd-HIX*S+וs]WEP(hikl~ЄhS܃FLN-ֵ؜bC#5/DSiVfYD N-hM21筟1Q!k֦ŊF) Ԃ~3J_~_~֮.WU("[RD`KM*+NW(s?uNLJ kn ,5t\W98HK7Ǟ/*5*N*Dj_*R]}F3%"&i Wfʊ ~Gf4J-]TO7 $"W_^*]%"b5t:RE hR1^C|[ ?*ipiCsź`u %%("e^''21e,y"N2ҳ׭,c;UXtqlf ) [a*HM31;-G*OƭtUm+37W4 ܑsrH܅6zmZrHV-Y1˻+(""M>&"݋cGj^clz0"ͦ:|Jʝ _snn*}TڷPnp-9Hڮ1ʨ`"ҹLi)vZ!7QD/iu{&[J>zYc,밙rjj93J+.-.M춒N#fϖڴ7=.Knb7=l֯BJCҸFߤ݉,5H^#b t.& bzbL7BƯJ[qrq]DsED1t~SرaƃcuDt]RD1عD}kY`alb|d[3eibъ6zn|u/6+Oֿ#+6Rh]7WeNu-k\NϔՑj Z=c]dS{vfgs,CAiox( DED;8TRlѢԈ[@x3*q%ym,9X9qJpᓵݕJH@tRD?Ƚ}_w,ee@Uf>~=FTvn3}n2U=n""ڠUiS+o7AZuSLj1Z,^ܔmc֖!jmD]fQ/\&kO =Kp^D7vA&+,"X_HCffLmW,^}Pt]sE8y_+ Qh#"`!3Oh4ݴ] 1ee=;qhkvStT7fP*:>Ҙ|䵙SeI y)kS֦gTLҼJMF jΜjnuiW /q*=qnZ("˳"[VŬMLrpCAKEG%>>ERsF71b/f U/?_89 VAb.GXع7\GbNVi,ef.U:κ~M7gxtb>-Y]yPcʬ3"Rm䔬1.]nuSu,ԑkӓenbӵ17yڴUbʬ˳JSbEtUsDNL &1$/FJN\^a,^"-"C~̼r εk>^ {xY1d 6(,, m6IZnSQAI1y,xmhhhnnV( &OQ<2uۙUCw|4M{*,2B~?%tfl6fsqqqww >ĜtV$ĭ/':*=ٴ0vu޷Y3U} >&RDbn4̺b24so#gfwKp8g>x#}83HG px#}83HK]PP;kG p:XXXȨnLacHG p<CW|Q }:a$Oߦ7+]\zj(Cjߧ&-oV@ ]?Xj6}] i,G3SK-UVʢIwppMƠ@Mg.r_ʑ5{G 7vqiQۿiےz3Vȁ?پIٸ>>+oV}K )""W^T>vzY?1i%_xil=ŷG^EDG嶸4'wa£>;:&uܚ0E2!(ULr~UܽMS  z1!p:+-f}ߧ6ᭃЁ| cmj<7SnJ}Іfsƥ<ԯU>ks>Z6&Ea|^g_;y<2:hFa.:"""M5;K{2_* h}\Yڰ!PF<=UZ^}ϠY?'((^U]ɲLqGvǗO8U[D>uyG&?{EL*{d8W pd}T8>t$Ͽ(Tv"梳iͽ^3dVDt5-aƢ*6nssY^xMƿUsU#FX^*"Ң;%,aoh Զ^L7{DbRp?'EDd԰_N,yC>B w`Ocy]u?VjW5Yz4eJ8{eZuesπ٭޿OkzO蛻!!QÝۆEjZEED4aH}y;teq:Z[TEVL7ʖDQ\ɐ5*'-"3\[}j~rbhAׂU'H7iM3vvMfy^jD54/O;2uWW*oo ~Uު;5+W&٭ǏIв.itcgJ< .<]y6[*㮮{uUC

eہv@Pˡn=]WǗ}ƍn߫+^4hF1;lorWL6V9_jWg 6__ҫHk֣Z6}|8`D7\}eR{zΘƅ{$=>ZROVYJ=|d-νV.ԦZuԸQ)Sn!FSkhGn!OWrOݑ%Ķz'=NrHӒ;5|O:|W8zrɡ^)"*sSSS^2t}㦰l<=d:3-ώxc x#}83HG px#}8J Ywiv[=YۛQX @v83HG px#}8M=ELJ?#GnK/x) <]TS%"IDAT7u[gUhFD|:* ʒ+Hɧ7^q@E#&zp+uL,_h0Hm5&5/xԑfcU/-znJO.pg鳇X ;~s2_ڰϣe靈WgiZ0&)U2v!'>j,\ZtY#>mZSҽaO6$j_>ceUYyJVݾ7TaK{kWvg~yqeoUx;j@1n?x}EՁ+ 0@u5ӏU[ -,0)Zh<_ٽЂwCR3kLJH->+g mKτA E$bݹfZ˒6o):L?qHvqִꯆALu囖QWBo!:׫+tN9nQCd^2E0pKق׎,;PdvqR_P;ʵ}v6%t-kcMi_ʯ֝m?1H\؟ԯSc|n䕐XǯgNۚ;ia%=e_V4)WW뛌=i[9[US-"9x#}8VOh1V3jSl6FXpx#}83HG pT.>iж`dNrM}NhVd7]*ظh  5H #,:T0 u tm5/:W& _w'][?|xj' qM"^6޾b!) ̀hxȋ({OV̠mUHAH /`SXZhd#@̆4u#""Ad f`VnD_-l#k1uu4gvT43{(`m=ǾScTv&5bn .|u䷿}֕+'|; P*rwk`Lɚ )yjz˂ ysxPIŅW%n ;^8ii}ǟH2";}V=QY_iGxpKnڥgW[K93BA#G#܍d?M\t!Qgѭba=!ޝ6s`_kbr>W _]w%ɑpF]B7R{oϼY~=v۞6`%'w(E+ >׿XxeV- * \uN݋O%H )hND1X/gg,_2+vB] ?)SU3JsV[dbpOT#J%OnIu Q{ _۴ߒeKzK1}S/1;vDHqlk|r=KZkՑ<(||E2n4yM.d0`@g`Zȩ)u6DDqAiMrdA5~KJ pS#G*Jס{K>3$hC7W,9dԯ_m@ɸY kvO_suĸI4O-.?xI{Pɬycꈠ;?3-<QwȌߖK+7q?.]U0dޢ'MR9i~\7)R kؽwbEuIӁ<(I ?=`Wt;s.wοOק=7İ WFуz<@uGyt4kY:*YY3W73|I#)Ϡ̽S;з_8$˺:?0?{w#z-x_qK;﫞-oE jp/#=m=6,WL\u7. L&Lעo_L2ɘi/I% Ý=I?keJxreC/]A?ܟjs01ʂ{ c΋*xrg ٵf&=--p4eݍEQY:@]^R>N^XtݘE^ޢ W6G@ע!&l9s_OFO}H8Wik=I뱓r~do?u 4b߮*,Y5dj:bEGhbϢI!nB{6bV^ϰإ::ǜ4q[u wh͈֡:t rvM֯ߧR.Za-rT+ xo:x|WX#a.UsuȹqWǩ@ʐ>7 qGi7۹MVrmG71eO&ڃog tj[zjE?[x8Aah0Q9*oE)m|vvA U[Ā[x[S.OVrm@vp.]wڭ{5,SWaG_QZy[8 xod缘[4ZD S 3ha?HnE:mG딉;5oQWB_Gq|裫6mػ{ˁ;.$fiMdU_ãn_xj}㧝|n&') }v:3Ea-zsO=U8R0[.=UV ubw~^>% p.֗g9-DCUYhLol;0f\;qҕ ~Nޤ I*7.;gʼ#_uѥ_k~d {f$2G"Ww((Sk{M,jT5/F]uP [ŨK_o`lZRRjC'~=Du Qɻc瞥&ڝŒاֺnaiQۏ$-./iJg?K|~YWīaNp5Sҹׯ.\p5AtV)U*s _Ua!Ayp"$"Ul;,r ']ѐ /OȪ;i4DU'W'/Żޯ(I%b\j$FE~z|o6Q]X+ @u+^@d:4%(ݘESՆf㗃\;og0ZbmyK\ ~zd$8,IdJzrGTo#=S+zs?+Ɲ4pdgӴ 3Vmֽl;pز^f>G039SafE7zq1ö e&id!oL1ݭk=J;vXy+-'?.L1lVݣ0y*(|kQ6N%?(MD Ҡ?,22wmԭ#w>(aSΛ ޜglb:fEP&\u,QZ]ET9gtLb1;cK'!=^uҨ2 0iw|yt=%A#}h0LGKZ?󠼮(N"v[n#M{|qvL=|Փ 󠼖3g J EPKi1>c~3bd2?@HmЃ;=%+HWK^Qm{"C<]%:$+ Ѫ@ޒԴi"(љh.}O Uto \P$ciZ=tCɦob6hQoPO܋KF_pj:MlhP[YjuӘi%܄Ǐ*@Y*RDu{浄)EGE+I%hAWϼKKF]*gF~O.Q{\nć 3#ZLh.z.|[*+4_ p^^:2M/}59O]25ظ Q&<~PUF 5NOW|dLg4LfȫZٵ +:k]CՁM43A6'(DV?bz7NK'D̔44M|iJɓ0c-S&A:|,z|6ݎ&HӤ:z)zRhPv/NЉf\[yKsKJݦisP&ޯrd >&%'$ZtqÇ >ltDɯ(7%W VKӶ~2wP;OJsibV|Ź*(:jOWBa0'>KLWhJQ)bWy鴈]7[%+}dszMsD/k|֎ĭnzu'^$s VK "}ԉour?E[:͕ŋkEFߖ3Tq\BU{'y֭g0үnΔ.>pkZ 錦t&Z-A'7'$.!tn=Γ|I*q3,4m.Y|wj;@[^ $3 aCR&X@D#.Q"A7x40fYUְiKM=K͛5`NHxT&A+*x}⏻6 6|Z^Fzݮ:z{{DRm|ig\o@sK8w7*~O jvM[y;p_J@@>_L{Uy@4m͢6o?|V>.Ń./:ħuKs򭂳.-?)jV|^&ʬ łkֶ۸? xx52؁8z-8?=xI 286դmǓI?)τ3٧}&/wzw ;86([3T}f9g-|Ɂ[%'6ɂ.~A͛7k%Cy͛5]>҆6}dfth j>W>4I۷_k f^2kr\$Fd:*xGv j?|z)ŔY툴Mn(3꡼wהPc.c{joКӹYF^25k֬arEB֨ v[~-g/[ 9bjO􋗟iQ{`i#:>mTǞ( o{7nҦk ÖNm|vQN.r0+s-֢PmvDjmяsD_ԄJ;wXgE:?o>l7ݿ[?{U|Ήʎ~r[Fۻp{58ڴ}~Թe]ux}|lį˻>1.<2F@'~9C>D56fן?u!P,rל'3?Q?;G/G5!) #sB'mCbjʭ!ait_ߦ,v?aQNʼutwN5ckv,yp` J@?}1+~%%9-D ;7n>f,H(E:e>5V7w$(UVˡox=XuΨ^}^.6iXuӹ[C¶A=f0|WGSvZ͗v?cg?9m/F/2SJr~ǚR:SLV;dёR:cV UzOw\F a E -0@./8J(!vȄcRjr^<_AT2lI8qSy,m:ύ0|%dt1V3r>IAt2pAx`^E I+Y. K|z-:7r/{>Hx>Ku@ dւD\[O;σ&qRm}Dnu r55Ff^$@4&E|N(yfwX,f%dY++Sdv Jæ ӣno= IDATM(Sd7l}5xMV7h((ݸK^bEtԩ+ ͐Sg}9io3%³Sؼzd9 4 T_wN-aq.ro9ŸK^+"#pz6BK.4r;l}@BLhY>-rl'p@ԃ[n?؝*zW&&{ F-@(| 79U#Ǭo n [SDzh(ڃKs&p9Ŋ|*' E31hJ D9^7p]3&JmEzb[6*Hvl56VS+bQcp<* p@,j VN[wM4 &}Z DD"tOy-2I%r`hB|Q[,lSٛZ k7 td|欱1p՘a|Z@*evhNmLkB&ҟ7PN mhE>V&ΰDq'`U|$ĉKiJh?IJ6þ=ea[ [zGyÔև[.9%Ϋ?kf!6$ڎ],% 66Z4,b8i\cFC h'4mMV\V.}l:# h#H,ረ=@?y:?}Ƶ{(s7n_qru~]ʹ+"{n\z4q}α _pý'5M+2 xPh/˔Cw-3 x[;_G 2;K6k #anϺ@9b4' !w0A/,7[, .bH~ۆ!ЎΰKX̿EW؃"@|='r@DNͿv؅n>e78HG5# ^AmJ*x:tfzJe̢DN #L]=eĢ9gGJq?/@LO+iQ+=GC&Ygɚ w|bUCj[ IMxjH!KPz]5JHT hN>^B 廟៕'`_7MMuBI12>ɘ-reAU)i+jk29r ycꈠ;+}wE_@ԃm"ƽ˙Le="F ?l{pP&;+A[UC  "$зmvN蘜U ;m/ \,Oil{_@] ͕k5Eȹ;>_?}zkFSu>kZޖ4q$O,D.zƞe"Q+ )rn[3}LӴ !"[E@=X qP'5Ւ5fU_vk+{ĴB؟>e'X`AD$@2 /'|.Wz6/Ɵk~J=:3Z,pVLQ$rqIWU*rK],2] yr:3"Pc&HkAU26o5`a0 19 ^AB%@N*0|l63L1jdyt kH.)rݕ~HUD$"es o]!q &h@k>Kͥ^q5fuAP@Y%W F42r HgWQPI4 `e+Y}GǕ{lsy8>̋{lG,GX9hwn)អ !qaߦGh`#%X4< W(tMsbULt-RPFbC9F-m%FAZRy0("PFxȾn1 E6R09]Lژuzܜ_;s@,k2[(H $tMźizE.(s Y?ab )3r{AzbLl f,:L ĝӿdڽrzoq*nt;{xzfx-XԚ B( mXcdxa94BT@QUI]pK`CP'ؘzꄎsD.AΞ J_Ցyjulˠ gDyD@[-O;ڬ+G?N5]ō/n4rTN}7wVN2ћ;RIuY*Tw9Jҫ֖aO|,tbR5YHp+Mz؃]cE9$Ba`pOi|izCUqkV,kKY`VSrォ di77u@ ?oVFrdUmDsVb.ȿ5zetPfHρqP_@QBL1X xXޙ֑eڭ}PBe?G@JʚݯZ .sb4@k_(vjǾA4c C8{&)tE)`KD~DTa>Zc{/$VkEyYaAZbIbY=-|$\Tp[50DhʟȺPG %m?:e\vu6d(` HZ=@{v'do#D  ꞙ%7$t0 .|j1a!;; >~Y" W>@zIx |)F_+BySof{*0vB?g_b0 2 P--9 ʄȎ0p ?*!29Z]4i/A*Mq˘V_?ĎILs}W)^lچ`K, P;Ҕ*RT7[ozyHem-=%5nJ,kMSP#4㑈e-1ǔ7 Lؓ蝪NdN 1Wl6`\p&IJB |F&@JDDQL8aA˸#= DYC2PQ4e?A )9BH!z PdE&dJ剤 2u K׵sipwQAJSEƾnQȳ~7@)Ȼk7n_qʍۗYo NWw,Mv[ r{jGp~9ո V`쑹̀k',cm r4 pݩ62;|"tz {Rc x.̵"+>7/[cvv"! ݯG7[p?tqeClRWO 1]#9Eo?7oroG1R_ts'ʈE#:rΎV~^6Ryѽ[_.I;' O,m5ptUP30M  %0kF'1BM$'m4 WhVY&Pq>Ahe2* [V+6JaBz,$䫺)izոoNʡ SGYϴ(:}$,-62k0$o1hgwR24!b;㒂5XTѢ3A1J8\i-B=9ؽp{[X8&7rbi_d.+N&J3??oYVRS-uR b-H2lYf֭d=0T@Tr2w;f (r jLZw<)hs"nDk{csGXNbϓ&A:Qf_A(ҩ'Ť@.ƌ9\EY”iQT؏ۉWZV#B"|Z kxnhk'WBt9A˟7.pg9}v."굀&(RԮ!NK bwWK]t~^v*N'k{&8"eS o]!qi(x@[kOVMTp1 ?tK習x@xE zy֒̉|@{u.xEjȠZއaĢd\] %YHBo>,$ZZm5c3ja^ܳe#=):=,!mMx)(-@>B%n Wt`g 5D."3QE.AJ@ZKѪ/*6z4pfNh!bpJAA<HP@A&a7'`HgN="ut@V %YZm#-SGnLY[xiVҩuABњ}-51q i M)g"_-vT94|̰vkoX82TdDhR2hbASjp jϴKb9ɅV Tl YF%ME3|{:)BXC[Pv ƄZkgmTSbҼ sSftn,dm7&ܲځe,89_ػ@k)[??VnXDQ܂O9w\TO .3wZ=>+CFQ6T|T{.~ل޹GL I1H% !C] U/b4tG5[S2X' hx/HU^ɼyX>2_dHt߫29hcgru~y?gȊ@eN\3si@oi+!dN\UP|wÄO^7S|xji Gg/6gPW(N5ϴ>ۺ; ]m($_4;{xzfI)* B\rՙ`JbXa0DPC?Km3%F^K!qzGFlbU@*Ae<#1u|V;%%m\:OLեM8VPRx;ܜg*ːYֻ 4 rnN ^.b|ͺ}ƣ<>q*veDnܲ୰"`O]`%$aC+DV*_y*`A U o.UEq+ hˣK_fM,YeBT*-N&yC ut(~kEҞ4wuU@!%20J n‹SnfIpRD'L{prE8 &$H̓@[򡅆b 9L;3w:LUl=>x K0ê,(MBqT8y8f52X: "XRVTn#KX8֚,9FlM2D*Yok-2bIbZC* ZVq7*7/$D5FM_mYʍ7tD.ba"8 ( ]SM%HKtIE]і]Aے93mW)9 BXSb6׼\)ßȆmU0=h? "E B8<"ԗ?^4  眤UмZ(%8"6D."|@X ؠZ1B}Vw Կ`` 4pٶ}{jnE-0<05vo~3 "pg[@b2kmOPa~1D] JW%Cn$^Ȁ)Xg{!UqbSA&`V{c#}tRsaRi1 )IrD{xJQX(,PdjB_(lѬRm2_-<~oߋ_ѿSEj :}Ii~ t_w%_;v/gFs{_e5\,Z3= PC*7;zL)X) LςǪ$ G ũ 0t+-Y$4zSK^ k ԪiG)2a$6ZȸxwoU6eLMAPa/[6@N9RP:a։!6~>|i#KQF,БsvA Ĵ4ujfG{Ox┕׼>\qRS'nɻsrd@5@i\,(yb)dEL& EAqA[U=\v:1$o!1'q0;|BI120NHQ$ri$䫺WTI;~+wQ7GiQtDx<+oܻY+4$,Z6.z{ۛ}ٙ/}1-3}lk?!gzl6`7gO5CzI,E8XH א5NSѠZMkr%C}߫/i,WYIS+xR cIC̯"y'.2`$b1 J93cPJ<!3ҙ l Y{:(LN9Yl \5]ρMW Ӎ-B8\^a3(E$Ix< >ezo0:o|t'k7_3PX1%bY`N;8:LM2΅LEl,iq|*Ab]"mH[8':b5z +9 5CsIAHQth?%^^b1CMWgbdC~WRۇKE\t.;kDtB/}۩~=F ٌu:Od>b~ ]AjZ4]f)*r5 Utޓ@ ZudYw잉h-!^zo\670RIUYRsTp-P mAsQX vyr4mfb^&oSww8#&nV gs9u{ p3)hiuz>sP<9DĄXhQ@ǘ_J4A!:ΒA7M!@y5O[a %D}2 E~gkzn[ؒخ8ZbImP'F5覠}}yE 4Xxʱ]MȾ!Jl `A!z}3rai9#"d .bcWRUd`98晊}mJjukX>@`^",i`h`Vanh'ـ<^i+P@%W aV+|mXT?5ci15942մo aW5I+4&4a, T@z|P+B=YzjGvE#Ah#1ʂU_+{W%2,-~`+S)Jm-)qʟZ"tƎ4oVGem& 凩[[½&/ضaH4T*EA ǀlFè96+6&w 0Yv6KfQmU* 2Q#+D]=绁2{EݾuJK8@[;__]|o}op0<2+n+gjs {4eGZJ5]jyYWeIf|q/`~L˸Du5IGYq=w5Aͦ:esD+ ]x'{x<fzI\H~b84a։!6~16FjkFF E6jΎV~^6CZHɌk٬Onjdimo6~!w0<+ s][ v]#_HD}*GzLdB(U@>ĩz^k?u>XS[@Q) vr+VfH|? %!>K;0'_Ͽ^3NʡSGYGi@=x(A\". sw2m_–}vSCnI DVmC+B{u-؀Te`pSBse\Lb@ Rw]"JM;<3u2NRvqi?@ Px%3ulq$CU;Kӷä'.2fT"b$R 6~Ϭ25<_2֕q&w}ngU+pb֩ʪLwbdB X Ivډe=,.CYWwF#wY_=Y҉%ׯE0E$QՓyqүYLk( :hhOI]ՙ) "z~N=c%߰'6Kxȑ!G{|r<k7pHyzӜ:M^r "FM?#&u"X:JQbw7(H!GWH\Z- ߨڧ{pɯ?ѥ tOX9s{0{Л^M=1mz\̍)P4W|VGHwHLx vH+!`E1A J8FHྐྵ-HZ4@餢hWAr.`t(\\R$iw{'ubF]XF@<]pqče=!>HE`/.AJ&:0V]F4y)1y)A,竑-w-b7y!T@rȉKU:답mO8[k$v W[P_v#r/mk?>E?ݧևh 0vцÉ' sv-43TN"EONKu5A8&6!-,2Q.ΥoLWP$ꎎ̄ɵ@cNRs$ÃWB = +>m5YkϡΠJ6rrHBD:gNW;гlƲ!woڬ1EQJhlwODq yl|ЬsrR(u"fh.o=d;<1 J~qMz{}6[Di=veBv[  `mHm aa U' M Ϫ‹PavOC2J'  e0 6<;;6 Xem 22XygAܝ4GI^fAIAPČ*)^6ɾ`UXB1$ "@1]64&(2qC1QTU 좇@> 20hs:#cImޙ# ʴ[Ŏt.} 9投u"$l9٬GhCHyi&`›6@j5%< K5l["rX5Ius@huR9^uz&dvکZBnXNanXp<Ѭ܍` cS6!A OI5(W ?{:JoKs{_u RN IRs%`G 4UCI"x"GK,pCҐrvr![rE\no7k#OdC޳_MV+[5m |;]X|"R PF{ ] Go5`ٲr*KAQg{ӭ@ڰ;+@ԗx!QowCOU+-2  ǂ Ԟ`G#@8 ZgTټ%/ylucbUkf3: 1K.)U9I$ezcL+宙ENje $!>K;0'_϶2ʤNʡDI ?vD]w\JWP&> z J3}(*eDEO ˥&VW=<4(vNrʒ'ё誱CѮ\N ՛iD ayCgq|}r2@#^ޯq.)RMSqH8^E=zy-ϕAWMrKJ^Zkiԫzx鴕r;.)u {*1 )To8X3(BiSTEN*]i7zs =}P,W-̹#)ɌW7/_e8ç`f2+vxZv΁&kNlb@4F+,ƽ&=Kh&<Gi;xy\d罶 G{WUϩ%BB,E4 =6K€*7:"=ӎIw8- =3|GmU2M $d/dJ[-z}.ܳιZ,WN8pz-<Q\kp4|8\IXň"~1 [f  !!2@η8Wa '=hrXPCڷ +;@B8GY_,~xmݶ ;\Ojb@N;-s [Rޚ§6:һ>a Dyv_۱`-7&_۱r%'If1-D`wTo"!i9D#5!Wz1J٠h$*0%)b]؊lݚ6CFtw0d|ގd8}*#g7F,qk/ڶӎD֥?N[Rb^ufA7ʎݑ5n j?eLq>C'SEQD.[.1 m? 8]Am2'1"`PBUX3 ,VYIy *5d،X:KKVX(e~s-;踒hܫ^kmv@5ݡU̴ۗg@]iv-htCN-ŒK̨fC^c VGFVVZGw]]u)KhbwrstCĠ( i'fyRl:t,guK "hԱI0˞lp*s\O6z6'ڂ8󓜃dٓ,E?ڔdmAIGuhwffeX$ʶGgl Y>*L᳇꟭X=ḿXnG D1~i3nМ gusAiA:R)PS<Ќ L+G*S=ރbJ֒v~^"s_ ~dg;3tg]י߁2nUT v.c%(~Ԍ)4lav]W^"KF{"(ܑ ZFqV!1=%`03\@ T*inַi6r7Wtu 7%=*{iNoWk# 4{Qz(q8r[ q#6}*B!) ڴ*,õ8o!" 2ڥ%U'2= āhY)^D!Dk' CO z"(M{@Ѻl4.ͧHu$)))@aL+MC^K4g.qi=xP[RgN"pOEx退Ҵ S f؆>L(%KDfPY@ CGG$&  g#r LG@a|6,%3~ !Cz_c,7 QF&ZΖE&EPW|(EE:f߁DD7VЂ ;|`,80_\`hVytI"+"v()|IH"GS&EICJ*e9xgTn=C>!B eKm5vL8$3U$O=q[kT-t 8nU8TڃRX@y.$2B$Y4M*6Xk!Q~`NO=()OLDб&iYVQ4Ig/VJO؜O"  ň6" f 6IDAT2K(9I@}=͹oMmҿ\iݍ>{ߕ܁";ھgo}|ޮrګ|Y|8-8߹'[;6R+55OoLWɺ!"> +yͽddjI \‰e]ڸ4ΔХ7TQ%)\PC 7[w;-RMq1&ϝ6Α[xͅɽU)3L:Alv+1{E00*2ףw G4 H Sl(KP*:eDظ?[zd"śq-LƮ}'9DIft )w26z]+Pk_UBz\QD.xhυ7z'7Zrg0qJU=t۰ZQ}Cڵh}VB-+L*ldiEݣ|ߜܚNu_콐-_W{9#y<1{'᲏ 4c2|I-M#DcPkG %+wirOkNnR|e⢁ެC>> .p\6{F=7˖?Պ] nr^;VN.[4M3,h@wƼ]y[#\7hF_T7L6QZQZG!km:.GEs#BS}l>2 tWVۼ9azcꜲS7zRQ>>_8±Olx/|5yɝ3ێ_i34q9e&%Mzg~ _y6x ~U#}5(73p#qRK%F޸M MkH;|#q4|3Zk 8~woɼk?}j'zչGiPov7R 9VѠt^g!4b oOkrKc5q j:FL6poO/ipZLp5sާ2r}vc{mklzgiO\I}MiG“6gO~c4vL#-hԅ+lzu]cf,8XUM/GL uBi/=nT#3@Uf5:F磩_LR$/ߵ*ݓl:B:Sn_uv@_r]R{tJQ hHhO Х Tqޱ/K@_]/y ;khjO4}-m>&Wj(D_u).p##3+Kdp!n3( !NM0ǨHKzLV? U*uEbHU :-=ͻ~H$WnOXQk߳)uڂ#:zОb3jLh o8u}dT.5҉P`]NϨ12?J:LT z)b] ș~ KiC3G"HU #D -(&3R*|h8>\SHve}^%3)GIsj +}u[gWK!&gdR<(N"ҵY-Y%3@_ǹ/j0b:ZD* ƑוlEK%d+T$M(k.Z$˪' c`T\˨qTc1%48$Z XZZ9) 2mD"}JS:[mnq͇ rjH]N)OΒLY>iMe"jP|4HYTK 5ԍSdl(># A )XBzH3)E_13r8 ] sWDbq\d.Gn2 FV=TzٌZt $.#kJ#0M!q4$$MიqՖM@McLM8q$!]B.>J =!dHvKqQTԈF?~̀b%{#*o0! p`XŸ4 %t&*,'_@ tdh?_6m/]R9/_ǫqNSAu]$s\p51XbԑYETؾ`o` &$D8 Ǒ4J1<$gNOH 4V >Z(?$1&2ҭ d֚ $2cp0IL(JEE$ϼ#v4 ;9x?Ix)J`+ y‰dp*j.HqxhM;YPDʅXL ąbo iC=UT|XY#TmR<0+儤d#(ʠ)l#!~82󸑑Q$&RC-[yd`^TE2yHV`E:a_66e~y3 qбG%9@ĜV#\A'N)&"0oD(FT 2=Tl\ɥIENDB`glances-2.11.1/docs/_static/quicklook.png000066400000000000000000000425751315472316100203150ustar00rootroot00000000000000PNG  IHDRHsBITOtEXtSoftwareShutterc IDATx]wx󟹖r!$(tPEWA (4Ҕ"UQ Jh !kBzҮ$W}޻\bgfggQ(.dNd}N7 Gk@@kBU+1:V׫MN=6%ú`Xr B[1]9$h>!`ԧMRn@)Zc\r%'$ZI  UY]Swa 1[AI#׉4ق q5qq nَj]?>D!zzn8[es9an+xơSYK8hϣ|\"Rm €5~rbt0#IRJa`-@W7 h:P#CC&mP4=o_J3Sr#]HLŕzuiM #缒$}`".!_׿ϻR|ik̤տw3.!c3?r~y,tS\+7ߨ޼o\Ba߸rVMdX/Y+ΝY]3|7bo^^_7ЕAD^z}Dw=kJdǩظS?-JZw=GQ;έ.}ſ ?1>d{7y-j]/'5S.!o+&r;dtݩe;Ji$-}-G.&D>sHKƠpljcܽHoxIABm/"Km:O|Lt-3_n! Ko?s)΅nG/t"*jLԩ uN~s_k>Kql=%1dA.H[ Ғ(Q Ct#e*"[:qKץ6L[ .&",f(xLxۇ_'u/wK`)fl&wԴ9JU~̯w/ۺ$)3m9#^YC4@Ri!8>."|dWpxBߨ y/EECc4ĭHRy ᱔S7<_7 ʼ3NYœ:ZNSIӈ1]5Q_1E DQQ0iJvϙ?{͊uɓvjϝW\n$pr8}pޱ~TѬ}WZ7@o藫#\.p侲U_*cJa(v;d v"L/ԯgt̢C!q@fի{MRd Ty,xÉөOݭDUe5rHO߭ԡ8wz3'g=ތ;zUWu˿|JoWVw~YEY.(9bW >+PزS s@ݮ6,/rWʏ`l~#6iօ6Du݈bB$Zh:X `Tm3Krg>PFN{吱SNp'JAm kc,q&_D7p撹ohȿ~dݒMgMP/ |yWڏKTOe)ՐCWFtk%:SZ?R=g9Ը9|;ߟ(ѝZ;l#y`Y_;WWAoޞX?d_ş?t{.E;WH7z(=z`W֑,E+[gQ2blP]NA}#3M4 $3DτgUח'U9>U^_~MWy7U*I5q 20"NCÿ%Ml c Y^n{+ʟӤyJ>5fGfhccPfmE "SA&Dj@M/ȷyZ K^57ח Y4 "eazOIZrXչ ڼ5,)d0p~t0Ks~ :E:_>xڷa"H}}g?ĨVuA]fR(d7z͒&!$jIU*i;+v9u{$>5;u[`b_J=E5 \gԵy8y<_?GyAD^;u ogd=q5DžO0/򛝱Yz3Zkħd:~4 B|8PP?9{A9tag7E[@?zFob7EԑE?Te]gY8w>Zo\|\>iwu\}\}]f%s</آS{3K):kI2e/.Uϋf}{yg<lcr碪4~]>P|1*䉽]"{io.|gPVwrBȹl6 b/_x`oMD)dRc{!\9Ьb8Ռ jiI|]U,חCsQp=gͣXUռ~}.-V{8GZ_Ҋ"i/]tȜ>ܥ1Ɯ7N2L&w87{?Bߌ݄d:ch|Y h1D0@=T43͓HoD26CcQlIIYU J98xƼ}^\|Yq;τD *^T]Y>ccsDZOy[GyB3Z{@STFLP ƝYoȵ;{sU~eW+r]uV 6!SMo42[G n[\?kj5ƒaSڼlr)QJf){fGwt`[r 9OQ"'W<)6 <8tkPuC9}ڧ0x-Y Qۗ;l]^nU{-lӜx$h;|'-˜8QQ4$rbs̋3j!5y; ͊`G욼AInxcQE9+ rr\NZW't*ZH/rNQt~g?s.{w:Gch;t'~\Pˡ<輷ZZ>_Y9_gA䯿&mǫF>1b߃*kz3BfD( 0r`/@T;(ש5_5$)ltB͈YFI57SlWUTOzJ2SU'&/ wNĞ 꼂NPUTibUU[- wA!׬2bЯ#JGwק:H?%p)MT:1EF{fuT'I TUybǐ=dBO^x=UEAuՈPI@\""PWK*UΥ1ID%ׁL@r&U赔-ɭiʃj~"vV$y5t_5i>!C@*ԣ*+97o>`ޅqSxwF{ 5J.rPWE3 )Jd%iJ@2Rx>7m[R $|>ɉB5T:KcWFЙ_2_r؎yg},EQ1̷:rS?tlF{ »?og1l{` *$ r*jQajE# EQfrJ^eJjTa|'cD]>? ?54YUviSBYMXն(QCAtMJ` -sR Z,n<3ԻD)SH_y2^|i`Juґ{yizgJ9V& [/)ȬnvSP/YvMsKCkEAŧ"~„_Ƽ"d)jIOIIKIMK˩Tw7ƆO>al%$q`Ɣ._'_^IvHy\DBw$unger )$eRA;ʠ|~REYVrRrJzD D&)Na9:ԯ*͒yd1hnIʭ<綵|ѵNRQG'O`t^)0`䊏_]t-[ĤBfT8LItz 1hr"& k;jKøojs lL@txcn&O*x!C8E(Xy+! $lP'~ũy> T҃;uMP=+|/:xw sI;wKT6p' mߩ𩟽 Ѩʮsg\@@=/:zҫWb; '|V/ɃdgZ@AݵKڹ{eYo J3[nW妧eɉ03D^:=u4u7o'>*G6k۶aL'U5Ŕ{+u\y'T_pǎx'cjY8n{kBnyC3c/F{RNFzϟ'8焏#Zf;XXk},~ghH/m7>Eo7UȑB%L ?OHpySZd;_GcfHB{%[_ޜx3Ty~wtҐڷwpZ֯o?zt" ٪'oPV:8iPW(Q|:2+|ޤ>!A=E>~2I P~m^ӿ]zh % } ?;*sYd#nP_][  M_h֊]AV/enogOrwFQ]zIա{ |zڧɛ_7S u ן}jG#;+D^h3G@J_<뛃1y?^x.G}^g+s\9XkV[f̟̐;cx ]z9~I%szC UOb/ZuJlC?ύ8mk0D,ضc:صBαwXğfp^2}owx#7Mfo`]N5nQSz~v^ŽlϯuH=.bwR^-,qG+şNl_ njλR >psSt|>u Sݹ@H/nY7Q3-_QxDwq=#62[pإqd@ֽ!@Z@wB R4 O ()⚸2CJBƳMߖE#?.eank%Kṹ3hun8qGgC_a &P M[dZNoM{]l`ԃy ')78ւs6` .!02Af&Ñyi^CB2/@c9hE.[㖱Sw:oSp`ss kY^%ť8 6fxb5miDNK*Kp̬d268a+FR.#z{}0Xod2[a,%ZϧB8$ףV$&xawXN?euG+Y5-KסFX!2Ȧrb/Af1Rb`d!Zݜ~nԳhh &w>ny IDAT ŰBfu?6It)r'>2 f5DJіm%/z S dɂF8qSpZ6I<Ĉ%<΀I}@y`&֘tYi}lhhόY-`]`j.Qᄵdן8\ȘׄMf@DQZ|-c|͕?iu;XتYyb4v3F/z2Ƿ[H9s8|zE!Ժ6P1QA朕6GV D&gvlY7$Ҹu$zD Ϧ.}_ O,fvCw-{=W" 8t(Z%rpEJUmR*ustb1xt&QWIiqwP#rE9vv"W$` ~$=;h}2؞?5W`N VW%Vl=@ -O?'թ]WBjPdIJKG_yQ( r>)|î@??GyADE!Cۃ} 㕇4ț=wzK\م~%T}e%\F=!E&n3 2$H IVٚ}n_<&FҬY%e4ɏJrMQ.T咔 9}ynB1Y{ϺJnRt^ު E֕76g4y:wt* D *BXzM Vӕ&㲐E ,;E/}^Xw O{%')9S-+φGg ~\gBrn;Oٶ֖mRHyNn0ߕoY̪T$Ye @PuC+[п{͍X6L["C!dݱNi&c7_ P ݰ!gU`<yF  2ܜ(*+};&n)4V`EuN!z\@'[3-!ZR0h2:xV˧`B8qrZn/H|4Q,RH$24}s@-IǺڝfO 5Z#yB f=AN#Lvp[e5?{/n1rq65=Te#;5:EŠ5酳ry`RfF{yx I?p'dm{ ln ))NQr"QʮIPU0oP6)vzvɽ🙤ͮ!BH8NJ^ҧg@P]-8WUmN;rǀPRyOJkSeP+֗P9ډp}mG:gHصh38Џa 8)v N'\PFP,4R(Hȡ`8.ųql_#y˞QS {h'u(ԧ@RV:f`5xUĆ T_X'tŴ^<3-LVჺ/͕ʤRTzqֻ|QaOxzEEݎ:)m/J۱USs]saarG8-qV _`<$ 1YHrH w"Esÿɍڻ # 5󚋱Cd4e +oIy\xX[<_ߺz !0o]=k뷮^WZsCoŝ|nE!->KtEȞ$:qLX,/Q8rްHbӠA]dФ6esg|p{'_OcL\{ӆSktK.2uC?a*ҊExE j-~Ž'"rꄈϕt˛)spjlS֔톣!A ije!Č~ɾ q#Pg F?WA$RA] KoeSNij9JX)+k ,l1jnl %K<1[(BAO}Bs..?y]dYLY5Ⱦji0hהRf'WW32U-垎|່::{{|/oUq"p{@QR >W<ڒm 0kkIEU FN{([Q"L^S-ӃhjS 1bL؍nFY`<+ YŶ%1&`Ŷ (3jt'Z^\]hƎ-d'l.23ƅPGKЫHb:VBDvP>019qjPU^e];Vzj?^Κc% xK٥-$0zjbvX@ #~aoT8ŏ WGL (LhK kGXUN%bC]rPzYڍpߔmmh}CmXC*\k+Q.^o#TKeҼ!_ߌ~⿑_ Sїwe+q +|k- &ܺpckg fX|өKϗ3o4E[i0 1B=%0æA&T_XWox 㯑VV%ѷq{-YX<:j~~_:0:.zuC$)bE~G7ߚ gw6oUsde(†:kS+Y fwZ1w^F`A2F"&jG_"4dW s׆[.oHJ^0f0Fn>֯spU|^4Ad#u:< Pxm%&ݻxX(| '~lRkIR tu˂CF-/BEDT6Yf5+AB30m6w9`RfzF;QBۏ ŗ/ <5ڌ# C^=bt8{T=:y ўbDڼprVgty<]y"ggUeݮ.# Jy@de%flK9{;:vQ)Kr0p .HHSATA*B^8S#![s8#zOd0{_Y'8AMV)B7z45ߞ<6c^N- $-H~Eb:goW Ey֔\6uxw6Aև=E7EHiq89)Ջ?^<% 9] yYRFJR:ñew^IGI 6#w`h^z+RlFՊș@p'뙊 fq]bu$A,t !ȉD "tJX!̉ҔKM*1+olBT2w_z ݫ oo8GW]xصMvCg]"<$gUwHS U'};g)yضK\Z`.hhԿS 튟Hm42X!&6ke4ȔPgMD AQެH(dUKTe* @-C{h[u{s rQ^t>i/m{nbn&&} Nʁsx;Q9 s4m+{zB/~LW&HęF 6%\ YBL}/Ue(rZuH1dfEbHy@a#83!V$F YF[h^;8 +W9uzfB{JRsNe+ݓqXwPJi3a^ IDATry5ה.ށW<ښ3~͎% 2V49З2hSgT[Tq,|nZݻh_?&@V lj+n릏}n}9iI|fCaL!fWs'7)zR~-]x>U;& ί7qYn^ 0הo.̬]UJ;}^Ҍ/ovgDA8pd?*sj?lVy]S"Qՠ[2Rr3aR2t59EH owq= adQHq` ~XbD5}> 3iJ8z@fW# :1i&If,Yc3R<9VȦ_*TbD 덠~.AenO:7C]˰ Lfc~d[^4<[fe5lvJ3RҸ̾~"wR$`RGyULPU!+^,l?N6wǝpX t=G g[BadK/;_)dw774~S݀As޿Tgq5em|ImZ>?7Mڙh&;Phݴ?^l >_ 1WW'(`}ȎJLr`6eAY>1uxdXl7d7;em+^3nLˉܗ{Zh4h偿\b_ye֏rՀg2({,73 v]N@ސ1 OyK=6@Nh~` ΰkeQ!Yb߉i~+Wh8Y3ʈi.0[s ? p9çۑ?ykSߟPvnozTڹn*#pefU2!e/(Zaߌ ۻiX#@ҟ9\bsX/ZfzXH 3$錙d&&LVɊ~4N ʍ|\?l 6BW@Prt*氞R_rgmN 7f[NG8E t{Kzϭگ?@gO(ojlu\񺸥Vn>~+~fZl^\U&kغr|Ir=`&)igp"靦cWx*򼔻cP DT"SK&4Wf+nY엑S"8p+UH@f푕C{g;naK5?$Ie_yCb4I@g &8PrfuW@̆ORme5R*H=e޴AuiV/\v,bǷIb~]QH JdIJN.aS̕e/ &k-jhʫ#f$렪[+|<Lmv39|7} pGR~6/T V3d!᭰e_yTSvn-u#FaaGh Z ;DŽB4]wxpPpȦL- ۛwr`Du Z=b`G7/w e>o墩twR)IՍ߾sD c#S+' :R>uY־PYƝxsKZb$cWvQ)(l3R lJ_]uZNƘjiQ mq+:k@q<3h}^|)xMʭv&e 7Li3Iq{xMZĮe>5?oULpz=UMx۴sKUqcjO88q?pؒ:?Iؙ i]EoʐdJ}zdya{)qB7jO1ڄ;Sϥ&U\.0N3%Iosϓ\>ADF(PW{○.Plxڶ"ݐ:NBBBNBBNBBNBBBNBBNjzY TG,Hr]ڿ (]`lßǯ?T'ydLܩ3{%j)@c9'a1oq#6pD7yBI7_:yGhAe堀ĝtF4 QzckEq}"'¸_}=gY~zq>wNG*l{_pΟ3kZ3$~|Idz3E?tFw p:~' 8ot'LŤW4dEՕI)f]G8##Ζ^RW'l )˄LT*%,`he8Mv&txS'=bQ<4&$G,N8-ô.+g ٣]o9~XSa pÒ}-΋: j1۬1:>ىLQ^k-O* _9JMSPسԎ8Y'aTᓝ l1mge FhtE5Fb`.E&ֺBNʞgk7S8ť;?go97m>&mtŒΰy3$sҞ@yr,9uU^) :y"ځ6H |"[G޹%K$F&=:Jq)=q" ch:FtD%ݺ)D:ҭ{A[#ݠsHn"zB["ݺmH7%["֋H!ҭn"ݚ_=[ăH7$vIHHIHIHIHHIHI":Q_I7֘7ԐAI|h\D6ҍj==e_9gO j,"z&x7'sED8:s:HMidIUYWDbҍj6s8U]dnt#h '\_uFB@"L%R6E}'"z-=YҮ nt#yT3z<ՁLSHz F4e2gz椄簜F%5K=  /޲-/tۖqAͱ@ʀA'2 2̾A7gwI7ng_*9v$)TIq_exLN:EniO]tr`odr29YY%̉16ٳ1)e`\i(òQVrI7icao?IJ{;MZyדnz|xte/*{'.Pmaqv%F>a,qG%~c=ǫWu$E7P(+(eLv7ge1Nǻ@v|@aUʢrCrۚ%5u`jFҦ#/}k~>*ޑO90WJsO-{mР)Z>g~-ӻ\!0)JЀ\/ kFzF2ҭ1⟗Ғ[u}@OIo9? `Ժ=?Xк.Ȫr76XMT^:\MR[[[Y<q߰Id|we4'O{֎8t Ǫltt읠P6Ff {>?."cW-R_)ղ^㣞72"݈ h[?\l=22ɒ@5",M۸.7,O:^+/8tBYU320>8Ss>Aᢪm~ "3agt2)>(@ +ڗ{Y:ARrnl&uhtCK!@BNBBNBBNBBBNBBNBBNBBNBBBNBBNBBNBBNBBBNB!?S|֞IENDB`glances-2.11.1/docs/_static/screencast.gif000066400000000000000000041206671315472316100204320ustar00rootroot00000000000000GIF89a                                                                                  - (&0+ $&4&)&*%Z6t -LiW%Q+J_^_`Z)^`%[`+G\Ҫֳն9! NETSCAPE2.0!H, H`*\0O#J8ࢋ.iȱǏ!=ZDpDA\ɲ˗0cʌ͛8s ڃ'ϟ@ JѣH*] ӧCթXVeõׯ`ÊK,8fӪIfm[nתq wݻx·߿ L¸ǏhB˘3[# S\v1%ӨSvqtk'b~=&Z6;wݽ N ǑgXУKNu?νËO|^|˟OǠ {ȟܥw 6h >(aB`AІ&Bч ("<H(#HK$J{T8ӎ<T@)@:EKL6$YtהTUؕXf`u٥f`YgPi暰mpoiܝxމ\p{u*iy&袌6ڝF*餔Vj饘f_&ᆺs,Md9 t*H-K5H#K{,9)BN:&"yTNAVmfR;mSOzȰpZg Ǹ.+K׽o[{cO6n3& IgX&m]<kqfoy,r~:s20'| c3& ~,v"M: ;<48jKg%K78:v֐#9xȤ78 #݈s KYl6<29%1 9uvQx-68>M^E6<邏OzB:.8A`cOZ3=3ps-b\)ol7.4c9yWs}lXk6rVvW8`o|+<0#èayhL07ѯ1+o XڞZѠ@Ak\c&c gxYw*f@ Af35dm>&+L?=K$) =U s-=&}npS4N%-!:25Ajڇ!WD85816J d`҈J296 GULf q9Ï`遃h񈒹EBs߸e.w9q1͒ JӱSk4GhIM1sҩw/xH^7|*ȴF9ƁK]B < Jp,WX d˩ܧNvsY$džq Oi>Z>nե&Ҁ nUT:;#»d7XRmj8H5T=Ou(Ն ^6jnYUq"8ՂjxX>F*ZZR۸9H6)69ʑs8[c(b4e ED.gӋ*?lWuUsz+Grc6ro8:qB:Txh+5rVY!6 5+m^թ-UC^=c.m=sT9;TEUL1Gg!P-ijlL)STTuqAgVބ ٟ†5#j| 7.8t2vjU*=j|ԣV ~֮BM֝qnp81ǹ810Qy9U}xګA\iyU>FY-ZରW;>#99t܂x6鱎yCS˃I&?ؐ4J.@0vsvkk/1}{ĵ709[sj[! 8\S`[2X.Ӫf7`6MyrTق(3P>P&L7KqTs4m Muq鬱dUq±1Μ*p!kx,fU̼/,i[-sWTKܡ]ٰdlAq3c~s:`%b /9Cyb(92Ըpc˧Gfj%fs؞wg*} E(BfNPhFG)+H+Ab0ʹ<Y:?6irhNѳLT́agF Ͷ:kLg~~PFVMsl9|$<8M;5 HFYU565:u GoTobZZ6S#*SӃ05-Rp#FRG05*35q+J24p,re ytrrQ7,RhGc$CskP#D_:ϓ8K .hscHq8WAs?$bvNpWb6pS`hljK6bNUwzW>VbQaƄ`ZS UyQxddf7_|QLvyZA\ z@hQA؊&%5SSS57>U{k{s{'''Pu|HU3}D7Wiۇ*SLTw]: 2PmUGScAipgUlEpSrL5ـ rK$pC ($!Ӗai Ce J wjK866sA P6w@L?7,3BD2iV7 Oz/4A{C+P1lVkxDDbj^R ;k ĔP x<5 ~űMm@XA) nt( p3qt 4 <Q{K5H8*ZWnT+wmJR+pɲiPn{8ɸGJz-)- 5̘zO^4qs[ LB N7NK9*:uvwv]qu uuRTM? ZNeͦ\ p :LWU b+M`:>ʣ" Uѳ;wa x}mcL&d5 Sa>9&t] LS ~Y!`vs=np=zsz(Zc_!Չ<K=&bmWeWI L3-;@ƝaQ4_p@ :@BBxo^` aY֘X`>e԰碥:S B+fP ` c}f13anBó{F{qCsMw=DɧAC~X 6p0g_GfYWlWa%ȵځ:>EwƵԞ]lK&Y.} kdu4 F)H";a&+\p+ oߧd#\zYM?G,BGH5E!d1aKlSr*/,%!1_04_-<:&hRg-֧꩎:<N!6jh5;)7]V\o3yW^ :"Quw r(_x G8Ru?71Kosb$C9.' "a"_JBm/s_N%-y #󐁟651p0>C֢GGE=ΟhfOFL؟ س1/h?0j)s*wyOq7orIn,,A .dؐÃJdb85nG!E$9RIQ<ɆK'̤YM9uIS̟[R(QXjQSQNU# SNׯZ ֬iծemZqΥ[]y3Ȱo\{[aĉ/fX1ȑ%O\e̙5ogСEcҤ!NMZkرeφܹ"E-wow#*qɕNsѥ?oTuٵo|KկgEG}p@h@TpAtA#lPJB 3P6R#82iDz2DS)(r(bj,:jGԚ-22/$TI 1(r8J,ҵLs45.RMm:8<:ND0oHtP>ӓ?uQ%|6J/մRIӃ6tK/0DTQ(UV+luCXc90D C$Q-xUW`{zqXU)nٲ|H#vIle0/*w-5WLcmUn5xU/Uc^=Ά2?6]_ SNsanOs.>B+ͱO@Q"BDLt:]IeRahutUWu#lI *w+,N&x3ʴwI yZS\NP#IOzVٮwDrMJcb;Eo룢ՃpUڧQv**9\96jt'TxGQ$"{D8>L% ɑQAS!  %I;hxI,G<Ԉw iHmIxʹ ld# ] %ʼn>#EDK]>Ϡ/$&zỹ}QNcdǍCc1ƿ6'#0GE.Ď$gCG bV1ґDSea84^'[T bn>Rvd5 wnH. , -)iz+ e-kned^W:\@-.KZgKk|ؾKfɚFKٖ x7#skLgوXmPCiz|:#v8C"wteȽ C~ߘu<ՠ.5;[vFqk|ַhEA7/^I>[ &=js+:|vsa69@M^oEșg D`RU25O4ԣe%Mšg׻ΓL;w1Sj$5 N;\ g;5%r;ěd)Y<2{Vr&}fao9` @_,Qc2?TT/C?)Q?`c/v(R?pc3@^Cܨ=( 9 @HT<@j{#2=SA zcWA`HC˺`!#[&tBSB$#?lÉ[%*Cel"7{FhFiFjDFZDFDH$l{3KD:EJ ţ4D34ڳ3S=Xyy EY܉~EeQM);BR#(B&[5/ c ü#e\ƻf$Ô@t@\ɗlI, \=9fKqt@tA;ãGXJPH=u . J>X$ȂtIBaH%>_˸HT5blVHI8^Z@?IؿCI´?CdLTLGFTIt J;jO#SMc|G= AVǫW:1\Դ4˩h~H%& Hhuɥon,w68|aקLopy[om؇=7}4_Yi!-N8gXbs0U8\\^x_HaY`=xTl &-Pgb,ꚅ܈泎֤֩Nb8)Pa1~2Њah胡U86Mr{ѬZ々s [ N.LHKZ_!ܽM ބ¨-3h)AΆbӕ\>]t kxp\mZ$&m=tXWXFEsn?^mk_0mimH[n\=eF-hƢu^5hT`fހ^]wQEb=n-V gSXqЄ %zF'MEL_dEVH6efr [ƌw=aԲ35i>vXq cI[oZW^Y͆,_[8;S\cņg.փeNѕYיtt:wsiT l0lP0VFub.f_`[4e5N1l+Њ,g@VFl{zۖ^fv%p8OvcؚUms7;o)[q`\Oud nmDg]2}GuF8r?ۚ3p ؋f^s.q-[Sp?-G<;ymƍ gi GlxiO.]YkUOV'=9!\fUWt5eYvM׎ec]W_hU>hE r'J0Tp]ͦDawLavb1O=f3 1-b^SFss<A j1j[E@wꞶj8XE`WSx |t͉ݗt-P1t0yօQW } b Wb6Tp]~[u+u5)M5.c>F6 Um)n`Į"-#-CW̳Op ~:v`pn7ڨѮγ71K#F֮  @9|xy 6"J8!VRa"xx !8"$zxG{G-"18#5x#9FTmԭU=BSSD܁ ug9PYEF SgUFN(fSuU qB |x:837 7Z;LJ%|b>ŁtQ"0 FUɁTRALJ äҺl,bZXjNSp !T>U~UAqq,DXf5PYN iAZ*6rk;/.]Q<ǸXre\\"n&ǐ@#l#3F U &- y0#MrRpF9d)I*L0 N.‹fV* NP"HKF(AH3e {3Kfp[bsn8%41 `f#ӽn-6J4\o3;\1сkB+f1o ըάa]# [8B>;3d)[ 1sNr?f6AӼ=tx}hC4^E;[-bCYq%h[JN#SWDiU?|ݎ`c@~\ݢ Q gֳ58awtI*~pFbX8l99Ҋ~H*:1BXAle+-g9Kbw9aw8R>Um5MƶWn܇ȇ"*f K3$BYHC[iH"&ldcUrWb%# K h)ŭKޝd8}1xWhW9|q._heo/=SsoIl୻8Jar^ۘp?Mi}i> HwVfs2'v|YSe<``nePE{9N>.ej~(j5o3X}̶? t{5B׼."_ MXK ٫HcR!-{ FV_Sگ MFM|7Iì E(ЭA EZ Np_Jaal )[ B@p 7eC T E𐳈C6p Л  H»C3@[1]@A 9ܯ%d@-Ax^dd @F Ch U\ChDni:C: $  bP.=C|\z!tC륃8B Q$%EӡZ8Z.ц(*ڐD`ajNa(E@- x 1Iq)da}mT5N@72@q|7G ^ O"DI9_=ޙI#?f_i @: @:MQ NNDDFd>Zϣ4JU~GrШ`HzJ [LLK" eUL KN$ Or!Q2PR.%S:">%TFR XT&UK  N)ؐ%ZZ%[5䂃X]%^ޞ9BcA 0;Y=ENHfH^}J$mL$ K"KN$p$%P $Q8%s%R>'5tNIu^'UMVE-Fxe['yy'zj\gu<™={|g^^΅`^$O<*U$cNIZf"BgCv D&ځڈ* X kvh$^l֦do* fp 0!rVs6@' PSbTEVv<&)XezFN)'{^i|ҧni'9&T`N&(CNh h⩎X}ߏ4zIbI艮$] M ndj*Kp$(qNq2a±֍& RD+ѬUŒ:Xze>+FRǕ\r)f|9ifc階"ٞ(1&ڢ+f:IiI7 ,,&윾k6ʤROϥf2[n,VnzP䭞 4Qk**N',j,ϚRVkj+mqe_Y+Hai:,IA,,؎-lZmFfhjNxdłźr,݂`mj 캬%Cl.ҬJer"F.}^.Bk Bв6&詓D{B6Bqkη^2m@鈤*FթYjf" &dJZv2XU>X-rۆ䦮lL- $MNmᲖ=,dL2l?SR?pXeRRgnXLMSnl]XŠqS ?v\F]'ꖃ װ%%R햣)@-xȺ0CR%$3āދek|TIdPfd:S摐RFl9L:,÷BH"1Ti!A9\(!KF ^d ~ hުjnhbFi9x2N2=ù|,DreLKpat nh D_v7D!Rj88uK23JHL(TD@!^-3Wn)HF)Ey2:7r9;{b1/3Y3-neH"d`C(*6SdɪqC7T84 wNvNjFp)^tgH@9qK'֙E9`C8QeAD5R5*fC>d@:TAԿT{+.lD8XD9(D6&oڔZqOtЈ6J`٦frM*' M_ AE([͊);'neKK-lt>.`pCNQHlvgv7tCCUgCLs6"J3RHiLLC6"EI)@jC?rd\sy*ggOac&(ij *Z7aW 9h“*#;7 n+cG8IXtv|.|؅F0GGt4|j:^J'KqC#戝%HKlV9deOW]HRh"Q8uRAMI S:]A0,j_ud,,gD쏬B\U9 *ߡV%Y\\ 95WhA"8C#wPJ2 J J۵iUdhNU6e XP+%CA312!\C 5A./%Oa:Dq&<8-J );4$9IzSE!J5xRU<Tw@0+ @ئr÷=S[.NS*M;G'2:F7ED"Gb;)ex/ēIPF:;x#T7G W#HF s|8K.I~Fo+Hb+l4|x4 $UP '\wT=e5<@~DؒWE󈯠d4lGVEJʦLPA9FZŹ9l'a_od.:4Päs٫D6M@A6QldKcF+ e7~-B:j ƅa֭vF`SLDX} ݜ3vAE0״I8b#PPYz)T8+3[7&sDY3 ĢZƘXSer0؍ 6th0C*h;pq3g t ns LWbÈ1/ZcDkƙ{wfJp-^\8l rCFjVuڕܽt*WYٳiun\s* oo` -|X/`Ë4vc;h,tI9wyQ;mH1}6Sve{}vM6Yx8 {@z'9sɟO׃'9YyDf%r8wCt؈oR8򗶷}oߧŕ'wo6<`s-9M=L?nC4?(q]o srq-F%pH,Ă"B !2TL"yL5Dzf./tAL/<3.ׄCbvN_ )?)C(N0OF|ї 24N=4VSQY锨K3 rK15Y3@AI 0XC[`_*\Gҵs9#FSӕR]5ElMH[]qu"xy&Uq}Uv}&^jCz0y'J42Ul 9" pU#fبbE%liT*Ň-[QQƜ:*p8`vUE9f2(],cSΡtgs^Ҏs#a)phiXg>V+fIZ(5S|K^JVf zyea-l$d6:PFmi0Fmz[mF6%rl#& 859Xt)9Gsu Wi(3Mzbd>l|?Y:~%; 4tT" Dnu+9&.OC&.эJ~1{f/^֍chYgĨyIl *?%+#t$VKǴ ٱE.£sX;Z.҈O* v㒈DĥQb5]r0Iz \4ee673 Bo|+ 'jf6P<BqP<8.|8iN%ӃzQ?guc< < RZ<3vO9r1AHy#8$bH!Ї,DT#)¨4_ErRwZEb~V"ȎHqnKa$ـT.i=5!MOjBt?Net'?EuyEu4>N`HY?š&:իƔVZPk oYn)+z_e1+F1bl H(a,hSCAhBTI҅ &=ZyRsCpaoh J'I[{nرڪⷿ|s &m,{;&89эqdCq@s3Iw{.)GQ. λݯPey 3K.0={ۚ6m20ynN/2LHsʃ6"=A> y&w눘7đ B=ఆɳцS?[gcNDz ڑOǒj!(-ce˨sErYDL)CC3̾J*ײ~<hG 1}cGTꔎm`CDxUO[ w}+,Upʡl8TLMV\RxAWA!`e^(Y*mNNWTAjᰆM1ZXpZD>GTN` pM`:o%*wB6G(Acl`*ࠐd6o4BcXB̈ a(bJ^KdkH_KߨP_Fk9b x$AAK @Xb椋hfpx-QV)/>q.25H m:# IZnD4nArNt(0 :rqNҡ;a8zā=>LIoɟ"@&A*Aa,?f'75@&z0JEX, @ \R'!bEΥE` v!Z ro\%~}@@dDr$ΤЈU e~~  hj' h#[F$d Dr$!Q@(a;JGO4e*MO+Ҥ/SDSJP%&_%&@VZM4"_bQ%Yt)g$6R&v$aPU0X҈ 30&Q\!*&($!m3GPh$G&n" ը&  #m (Rh\2b /_Ŷ0(0;50(r~ib:f3+f!,as\.DjΫH2L5Hc2[3 븮S$g,@aqa9T:qrXCfʑ>VCQDG?@]y'z2ERV䣴GFgTF,H$g\JGwGYHP'*-M4 IRRt'JK+JW>1TLǔLU0]4"%&z8MTNNN%: ;ƁQ|Nj $uSk&1L>.smmΘD):8rq"gUz:CuTYDqL?HY#SS4RnVtER `FE$FG΄\{ \}ԥT]oPTI^JI3O.Ot d_Ku_5K+KX<˔aaͱ0]$Mb/c3Vc7Vb:O#渢-*1QRS=cRa)S1=nS91uBT'4?5@iq#'~urj)qN=B7TαYvvxZ5Um @ n5z|]H䧦`oӤouKPzP2H+IqL4`ӄ`q +SEas?s#VMۅc%&NKuSN{mu u"v^u df@ ;QaAx_Vy,ռN0X >Cgl'ė21cdi'dU+Li)j8 B1g:k5lSc5xPzl\a֦i3xpT{҃4O$ڨV `7יکh/NYvXÙ8w9ww7<*emZv庮z˜θgzז3U>8ڏT:VA/,8@|+j1B;̢XPluC_uL:ǴZDɠPyzh{D8#iocq:HtyI}/m^ I[ETr4*z&Xw͊!8fyxmۛdi\~-\dC \PZ,N.+!ܯ)|-ᢞ&Ãΰ=YgDQ1W'; *;5xq5*G!ep('f|.r$Y)r.9 d7WYـD!&qgvwá64JPضN **ŕ{^yZ%۹wPB`ORNM8MLHT<<%!Dh Z΁r!N=չ{U%;[}g 4!$̅ x8{NyGpGY+Ijӌ %7Y-!ƣġm@&%v͐/Qh.I+,|]<#|5|ÝFfC<0=GqJѱ "hWc5Ip5,rhrc$ڛ&I7jqIw]NzDuA?VZUt^BU1O)ܱvz^˽A ρHnzoL dPAȐRAAc Iaѥ*KID$ҽ Ftw>eg>RiJ#E_YҀ/ϡ a=% N]N>AT Bv<}wjc!Jڭ-X᫹6ޒZcB$ko:!b8aP=h]Z-YXfv T#{4.Lp!,"P `n!񖍇1A{g߉)a},b`98LΆ'D>Æ؀dDHn{׈6ÕY&e\Iـ# PWrbsX N`eFg\6yN)@YH)hmfboR'=iniA A@TN4q3A` F$hu2ʨ/ݲH:n@Cl{Q:{34.BJ[36Z[mv;.۞m". n;oދoopGd0[mai\%LLqO"hFmA3ytvC1 SAM\8EqDB,"be2$"{U9!8A bYa\fǔEEtl!$  =Dӡq36x^FF:( +DlbX䶷 -fe[2 ,.Ja\: $-CX?DMgRRՑFyQv.m,wI9܉NzZB;ӻxCeO7`^l'}.֟q}Y9tmJSJR_2V`;,ыx@$P/K@ ]>룼zN BdTqJ{dX%^K0lO]5İwTGx)Vf'R4n M{T|& bԥ.$1Bgљ;:duÍnc%6t3 = 8dɬr(&1 $0%EIO"]%R^/KҠL]җX&a `{uJgaMX#H7@oH=aEӲ1k}kϩh*gKY5Ȉ#ga;kj:fXmBllԠ5i[LhL4i&î/p~/8hZ;G7kOL oMCvtyTϣ:)Dnl?!eAM *ǟߺo<R];`-(X ڈ99L!c?pNM+Y)JY-D+Z熩==`)jsoi'9`6 o [ˉuAR_qe;7]݌ )F Q93G‹GhtcU+eix8 "[GЏnɤx ^0uy20)a\wKėEe1ldE5D7f^3ll*;xt$hSq8Y06c)U=i`&"bRqFin\$/Ov Xn0Wp戨[x|.oLG ӝҨ)<<14C;JcҾ驦JV"9xc"''# q`$o.q') '88%1@@d /s@sio!,W,HsX`HwJgtzXtN.M JtJW'acYG0]Lj1a'vcW1f1hLp Z(,P3 !Ô 4`yPr! yccd@FZs *+DyL#6lwQWNQ ~@gy'R^kE' tSzQP0#l5sggoO>VRħ,ՍߨB:Sr1c!!W  Ȁ%E!#WW#`!nMS\ 8)` $=F$kPq3(˕$eWZW)\bVA(pҸ{#RgyqgK؄euq S8W)B 2rƄ]^%`^Phis1 tʒ_uH,|`DxKiV//SuXKK[׈1 a'3$ 2Z/rǜ尊>$p&7x yd ΐ ߴ@09ȥp@9 *9eaF?wiDUDxz7~N@ep66ufp28៶7I$:VtchCSk`8IiѠ hS!} SFSYEG<[恓WI6yqFp*WEC"HXN8 pARy$2$@C@ p RoC`i%byYJA9OZ(3R*#PfԗIbS7C͘ @dŕyLx儃قcJRH*A0rLA (n[%5k8xP_t_)}9`t8JuۢJ1n801Cb2p ΤJ!AZ3y@P zwx7xߠFݩ50۱Q5gbˀ? Pyy~١"*q S~`xyݰq(5)qɤ; > |gӤ%5E145W#9 T٧ i &C`ubRPv'/u6yb'"+-Ϡ@׶!( mh%J&| +TT%)o \hDU>[* n=+eCX4WF@`)Go)nWLs}Kp |,@s tH& 犮z.Dƒ`yaz//,Jz31}i11vd20= @M<34@ӝ N3eWy_O$yeLx4xgho(UHǐ6qx{<<}BR~aalkYpL27Yֻɝon%̨ D-->.-ׁ`%L j*K،a 1pmuA۩1Nc?cC~Z,SaK.MDhm

sܴ)ɽwҀܣ-PTAɱٍf}}>HNML oNwn'~ߑ>:,l_~, ꊮt#fu-ª(! /1>ZGl; ܔ݉^<\`\W,mʎs\'9i>[`n:NZ cn*ijn]ӏLrN'-- RED0Am!t>`}#MB2n' v)L]<_p9/f",R؃t33btJ3ٜ]Ġ=Q,ڂ'Cx1m3Q0X5Lar?nmMu q@:Q7Tb~Ҵi,UbRUkV]~ v,dˎEVZiEܱs+W^yҵX0neXbƍW[Edʕ-_L/^"=ZBƐZ5]2wkڮOKn|Vݣ ŋn#r͍?W}qƧ[W^aн^x͟G~xς_|ǟ_~.@!t4Ge xeB 'ܣ8ȹ'q $`)iNd1YDQGiFoLFwG1G $GA<$dI'r'#2˔P $<)L1l4μ$I&&Y8圄o=,Gg4k1sP(]H?CG!n9@H7h vԃL "<*#ZC"Z6{i \w-,Whl&D͉'f_ڡRcK쳙JjiF >! ]wxᢷ޶k3(.~)Ӆs%fx1Ȥ 5ȹ& vgZuqGV>4M# 8`eړݮÎ9zŜ tfΉ Dixd.ns):n ;q늷5D&䮭+ݦŻN8(.%>Ͽ,NOG;N>tq~MhAvFEظᆜ66@<ǖfUv`fHG!Oxx+d~(T&ri~6oE.M7Y9sFR<z_G'IA:hZ@4$ȪjԪIP6 sY$D~կw 8e1Y~NW', QԠCn+J>ɂ}Ǻ•w5]d[ŵ.~A]0.1=;昁9F2yX.c5q#3X܀c7ƍnATVӰ,4)kkfMn9lmgdBph?#vT0=k96[,3K@hk)s,-syb@AeqcTġ9PhL<= \6 g Pw3q`&'h1g0V"*t[#ÀP;w˵`[E}l_7mF1fbò6bQGUgcb^k`ZM,AGoKG]R4D0ySIMԎ +00Jg6F̧ ܠz_$,W$љzfG, |$qZ)0"AtU4n]g '`S"uwu޹;}3N7 81l.FVgAr7$;ipUwn LAnA}yBafɘP29wHr1<>>(~rƒ7R>^˱K|qJ8ta\ӗ&=1~N7I}PfuҊ؈Hips2 h12 dArz_k6Ʋ Ȳj!o3/BsC-k[Ӣ |٪ײ~k{H!'k?8x̹*RŒ.%Rrs#5 $8B.јØ2P aHz( :LBDLbbMҥFyt[W*#"*PL;=$h1PE k%4RŴL QɒS"E+5W@XZajpeɛ9 h@`(˙j\4fR ?@Z̞x u+H :e7Q. K7j-T}KKYB*L ha,BĔƬ+X+2F c:p $9 *LL! "P$F:XXM>tMhDj%\ 1`}VXp(MN9#DsH#mVQVYWX$ssF3s@O\i'ÑwLvkMi5(}'I9zGɝ k߻(S}P2<ےїu rڃ;7q)c4$*UMJ?OڔBDR%ZT^mІoRڮJlToH dT2u@ҹ҉%n!ɺ!-:݂Lhͬ2h S?T{} !tڢ-Eu -GBp(׍]2.rL+H#K .]N +Rm8,$hXY͆2: E 8Eb XDhZd WDYzhQ+c_p_ [;3Dy_Ik-Z*WDTt;aȟع=)%F M?]Ya M>b3SXUIjRZ:)?hl@ ꠶Jipci{9JRgȅ8x6nJ?cض)f/Ats!q˪\wz @ ݷK x.X]Fs˽y8c+< ͌AE0 gꪣ BRu7T9†R6]F[y];)Ya<,ģKJՄ֙Fl$_U_:gh?:SԺ/W:Bl8p-1vEpm ]t]vF W ?2oZ{%'.Vz*ĚA|0 um5j a( Y"&=xub<3E> H>,~Y\,p oq6_  fbBz "tfgK`]*&i)Bn .b qvp1wg@J̕g&l8,b(Mŀ +p&h/ͤsg⫣c1ߑ_p?&|)/ oҚLɂp.umx=ddq8VW8sA9{@tp[}XI'%Y}(3鹳~쳔pY&ȃQ@@eV_nD?l=Ic> ^7Z:@6+guxl!YSYou BW`n"oBh*TPT.1| d~ d68w.0xx\eCKg%Ǧyא7 wސjqEX1KsG kIw#ƨtMw(.>. iG9*Z䃒5tqYQl/@ѰHbo  8Z+vXHzg k bo'wBGyuc~Q]{o}g 5L]K׮@9BBm0$qqE}}}z7_ou!-`'PqtTG=`Gko!~3~H?)Pi<Ã(eouI<{cT)# m`#P 8l 4 B B/bx18? )r$ɒ"LdȂqԐt5lɩs'-Z~ СX"Mt)ӥS>TRbͪ5+([vu,ٱRMk ۶\ri+w.ݺvV6/߾~,8ZD#NBCX2e!}`a3Ξ?9B͚Kg խY {ڮmέ޾.7kO|pֹW-9҃`Ϯ};ރx /~<ϣ߳? G G$lKmxp 0R`#{шrء&aX%ȉ "H#-"3آ7c9>nK u4G" R TO ey`w,rp٥^j"wءy`DjǚnjZdvf@EQAm$D@FbQE &h+GdpEO$ZGTSVVUWV^y5EX'HUkat]K`"l_ŘDlJf ѕeQۘV碛љ˜QW]s6/ov,z!|%5O9"ŏ HVqˆ"+\*l*jx"3˼#<|-XD0yKjvڸ{Fl\rc_o+\AG>ܾ 噋m0$ e)KR@BC;v#EFZ7" .FJoV=L-kWRִ5=NkfñPwaCA5qBDHm"'.%H.h ' rdnsbt TJVi$]R 2 vzlK^/g dRwy]7`[b%9=/z^tv7S)Kɜ7[(էJ2_j0*q/?|D,`9dTVֈe 45iTkF <`,B)O琚s3PrԨB]b-`'3 Nqgܤ:0Oq R!捈Ab(FӉCD% Bh-n1T]chRP* ӥN2- Zd`1_IȼH"˴*-9Z–RŘդyQUW0.VZ4%WUW^%YjزMJ~fIL C5j _#"f1,MH?7v(rBVhzDӔf:6 wn LlaPɶI7\-E4Ϸ%AFn|c(ТAJ%.E{QÑ&5L^`JSj)GZ94kT몕w+C- )lǻ?~FB2!c-KbrYmU9i`!8kC]j /ri@GfqWB1,A3~,#mn0 gsd6v:$=\'n䇳 "DR7LV!cw\F#gFE\*DG "TE\v7]UwKiE8W]/{^E>4C-2cI dx1|j[T:F0lia?V A#Nܱ\ DEj՚r )P r5uLD `h%,Lئ|)swFv\$a6ms+l\GmsG=);WF3f>Q+ 4sՅ,h#Y;*7[;hu҇Iظk T tY!ޘ٘Y DUQ٦uYWŕE9EqĔLWN9EO_@a!-#91R霵U_ArȆsqa_Z JbL=L Gȁx (>fbML*C9DA6PbfEӀ` Mxۼ͛@ ՠoU `3bH$t]L tmJ\y!\&PAL˵h\R5t`EO@zq O= CzLԥI~T "Q#f&`4VHPl ]0 * Le !-hɓ \L]^G#0ۗ12~8 p9#B C5ZXi#J=Ut7"N:cK;㱨a_$ƴc@A$d"X,ejf@fOdv@d h!G"*FگD IJH%3]&21eX$($,L f9Ik Q"k QzT Z% rVz1(^ X%JH Mޝ[J"rWK]#^eY0_:"沌`(#ڗ׶HF8fNgZ&ekԡ@ afp~kfvfDjGvmd [X5M]A&>ڵ$tH'F[V[U ͢DerM^+b)VDIy͕uɜ. Vn%0`iG\m[Y3BI4Φ|6.!~]F!81*9%\΁j^*Kap*_D&cRa-UcD& ?fRj_sl&d'-!*B:݊bD腕f (v{I0[Gp n>#d $JsڝPh Pf+RFԄ^ ʐT乍 lAqp)|)| !ꩰ8av\LZܔRN=a`6(_bg$2dj-qH!vrmR/ٞm*벺ORd؇E ĀmRqGBfm%)A[vMbM6ѕf[+6I_+ޓ?[jyKYmV l.5.[y&aj֥ 9jXz /O;ҦjzBmJoj~Rn/&zс/X.q)XXگ*B:w-Lr"C${Fpn\a+] kfi݇)+*k0tfI޽XN.==YvB(JVj%LdnPJ J'}9W|>HaW[K-* hx\o[NEl, BgU!t.hc-DKto*ұhvv-rG"I4l`N3 Ss~vA+uviEсGkG1oJ6ڮ4 ` 6ȭGA]ޢTJ0LR).S7kPk.VIGle Au*1j H 45@C|*\\_+`'o*6<='hW6&RIfO/ijU4B3i1Dt'yhE$Ivؾo!HvKF6Q $\m+*'3 Mwߚ *̀(rwDeV,ϲT:E|z_u~ui1Q~MmuA[]_Ch3%7w9XLlZD*f/lc#b8?kUB1z{nLc!*B:ݐ4!/"H';{"{mL2%Sr4s;4oqvC队H^@S~9ŹebVlkm00fM['HT8K:_Svi:6jˆʥzN=zϜ:@3o6:BOtnjxo /rl6"yG#w^{wܭmj2J6*Жo9E0vpژ7H麓x}YD,pE|gE|5X)~ Ѡ' o%)5 Wa7q?aV%9 +U_>┰|ɛ;*s@c<Ӹz ծ1 I7;CӻN;Q@0_HNV&nz={=em7+-Y3ONI݋7@ƒGOA;w]RaÆу@|6qőxsϗGw.෯ {w߷|yk$g~}ן  P@G\,"@Gp -|d H%I,#ADalDFQy RF,H-JR%ə4J)J=`\q#<1 ́rMcI#%JI%LBB &Jm4()R#HC 0*M+ UP*TBu- Ll0;,[qWx΀ 5"bWLS-g}im )C +DKyϏċILEcmL$G!I.dAYeWNer<`(48vV{2.hYi(&*H̚>l%;޳PC& Ϟw )Q>LJ+N?*I=UZ W]We.iE 1])| a`ֱHd-\i@L-4ft4YDirIfmh@CF!=OYC~qpۂYS<ѓ?IWI}Ŋ<^/z3 ȘPUfsjtf ˍu(9ֱ\4z@:l\GHO:+m`S0Oyd~lZ6ozғTIG#8(vA1hHKXH!JIfUh`2h+-[V508: LW5} ALLM3,Ӕ&Q"j iivH C~kKnsIdP)7wI't =7|+_[ K;)V 5c&ud"jQנ6}t-7*k(eݷCٱ yx s`;Afӛ. ^mweh #J832t3Zn DR~Q,0Sd'@tɋL t㝍gŨ }LDG3tf8jѓrBNGWӎNZ^Nw9$G]I .m `&%1#5UYi˰Kr=v/@2;^* M[dOMMVCzrl>[ ӆt[~[O *#ڂ}{xYV-Wb`+1ܠ ɘ\~t -Θ.MS.Rp]HRI7ŗyL_wo>w|N?7~$sN I]uǒԲp fB)k;bzFg2͒M ȃ6n0ä.L *PM"<&O-PMЍЉ$b/$Ooh+ȶ.ՂB6Hq '1ƈ2j*3 t>bru ;Pne싼ZOX8l 0j?'#_xA|h"O ZmaoraȄcVFn~.$ 0٢qLo(f&cPdp̶QG-"p @q! OJ 1 *?/63ܨ 64Q35cpC~gps7u7y7o5r8#9#- $$NO&/&;TFnF'2(FF dofPJ b$Ƥmޓ/ +o?R`'L -AKPM#x&.qn),ߦ*R :p0DST0q3V̱ 3W$y2+s 13GQ4:?sXquK`Gv6R3IT55s<Ұ;`*J:J0"u8mރ#8D{B2Ie0Ǐ萎۬J$ڀ:cJFo&Ch(?If@R!.ZэAk"t$tBQBsB .3&CCtpD1b0E N8:11FSO3&F/.Ga/\YR4:JFs 9t^5I%J"9;J`pLӢ_DFM?b,@`Rޤ|T Z)gK9PiP s(ue#ARm"h|iڎN+ф+V+dg.KUW2UlAmH)tmW-OcXm/+̘5`LqES 1Vkom\;tZ3/*H?][7^qO3^k3_UJKEf`ts3s_v7E7G8}TaLb@TbD 2O%F fuKuFBGf3=Wk!gDdJM1H:h ́{~TIB@x|JP,VaBmV|flm&R2/Rim6.61;O*H1+owo}CEpn4!qؑ@UvSAS}-T ِgD A{jU@AV["aZiYTwU-R)4l'xoՂ/,tlZ 3UbnA'1$grlFI1+10Q8p[GMW4e"'z](t/gS" 0=f5҉oY 8!VY:x昬܂u7,.a!āTddDXiIV;_Dxa|Dd[IJHZxox{uaQg9uًaaځĀJ^샂L|%eA&۔:ɁAd=$R(,i- a[Aۻ9½{@۸[{[e&S2uUD=Z$3-0ߖ3P:[#g]#skZ3P?} uU|ŗǨUZ6Ks;iƟڈ8!ߋ6{ttܪ8QXaF==?}=iBΥ ]!=$ؗ,m%V rg 9yuol Հpc$ n Jr`[9rF?2DK ѕě`5}X4S >!Klso\>`z]!aҭҿ<= (N.|@ITݲ؏=&E$I|P]ieF: ~w<'īaB&dAX;&Ց,";q[{=XQ }g!?8!  y!yWᛉ˘AӤUတ!=?&_ߧ >g @?*\ȰC?qQŋh܈GZBI$-XRLr˗0c2͛8s Ϟ;uJ9+H( ҧPJJUUVAׯ`B ٳf"[pٺ}ݻpK߿ L +^̸cHKˑϠmMӣE^ͺװcF۸smO*N^y銟6s\`n 3ŋ;xVmygڝrҥoRK}-ZtRvxN6BN:sLm K7 08̈́r  $(&."ȋ,"x/6!80MH" h"&#2*(x6<~K3>? Di$J2ys B B,DiAa n:jA*T J"zUĆ6d/}r ^vֲ,fmPYjUkMBnP!Хk 7aÖ@t /_5 kb)s¦HEd%b]"ŶE` Y^62q' ԘF/-55M158G 4BSIa44"ɚoPAksNNw`3fggbxF^I,E˜>hۭJEA{Y֔!`X9 QN߉PT?{ԣc&@8Ժ"5DjwqJM]`.9|7LnNL# 55gz+՜w& ʔC|+53 A8@ҠfsB:r)=JWlɀȖD^aMm 4A Zo`FSgIZ!|jP B _o1X3G%֏]'I7"_6׾ޚDX`U̫^žUblO䢗EgLX񱐍ndV<~& ?2r6ALhH~v5$e%H8©S',nc~VǕRqdxmu|+z-o@ĭrER:2rQL Y49QӚ/"A1G'Iv~iy~{PڎRC nP0U =ScMq- *#hQSJX Cb=TR]#bm Ov{i ~ uF5'7ϒSKiQZ_j­KaY;‘5wh}׻Jgٍx>>õg+J*ЈJ`D b8i d7H8Pc FL14"E׈4.iHG/0B;-Ou\}h;9{V>ϭ C.1oMyn3(ɉ-їJuD(G5҅ɷF%o z>Bvw=> `qv?P:Ŋ҂AF,bTnyx3QA.φᤡto#a `ڷC~`9 /.uaM5pܱzAve^l+P6daBb)b.7z9nMn2<LʟH<"B>aN}_hG?Zmt8Le)SY9-א`0k2_#򗯃7ΟyAؗ)9"4_9գmR_3jL$ZJ]jkB] ߠ]2 ^"R^0MM6R@R#+r 8 6_7$ `3P!a `{NPաuNwq5Js&@ < Uc>'( h ߣ!9(Q(aYtɱ*"c%e%'J?@br@d&pP=fРu$ daGc{@Â> e9Ȉg բR0xHxWCjf:xxy8Qyyg|fD9y7y(zfqvz0%hhi8iF|t{Ӹi1}w2GkGkkTxӗjUTSIIx[**XyAsmf0$du"hŀݕ !5:S*"8N!XNQ/Y"#9M#9^:!i! :y&xaDV(.W(>$P?(%}BR2n-h"D!,!,ƒ,vaAjTv9Uӂe'f&-Vxi.hxx.XtƘ*!yBD(Wg20/xՋ)8^1'Xz{#{17vi{5wF=pk긎H'FZdYґHlI1\r37t\vr+{!$"5M'>+#-:1$Yj@9IRz`".%8 H`n&ѣ2s63''!#sy($)_D)di!fl@==*, qvs,w"$-|斉8Rjip*^^`_ECdK18y'30I09C0 0Wc11 FHF8{I Xi1Y|*ǗϗJFF|Z}dZva9 Ym IlEjA9!{u"%:&Cs:B 9zZIRZ*9-ut0b(97Sz1T,@z,n9TZA}@8#TL,z,xSzxnf+Vj5grLcб  ePcpcPzjzD/wz\E{Z1xسP*y{V!G4ᘵ樵踵fW YLUQ+uI[Uȏu imm]!*;6${&0Ar&0:! "M$ +c?"?'Z(Ka6K*AkAx -hְӫC4׋UxZZJ_P !{k$+y~sD>a79a!Za?۳jU iX<{#մytjkkhgH='g{1G bGXi\ GҨN`m¦bM}<µr ^y{͝}2|=̝XÉ=Y7s( ّń^h#KP*=-ij2ū=j^}]*J]$]9mp9vkz{̫՛xԭdC֝.]#^bB/FMF8+NPmʲuu.L`H`J0^nLH}*q'SSn*l *p p. i׆YI}" 4e 0d&eo05M BN+yI#%ڣ+%RU^Wcn#Kc[~f'M u+˰˻+f--Bݢp>DH#{lڦD3W?ʍUM`on{A`2H2ÌL0 r vx vDܵr2?1P'g8/MIʓ@ {'1_~.pP*bpq͉-7eAޖ f+N^{'>_hRC?tP@ 6MQEe8HP8E>BtSN-DKPCPTTSU2P Xc5V"H YZ"^{W?(c b c6^1Yh= `6&P"ۘj&p$5\tRw]v +L )^w|ݢ_t0xTsl,TDل ),T8J0`B8C,kMeUsyepbfqٯv0(㊦M/ c btAO:K'=2'@ ݓ? 9T+ k l°Ǯig.oS^F<\`qE YV 9 C BHnBHND 84md;!%Gc,%esOlX>b-WGZ5RD P&8Θ-%Bwrf5g6C) =}h=pW$ʷN춓!<]wyy^mp &)_+hQ$ 2+ Fp M 0+.}c^*UR4ZS fD]k:(3>⋫El=V}L,IӰnDc=c}bg?j~ Af+ C B A$;(}Bh>2([J^rP&ІjB.s:Ӟ_bm/4!4Oy[*=.B\bTpx)Y{ֽ.v}ͫw%6=>WˎzPYjK-l*ob* Vp &a4Q3> +ܘb .1(&4Ɔ#7jc+gG1iEޜZZšYaЎ]NzsVlNxCY[vARy]hGLX`b=7^p3tG>)A\ehMfsZյ ŒTw;=s3y— z@qAkARέ5nD B|yvJ$BxK[ߝ[&?qoH -j&TvmEÏJV6Ѳxt _Rxl3? oF/·V`MQl6#*STb,bPũnqd Yvx3x0@b0#̣]vw2 <(9Xq@|Hs08#,: #p|AA3BW,&9B$!)S%;[%;Kc=<-ܺA-0t&H1eZKaK`5Ma"Y.I!ʳʼ5C@`@Pc/X$E=feS$Y/ڻ0) =N̶؟ŞX jS$>80C0us7ŲW7? &؄ 1!Ϡ1 k&z8 1?oh2qGrG+.(ۏH+Y0;GB+'`Ƌ6J9:-*#HCBC&lB*!)|HρºsձB 9a!OIk2RCh*CɞPyDp5jR.849<]<= -Ђ@B/C,"/cD|HA (p/K=NDo!E ȠTTŧVsK>!Z$!#E^W0FЌPF]dLs{hdjL8j1m$LӿDԁrL3AM첸GyB6E}tH@P%+AH,)a;tԱֱȋ\N` &kN<=Hd:&e.2NR5+9I6|<|CD8J\'?pKJb|ʨ|=JQ/ʒ1JʛжoDmK =KJ PX Q#1 #̅ˉiѿhǴF[ȬQaLo,<,Ͳ͞b Մ{z@j:GM-Zb=P%QB#,A8Xz4*4) ;Y- TE-ə:%Ds<8OOCYd=f PٻQЍ`KDPRPЎ ˎP}b [<7´a[CoflLkFrűs*$H \̃y]\ ydt\ezןxԔ.RSLJ^H-9HT;e -:%M:mN&݃6B-YHmT:m.ZQ>z"YCo6؂e\^ _^D[9CtDQ6ZU_UPLJ6^5s[[<[z>볅Rџb`F%0m<)jT8t $X?1ƍaA+uR#=G%(-ΥM` :IXSIX)DBY֥XӉ]ٝ];]ҹ)SԴ-.c99e\Iqɕ,UQ^Uunj흃_>cY+_u:_[Y'Dէu_ԫߙM[\nZ)]0+c>_Ty `[ [eHrb^8( w-Rx Ȑܚa>ҳCa'5M'|aaA1`Ǿ26,aRy;M>Ă1%MB%Xr4ҵ،eN,(b00-#y#ﭴda(`N+Ȑ !Kto8JbHp6lˆ8"* @ onz𨱊 W ~alq~Ѥ5p:l7d(^>۩ 0 YF̫"\˯[hTL6ܿm.W $f$pE1C" 5x ?6'G%}\98Ѭ.2bp B-#gB,}-\D'G?c`l:P&nCk)u8[opA OwXtȆGΆlm<)םN>;YGh 5AI5TuTcc5v$O_ ph_`[1XBVvQFw(Kg,,Hpʔ!n2wC%Zp bR*ɓ*I#1['ixE+VYΠB]c.1<ϥ0O eR UX#^:p[ǒ-[vCb[篣peȮ_W%8(OnRL5]7 B$M^Msرː9gU%/ 6$Ip#^ߝˆuƵ\9saGxso;8lj:ǯ? _|g&H ןJ|Z}&QqoaQw+1x").`18*ب. ##4VT.O<"Bi!UƀF\%x%Ly2lpGxే yg#}'y4s?8۸y2,yuSq)x){f)v:*摩z\jyǫyȚ'++ê9jK:ˬ,Ųj`o%n >R ."~~,j˰/GRSf7Ȳ0 ;Rcp@ٵRQ uAC8 4A%/tGSᄓEgڝ#G H%J*SQT7X QMeR:E%OQq3WYp*ULdfmZHm?9d6u]E@5`aBDwUSMSan{ofZi霆?q nVvDF: Qlh:FSQX64{y+|{;XN=k!?_==./>$6/;ޟcTSg(Jx3C 99((Uq4uXajլWXs+S9mUX:)%$  c]FoGqS6# &=3D<@O.w=!g ǒY = N-yHd6{Y*CTQ6JV c*2wJat3=JhӞ6Q'!.UMW㪭AT*kȫ3 Z#>:A|DIL2 6(!(!..eDTT6*_ :ֱ&DßdH6!Cr'8iSֶJߩeXT܉:`2-FR<&..1ݐѺRC!rQ/A/݂z]|J[ЂT^y=l)7wW‚T.P!)3M70!d*z- (aJr ;)[%y5ИMs5a<8*S#ΙcXAN ۥD<)'BX)b1z{|@IG2-R%}΄ nj rs=oLWҕgysH-"s&"480h:% |AT5YVZF)H|h)OrQMMA8^]t TۗD`XDy۸  ۺIC#TЛ Cci] )\9 9^Qir9KQqqYsAזX%`a‹Z}ʩ\TyUMx4hUxQE:HC1,L\ Dx(Q"F!@a* 9 BE3\b؉`AJN<=@A8d 7(5E@OXA#YZxUEZ #W[PO UTA0C/M#9M=I`#b8F6\=1M`ehFn YQiSD]n$="mnaFeGԜX61JI 1A=dpx߀h$Gvd9HIIJH QLʈ҉lAŤUYџ 쟏 C<7lՐPRLL"8 /8%0D%S$e   @dmO,P@EL7C6% ^`h͠h -&n%&bq1fBp` eatѹn&8Ș[D.%,&,b8ˈB!!na K9p\f Q\Q<#J4H1D%D%n`Pn3'ΌRdX/AJ+e*AD3St1bPt5NdC*Έ5-"Y+.c\ }&}F~& 3:S2E9&5N^y94R|+N9dflm(&B;^{pEB"o袰&7%~fd 9)fv<=h>F4^EdaIڃ`HaF)jZ~mGdRT(v|^\$ XUM.5dy"8EԐvDɋUS:URTL$TElG6͉ux ĒX:`, W8Hj _J`BI a^+ikA\H cIfKe^&VTv!g+7u\1R~^lum!=@up6LWIMZDvf%En5SgR,ΒZl6@oN#UAl>M^=QbADE8 $юv#`>:hy>802BF u#x(Su\pXqǐ*Ӿ2E(S<..B)<_1HڃMe_ߝzmI)ňMY4*.*OB|n _}%,"FYM/VǭQm"^*+V>3s0wN.Aw,I 1w0Y #DEHFg``zfnh+HqIJPsqMh2,Cz~~iS7uڂdG\8gGOux\8mpWH 5Xo$"5Zn[Ǹ7j$7j\]ri<`s-k/sc;6d/kVB)n/!|c*i!66k9ksl#7p!ANovs< 7}xs0%Rs{"w&B vg7BwwW:xEߤ{ Gzf=.h7ھzXq:^~w:GyFG+PC/8G;GZ1QIkxm!:IxWmXOX&j#ϸ⸉to5^_3 1B`rb.kbsh9v; av[yý233n9&W9K_ɡ9k yA9Üm6To3nNu0OR$s33:ح0uE:p}PhNl:қ_@?}FHS>[w7.:1UT)SXϱ_;{PT9UiU=x{SȵꍈG@ (>#;MQq{c+ ߥ/|e[66Qlkk\ܖc‘vycK9oM$E@=ׇ6Cp `h0S0jW\E0hj4}hhArnR,A\I@0rэNMʆC^TqhF$>K,eiԥ2]~<)_j1TNS>u#CcS %. 8Vwݨ\O X1Vcoyhl\J u렢 F0F׿":,{mR\# kوVW$:.9>LsB .H8+*%V`؈荨e_$%TP^d 0Zg~' ΀kJi箃"2 f3:34ZAtIFF @ dNk2X/t.al6.!/ῤai>x;6>l!x>DR>ZᅱlA$AI;#Aܩ&݉'l'D˾.D̊K p$I,CHm.f I  . #7E, RԙmnaI?##уN5dxhN?JRpLolUCo(r9 rF8C2Fr,Jo0V/oAuItdDJ22Тay򤨧dLs0Luz sg ; S|btF!2 UU E VaZ4?6hmH\uUd3$vUGV+V`7qV |e !8h9)9#d(::HE%K;u)%%mXA<=3TkkQj$4el;/Ơ^D#: 1zN6 1l43q`f3vTB}tZC@I 85*I'  tC7rsK&4TML /M# gW +%c#nw=Oyx?LPQmU" A#]RxwŌWRNzxOp4:S|}D07L(`UU7fIjp/^u |dHuXfx Y$y[}t)[?$2e &0NUՎA%:P$QL N%5<=sZS SaaˊMO-V67;vc=!\bd R6 K9ui\ReEݤ#ܐZPu)ZLf$``b|6gV = ߔ6=Z<[Ve-:HA*W3GKRTQy> ]DQk kQ+@iKtu{l.4jQW"mYCߖ/Dzya 10-q: oTf1F3\f2FK`GY#@/b`Ti16IC :xl}t ]$7T>TdM2v%M7fw!%wL2%#Ôg`/=hoCwy"Ar#Cf9z\.PF;ToXO\#M摆4(&2 6eFvܲA C lfLPMD+\zGzay. cTCu>hW#+{iO%I2>wPMѱC;?c{ ԣ'9D}CH6 < 5.lhPĉXna]6f-_bE)/cR$DvB ) .B3J.L3 eRNI+\VV*8D9@ffI`:&l gEAg@*(~'HY*|h F IPTDejCjZ k. J 0 # BB lQ k²> -B\-/j{I.q*},m枋%,r o"n9So» /oj L0 ? z+y\qo|1G"Lr&r#AqF1G@PpsCBEFS4SMTR%4Єu4u^N%URSI6TSy1UmYfUeXX7[lM*\zYFxxe8ii㭁T6\pWqYuWyYyq'qsG;yy!z&|„ GA9ߠ/ȣXco}w*DI>H2d3p~Y 'dzGR, HIJ SBpz $6S# bj$\U+ZV򕯈[q o@!bYZV PX,="[E*3\6k"ЮK^LE7QnCM"06asW#8 -Cbl#02Ah9qT@ d,+d!_&34.삙*.-!#1Ӡ&Ii~Tv lLqQ4mRq-F7խ-Z˽o^d*2ɌF= xY!6R҉s9W';׉=MӞ3=3ORa >D %@A YcC y|\.j>b4}MR"oX)섿T@"*A'xP9Ё9^(AlrT JTp-dape+`4C 8hp:D@b\–RlFLQ^0LlāػXwg<;F7 etXbGPmb`s 4Y&0A ~D,YoZ&\o*{k{ roW-Eiî)ItRCN4δQ:*cHJ̩d!/ܠDB)GT7UbWAus3*j.;6*|"ΚBfYFw(hF/kK+>ӚhEqrQ$W>(??+7?#6W't)רs/F)ď1((tsDSA6dCvAq) &ZW+XDb*sBhf ,Fxjfif' )ℊm0TSX3vw6c=6wӅhIr `D0 h~W &Fgd!h. ) fymujxj7IRzwiZևxI6[Itp J6GKG|ĉ%zcm$n|f8(88o MoDP:) ČqpsO OXh% b?(2A;c;FS9=8As>  ِA}!pET [`RK0 @`/ fER-$mi}l+V`+cUl-֠ d # F\{E=*/{0DB -F:7q}z OWQw"D[ʥ.`d0Ead=j/lzi+p XgyJ2b֤HhV}`6IfHrYy(TZĨਐ:kX')BccL;k?{PhIJlWdj֓ K"a=_X o*Ȼ.O3#<+'-g¦`,L0P Ӝ dWK.Cؒ'`JӚ l#w\#`x1{[ך B!R̡11l2{ ɫ._goH.z2vj)MWjD$5@ !* ཾf.C &:q\Kf6v[KÇ7lZcP( e鐷qsMs8b`:x8l*\9d؞#NU!:lNMlj=@)BӘ_g=ـ=恰 S]ڧ-S,9B ك)ʻeՀF$C ܛ@ mDs5=w,S@ ,%#r b0Ꙃssit h3  c Z4qn6*j`=lZ*˥"^Ov1¦-Ġ,)9d@  bQa$>*@Z;͘; \5UZ&t`{Xc;` 0~ /S۶ `=Tߍ"b. #;0/!gMNJ. 1Gz2p:u{u3|Hj,3?2wHZZuyz0;M= 8-[(A Բe!@! FcP7z7\`K.p|7c c( zj!"qM}~~Qݚ6ZOlʦ x;JY掱 sq  = "]! S*"= A =b} QP #p 0B} i& "qaVޏ|8{=U=cC[3!9#Zu y lA{Il"~"9.ѦlZ~.4,lUlZ &Lvm Yw2,S2{?!b=Z- - q*w|VQd/p/r.tNz`mFrG|otmټ2d>CzZ~Kr+-Bp_>16ʉKCn306YrS,?cpE'n;N\!޹gEbNSZ:Ŋ[ o"[:s̝Ke\u*}޻PRxA6g?=*E҂& i$$B(i ġf&c)'|'2ouj'."4*XeYf/->CT.Xu ;/vS aJ,',5NˌTDI[MxU5]tj޶PH/8QL7n|p>y(V滞~A4H8?h?`ԠWBQC"Q1L! Z &P%#Hya\$ApH=ᏆD$&I2aDMߓ(6,z/z4)NoOvCMBZ4.I([3\rO,5Ja gT"*Q@(IrUU"gU+b W@0'& N)5"(?iZP8 5 Z֪//[re|5L^_D܁c0D&VaakbV1G+N 0qT S9#xf:ԌfBKhJeʥ=jA :5M [^Zvrmj mnt#!J>!8\L[RE'6}T҅@E'өT2)h+>\ʺ1tƯRW.wO62d0aʻ(Af%opA^V5>U蓾tO8 _1Zq*@UD"Y=Vzk+uILXL'?YA [[EИ+8`0ia\0/a-B ud\$&-x%Tma{S7#Z1b<| !K 4{fuzv4 T[DAD v k D)![AR*7|H>ZToao2nD àF*<RيN`Ԣ"+uPRAժV.jT_Z߅3k}Z'qȪ#9{5lw bˑO ѐ̪ #:Oڭ9.-Yr "qkת:k"'!y:%ڒ&"®G/ѺxpD(&"ˢ/r d4j|l؂w8T{i9l:hXaK>(wQ_ڏZz i㘺70D>AL;,܃IJm2z;{<:[ l?la lA1lE[(b455mHބl@D Aq:pr/p&t˜JIl *lBl0 􌊟 wQLp@OpqCg(()X kCk3gCĘO(X 0ijJDZ7̰Iim}J;/ۃQAHtzr!yLDȔ t@ LDBXRECL|Ih،(4VXN///h<2PDZ| BYj ٮh*s Cjl㪢mЯ*EZ@ VxDTD ګERk,DQVb ڶh۸i$:g F1M 2m-[C:Z!%AT9UO`= m){,zy:T},)';]F}'hTj4JTLTQ54@#mI380ǃI\Vm0>VQV [\^U @VJԔ@cpFTme3y%W=Wy-'{>؃z@%`|j;Xp\e,؉`؈8V-p =Y2! 2j٨]*P6aρ1UֹCQbá⥕Ct D\. (ZUW4E'z0<#c턺[0c2\lԐKSS&`dF: jJQ\ \>dA:Pu-HHFm]eTfZT6=]TI9#TU%U=^>[2!l\ DFE>$C-&JGKd ܋=$P KCΆvnan4m<_{Ά=@hiLvՃnh?K`]֜h6؄h `| iJ6pcU Rji}iY iĉa_B6Y٣ ױ&~ꢕjj,nNj3.b7QF[l ƹ-D.\4!bDVFFp4nC] "S=l6.sK]EuMLebB/Y/ٝAom,\UKA0a@ܶcFfWE^KYnE^jftړ<,U,6$q!fVwXܔ<.hrz.680s@,v`h,(YAT`8p_v_im/ ppiY5f,aЊ Yh )]=b~oq(л$jW ͘ ~ۍT>WX]k !T"8$7c&GU'([B-j*ho69 |TN BNz eO\ϝ8W1AtTW60󂲵[m4 t/KeߝmGۖItfmϰMO$ih^ۓW'| |{TI|q_qB16@O>XACoG^XFM`i}l?)ْvv-œp a v'jxW*(b |ٙjԈq:x_׌ 0VD?Q8X% Yrx%p Wuӓ>d!':hQƋE:lHb<|d%˕H^)r&͚6_Λ3ct@WM:pЦNm: ԧOTƤj^8ib6h\ƋW7sށ;,]lͫw/_[c͠h1Ƌ1,y2ʖ]`v91U9)R(=b֮_Î-[sB*[h̓$|-q#O|9r}ܱ#}g;wUO$qϣO~=OJ:wyϯ_}AGQ"es-bGY GpqjVblX!$"jbwQ3X_|:أ?C^|[GjXHőR,[r٥_1FcJg9RZѦo٦s9gsB1P@!*EUHVfV!((RZ|V!n F*ԊJ*ڪ6$D6Mr1l҄I~3O& o@8 6$C*6(C;b=1R]Vю#i =ғd%)Hf2Iaʅ24ʲ(Kɤ&.6Ͳe O4( 523S*O= Hj;kꪜrVU`+eֳR+ײ!UG+\% R_֖92 _.6\l ' ȒKEF6z*-G y۲vq qdf][.&-Aci͔frtKAؠ@\ O>TBN$]-PbQ(R~ASrAy RTZTRX%NTWBXIOAAL|JRIZYZZݨ^ 寨 a6a:DiM]F'tBdJ+B`PQg:*_mB+@2iZKf+OlLlDZmubVb[mvm988Ѳt6#n=#j}WnE_vE56vgL eFx'ypAmgtkl'j "9Bg'|AFhHFn 莌XmP9^mSJz+nBSSCuTKTC(Xua5uV75mBW۪13C"q>ⷴiz(j%bq]5!HGG0Aʸ""kNn9-jn$+v$%3`&tpegXHAԅ\Vq 4] -J`lk7R26x$s|p?F7n3 t7s./5W3,f-,jGv/ JX4}0]w~HʖCIUKPfT? s%4éA!"@7Abxksxw--( TIV1tXYZٙzm+P ePy ̙ebu:"P>'uqf)r]DzB_w"faGE9cm.b/bfVbEp*ft\E236\k2&x^mvs[2'howp 7:qOymssF …`su0f5CZ0և<{d(>wvX7˵| |ES}U;ENJCqȈ ȷuGgTHA Xb80{{;{x$HsA<H Y)ԢT Ԟ%YFPոiWe\|ȋȣ)1JDѮl/9Uiu#F[mbFm%Qefvѿ5*HT J챹T ι$SjƢkrdWEL tLAT6/(vp~x_& Dߧc E贈N/Tc 5ԀB8(0 10<8Cc=QGLUTK.MyEHIl>I,#RKpq@BXKx5 K8.31 1τ 5+lM5u{wcC8P=dA =8yd\mG!TI)K1ŴQFoٔ[@N=-SeIu(XeW"V+h*[o}U1Va_WbEVٓcV)^yZkjHm-衊Ze#Q6aB&n 鉖f^|wr߁{:n*(*bB0X+QZהšY  J/U:L^qb2qf9g3~.I4p[-6[ ܠέ7 :>dCn [3O<ԣX>>;(Bp9=l ;CP) amd'WܑEs!L+qD=D֕cqr2-]q+\sM9MU;ž8bMцڠQ5}h Ӏq D-ih;`-kɻs(H`!| vdO{޶G1I;-h'5(oBNPsS6A CD\VECڜ^Kt=ҥ>w!F#=MW`MmNl"M)k=DzJOyΓR=IezT`10 VTkXC%J4$`p1@0[AڐDĂyBhȔƒJHhB]+WĘSxH)PDCXYXyB:;(2@P"_`fE%dRjc$caπV2q)cJӨYlZ#ǧ15vP[rQk"dנHl*Nڪֶȇ> 0In 8@8e*׵ .B\,a<̖D 9lKs\0;:x™„&` fЄ& elM8Xx875B|j:NGi}+Etd>>WR3rA^Q >8 H0FQf$%FDHZRݯryLhId>C2Y ~$iyQD!ؐ+;XIp0U&(Le8GJV4udSKɜQVe 9Ƌ[Vj5#\}ƺa/54\ 9!]'ժv[z 6I6>y}#j6qU.H=Αv#Sbֶ-AiPy!9sHpǷDؼӾ.6F*|\U.-GT:^8~.Pr3L>;]c-n;&./BEgDX&S)ހL5*|_!>_t#;wqoJg*?0!NŲ,aO=bFG,Eb_6+q%|)@Eԅc@qLPXӜ`ٔ2*\7L'?UL1 ƘEʈ.+*8eEx3 NЙ.o0ϙ{:  QɎi Z!kiM=‘,%Iʖg&fMTb89TV :i:?16Y7DA- Z̸bkDxkkP*^mmt*ޖ uvm`#Id6iB͸+6pؤND؄NpPIQka{dnXRd.S`p lR.R' ~梨=nIJeF ® 2(bLخ)̥v,ex'+) /b"(b"obcPA˖x(+B:Je,͢hHhF1@ /*93q/hЀ576/up:o7؆փF@GNNa:p m*mΡkpHs'}re\ 4DL2wn'#6B `pH۴BR72ܲ `za$0 'e,Mfa 'R2'[.ρ|2/m/!01].%.L1- paa2-nA3!5' 4+0E)ް Sd rRA64`Ų!|4b([b9R)sr#b1s6!~A;9+*_A5O&K)q)|m6a=M/a\B̳`E_2_<_"B**LBYCB$mʫvdH/JqA 3&t (qhШழ8F!MyvP +:k&8,<ȃG !9k/"Zah#>bSm)9OyA_aP!vt`aAA#.. fɨl!1t>"`)$+?-ז)\!3(ċ@b¡0.u*|Ra;}5"CPAZ aJv"|+܂ tF+qqh0zF(\r˃7ώHq̫Czh1&ːxΫ?H?#?F]е }y\׾w/sx.!ARKZAAظƺK:%; f={Gt.t.۞>.]ī#nyMD\E-:kH<ĸ脟K.^ƋY[o䓻[oh!ap 7f[D,ǰ1`qht 1`(*ܲ ,03`&;w3=`9sN744DJ3=@cZl<7lcfpfsAx̭,xAw_ H7pC;b8cӎAH?#0EvTEzd B/ C QY7AqSH#uI;Q AIe#)aټF[#6 L" Nxz< bvbhA9 6o\TL.%~hu[|ѿj_XCTPm2 RP@ 5<.o~Cqٰb\8ۈD"↳x4nhn,n J$٨3j.O}3E蛑9(t9 !:p%!ч! %y-Ħ h+#8RpBQȌ$' gH?IE0"vihCb4 j" t! -y@ T&͑Jՠp'FbINwS0" SԤ:1*RT: N 3'>$TQ*IMk5UrF3X(U:֯rvWJgҩNeժ&.^^iҺU~܉G%/x-^B.2dw 0 au6J1 # "fd<^"n&:\Q#+DM)64AkZ׬xXQԠh;! nf@hd[VXҠȁ+IGRlNt(A:7<|՗JعHɊFhHFX0W f u\:?h#[N$Pmb*b[յ,fa<3PV! U`n]rW&ntK /Bx}k jY;KBΦd7.;F.9G|+X!Mp) U(/cyK_4F{z[L#%}SR>pE@А(ط" jdW"3P(;/~vg>2:4+c @zB#A ~),W܂F%2hr*RM)Ox -P> RTTf&hBv4>gIL<7iT]3f.Uԟ0NoqV[}\qB|(":ZBWĥbfP|5V":nS4U$VY1HE> '7N[Rle4)Mm:~w3~XARx67-zKD9|㈾ gKs0WHL/ 00U#/ə(R1ɴ*ʯJ<-ૺ3W&\؅_qUlqq!!'v$WŽ4AmK,z uts׬Sq=\K;Ͽa ,x5Xx$rU {PPU M#GѫW'ݎ:ky# jBK&J.=--L]4 X7 9gdpʼnwԗ*8K :ՙRL@ (JKJn(a` ]:@6 bM*KD}KY,DH(zڒv]|xn*U |}+Q 0 .2}Q .1]EWFQȧ:2cٚPA*٠3MWkʏʮݬqu7ۻ\ss(8+Hɚ-{ܦlܫ z yQNμmN]~< wx77M|F'  >:) n "?CK$$NN*, ( Ib( )KݑT) AN+m)FiL^ +(LKĂ Đ ]ZT9j6kikziv^y#8A! /% /hh 7J4  # ^9(0MR頾's SMR#3~?e+뿋1p%3;K0 /6eHo ;X*@?pPc krqG{QG\@r !q4r%xta rK. ӄL0$3hd8g)N]D=tS#;ڇcv\:'zwwH ntQ0HUxpy\? $TE>7V| LPFtEpuJյ&tk4Z!v+%cU O2}2SqP({#Q@汃T4<"c!p8+@.J߀^$9ӪV( "9hѧl!<`]D(eCI R5t "mc 1DE#,P\ 3(C D, X!xدKrU26SP`"PVDҰXꋚ 8]*C\ucU1YqLVs-;QÖI(r]א~d{@r2j#-ad{eJbRd80R+%)O9Tr~+c)(X!XBd2e٥h"3(L4Cj Y"#-d+Pllx':I`qŜ#Qg}Lm*JVΞ>yŠ\=}k c$892}*.w5Tx`:ܼ.vgU4(ݝYgDy'Q'd49iH>j=1(ToU~ D g38E0G:h]L:l(HWU:%eL =R ŴX0M6Δ&9Ғ7k'nA ДJ}2.{YZ6z#,ZY4jʮkB'[9#/9|y/}$O CQ0U2:5$08p:9Q4ySKtE4;48y SPl@.^p(Bs q0aDx?Kx?{ Ip!)mr+q\^ hLźt@zb @ʒ;ѬZ7J -ъ!A"4W1QᢀKLٕN-k)#Dxk!T#LKl*Bs19 C$DJ9E)-0-̗9~/\11t)ÉYCl|CCd:CCʰ0:089D1El:EhbĶK%JsMMԁ 2! y4ETjЃOб*>qPia^(p͆^ 59[qplH,h I jr *yr6d 6b6p˂2<7u#>i97d'2;-/-XJ/\)3ADAS ,BWy>x_%KDuAT¾V/$̞SL,U5XLUmSJsإ^%@L!D\M1T&DfM|d xFl%T$'N*hEÃ/<״ćj_SRTU>$69'$lBIBBLKVB/:]14USm]U9qՋq;ZtUaL!H)_:ֱ&gh^gMXfMh^h5 pxV a״X$_ē1S߆]E; ||_e,0=:WNW8JaDQ}YAv` .*W`^| Kh!L*#?faK?Y6bƂ)#ʂ,I.@JB[2UJ 7"b"4 \ߚ\A5}\7NKRB6PB9N9qQTBD:$)B+DHA0M9]FFPJ%Ru]IT]KYrU䙩 c_`:RVፉTM(՜Vu^X>kڴus^]1,@QVo5()K qQH,S_as׆BCMFE O(d$j = nFx``<*`~` n*acWJ 6v5zhagoF3@ln6Ųò!oc FȂ-!)V/}$7l`.6JQ c^ӫĕ=GH=ͅj4R7j##ɥc3tY=˻wa$@T%d{y59N%L̈I돁Kح4M΄fpRƺ[^-JUVN^ۉiXix^M[nt]yNl}a&Xf>(%%sfv< PmO ŜkϹW{or=j4fFOp0X:X" FOr`gnh64fɢ`sIB`h,YiQ+vh!>!-[YҘ(i2($1=-۽#-7E꫼t#D=.j@j$a96$<>Un$eC0-\CTbQd2X:ٵ]+ݙQ0ƾCYe_1 ]e@`sTAcpjsɞjpZާe.t  e.mT\ h|" U VئmO2e \N("p&AgiYCy^B{^a} c~;(o8}>*n$h8"yh6,p]LpncY&!,i"x/jt&Rj-6jTa.YxA#+N7(EBaGvkF  c!rC^\/PwQ19)]kS/,-Vx0Z͘ s`J<#s;;=e&A1$0tuZ{ ApG崋h{N_ 1 |mv׫ίdU?Sf {jQ0^/n[ncg@dWv1v&h:7Uo*nnv5}:m665Dt7v7,b$Fp618Qw-ւ( *V72e~g:zŸ7\@E=o,h 8j2dpaB5N/7rF?d!*)$ʔ*h..G%Μ:w\Uf.VZZtQD.m)ԡUNZ *Zbͪ 1Ʈk,ڴ-!rي#x-dsV0j3n|1[Rao̙hК.m4HVaz"5zE6ܷ_*QOE8qQ~^ 9螌Kn:tck;@y_^(T֯oɓ3-6aߟ*07+f+rb J8! lNh|z 'w&18#8x;#?1w؁i/M:%..HYj%lFaaG\r 0ifS"i1)uy'y.1h|z("z`JiX2 jp.`X:Zy*^4QD *hșQaGx+w: Ok*f."GJ;-J GAZ9kz-#ч~yPA 5QDIFj[/H!<QF5{08 ;KWQ[iV_}XRZ%[`^r%e-}b- SXb=721-a[m4M{Fӯ75 ֺF ׯr *z^ub}vܩ6љ'^ym^zİ 1lɊLTMluof7("*Ʒ!'gax/ҸzȎHA8dhH%6yWr9D8(HQ&p( *(@xߦ7ѯ~KU'[e@Wx8RavNR45ЕAv#E .1%2ԄVH<R @bdU;.xH/hp _S$Y~IEĜq9DझI4 Z 85X$ C5D D AM ΁"x49$ J "_:HC.`[eB`Q! Z _II`QQM0P9շ.[*ta&PY`:_M!1XAtƨW` \^Vm ʤ$_ &Lab,=cT\\,ơ M~HlWټ#yz\A*o\Yuq(u޸"عݥ켘-EHe$ﲜF:HVjEɥIBqB#*@MӞ\QD^^^qYSAeC AAP`!dmo TIO n[*@~Qq![!9S-f_6&Q`Mk;ʂ:%,fRR?ja Qr,[Cٲnk.DЂ`lՔBBO> NCjSkО8xVoC?0BU@rϚ) ȉ Yld A,Ke.< ||x \~_Zf$+SB` C0<zjZh6ĪKCkwl=k#qn7_ Ƭ1lqJq  BO_&-%owv h}Z f`'7׮V 1darуEʅ^Y`.3<-,'# =+n2C2cWb+Fب4Z346Gn'\/8cno:g&uwDGn(xx\64E}i,q8.4:B9Ǖf?cy}̇z8VEs81Bӌ]HBiI+IJ?0 Cy;PW5 N%*LvD( ,|kJ\*7B *8P.peTC4T5U5V"TS4L ,8@͏WI[;@\+LD 4^O ``/%Z Pc+嫾~Ы+F8Z&_CCB<.jcqj{6kClge6H$I %ǎ,ǻp,6'r3,_a؂Р4 B!PEea6aR7QXxkuǧ'(gj b(k >Vx!ck2Կ+YFmr+<2x.h,5K:88_-F~W(<k;O8hswvx1縎)5J)>yS2Β?onԵA|Fo]KoQ3H]p/:IJ9N 55ɉRެ:?B^&F- 6TP Grx#/7^;pܜ1y; NteAi'qu3..rY6.[ltڍ8lI4N8ڝˆ PF*&.sഅ.ܥQ44z;޾%k4g=! ?f1$޻뾯NH 9i-^"<(& ry&zFx!ʏ8FowđFr*kr#L?8VoDH=rla-6nKG0dq c l*c4ͬ!w:})9_w?*bɖ+9ɉ7X:itxQsk.w!N;WAL/A`?a]:ӍuD(޳ڋ]0wB8xgXIÝ6$"'C0щ` d /qcE;!FKR]Tͪ5-'0ZRUqk]N5yiTVň|+`wX^1= <)V #ck>1^\b 2n E3ZCF33}:= m(`Aj 0F ~; VҮMn1 Ԡ5z b 3B ThKFv39%Q(JуYVժaX%zm氙;%V8nM^`?h= jUb/X(+^Y~ֳ hAY$ZDY;"ȊX2+"' v$~ X\&IJR;>7d +\!\궩p ل'$ I*꓋ /6I?A_2"Ҁ.6coL7ٮd~ȑ*7 8Y|e!C#Hcp  Ʒ59e. PYtozi'g9fQe8 AUd$^O[讶Ғ=MkW^8 jɇ N:=pf3j]}f\s ˔α!Y~ZVtm!p?EHIJdmݬ+HLEJ1ph$҄MP!BPe^P: S2)hP,D)FSLTk+I^!V慑l嗀)EV[L陚 n)\a _.Ȏ#nbxgRX_ Ba֮xc~l`e efpΡ` 4g<g"@ 0񣈆&Q0oT ,oN1 b@ l"Z `Q db @Gl(Ҷ~|/ªF-eVfbqWFeZ/3R ů r2:K tGVjȍ6 MLj >DGm$KHńLȺ؄ lROP.Q.2.yQ~PLΔLT VkEWj8a® wjM2¾0޲œp\.%0BpNi `1&d&X"Q..$b3-11v& DQ2 ]SV憥 $@`<p,!!TohF ag"l qn B Pɪs1QsDZ-O==A ʱs>efm@@ 4 ="2۬("- @#TjF: Br$ J݄PI`^CWRIl7FL4OnRaCHR(Ckn)Q2PQ^UХP ' Β 玅LM . .T\̉00s#^\UP PQ 5`,c.1 ؎Q RklRsLe&>hB 4M5y5 a"J5a63O/psnF@ dY  !9uq-#3&r|/l/4;;p<˕ysy-zT>!]Ϡ ^9T&?_: T` 4 "!mA "1ab#a` C8#I$#7Gp${GRԏV \4e%F+BDk' (Et IjIVTi;龬iIHaK6UBaP w,-NllEV0L֖mǰMP. 4-"bvcFNP7pP)Q7dxA``q3gX>L=+QT,,H/dXu"@ iaflVV6qSz$ &U YwY1Zj ZWQSfm;[[%5)+l/^]Y>!*u^7S?5ӯ~u`@4A/aKBG A$b=`hla:6D:4F]E@$XV eDAv|kdOrD \4l!Y!>8f94IDHgNx2:!$(6(WAI2)iiu0OzRNS@JiSjt4k#HЅMt {)ZTM}m64 qEn.!꼩+!a6!A/9w! &'( qQB&`HI$yЀr-/B<&- F!!(l(siD4n ^VJvqLD~gF @ @ 8w^'8hwxoPЮZ)9{1Y:r<ˀ٘ @7ˀˀW9LZ V BvCdt:kw˳\˳cHIT} tQA{DMxck4fȅwEBp~Fo8h3OZ|2Tv)ҡeFPrl{N6 iMmlٶ )#{.8> 0#P;J95y;J`P_1ُIs;QfBQ};;>.&sf}V`29ri9Sb)M} 9fҽ`;7 [fxal!9l^;H jj5ZEc,A&P`ead"vjDfyU/&g l/u(8Cl|}A''!AB"wgx噀@z>8 1HAB_}G3I~*>=t\}^  ?ym @'_{Ǡ oCa 6dzoZS˻芦ǪkHHBZ3XOGNf0U8LDzF_᪡Fߤlҏī+f %hPh =+BI#i'87lvY l)XЉN:|!Ą FT)W:zc$H^l;NjWyŜY4hRڛwܝDى̚h9Mre頵|4kV\Id]Jj؁Z-B\:p־+ ,f`dc%{׬[荚ܹT[<&| :ʤKV.6oMJ ܶGĥi/ضIZ\̟Q|v<M0݄ 1XJO (Ԩ!4kZY˗&KhɧLIOIgGi NpG  !v&V^٠F7휓 6dS`7+TUG]~!.Y#!l ba6*Սd\W]ȗdW3f+c,Dx3ӣ"^Beb )~& ^Igs~Q'\xh hegiV,*>*Jf^in*",r3L kLڪ3TkVCL+ +.챩H$^+-$청@+mҎ&r1ˬnĸkoEҊ+*J*[@M,Ll+K(\q" rȡh|q* $[r̞,3{BŠsϤsBI'F}F!KLLIr&OMVa5:uZc}5b5dMDI1'ltR޸TITesK-e%tK܁xRJSSH^*!sKlU]u`gtXO5u2Y5HX6Y$ezyh8}Q9Ih΋fZ[fpVN4äfܖ0m_N6Gmgs ӡ}1! ;Q{4>9 c7m?!)rICAکh 8\HzUh%aCZ*ŃBêH p]p("i|I2xB+DcB2Mn`tF;i?yӜT@P:< z"'@vjԧ<3*X# [U%}5 gk*-cBVe$ A[ rj+\+]H&P/Ik\ TK̴ְEcBi3d51o,797&mhlgѐvMb#!Ĉf8RÚغ6y-\+y THC6I"osE 'dn[HַtC%s9GE4 9JJyrkS.cl$9aDhrJVJWӭm7$D6a`\V׎tw".Tf"젔t|G*VT?Y*<靦c 8T{1m|lkGG4=  fȖCz(~;{p1D vzF] 'YC:d8ux e8 ])F1l[z(fqt[g]INT0-CxEYh1+8r)|;I f0?q²/=jQ, Lz-N| X ,$%Kʸ$.Ic2E-!P+[1+^!^D6q(K^ & KbXf39 bK7ωmyb|e+ֳus>{;ƉirA MH-lTOl B7KSĢDPFz!JrK0DNA[kŨ4M1s)T!"$e1E s 0-t, 90'!Xb_vTnI^Kӗn8x^IC=,|5Kl6rVpE ' Ή[;(3hm}d-\ыScD&-[o~ۀ(D5$Q\XB2T-\$#@=xk^Nwd*"BM78Kv6! Bn,(,AaxB a+@A qC2b-_<ؒDFE,cv YָT4dԗ\钲qVڗLeO։B(9M1Qt"ࠅ j=fX@p? aJ; %?YS0e?'ٝq^֕Ո8 $4 A+ 氮= ;G]U B:Hۯ6"Я1B1L 47I̿I - ̌˪ai~& Ҥ `Dq ֬Da9 ,Ff96T3(Yn,lְ!k?H!4m:Fß &ĦĀćXoO Oc+W9 Z\\́\yUf| jI,nuq=\_u@AlPsC[,K[Ll^ؔ\zڗ%`s7 ʳʣ/ zʂdkM İ~L2bZҤB >tXDW^D#&7vHRD2Uɒ.S&P,[$JH8m3gOEjT):eժł]LVZVXg̞=VUZmݲx \uś^Z ^t'…;FXN)W{Y;=34wHNZԋXN[vESA&ϥEYLplCG364g\tٴ!q`ϫx4fĈE뷠|ǟ??,LJO8xK»bpAO8 P?%C 7CY>D IN>bPAb FO 6@DdEx.)ᐲJ+H8K/R 82<6@I7߼9;cL6G?4PA%P/E4Q/xTC4RI%-CK/2ưbRO%"TQG%T(Ɛ\V /d^5cfZmvU)1 aT^e&YeUZR9"$VZk&dT^u,b\sUKse7M ^%m嘱RK\Rx]H",z%M6$B ɤ^{-i%Bbډ'|&HxEfj)7婧/gf2kf|w,p:h&:V*j\Ae¦D2-Sn l4|l7xDf{&{3N:We8 oCϽP>THGό6eI #WB PÏA vdD !\]m$O!Q=5$|6ؠ8)>M0>-{<_7够;Sy>,Ԣ:Q"*pRT/ũOyT$ YʃGkUde+ZIxիUZ` `,fUõ-ZD% ]E,w1`c¼qfI +R<1"y *41 sNF$'XØQdAx”lLeT "L L I+6rzHF.u)Z&5IM^ ̜Hmjd8 b%}AtHuoN66q["f\f;yi;$Ǚ\4 !qKg}\ןAbwΝ : ~׺ QkqPC !Du/"gl9"5/y܂?7zG|^4R-ii}FJ&tRMs"0=a8G*x?H |5w?M3wr`)J0`1A(X! IpVZ+10a cXڡ}׼J R@%Yb+2E(jB#r ]N|b6W}ք3* #ѵjY1eMy [4iJ%%k3gH %3se dntB*K A"XV`Yrl9QԲƽ/{̷ɦml1 xX9HMp ޱ!`mH&Dݓ-' 1H=Dq<`C= !І 2e(ЌbD#1tG[c.)E4*t|WRHg}-h7ґ &ͯN@@)/tFߜT>7js6jLA ZVGTU%+lVJW$Mxk\,^jlm[E`K%Bvgj*Xx1Ah[{/nBEf9"! m6ٲ\U"@N2Ry ]2sFUYlx aY SD)}*-ҒIEB cQnxٵWwC֍qιxpn;OҌ"h Cτ RMt!GQk ;@\D3 νj"-mz!c4 }R<)5Y:h&l׺utlE:Y`##G# U86ڶl6ؕp ;$Yt.Kt)RxZy{÷$AbkOKAWräj8 \kxHp AZEl ; &9Xט/`i4္)Y189¡G9^sZ`x8c˜虻&3qKx7Yvb{'k9C;{A,(;$㰹sApk3r8 ;%%^hĔ-YEY6@/#J,Zy>Nkӫjm p,y3??V+s@}Ѣ_?$ D-8ղ7 *jB !ᢕ-24n5|۾7RA*L< !0W L.Ɍ8Cp`EZm%]ql)[ %d³) %*l8+'dbBBQ&% %9@C2j PBHN`ȅE0m&>nٽGX7E:Fli1tPh'3D5DAPOR˙D_Al sk؆7:CL9_FF"Bq<[mɔI[4dH>–yIUc?%B? TPʬ"# 1)J˱,5Ǫ d{zJlː춹<˗YU@IKn PP V"7V`,̄Sq.XS7};VAzWjAR ]M9L͏cBpMr i%ᎽQBYLC9`433ÓBGh0c>YDtb1Z'c>SA1t yT3,u'S\Z"S4pp;#Z2Z:~,E%(9ChH1$%I/%|CSB4tX3e3sl9d\ʆ%P%<| [QBG@l5[ũ/ý%4/U _%h=BG<=I?uɮAEB4keG!T^yae ]\uZ"w)~Sc V+’sx[լ?y6;" ՘<6zõV"C߰ +e5!,h KQ ?Mx8oo5a߃.tR8vW Rp;MF$ \l'TCڄ 4p9A;Sfz(2:8N.NN:0ɹH>C1tGp&11m'eĠ:HϢ5Q(1}JO ])U؂Ȣ"s 13eQƢPYиeܝ*5h߭HHX0`BAEU䅂_){އ7JZ_{D=1Ո6ʆPMR5l,J__5J-ٺ-,X?*o 7|`q.s+ n&r,ӜLK̵4P r=k4WSPW깨VQV$x8Bb!|l9 %^b٤)"cMb/^ 1#m8Ep]^XN6 t:Q:(6xY=hiuy3du2I=߉,?JGd&1PB߆EYi @[;~a \6]6#[&a#9f3sjFc$ĩg^nGl?.ǒLs5]p3%l1/T@{nc~q6I=ŋ\(^O3P!ohAeh10CU+H5I*ǖoVKQ($]Uqi&ڄ~5rspfi]e6 > >΢˳D˧lFMHGv,4@.`rq Q'R %׻`႓j \PU % f=B[a}l-tؠl)ՐyC1dlЦg3Թ27<1s0I >l6>c3x%c!u +nxHl1XnFsdBUB8;묓@%݂&+Y6`[?ƲnM۰m7<cvobةe+lPzyd 1%-\:)랅\s]4]sTN OUݼS8h/Ibah"?Pa?r$7B]$W '(?!׫+ocTPs y N?T5)7'9:;O=sJqiCGָފ7ǒG}tIG7KtMWu}3uN xo~~8MaxUW8t{LpaR2AК%Yp$n;gs(|MX$pQ4&*xpDwy("4.b F.nɲCI"Lf%˖._dF&6m#>y]dnj[=tMy(\!4}. &ZŢmY.\}+w.ݺrO5ab a/M$փ'rB/ƍBFCfaάysfH*={9M\6Ri۸lx;n؁'6ٵ>g fN,6l{o^wq٤㲦9fS}TM]lttXx.Ac3IwN6ԌA83Qf`FLQNܘG]Fҵ(yZ*\p3pA86FYd2U!263LSR" ,`p PTfVX!&U@aŗbV%_'I$!F*r{٧ʝ6A"(B(ڨH(&آg*('+BJ*r HʪD+,ӫZj&E L4ѬBP z2VK( KL3L9%ۮˤ I(I'\ڊ8S;S:Z&s1's2'!w"2("ȧJ֛sSRӳ $#hI@o" Jʶ*mpBPl{c/Rp5Jә0qf%x\$w(JR4W6sуS- %Vi,gYb.o | { d-/i $@יeO{3 HС f*W++409џ׆><² "T5H>Y-kӔ f0-mkkN!{Tȧ ] .x Mđr\&ҝ.,6*]̅}$+QJRrUĥ>^ R*3)Nh *L| fX,! ,;mP\0iM6aINSb2EDYJ+`eb)fe=1kfո:(u{[&Lf*3ɽ:3ULzkg>0O T+Mp:4@NmL\\2bm;FCtl=ۜϓ3u~?y; 03o|#g_<5GQtڿٸ鴙nj[$m uB~0!"# k&g[Q\NVéTWeNγUYMZU\@[Zŕ\^n) \`  Ā`Qϻ!E fMmhAAG۾ՄW\,NS0ǁG~FQ\SV up|Aȉuxrɑ5h\Ĝͥa \U,A B.~ I2T9"Iɫ|׍3A 坮 lB*]J9eد%-*^5Y) ]ʼ4+(RuTY60ٗA m mB# =L̙@Y20 =r@EeF]G Mm qJIـEFޟKbQoFU\UŹ! [X\R8 XEXM`EU d `h\| \(R Q} Za䀅i [SWƁMHVK!i\Mf5:J\]%cqv!_:s!uޥv!c-,ԡdN"9&W !}ה4#1DLbm]A=-)](띊\ *]+Đ٘J$ X."^&8Y0®0)Yx޸˹3(4V5R6m8cS9Y5ѓ:Rc<>B31*Yv#DH$mTNMDTAjPUMDnڧqHDDTM]߄¨udK|ԩQNU `J.ÙELbXَMޤN OF DQj)c@TR 6 [U]`VM#VWPVY$e1~8[6]lYũiR}\f`2NpA*˵\[b#2"yQ,yQfv`vA&g 嗗,Phf!0$ k.J5k&J&*4A*B|hB&ݪo!KbX7q#+˟$sbsҷ0ꊞh6S8QK4K4*)|ykg*Ki#D+:~S,5S̞hBЌ >+D,fg#Z GI B&ڐ_CM(LAM ,GMߌD W,<0$P0UL$W)JLN2iV |@Oϔn)^|pAQnxٞ-aN i TIEvuwMio=^B!lnƖu}UnܷJnt&xpq u)R*cnfrDdQ-L w\ ɗ2⬒&#ɰ歪&jk:J&**x±&kn"1 bƊòR0^Kek-r8f 1k%h{̈́ ޞ*ī(+իyZ#7C#̘}~S:R0ɘȸN,<)ühl@' ,1,JD:NlGʪ(zhETŬ@$ħ=dlHPMM=,X+T'&cqKౘr81Joi7ٯJ/ ALOhYԳ{7K$i2A5>IpFhaRS=Ɍ*nupB+,=b#E'Ģ̀l04LIOuy(JJp} 8Xx eC"PdGE90 L8ADuLug=I [ IdRdA8)*)YEQ]@ \ {PBem~iR1[Y4FaeO$OW/hKHoT0d# AA[5rn:,¡^BnuIr*&wmRy΍,{wQrxċz!s1[8!%sd 37sq(I3PڝT%)7w3:8gs+Bf++Y*+o06= 1AыĄK3ܯ?3ʫʫ'B ᡞ7+&hkE#̲0A'h}b4=#GF2z0J3 OԖ#ZL[HWMGH04tԔ8pDٰ4@R74A/`sF0t9pVFl#-FtUp?":GŸF,CZ-hؚҒŐrٴ_3LYYEEaO c ^ed3dge˱eRq[XCvȂC39jhkS;'8hQvvnBowkMw͂jsSF!t;u |yw39xLfՊ2뷭g׾]cr{y;k֌Ǘ~vWB5)QEēN,NlP6+ږ!f54D g˰߄Od'R-S1k] ⦛vҁFosα;Šeӎ;@ -P@(DYQF!]$E(t4xyGgҀ4nJ̓!da':AKa%D_CXa1ViC6 56s4xKyCVe薍6а\RGdEcK&i>%6TRc{W-7,b(]88>kш)>MX96. .N 2@YnE-L(TxVK*(i΄衣Rij`H(*i [jN[n2ũ*,oìS˖[fi޺K*\0L2+M18\.Q63,3P mP|Sm5YvrcݸR)bUηMZy:icZ\qsjOeT?dPAї1 :ۯkeD5a'fM\4N\"u ;mt p+AoH 4'ltW4cIKZ[aJ]2 eaXȢCΠ1,aAO+ T(H*TC)7h9]*J&NwոjՐEP te kYmbՎ-x-=v \`HBK]JU/{d_׿ ,L` S6Elb5'g`a?QCf*fvf"s\DP#UhM5hAUHmŏ+*#(7rzJ !'BkJ8! ;0F)xO>Ep'A <Ӆ)Y S:i-UeRbԩ+Ê)P 2@Wwe wHژGoAf@.VbHF:W$fɃshג *FOR>ʍ}+a1Y^>kEbЋ& h4\$x爮(ⳳ 61̐TcL2bc$nCb.ᝫ 9@|KXNXpvOg -gZi9y.1rA ' (XԎI(0ƣɝkD*O[)R(i_yhۓzۑiq  (褾NmJQCݣJxڟXʢHNčSխJW$Ճzݫ[%])YG J)clv30Nm"v.lvQԥ.u4@Q kGŎcg+ör+\ⳛ'bJqhC(XvK[mG }1+Kd`[eD֋$%0- `2+1vܯ|K35% 0W(`_ۯ|F Z"cgh)/ [d"#;5oǠb_%Vha<Ϊ1Y@ #dAj~?Lˀa3;(㚅JY8fEmjA2'={XYUTݛ#VZFFVqYzj$ֶn3Nq .UZ-3V;0t!|Fx+d4 WWDQARDeNfQ Y\ Yݼ( ȨW4AݤAY| n"\ b@_kᴋDNF]4ZfXn: cN ~bN)ctn YI*KgA b`ad g!Īi`lj6 .#*)&-n),@.)-ڢ^l3^Q3162o5:JZA0o4:4 1r54A $O1@{\7P. 'd#qGȲvp͑{_J1}$,z.D14OD| 8 OՐc\b*IP Ko#dDAjf A&XAN2RŸAsH %QQ"P%PR20R%aNY2ef%HP-\ LZԭ V+k%]~P  N"I __. Z> <`.N b1W L 3Lb2Ra(DhH&sAF[TFs&M3N( 6o7+ $q8s+I̮=FqN..--pS"jk1tuhgo861.j:! F:B5J@^FOs5,zA%tIn@->#/47~=tA"DB,ӴJQ7ʫ4bt FR!8t-ff$oB%8J*TaԡSi ցK!B$+lRtrNQ9>嵼TT"k|| `WbWxX Y`Y2Yڠrt-{p--@0_^2/?faas尐0Wbf! @` V[f2)ScA%Aޡ kWXW UKa^ u6sS77k$8ѵ89 3+niptL:.3zނ 0 <w"uZ!DS&VGd'aZQ6T@dKVje]-OC7xIf!CuZHDYBGRtEMdQBzC@ (}Ht{x4H RMHSh"4IJJ RXȷdxk8+M(PD'R&MEoWe P}!PY,%7в[z]~"ESC_`JdaRu0mU-F a@Wqd Ku5QtY t92P[E"6 \&uĸHb @8W,] .]œ.^AQ: _qV1_,`< O?=CGM2Dc502@ R<6cSgVi5jCeld[C@(6e_6q7KBBTBfiVgߑgg3$hOOPDχgӔv/j!>k Պ@GCBGζ  WX`m۶mdTX2+Pw%ۊh8 W!nEPM+9(%XXX wr%W&5]T".!Ss50t+ NUuUwYU]^ HiawswwgV`ހ˫`SC $`y)a;bm*zWzmd{w7B}ݎ:qb~~ '/;"8cE?l7>=CC Ba˄+zq7vxBDx v6BBTcÅCBtcxi>DȆJBO9$|hiSDB c#1)X=1:Z:7\cQ:M7R!2|4 ;L!ᙣD"Z78v7"5Q9SdgE}|B@^`k|HA}x<~La;DE6n~K^vX~p{v˧!d Ne܋ \Y‭'VP]5Ϡ X dժUM(܄P%DBE$L6:vl&CRdR(S |ʕ@Mh eeKV.Sɳϟ@[c˒ СM#«Xv괉ͯ`~ ٳhӞ UԷpFj-MEͫ&ML0LVA5{u*Wa]IƅK˘)k̹gʘC}4hҨ-kf)Yװai&۶iÛ> N\;vzF<;@Nꉬ'~|E{ߎyBi~g"=h;*Rfx#=#?%`xWnF=",%Pg0gG2SYBgb"`b@>/N {b0 tbx =B{csw+f & hl@i-U-"}b?Аad P!#Vt!P>}}y6}Ґjy}ck)c)"X)(s-ՐbbVP+2 :BBZl,EZdim B$.pEL 1E# vo/ؗ#d7h:r!?(CepWJ؄4uoS(`W  ˂C`,p)!?ᆢJux_J   K[sP6-=w`ump6w47DG69f1|̠t࡞2ztS46 Xc88Ni0!^WOxbpj'PNO RPp{@wĸƨ'vf;xѸQ6r# F cbĤ( f Kky[ @⠥_0|au!!Y!6 ~"hHjr'g)+Wz|A@ XA@zk*%j:+ B< کjDFYڢ-0MЪ uAn-0xt ՗2a^GqEJeIFЪ]Aљ?H@ RJ3Q_n5Pڋ_- y +41 dd{?W uePKM{hL.ر'}p5{ΰ-RwNW59?!ceccI[vN5P ldTK è:P!`&xDžg#$'i{DR_fmo%ˣ`Ryk=6zN:-S C\cCjEzG .0i0ZPzbN:|r2V+@ AU2Y)0 cXXkCiXR,B:&YL,/K-60PU;[@MdN4 0 bD(ʌiW G@[)m B9N[* ˈZjPJ*}kͫX */`:4ֲ./mXDMpD 1(a" /t鬹*LFgs?p1\ 35a-3 l]& Cqإ:J`!Ϻ \x7 q'4 d"LEi8aaj1. +.!J- YՎzȇE& ~ $gQg!{Yľ(Ly37zbw` Pb* )6Џ٠mC dOzfwiFF dٛ(wW:Zڃ;~<lm y ~ɛ|<}NW Cg `G ~&ݬ\>sQ1  iCkJf(#a|p (P. \u)` P)ߐ ~bΰ &ـJ*iN\9N-;ӆG.`,.D% /MJ7I &Ft1[F]H F|PEH cM1>Q 2en`C @:tԚ2ڛ(+Q]? K诠 9zMĤ _s4$6v].rbqU0.~8N9Hk7ROΞ;fB 1u sS;,;#.$8 `(aC%N(E1ǐ!BBɋT >ȥ[;xEmݻt3UfgE-.szBit\(JKaŊFݻsϴ`Yŭ-kfB+zn`㫔S5jt݄ߥNwEMF藫H@6Gse̓L /^ͺ15>D8 V̸P.r]9oy2pV/gޜb[juٵ. T'_޼^L޿ϧ_?}:i%%@D &DI#dT4QBMPPB; e&` QT”cZLSdPMLAbrq{\FG RH_1TFԤ&tRM4t)]#HTK0sL0M1Gb|TsM64sf~љisO>;yMB1KTJ tQH#u-uES8фN9)bNRK55f^9ePFqUX]EUD\uJQOu&U+UW`Jb2dUv8@fU<}l[;;w\F]\tEw]vuDM4Ҹaz7^sXx 7 ^U8Kx];@c&$E$66hcCYd6J6/[ 3bfcAK,аg炊. FP脇~.%DA@ i5Na+XI @eK,dmIC@ #vZ!Ћn#m+mDa#r|,Ԙ%+o9\P#3;|2҈|tE3@;}u.DCuc1d +snwީ۽;:Rѵ5AEXED)>Yکބ&>u5[aRFGjwĥLծk]vD lG:r}H=JBt6s'o~jװ$d.I7WqZbt[v773r8{[nɷ7$#YsKXzAD[8{$8Kҗ8{ |PQ9!{٧bڙ9!+qK& Y&;a‘m:1K X1c+pDh>CG2˅GÙ;>L+C@;ۨ[D߁4+ګc k=* k =q5=9>i< `,l,t+] Ҿ BU[GvĬiˬi6zܶ.JY??K\@T7,\dI#T@\{|@2py.M"u+AH" ,!Nt8̖n;%6@:U⅖X!"$@$: 0B.&1l*/ `ʦ:c5|C8t>9!ÜY -/h=C(;);AdCĻ[0sLDLaDđjãI,[LT)Ƌ<$MHxK` ;S:< $S(;L@;eA$8TCZE]TF-|THRe-fd"MM,ܥViV*W…,WCt]H7wIn<ҷmׇ@U$8@R}rؙ\ ؉UX晌1X%Y*ҤbBLC-b+b,N-f4I3]M6Wc܌*<+ZeYc@>j)AE~cHQqds] dN>O.kQR#DeUe4P8`dW~-e^nxP@ eMl4f~招l|X8%n،azgr%9JfI0`v6&yG06& a~Z2ڄ%}l~>naZh(3L(&>ۓH鹥-30fi{;4XL\iMPD!ZFjFj'^V:F~WXg|dd?k5kELpkk0k/Nsqkfk^P7kEQ|5;:2_сu_{_=fkϾ>g F-BCRNC +G@ *D R&K}Y8K1dY})vnv:;=`n (h( n+T13'vDTWrcpT͗.⾝o1@ۄEVDE!=43ci֑%*\4/!zpE^ !aI7l\XRHO1 q+#wD|7lRqeg^Iq.Poe-e9z7W"`FrM%?.J~ClmrBnB.s"4gPAgsm 7%xFhg=zC9tOtf8qI'Hoh^{;ӄDĴ2QI.\bC=2VYuxj\uuP .vIKHkv_a!idJl?jipgU8)!iFIdHyjPw`-wMCӄww6-V?=xo,~x-ނl^x w\q$AgAF:y8#+64h]4A^ k3j&b"ƌ1#Ȑ"=(i$J'NXL"Di 3ur Ò%dRYԨR+PJ*֬ZN5jb<Ϭj:tңE}Ad./~.l-Z|i1Ȓ{ ʚ7c̹3ТG.m4VVn1cӮm6TvO jjUüs籣C :ϳ'DL'wodSV׫7زK<#I Jl)7 .C :H8ᄭ *az!j *x"1 B"-"(#x#9긣PS Ey$IV[. Qn UvJQb e]z%a2y(&mfȉui+y'}' #q&z:mH ))tx)w\az-"0jzG"+&k"+FAB],H;0jt+)ۆ@P%1QF{HCJd MS{%}#QHR2SQ0AWUMZuLW^UkV.r\tU]U`9b^ b}dYCgMWYjQK=jY lVdusVupْ )utn-syw~M0{"}w+6~x#R+ Ɉh9ո:-b31~c$LNBpbeT^y;&j 'տy'w =;"(Z)[r >G߂-wFkEXV&IZZJ[d-q}\.> s0{_z!H%CD`1!Lpa] <$Y0QB B ' s[QmrG@)N#1sҔt<籓JЋOU){uӞ}7SQc_w>GS:!AOe\D`.h2+x `,^Dpx֭uA f*u 4T"jE`T|DZJ^bl&@Ұ@ :D0 OǠRŭՊh HЅA|qh2.nXcI X1gr\L.>2},f)R퐉&i5f:Ro~d6UrmYNfq6mvyL9S'=pyKT2s>ieߺ@J/KY`+)hJOJ bV9AVHшJR.&|#WG,я4xEXa h'݉&Tzx0#,ayO>3SP h@A,bOTC۠OwDA*fUhA:?Y2iAc -|5%pjYbŨFEjR7‘Щ'QATvÁ݄1€(ĝL!PXhB кVQŭY4 z1 ,QA W(`XN9l!+Q3,eS5WKdֺڌ᳠qH[Zv]tlOm;ݹ[㚐n";&(c$r{\XzrXVBt9 M6;ttSA7;|mp$DE)̦+XlS|q m<|g=Y_>98McO mA19;WychJu%@fA0L| iExu b.x"`Fȼ/35ds98\IWf,(PŚdtȬR2DafZe X3D&`= Q тgH-{ɎWiY5W#ZlRqG.-QIa3?͗kIv(̣۾],-',D:TP MuSEWx[a {כx.xt_) L˭heӋX+䛃4, t)D\4PσS?=`]șʵ`8tZ`A܉%U. !]XJ# ٫ԲTFiJI aYo)nG*x_8N+#v9:jB)p ?Xs=y#4W uH ȗI \}9}C+ w 8]B> I ގ v+|K͑&tЈ2TdJN ኲhh PP%ިPُOKFlZ [ݖʥW}@!$$ƨ쥠Ȑ^RSj mEd j`ƧgBM**ΞN-&8ndkZr2j*ppE[oFhA3Q9uzz2[f&筂x زN'vH9n=|Bj5+w|Q8˩뺖Xy#ɫk.NXKhJRA"(/C:HCGAKf$!5<8T\BKU˲DX" 7"΂JXNХ X%Y-bX#^nr @LɄE'c* dejffѭgjޢڢ.bR8BZ0&G/nYGXj4x9p6/_u 莮.92}Gy{Nwn@Jmq=(d}R`8C3+9@/'pBga/h/ro$Lhbu6=l657߃=d.=O7s8phA76ۃ7949C:d<9Ȃ\ 8,OLTt;C0KX9Gwt:0YtC?_!EJDKK]0l$??8C.s:B9:Ӵ<t"9w4#u*Rw99G$wD/,5G1tC;p4U3X{2`PĀLPUYC6TF3585CY8؂1E@yUU^C:CAZ25c-0Dtdf_C,e5UZA dvY3pADXhxveqivXOCd'SCuQuG6jr׬]ji۵m${rG &eVWIgC'Yw?mGmT?]"Sn4N$$rUbgur2/ (/TWB4%A.&,kAk/}2.| Hz8IJ2B-33# 5 3J0/Ps5sm86s=Ños?4:M384748k7Gy:C/CA,tECHXtXF#"X7p9CgCH'"wG4@ KEKf0A7s[97N>  9C?7p;$9Cs6¦w9|:9(9FDtGDsC6C5HXӹ9L~ \LĮC9zo+(ucs7-"Y1#^Eg7l:8y6BD{Ck8fW@D[;8`8lB6B4#8Uk{1ۆq`5vCA:o{+loK|g,z6xW:"k:/>Үk?Cmtrxvow1(9Bl$?ͳ)i_ڰYz7C67#Ƿ+}s5r1vc Sz7yQHP2/*k,P5ͲÙ39 W(+} 96ۃ(s89h8 i;Ds#/x/A/0t654p/z?A 4֜ԜBEN(CtCn7v7u6J3EJr.-tgHG3.|5J7ҭtKY +5MM'9󝯳_zjz::I:ӂQtux8k(reK cThq9,1f\VLG.|u &>T|`ܯȝ#&Ko&kVRq+gH$|lƝu0Ԑâx(f)qeYHqcyŔM|d H rT^IE"|MLigfљ!.0tE/R49VLMG&GMWӕ@_ B %DuRQR-yM:sO=]ԕ/PEmM7U4Q/9%3SJ9W+m[ٕF`ubA=d]Y\uTxvڅG 5n8so#8xif6ȹǞysi ` !c$]RpxE nJGET^YeF`byD>H^sn.9tclg²ňL"=C:v;G*=|c'Fr#A cxOMddOo bbtx!qrb h91DИƾѡl61RѣM BrґdT#*V3%11Lm#$E VMs)=q"Vb O(T"AN | YO\Q,20DhZ/(cpxa K</8+l".WUP̾ehi>̔3\]t>՞~" kg;ڮ]_Âe +@\N}ƣn?W sNVbXM=ho ;}hpIA.b !0\$IhBqZ_(i6 @n@7]"?xfq((E)L J\S)2U2)Ĩ8VbT~ԓnz* D`+N yb-:8+<(4Q>bM"ڳ(Nѫ\@0k9 l;#(~WqS4W+7$HEN<9R+;`*֮(?@$t#H>4a뽨S Q !bT;P~$h"?H*L$,RҨM(Nd#$$LDP!oOThrPLo\R'iZ'/(oT dR8,QP)UX5**%R XWLW2XRX -҆\@o>]\ pZnp&$Ahm@F!aa#p4W&& kxF݀!LaH(TQ0^&5%JjР_ 8i7o3,&8W[ :"^S:mP :0L"t(2"<>g_0ma6B@ n b*faf}RnLLV+ifhh"# +/|C5tCCs"@k2Vn pxkm 4C5BE+ 7AbthB:rVQ;na̱8ޑ jcTI=5D @h!xC,@w]i(gnL!#0$t?Ԧz`R$ N@GO95a}sPHnUo%[o~9uM޷FT(̓KLiBOXU+؂//8%$T$Z~ʮ X}UZ{>YX/A \iZuY [%Zk/~I:`IbSD\D*bz1!0,s &Bf@AaXIS=MciV &tx͈ k \5 ?eB8`ĩd@];Z6PǷnf @fg]{v%~ބ,FgAOnQF@ vvyh kj=:l7щ++ty D j{C61:2lN3@ ٝB x4\ wy=rU49s薃T !`!XPWVu7C D:QI9.Z! :">`+nDJD$=f릍r{d ,J:|(}ψ%%;hJ7~zyO]2}Ya9hTX(X:VK VU3뺂̃KXeS!XWuRXW R `/r! [7{C[ `S[W0ZXFi, sbb$5wj*viPga;^/ꐃ!F'@e`9;[Zp.p0&Mϙgge9=Bt3>. Y*`Y<t'ZNV-\%|{0\?"1y` .iKVY9<:NXv4;Knu'=IvG: d=xn#AąRsnd\(Ȍ"eR\|ODa6Iҷ dڬ+P2UDZR:ŸO(خ#=]T6қA7Qg%,&گ҄O8|%TuU{ ^[^(;wX[emGM;s] {{` CUc;5l{;cPa/aݸy &ڵ;[ ۻS ϻ" &]`9e9t'Q+zj evf@4++}`@ ,O>&r!.y0.:<1dkK Gg<w܃ޣ{ǑIv>\w\ɛ\KK̿ʱr˳!_!NW"W02OwVNOR;ۻ1*e*wnS_FtB```(+Gy!*na~!+L&6+b,+Ec6: :c>xbBc>JJ"NF!ACeVR,~@\z G`I&laffq gq!m܉gt~ h"{$ȡ,htIwLJiNhn~颋/jL$D*:j+zW^Hg\.ˬ[< m-1\{-=mzBK '&ˮ /#U HA CNsS~@1AFu4/F%-)RK/%6S|`TC %AUPH|L4U.,QUViX6Yc,d\5 K^t=b<-[ӉmXeef%Derjb3Ė[h\ƶh1G* f AW_+]w1p8s_?N߾J+ 㒛'`)"#菱!."z'1xc4hd=I<§dJ&d;9K.!^fdbfȖp?~pioIh">}x i}Њ?.r)P TRZu FJSh^ XGX$VZI0ja҅va,  lÈFHP@$ CRH%nb,6E.jbaD%B擑%KWF8ft#Ud gy\KV&ÐHhȿ0#11bhLf2LDCӌmYXcjmk%nt9ߴbv Bs˼1!7\k4;uI1B8_f>kfٛbqOlC[N93=)z9=4"ٙvktn8W!Hr P Z)K[/}KkSIxJAoC5j _?!J H5Kʀb7)x' X젲,[fOPB,[., eK6aPVD$ %0 "撘`aX]ZW/fz Jf3Q#3F;*vQYƀ<欏cd!HaL"?|Z5ų$g&P:\&jܾ9q-Ә0uYLc*;׹7a[v.zٛj.|5כl=}{D >$tJ(AuP]Bt=rC۔CLsӝ.O$樉S:IQRfʥ"NVESU] lpE\٧ꝴ5;XHMR4hk'PUUr]U]W aX ?dl XַzѮx+#$, 1֙/9pQ\Dl )ªn4 H/0V1db1".udZЊZ0zYd#!tym'3v֥<+V? ]h2ךn9PsoʆGF9|z}L {6Ӊ^bWkfh\9OxNE+{_jH|D^y I$$?h7<C]|C4Ҥlp+!|^k|pFxn/.8P*iJ e^̼ҸiOJX<F$fw8nR90 RE}ҿ]tҸU#A"ס$^ L's#Jh4t(4hŕkv5 f0Pk 4\@OJG;"=kF.ы`FDd艢mXGh;!Ȟ- зk SlwQm VG%k0{|zP#Ejv4P G5Ot4 h TUrF[la kG 6lO:l0 a @nKЄ@Lmrx ґ ngn Gtb#_L]!Vp}M"wpp g;sqIR"3qHq8bqq'#ȃq%~rr%x a%ٳP  & v&l2>=bq xtCGt@(@O'Mnbu(b+;ex(' iv8Ҡw(ccug@wcɈ( †x@BFdt0v'G0=`wrIQڈ TR  F W0zز l~߈@v ؒ~6WC/` 1lC TR~ ܸ}Q~xEWz'hVyEgFj&,Ix฀QA`~g f G Hj@f<5F#r5Hǀ { 6(6!kJ=k%lJ{9 4Ka T {Iv8y8 hhi l :?<;8Q8tn ݉N'p!,"r؈tIqC_I#<գ' ({9$wP- b, 6ah h=r‹r Dg l( XQ~" 0n~ !#FB)R)u{s{9 +*@swcu@h*(t" nr w t吣dt9=YJt%Ϣ1`hT'ZBR5U{i1rrf.2|&aP0l`YJ~P}eP P S^p03 @9ʦz9e<{ú a `ݳXLru4}Xb@|44 i8b Ȯȯ6 mɿfA [r w6ΐsځڱ1@ P v̴QNFKN# #M

5I7}N>X$X.S닀[L@u.7,0ԏ ;GedFͿ)0,$hT,OE\8OO$1H)p'f[Э@tprs =?FkZm&[Ѓ m;بzqPB){'Giճq(ۘ23oJq b-6ۺ7\X\i@G}Vti4#Xh %T#(bV+ qe(bzy,Bw5^/&HPUHԔW\M `*zͭE˫ށ*, 聁*Z#5<3CɆC=\/LX"YͶE`le`6z(S39( +?ϦݸSnQ;ahQ1N0*`aծ@[ކH-F,:ZP1(⡰$U%cr9Ya1vy{'vۿ\KXבI[% 4ׁCnk9pd[QeM;xL*E a"VV M Jܽt4)R+Ⱥr^=W]^P޺MÀp ԭ)s0_`obhoC ?6-vnaېS.E"|)V3gl~/B?`5X FhMYa10^HQ?vHPRΆa|e 1qЧ&t n҃`cbH 1@(|rY ZY}%b:_:=8XA  AN< qDF.hddھVֲĨVk `]VFd.8l e.R)%Y+uB 94J(r؆ ZmЎM=qx׆L |}s@联 ik?$qr.bn x%ل,Nun>_0N=TIn`A?"Ȃ P ؙvHEШhXY-Hwgᮘip7ۂ&Jj&s،V60qnp$` J0'sk_pdd2j(\l\Q( 1֛Ys 8;;ߩ9DZ "D "ԋ C/V$GF xt4%Imkȝ˞-Ѡ(WuepPV>Ȟl@T*VW/gXuԦm{3،l8)HMަ5H S(+^ =?fg|fv5&dVff7|e=aX*_F4؃r"uxV>ygXӣ?XM0_ÖBTd-hR5rq36Êᆉ))ippqUM@+eC0j،f0vȈNc-ﲙk:?2Okjw03Gs5߈߈s>s50z&lƻIJ3  %t HѶ8Z[N^P53H؄'m4Z m.j߈k~n$f (+VHynPfɃw*"V7=-?a[zw|0o~?oCo0I%m٤cx-hxx(WܖnQ&aB&Л8Fb92Ij#[;xƥԘQ!t̥ffFALwvKJpwZz]I$v,ٲd*sU]g6ܴq߮M xpнz"NxO=;9e{ɬysfnSndkȵ;w4#E*H'S:;޾{7Ռ2f_;.yӽ`Ϯ;.ۻ%<[ҷU\ǁKePU@Qӓ CA>ʀؔ#&h7A`P<(N@VX!"bO:`0W:p3%Xc/|3).(#VT$n 7ddKFU6L.$=T8T;إ_zicdykPsYw {I'D'nZ٧ ,h @i DZbj'p)&ZBZQ:;"˺ЬB1PK bXhѭz;@, B[N4{.BJn9<ۼ`kCT㌓2aKV:t}DtAU;SQ[s9 H$Z(6"*3p ^е02W[j N1\cqdKOVex`gUufVX[lvQmjQU+ ƛUںTH!l]wsAgԥ78yav{yRwUU9i# 'Uep` 6`ⰾ>` 40L5PdǗA)/![?ϧMj;9N \*S3~ RejU #Ԡ!>! #T ghVl[ۂa`c57. D(Hid+|/]29%*˫bLkYfC!|k>S!ŗޙ^Y4J6s"E46_\zSn<&7 /8攜995| -賓ʳB(Xi@DĠ d"#2rM݆l1QG2rkD U4%g^PXϐLjg7~3?:O93LΔ JB:ҒTV:B5᫚UXGHD+3\!ny 18\״jvA.:qD] r!F^'H#io- ְ3-INCFQlaJQk߶0z nSǠ,pI 28G!"we@ݗY5V~/bNʾ׼Z/lpT _}ՒoǾ:d-ҠWS5޲N8YA'K.NjD'?{ 8ЀWBlr D[ Gc {7?D3toKz|lt!]@3_/F_ T(_y bdu[jh~ 6^%%SɌ< E `\@!`]LԛB`F AYA8gik`lфϵCG!`uĠ ΅mXG*~HA;!~ a*!`ANDBd݋]jBڎ@0T9aa^|&t^Ia҉J؀ޢ^  !b@!etY!AU!b u" A|A<P_+K V җH`-_ .ccH0cP`1"#2aX&BxUFӘWn\kR-n|6s@DA `:J%xc"W6 a*>2<#@maA]^ 2dC:$aCLaE PݏFzd`!,I."2_"dK$M"%nd vda:>GN֕+B",2%D 6B%ipF.ReAu/I$RXcE2̌eY1^,#36b03b )MzhD%6D- [7ʋaCHG88NS9 bf%P#yXcL=#?.a?f?_AAٌ=jf8BEv ^HG&on~٦IR= J28b=&@ $M~U$ L`|hbZз_ eR6,%6bU"dVRY%# h&c2%beZeP#]WI_~ %77&a b&ϩ:bcBwxD&h@A#gz+i]+ Z$ampVʫn!5iZJ[)"Vv©= āXix"i:J{*jْ}ʢgTTbj:R$EWz*0.0`F .©ڬʬjZ֫Rh\jҪ]vȲBa :"4a5)wa(bkg鷦?k^C+ +ɺJiFfIJn6N)ЙB #d h$.=B AD, K\]՞`)r,)eCQ`6"h(~%aA*JςX2o,`(}ACޤ`1j\ #o-~lk@(iFH=ofb)lPt)"p IB Bn)Ng`Wm.熕exb"HA}:e [FkǍ,IYjU>Q^Iʦlf,Y.&ͪjYȽ8w9Iʄ/ TD-=uc ]Nt5\ 1٠ (r1ވE:ْm?z!hf%&G$I֫r) rˉ;d,Qp+Z' Bk%bb0 P #1 ).K ƿ(EURX>yOHX 73:ɗ'fHFy,ֈw;|91xmoEp蹑 OIr3J tyTwOxE6MBصwhӫwlN?Cw&Q'Iً}~ m}+@,}m05{Zg{_{n{_3\8)#3'W@ pE,UVh{@DtW3-" ?^,<+l#6/#ZBo[ct|sgfy י~I0ILNjC:_~̣t<#Q<:chпs;7/znčM;2@K\l֐;*CnEn$\m1ݳ'QDeK/aƔ9fM2#ԹgO9{ԆF&=ZiSOFujUfպkW_6`:ǦUvlNoƕ;nZ,Xܽ~hVaÇ'V 5jdE ʗ1Oά2ΘAƼecӧQV 58qZ~Om۳a5ޱĎxqʕ+y8x㑎rѾ}<_ߖ(ѢE/z4~|~}F P ,@E 0Ͼ| )ƜsPCtQh EbOɻn û;Xd1<`qi銃θ5_5`#k16NM/-9C xKC$LSM?7BNH;=?S$A9C U p. (PQ(ti 8C!SN)% ϑƇH=%)$<IUUWaե^++^m Va-X" r.}Vi]k"@aoe\ȝ8 "2l+-3uW^-H#zN ?͏%~&.VS2Ʌa㠃lFab<&x Y䎛c#䣯>aY:4ȿq9kΦ@Ht)į pϹeBPIl@DjNZ=kNɎTYvN`؈d5$dX &75@MEQTcjR2ゥP 2j`y TX/XzфS8|j=A =-t.<7 DTp&tJ M! %O͘T/i71@硧V 7(~ _|/%f{z j_gK,0p&q@q=BRW*sy3 tU/ 7Qmh/5`+ۿR2ae3k"o$'9Ś. 3Cpۃ"VYe.㞚"tE-Od$64 Hh[t4k,؆ӔQj1xc E'l'՘h 8q4aݸQA@CK&7s$N d*LDY`s%&btۓN@ɲQc\׳G$51‰ B2g`S[ު=qSzk vbu>{s'Oy, (KNrfs~g?m @KANE'ь~d vaAWH0?>LG|/(ilb i CNh74$TT)bE(ENFp1@ c) `]c"#*Zk6Vo@$Gb+uX/PF8:&I?<5T`Q*VѨ%%:5lLY|j4>z95MrBvX>.Kg?V(-Ss%+1hejS(+D!gDxG:iJ-7IN&כ:ww*t1o2m-hB='+Lч'UiO*B}/SxjX]zX}g뵼O 0Rm`}fh.w`ؽ0 ncI/=|#lnK"'0{x9wֲ\O8lP<ГEKAФ:d Y1р2T^t'Ҙ^:ӝtU8NZm' +eY)ŽYpY-(0-.-ޮB.Ep\N^I [/K_n2`R/-`ލrd6jlp&J` A.a(h d gb@c\@nxOCLw#K cDjhCt0)Oel9ao(jFB#Ȃ qN h`  $ a 0L Ө!1nC:.Rp:4rF`a@2HD8 mDaRS7^UCs1X d~'m &t؏цn 2qn@o)O"F1*IMd1+fy'~-~+N,lk+eׂQ-GRr,/11-JMzPY,t'/$S-G"F2MߐP";>/a 1! ᪰ qbr" [>!0x;6GBrP8d%8IP4 _q&&1ry2(OP,R" or?I**b@/y"r/4-6A/C:0 sC4fr5ʳP5j2$3űDQtEt/1 oHiLTS\>`s. 1H!Av36gɤ̋I]ϫΈB@/>(d9]=R;',?!UsNXV|%l'.U @!pv%4UABS<90l1WDKtXtX5E?3cl<xt[Uo7 (؂JYSK385q5rI}#3WV&g1ujo 3cIGtv1wqWQWyRV*ybgmVמW.y'|v.3pb 7:418")4~_aj7J5oM5=YCՑYo6ojJ-Ooy=YtBXr%w6Kؤݗ_9sG0WsIN` CDgՖ%gR8KCLG92q׉9љ!YըmyyBтҾ秜:2 W7ئצKr8avPkZ8'e4Z8Xn0 05ۂ Nx^TwMMؤS#Y8`نMEtj>L;̖?Juk 6ttzO=t)z)wyת*ɋ+TW,[nmgG.᧌ٻ|C{uEUݭ{a!rL Alr}L5n!96n)o1?[#"YMxŽUa83[;J:#}y5rʙ!5,zg̻1Z<,»Ղ~wImK8l|GP 39}5ׯ4 E]MohM=\XlA~7zJ+8e=^\Wã[a[d;yڡ^ /|sڳOQw>GVvʡ%}˭9-'߿ͳً%G}`ml=[1/=qhs 1]so}Rw޳y@^GY}>~WXo|;wn)a1]% 3%/۵纞 $չA6)EQuw3d>Xe> 4א{q - "0` \@aÁ#6l@ŋ3jc/*Hq$lj$9.H2傕/Ĝ f88sљ= &N9=jѥNJJզx Uׯ`!BرhӦ}H-"p Cܺt%˷޿-ۨ[+^̸1G##fDʘ]̹Ϡ/]Ly4љ3/b$ժ[Kn Yqى> wQmqkЕ#GU~4'6C ^7WtIm^bݥ:=wOpyǞ{jاn߿lp b6\a{8" G"6vA,$Gi(grU0SfqiQśv4eCՌsHbH'$/mvT'SPRq^GWFeiX%+{^&Bܬ:k6ٱe,첕9[볹1߿ lAs[Ui:=+ozao[h7h<ba;+|6f&D8$+oSZ 8'}&Lg4C;tD_DB~1IEmP2 /")9u5hPU!UD6e*fK 3啴/o6V2;"(3v*eRE vdYTUT)l! )'0\x^1 s \ujZ 6/1nrd"'F˘+]Dn]/J h9Ʞ xXGFۡ1i*Ǡ“B$qb $rAIDzTF )#Ge`(MTK钚DZP٧PrL4ͩN6R_eP0TBa 6eS*U_f:$[6tg[Q\&3j*VčA5m3q=Lu6~FZXyURT+Ejv&51] yPKw"(yuL40>FlDhC*R$m#Oޚo K?)St# ?Po" ЎVZ7P*+b˟:%IQr6ҪM/-yZ{nQ"a,_A9JS84wMix%8Tf>aN万1 gxó_{-kxYExF/61婇yf`>vmh`ÃBSz^i*TXIG.3)p?bܝ))Ԍ=mIw uQ{Ava?Co]<Yר|3ЍvHG6 LEP UfqUOzpu7WE$nF-Ze8n0]-$Mk0"q Gp9nc! `5[Pƻ#2|[En`ٷ cpj:{2j<<&z .yslBGrn=/OI¹h031b3oQЗ',F9oߍ G:As8qh?7AYze lpZ_Tn6Ehԩn~W;[xXW/\7~sV-?]-#U~#ί~s`iv&yd_]Dëo< >(} >Eo5'7W9E0%#5kq?8Ƌ8*y]h ENEYD-ZL3e\fs%R.%ﳀL׀D 0]˕? ]ul'JԁM4nb܅hZ uq v`)h&h1`0S{7U1o6҃vdWcԡ.XtP @Axq SoZayM4N7aza[-  lpbl {`&{aa!hpH',mx[~hxP{▇n p haapWHـazl1|VaWH&y ʗk(`s(&hvb8c%5OQюht~~j~;bd0w0׏LV"'[QG#HD"!C>+W"fF,q(Q9"3uPJ2IUSBFAh` Fу>(h.).j&U{דFv:ɒ+\Oy.i{d.(Fvq:8d+DhV(oі`{~awyhxi'(cbіx {yȉa0ȶٗGnInɋuyywCpqi]iŗFxIIٕ! ٛ\n©iɩ0ωlƙI}LaHY(~x/Hdxd(G "'p"Y##1Đ;s3Sr2f& : j? ''y(,Jv.H~Iv1Iv3аT=aƝ?=i6.8G8UKWUVh0JvXȕla`lCƌodžmwu)0  І {Y 藫yfUzQ2vav zij։XnQa P 0n`bzal |bjwGaf *`{7OFO7W~Y~ ўs MFS@9+2Q9#:2*%:Iz373S5(@43A T(4aJ{LUvW' jx{Lk۱A ǀ< Uڒ'kD-ݰu9+bI-V`Y,'fyYMri) Ѷ Y,T,!ؕ֊궉!֪椷0W(`q n[^ga 5K:O׬XJ/WSdad"0JG)"׏. r:=ʮ=[4=$sP2:$cv@9k?x *a(U뽄wF9hо.w 4 +yِ ܐ Od) `Ac/ 9Wiv>;DOJ瀴Jpp!aP~iV۵|_fX_uf+`yijkWp QX{l +RǦ\0 /LGf*Kn+],k|tQc˹j>GhbpO剺*dF~XSvZ:Kɖ\Z{."keRy\VR˫$м,ss8>Q&(A*(t,a' KyBi>1(|ul^pw?P- ||@^ـ`_opwUGvԐc9zBlvnчnJpT 6umJFWk8lt:yy? ~jMn0snJ-nݨT oLpJƸ l ][HpZl` 3-`ӻYGx6p5>KYgf$Ȼ~!0G _ڒ& wkaGbge9gi+v<[{f|aMވ]]߫ 8ΘgXMtual+؞IL.Y +ı 6=X<;^)6{ЖF \!([u oՅ\~X.P\F_Nanۭmdp]lt^r.4IMd褄4 ]DٚMh6P,X6} w[_.4hj_pP{`-c9 K+_%{~mm ð =,l9Dl844.tObwQx-E.~!?UR.;\k//_Z*rs=P w=.& s]1w0%IB t]M}bJ&R P#1QY_ +Ypx}b$XР=d8F%jD5nGDhE)UdR%##9Mf)rϞSonÛ _կg} ϧ_}πp@  C?40"0*B 3pC;CCq`BQ<Y\D[PFk$QspRG$l!Ė$I' +J*|"2:/0!+L2i4 L6 j65\t\Av=A+w^|FmlF__`ܷ!dž#ΰ 3ƸJ;^rJCvhK:H2C"kEh&M8$tgz((Jw&CUbQG+LTe;Bk,X_ cnUW{_m7^#6cdmpˎZk΅Ŷmĕ\t;> cPA5SotmB[]kuk81v G+8v-vHx0D~{$R,|"#7Jk[HB9h)gGJhf5SʠFz~mXjn[v dVc_%FiLvBMlihu7Jo3 jo㡱C :p84+rcU'nsSO8t[$TGޅQcԗj7;nCPH FdG#iHHېnjqO<ȕ+|K>B>3yf/$@'5Y`'WgLɘO$\e]ɒ Ʋjԥ)I`۩cPy)\!<V1tRCCh6X tf8?\V78D Q9FD"v9LM(eIOFIMo=$JL OU&iZ*X54 R -\n*0ܥ MQ s¼,|4t[&3_gBS6&[8mƵXˉN]hY,gNg\'= {+?g yyqhe- 7R2_#QaH[Wb-Qz/|]DH:>-l#ˈFLz/e?JvRJ|'8!͆&Y(iwC];Ā]_I}R!Z"/WSV{BVel+X?SnjeplتCP8؜\fa:z+ $BNJ_{iN>9l;.@ 1Tu.u:l/c Y?#P˻#屎,j=Qm|Z"'s>LLd%yɤSNFw9៙$@I<ݩKb#ze\PF%V_Wذ_rme@3ԔUxkpe#ja 7=Wng"5xNw*}61-cA_LxkӦv/ζ3>bk(K{G}v|HN}Iߗ< J˼je) TW!xEtI7pe{wiSE<$SV Q@Zg9ٮvɜN(%Kd/fePEAYF'Sk_ "`\4/}'xiEksQ\.8 vMҏ9t N(n]\D}l"/ ٧;@L@;' 9;£#ː="Js@2'ْi,<*;>Aq>(A]J 0ڌs+B0ܾK+kR;?+k: ??:R!"1d3;DLijS@FlD\k7qq#I7(K7P !9, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0c>e.S 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餇ZCM$M;__~Y97$N4S@7#N*v*>AکzNA󎰎}ȂP/p7_1-7v[jdn:X9L⸚  k+h:b.>{.3(|U> 3>6 0-8T\č1.VJBS\k4} 'w &͎spmtmr@= p eq#t#1yHMVNuɼn̼LͣlԺZ6F5amByXcܒq]͸-xtuح|3簒AnykC9:ӄt#?9{WGV0v6j  @a@k7S:V9Ҵt}6O_"auķQ &@fNf 5A>03Q YX% yƺls36yI6l ,DGYJABH# KD (ؕLfr *A X:xOO ṳ&7Nz (GIRL*WV򕰌,gIZzgl*GlkԂN *5MMNj8MށY%/ 2Eyis׈% A޴pSe iN< $,:A@8`H@A2Ձ_(<0(X $5)(ASDl)(#Z# } ]B5B^ъ7.,'o s^RC p)S k'/;RenMpԄ 9ArTF!Td'H<$5xN6H ҙ}/|S%(/TFPRu 9C55br2GNnJT簓baTM&c(AcTֲuf =1^hGV4} NXƾ|i"⼨!nM ><'>sVeBMࡎPvu/cbq:lġr׵Hv-|$h1İ3oOlHw#|=`+>t [ΰ7{ GL(NWN9Hq6`d.&9_x 76:嬬x Bz Yl7,+4M1$1 Aep lґcm[\lk;I  2v!4?LXh씣SihHy3-H:0@|i3dVk')Y18PQ ^-#25<3~n#21:KOM ͘G]<3j9!>Ȋ꒮~*>vm!@B9DYFyHJLٔNPR9TYVyXZ\ٕ^`b9dYfyhjlٖnpr9tYvyxz|ٗ~9Yy٘9Yyٙ9YyU3\sv{pvsF>Fy㋅s=Ԃngvq>ùIhg7qvȜ։Wnyȹ@xWCٝy㹞11 9QP8Yٟ!u_z4X0[Q- ;Gu`Ƞڡ ":$Z&zU*.6I.zmZ7 " x(ڣ,@$X(44Z3N, \B"HAJZO  `V:maʥj^:;Yp ` x^ʔ z syz_o* hৈ{*0)l0 𣥕j@BJ-Wᥠ""2+?&Jk:ZzȚʺڬZ*10h9D#ID 抭:B-j$jjj|601 q @1*0*zk*#@:۱J3갃ڱ$KJ@_.Cʟ%ˬ",3*+L*4c"*KĂ;>; (k*H"bPe;Df+ ]KЈYq4i XD"k˶iT1;J4Qk c&Q*Xp="+ۡv\P11r+릆Z "P\E0뎄ں;#A X{me뎑ҋ" kK`7yX ˻{ʡs[Cf/6YL`gxKKq:q"fOеOW "<$\&|(*–u)0*1b,,z]u3zu8èr03Kĩğ;L\1S;"RšCb\wBag, .ڲ 0!#7ƣi TZ4|Mǂ<Ȅ\Ȇ|ȈȊȌȎ$beP,ě6ZpqUY8 iļ`z\nz0UzAP8-lYPK@x1X )̓q_q>r8pPAaLi-% o//! ¡UL-<; u Wl~К2߼Wqѿz ڨ]q ʌÁ- 0A%=|V @ VjFy*Y3t`!{k*m ֟Ljlnpr=t]v}xz|~׀؂=؄]؆}؈؊،؎ْؐ=ٔ]ٖ}ٜ٘ٚٞ٠ڢ=ڤ]ڦ}ڨڪڬڮڰ۲=۴]۶}۸ۺۼ۾=]}ȝʽ=]}؝ڽ=]} /m0L?;a!Pmߵ ~z;gN= ^ 7 "GxNU*fդ.~# N]F( _3R48$ʭqzq bz !e:u8.~iWߝ†ik1zAtESbPD0xXSag@1 (oz1q(>ߋ.Fv`toVJΜ!P @.GA.i~Nf)|w]4^z η n4zAGqZ)fՎ x^R hN8>^~0 L,cI:p)횠;+I:ÎZ͓!ޅnU>$ɇl@K9SX Z,_+ѩQywpA6g}[aĉ/fcȑ9f ۼ3 ls 04𕕼91*#jfN'2&^qɕ/g\0Dy+W)0& Fڃg_P= }UT+BCh9 S.sr2lL~o0YVpDK4DS`.-sh;I(e7lIGj2n tI(rH&-"JȻũKpj/*j>s+5MO@tPB 5PDUtQFuQH#tRJ+RL3tSN;SPCuTRK5TTSUuUV[uUXcuVZkV\sE|&us 0N|ptuYhujGںi 5QUkl\tUW\ \Wnl Ww_~gK0Đx ]rʦa#unyF=(+ߋCyE)>b(Cx7q8ekfkgxN>pzhGPD-z^&qhjK~%k-/V{`ef{oo|p 7pW|qwq#|r+r3|s5 T=D@(gZfcZIE:v½ۋ #ww5 s jd&LqxƄ aYwv-xXs&vFe 686 [mHg#8@ \ÿd &2("Gi9| jl ka[ɢua]dv]A "#c(+;R$zS>4$y 70 I;΁>0,o~ 7숏L&6R7 m#$` H|c8%%^`!AaJZ6q!4 鐐p7h,|"ntȈ 9RC#yC8CbwILB,{/4l&&*XYI,r)G,i0oyF$,H`0 a~/h1 ODLpnJY:f& $ 頠LR@*zIVr%$zB>!3!aB8: 4 fa ;M4&LъcK:,$w#xˑO|7xjLts?)[j +@ufԿD,bHD-AŃ]W#Gld V5rEn3 %"κIgxj2,a‰"2`ć Yck([OvDh3PJpt*z\'-@[0l"#kVʊɆFa egŻDDuGmro\2npbـc.rG,jbh."'LtcVpUۈY6|SR"ks `_dnIaoE3l9qKG";tG"]H[=7iu.|cmƫ`⠈,c hQh X Տ"""ښ<N2& | ܇43]D'y(s"d%Y>8s*B.8^?bĠiZSP'zSdiZS4w"s2 P(XVea֦ԬWM\bD NcZ8׆d"u͌WbV39 't |ALB0\YY` F P (Ԋ$LH >7 2[ W8>~HҢysq͍@=[<9-;+葧G∴+mV,Fi|xzӹ -?d,vf6^ ŽCbfú/hjud.&>>BRxpcfDcrGQ %Vk9ۑbC&4TIxGBzFtR<ڷL8Ȉ9#勢9_LR}"'ʆVXbȆTa(۱ ڄc+|`d‡`p*w WE8M:O:\ONN<Z +ZzJ|P 3uWx WӪPYI PVQ%kmQ QU}Zm-QQQ R!R"-R#]TH#]R"T"J$H#VQ4;l$Η衈ة&*05؄P(@:S:u<=> VӍPBUpDu۠F]Rl+,i$t^`PR1bἛ,i.# ң_]*9AE0Up]hqƇb'WVMUiUX=_30U|f- I7: 0hO,\R@vMRJW0Ӳ@S5幎 8 P E؂X؄>XSx? bR;S:5T(TDUT@fF 7"T&J-S$1YT㫄QV5T2JiPU2JrAPx=|s#n-08v8\T2#X@ bE>tL8(m% s)=T #n ;چiŇ(q n= tUWͫOw}[zצW%&rWX ݎ0ݖؐبG#5CMԼFeҎHa=#T'Y ,+` Q<=XXT--36'֢ lt&K. iZ*|`9B[(*APBg8`ˆs؄v3Ô . !@$XEJY$ང,- |VX$|놱 [a44O-r"p|GľJW] 3!-0*Н%4fjp%ZX =X%]]X|c?fKfMؽlMdϦH~4RN ghWPTT8efeDe_W~`af]]|miܵmVfef{暅&RMaLd ՠ Y!d`#;' s=goh2o~A_r& qz. n=r:(B 5x[ބq`6 %H #@>a SWV6J^Il @jFE\s'XOx͈jc&BF⩆& bN4\UXQYQHU` Ík2>v249%e48%:ÖS=vl?@>6tt5Cd==lf]Jtl|PPOmFmT/^UVY>n[XO^n`.n%XOYZmZPfvfuahp%j֫0Sk opk p v?^H߀}7} y/@hol b>ha|GT3zgrhV8m3B  f/ IVlOφ$q;|x'ByV@g[C1Nqc&XDr-*0fT@'6&թ~K5MK4{4Ğhѽ?&>t>AXD^^݋mmAXJMuPtQ&uضTmUOYZeXa.VWeVnn~P+'7ߨTf(<"gX $g,pw|qG|0-owyYb }~'$Ǎm.c` p0H.# 52ƋW؄sK k;G1r=;pM3FpZ*l>_Q)ɓ0`'"|:/+-Wl5oӛOʉ3jSmӓUFU5%2*nMHřBy)4r.+.e%*te-`3F8PJ\yd|+<ˡ3SFji:SfZk|U(lչu=wiΆ 'o3u6s દSW%Ws縒;FsËw˹:^{~=~? 8 x * qG"=H"]B 5I#0XS#:ux, >'JC"'VOHrN7$56x ARm術K' L߉RMSAh9ˉjэA&#N5"5f:Ϝ `# X*'>=`><߉H`PӐR !E!!J P)QJlIID11#u4HnⓊI:zK.=33]S4TO>Ob!uR< VDV:a .xLP^ANNZȵV\%V^v19Ƙ\r^%N) 0!bmĔyhƲupŶoVɭro6)4sr%Ww5>UgX5cqށg4~7{FW)Yk5]{rN# S\eAp6\L-.mwmw 97qs47%79>ߴs4݌3xLGN4ZBM逳9yN6Lѡ8cfK 90#M8>wؘ.~sMp ZUcH=q(!8jAug7!<1tص^WhI:= 0KO,E: !>1-0ńUN-@Tz sE,8$@NꊊAܫ.ha%aK0%TddF@3f<# \,LoB19,8y\ƲБ#c̈جy+b3;33pjҞɝjZB)Q`C!,!Kx-F0q k8LJbYMXu*3b_F$_Zd~6YA Nd#p o0t A >X(ѕ\8EE'>f$a&ޚᷜZjYr2NE~C)]01E0e__"625-cTe(3rF4oX%cQ7i}ldE&Yݤ41qYHgNI~&MS$nJ򶷾-p+L#.r\ iN$ rD)1 L'[fOyӫ}/|fOp8CP/~)k,"pE.)6c, Sp~Lypyl&>1S.~1c,Ӹ61s>1,!F>2%3N~2,)SV2&j^= 1f>3x6nV񉲁bv3|=+zysCb) І>4=WU~P4YȂ 43M/2>hN:~5ZUծn"І;<ϯuLw5jY>6ej̬~6faPl64AI6Ýd `>X4q8~7=㳭q7.?838#.S83s8C.] b뒿0Uo~A1As eJ!"l ,0*flaKW&5@w0&2i=wR n E)f|sRjUʹh]c(-1_j m:/A3#M0̏;M?t 0N4ao/z9:1A0ANbXFD珲ndF/aw˳RC5ҟW}u0 -T?jp +grq;1I,"X44N}CT BLΕNဃ2HޝH.(  88A@ `+F 8BB-YN1,%H1s-! D xǬ&^By{J!aP(aT9lጡX +tq9HL]00П!pN6u݁b*9TCyDTޣD A<%NFhIBpXGN9>S 1;C:C;C%V,*L*8c1-# b !80A64`#-^LD_\^00b2T?@ 4D4AB S0AH+E I8d+h&INI7 N&lUdPU'U9HEXI*L3cKnĉDϙ&^)$Ս_O2Ln‚*OAe60%\ iY0EU8L%#x_̅ n)}!}n\ʥAT|6&7P a"<(ݎ܂KDtĀo< }pggvif# !CA&NNdDAj1e2шىD9((*|cH`XH(OI~`9-A %aH$aG6$ɘ\DF$KKK]ĭEj|jj64>򫝀dh$b(D)؆N (ρh(N$9h&k`(8ب 1H*xGP 6Dl\ES( ,S|Mj:JCՂDI69@m)tfXȸiF C489j \)mFड़:e@ 4`rq >") X*85渢2BjP5p;RbSF) %GȂjA*9k.;j'>*aB4~.- GgC+dIGQfH^6N+F,-1oAH8ֈLGի.GhL c`ClPS()ShEô-YQ4BC|"Ci/O7Tm6I.e4q~Պ^&J,흸D5oOFܲ %8i+ :f_X&LAɈN.fnDl9ٖIFqғAb6K\ʮD.UgoD a6Wq/NݔA1T&`O$+W!I,B09E* C6&hlrmHȤ,5j+  DΣLc7őFeeWzs7mPtSp5l6kK1FCO(B5r6EHIưGͰApo:1`4;߉ ̘d:1ϒZ OZ18m'ꄲpq)řX45bgb'Gt0 21%EjFHHā"*AHjr.g9AO~)29D8]LvV;4Յ4K$~k|J$IF03n+O+o,,X,lT5,ZDz465l4`1 lJsNI´I ب,8i Yk3U.&OH0ײC7rg^mY6+L`Ze@PH M_a#Zta;ofZo8pͅ8pYnKLOGF4O+jGu*~?N pH3gOrC.@C!{D+U,Hf;8߼9zl$(rKYh6/{G|> (KnK"TZA3j~/,g1JM-, 1:06 _A߉LU'3ԅKl4X6,SHl7{'mOUޒ 196NĂj-:8Y u萎:vfoC4nJAk"S7# W6eI&؝]1WZpsA5*]B\>qc6(#2G/TJ]CA I^1g=T7}-]^tMOXLC]^R3~Hdυ1I2=NmIuC`ob˝b5'/?7??GO]7>gڪĪn Cp,y\$A4AF "~kS(m'D7seÇ/t6t!L Vo@-SbH! |ndJ+YtfL3iִygN;yyP%o5[,5Kq/{tz5]A|{sO-<[ڬh:ę~hr |8$l%ʕ$n᳢q$s&RI%RptV]}Xe"^SP֘"3!ǺA!`-RȜ5I6d1JY",]q" G IcQR=tqsd8W^<:[ e@7~Ï@>`|NVomVN|ԒuKhkm&Ҏjюg|8$Ә">lDig 4Fk|h0:&n4!.Ƚ&{oY'qyLՌ-5ߜU\I8]K/iMd"=hl#GiRJ7r-s1w0|LT)uKƚm3Z _3c"}X`G&89I1p̋ s}_u&7׶B!Gd{RqZ!qn>If1|D {тgRvǤd+J)CsDi/F}G0q\ (ꣶMLoJ|:q0a;G6Ԡhr 5qMh 4(E$cbэ, WG?4+qȅHLyWYK.4+v,"/K,32W#|,|I؃(iTeU)iG(AxQGWEEbOaS90tqO|\Ήd3g cdې`%p>+`63h$ $;dAr&]L>ti_|!cPȝTŜ#G&3 W6:ĠHT" UmByQX Z 0)BnR\k4E,h@R(xGn>QTaBH"kQ Fz۴4JjcIh=\2 /t--S#aiAϼcN,qD\EPb^f㗂lC$[>c[AFUPd=g.jfJ': WVOA-΍Xs1!#(1 6dw:>"U\κ\8rA(%Kl"|QLjsbxEݨMiʈg G0UE\I=4X/9ЕCfj5|U DG v! J##bq2Pז4!OA̅<+h3P<VH2c{ faY5dfg)l)HP@1D0zZ`~Cd׶!MmIulc -}adл!q$s-ytB4$  }@ϡ˫t{cN!H}ͅ_>&i+͊c!Eut 7rk]4e0]a,;\ 2 ^Fbè["-Ҳ1Kp,":^R -9MD"ly0e)SvW220?2ŜmD)tT*0j솼b n&l"g) (HHb̷SKFNMtLAZ D%:.zM;.59H ^s=z[M4svg"0Ň&((p M|#˨F6k%H5Ty!"ↈ&>,te? F^7!ZlL4o l(IABoqx2HECr[ RSfsI!W@^Wc?{3rap"B?/+1ئG=-bfpY!$Q@ 3l{crx0~oCY},vȈnBJbX^(jPgQ3"i(Ρ"nҋ>'62Bp n`@lP6E!2OhRЃ WB.!  $YEy4 ;MDoIx3gP.BFHB#0֡oc%oj]!x&x%HB_A&!'`<^2ci v4HFOPد 6f!P7Ork2go4p<^lpFbP;V5j}kQhb?R$Np#Nأk]L8v-P" j6cQ0G <!m!!"""- &f&4'";"J$C% gy6HSB %h ?D8ub7"U>|V-;s%$!sfaP.J5b)""b \<-\YB ئoP "^a ,&ނ($=bGZ`%.1&!Ǡ %؆E.bH„C l L1`C$E4 #W8%R"N"V5V^C" B"ds$RHn"' '#t.7eXI>c8kj oB=c' Ŝ9A"^:S:SNġ%3gb!ްAN"PՓG,RQJ`J3`%HIFM ?BD&zăaT(-A "*DNB2zBM!)GRIuRJ?CCNԄ%>SFE+"`XFCS&v46xtS*BH4NI/np$mQp94%p!rBM!4%uBMsB* 9gO TaO4$   yb\$%e 9dU Hv 8'f@)>)A"l]L]jLT'_lA &1i'&6.Du dW*XaƆ5Jgf)!,V&@hQfʉel`l"`dgζdNda5(jh^m^WlzQPS"P$D!#nB@peJ >Fhpp4!#g2m#4%Ar"A*uMy A̅rp!Ba gvV^h7f!yivȷ {hyK㕊Šw^w uv=}9I2AffK,bzg{gk8zٷh_V8Wb65LPbT$Tb-V!Y4JA\ Gj#G-B ~\$Eei2ax![䑀u̅f!f7z'OVaU$qi)qGe dEaBa"TR'kjkx^%ho>p[d| /6@ȷ /*6! 5!Ov;frUBJd,W"*!CTU:sAmيDS2$NwE4#zLA"lhuJ#Tf Hw7X""@L:Qy A:^ NahN"#!BJ& Pd/9P;™xc? z/A?XeAM;XG4:nG lE!`Rxj@k#Ѐ!@ %Y5L„WX\Oe x$kKӡiBG:κl^v޸܆ݢ`#@IIxA ^-b:$\XO,")EBe@\NFA{ 2"ǀ(v#!",vL;<۵@qN^bOZ!T! &S\csGmӢu"| :<@׌#vt뒳9q={҄*ۖ*]ՠ %&I5@ nGאE@y>@Y,._]h[M\$<M'K{91j#8H7•5e<Z'::$X X~\RYbxL/«a n L&hA !؀h Dif $`̅ ¯ (q!]=P˭/gG%"{(%uO  iu+ hQ7~Ck/,Wh @ Y\q^b TGjJ"ZnM3wN[9|ȥ1Åbq!ȅtȐ4r |5aA3S)/R3gʅXdZJ # VS9XlsUS"@{@5[ bh۱SH?몾XɝlǸRZF0e3`9X">c&&I%%N >>D0CL&b%!,a6#FI`hBx!m"8Od eDVn >J qaɐ(Lgc&ju&+Q%礹vHO&k>&XS&gOtO8Iht'1>!C2S2,SXe3PAB"iT>1}jƔ+H\mʒBR=(F2t*>EdVҚQ%K*UuUHX`YP骜Ko5Puo፿l1T9Y»,7٤B7pC;@\ 6@:T p8sC#yXn۬>0MܤTMSi,!Q78NssL.xT]uǵ]'pCȴ{MZ}R#Z@(`>N > MNHB%H BSh8$͎`yM.8x^?6)P:`V^' WHBc?fȋ AR, ZYD{Dº˟X&9+/h:MPݴ#*6|3KK3}RK|4p,c"*VҎsl<,\mxߒFĂ5@U,NVJVx)z_W(0A[Fna08ޠB]k1Z"@Ԉ6Liq{P/.G؈Ah- 5x:(fy4\b3c jy h1|b!tb_8Fr8@Ur#AA؂,M G;ѕ8lŔ̆*㠋o1ҎؼfKxk uد2”0 4IG|A-q{NY7 cfv;ahCT'dbGXİp@c0)lDD:"B`ЄC3$D8qFj;$'6a%|0KPԍ;L˓ʗIA-;佋_^ޑA$ڄO9j-$*ԙL;Dg(BUUV#qDABI,F* dMJHqbj8rj[E$5+D rhSĶG=k+“r-mM[3JvbHxBsmk_ vmo[ I Ov>M+ŋ&:ҷpJ)^ +Үw w-/ni^}N$F6!?eB~䥺X)'zL]k`G^ KxF.TxpSF$.Ox,n_ x4ox< yD.a '!X{(KyTb]j0\ ׂNlj-f.|V3nŧE2\Bd, zЃ!̈R4 k2a }=CAuࣕV8&elZ|涌ymn5T!4ani6I9R֛:ش.qE@@4/4>yL8X Th 7LQ%|_'&sBm@).G7.:y4>ر 2a 98d]|!6ldl{e u4chCY7M]Ażcv w_iL(0XEcg2d#>4 p O W| o~.|+-qf0ܸ t'uhnAۥ b.x 8tj`vCHc?P0{ۨL KGp$ lfTkqߘŸuΔ)ى#F)p8v~k4K&Rh\{  3`@#xhqxiz]1L H yrW'p`Rxg=)&a4k\ wc1yi1Re"(|s ~`P|X(fn}M#'S` S%@Jր*  AO820&r~#wc 'n8uWlV oEٓ=sQg2ې#x"6pA8^9(w0g!r ssp!ZuWVD,!BL+Paz q0@pGW+@Ekym{ $# bMօ\pNc7Cue a{MbPE$ $8~%[?Џ (`m (ِ=p n(9S( h" 5iՎ|r#p@H VihhQ"0 $AT聏V,A4x"^)V͈v ӈ7 '  GpsMh瘖Ca} ֎`!8$ϠdCy! nCuE}U%}p->-P+d Ā ч) OG Lm #9.q5d 83i$Q0;7/XXhAKqWi[i4ؔ'WqtPD"Оlj0k\{P >G}I їj: ۰ ivʄ!juJn9dYUbP$ Y& i~i+y,]*M0#AXѡ>Ғ.h(p>ɤMj/} Ƕ3D(0  Aw \9b:\J Bx8@4DI|0)c,j^ПٰQ{<̉z8!!h4u''ffhC E yY ٢qr\]B '.՗y@5J z:p8׊uv2P0?i )2a  jQ )C2"s3 @i kea022`Ǧ"\1ٺ e2aI Qd<Ƽ"Ď^^Uimf~%C۽}٣rQ)Aq^PѪ( QݚIQM]: A9m왮vnk͉r 9њ( -/_)o0O1>gqԦt<*ָ HIY`K/ȱ쏺S^)э8| @s>W\l-^ĘQF=~b"8Yc\9pS@e(#2 =!wH4%83%%T)CbPժTLd$دbzE6ml7zݤ)WwW4փEԪ-aÊ&F{k`|?*^\`" nkҠ+ j:.h][lڵmƝ[n޽}-iea+>A 6_xٜ[l޼`̮ؓ<1:-]GxO|F fnzCn( à1gAL10! . ?Ѷ@6)"{!+1DJ癙gs'=X|*¨oć)|Jj*3% j<{Ŭ**ØhM7۴M/JK0KJ5 3* 2 r C/J;4EMFI'RK/4SM7 F%U9{R;5U[-lhbHqG/+&t F \"(@a7m ;![ ǿ=RK9VLdh $o$cEqGgꂀx\Y)o"*;u[̀s\'teOL%iA*BRפ7BЄ'Da UB5ca e875|kNtЇ?b8D"шGD C$65 cc q<(FqbE.vы_cs,@gDcոF6эoc8G:юwcG>яd 9HBҐDp oP#d$%9,`X0Ѓ>8H JJr7t3uD +!>S0ApL&3 pҘ hτf3ŷxĮɯ@:8y`Dp.ӦݚU-YGAqgtAMw#@7q1M1(xp9}[&OeL?ŧj遪+o;.J#dIAfYKbq6,]ښ@gnaQI=3#B_TᗿF- zI *o |lV/5O e-*ZUAk\?blu[zWU|­Aж{=3#CGĝCfHdyG\&r^; : Ɲz 9`81,6'y&hEC@m4ɃlҠ e-s DU͈>Zp<(mcwR$oY8n+`aܛSN]31Y^SM,P3f$Ũ)A|`6Q A .a5+'4Rq=+Z:azDhH^#ֶup`) Ux% `S#U` 4ҟD .:`K_BqFks>0!=Lf,9]V3:~C:VgRHlKh0g:EE@'R=Υ\r@Oİ$, &\b8f ˲+ppl36L 8t` Ld#@Hґ0#dWn#h|${^>G=]CN*A=J3L PVn,9u:MMܝ1bRӚmA-ow[}W3`~'8߮E@W@I+[%a|hjڶ1A8Wlv(q%GN@Ih~Aȑ벘3Ӻ0G4RTL( @f Oʄ$|ߨNq9*-򌨃C[KbxB,zgQb/(>IBl!HvJZdӥ6٤WSG93-M|i$o?`՜^8Vrխ.F~OdtH7 2nX:3`p3pTYD9355%/iPt^LA~Hj5{ Oo pį+°+ ;8#@3&$) lXo $邂{0c 4ۍog($|`#).Mho; H^ҤX;2Av‡g`? 1FjddE ŒirCC;? ǏH0 1\G3@z0t@d,0H ]9.M~gBhLZl$2T9@Ç|8 ,H"t* !|.Xtvb2o;<( :L!0<̉(C4b(ö+CB<ć$Clش@Rļl@S1=2l†bK hh|XHLo3$5LXsx `;&J4Ϝa=i!Xiˆ;gLȌ%qĈÇnԷc}kÿS|"('NBԿs0tN0z̸"+H8N*|4}I,9g Y<p.3ȋʛ=ipH1DIrIbɂIz 舆 M|,t 4!2$5-3d3Yf2BʣȋJ/)=)M˳2R+=Ik˷.S8lXDqXT1݆Kqˁ.mC=F\ (R0 B% ;͆MHIEāڴ@Uj _Mx JF8 @ sN'~3BO,@뿎Py\χG$ňOȄ̘Pjחh aXLo ׁh5XW(#!XkfrB@`l1+亡.:ԃ8CHQ069eҬ $Q0%XpRY>?'C!/ı<4V8XZĊh0rDqDPdӕ Z %Cgܴ챾?3&0g@i͐A[ JF@sTݤ>XUXBTlkk0΀NXN0UU{dž[DdGv8f$ eʈO Abm%n gJ]p]|0O3UWW~]:T RPT:|u\݂x>ɈTb|lAZ%񮠻8嗊ń*Iɰl̬bbl(Hο"*.\5\/^ U\0|Oca˵\-V̕$8L܃΁1> `]9{P| M4ݘ5JJIV2˄njXXIYnX `XPX2)ÉʋHۛe+EeV(_@c&ef[{qZmr~eb+mc~8t6=u-$*m-[%ɩ&`3¡|샐+$0 g$HD+.  oCn(\ic׈[Y.},<yXbg^gsSQb.`a ƒM :%_5¡ר$ΞPoV ()ZgeK!p'sf% Ga֘Hg+s+Jrs0"!  1IY (%#2o{$!\f-El[|9誈CR2[/ّRF'n[Nfn7Tʤi;ku`5_GsPf5F)ww.y?*/$;4|$wx:b@Xxo;=xxA` {Щ2|W+$hˆ;t|cF:qs=i4J—2(ja}Q4b 0:gfysLJ+e$[! 0:R#x@a 5i<#>4w`_;Dns 6ʮ__~ý=>Xϧyo#s;. IzW$8fhlwt(Ap 5$'A~צ7LJu,Ay"L;X87{֊ 3q'P ; _ka Ŋ/b̨q#ǎ m`]mB.Bs@]G_0+3y(8\lc{Zr x+'nKPf4%^mn j(˟nГ93PD K-[|Z eāɝu'W^@41!M֮_-{6ڶoέ{7޾m`xkFЭw$'^d)+K\Е3w."]Ͼƌ] kz8'i _(DGY%O 4^pↁ p 7~#n!8T\˥38!SIr#JH&9b5XXiDV\[uY`\Y$]وQe#EP6١`vu)I9];fu_'y徱P!>R1E<>YvԗbCY^Q/5kt3EwCdWc'Fgiru %PGj*c5A0 +8APrq /l,J OqH Ov!d@vpW:v#A X&! &",vL$hFC! t#;"]\”񌇲n0 n0c9o#$Q䨆oLE$! &y<=2 e(AƔ%|[, e|%1p/"a &FMW0= 1TqTcߡ.@F 0CQ8 ռaF3'=Ya0e pra)q\> 55JW(ON ćsh:*/@p駵 CCHQfd¬ 1h;xDR:ޑB zOf֔}ҋ5ִ[-o{7Dk\= Inl:+)e,AdO,1 Ɏ7/y)lqOYR=ʊз"UA@AXv+"8 ^0^⨮+RD0;8"1Kl8*^1[821kl8:1{cwkjb! YI݁)a #E ?lyF^&36(̱;r׺w=dk|O]pn)iW;Jn4*a<5 $-sI-"[ԭkAam:ra$ -T­M$ >$B8pTKمFwQ+0&wo!$ FiSߒIBպ<#z\n1zWVlŮ|,S{q@%mPP!hR|S9}47Q{u0T,[ nc=Q}JMT<3y@>î|ԥ[cЍ@1CmDX[`t uCZM@tݹD` iQvCB-GaEIC|CaQTE5l mF{T~)t vhIE)؉5vPYG!Ha;9M%cޝLNx 9`BtԄҌ %K$8l^y%$ݑ`aF+Q̵!P.Q9BH͉Ct$V"nɏDᙜȅ&A)MkTʥ( fJqezglƲLx >˱Hb^cb ʠÆ]zDAc ,"9cavQb,(:tƺFPU憠&^{%d ":d6D$UDEaԦ8&n&8XV+ }qrIG58LB$;Mu PBS:hw*0jBԈ)_hzҩnP54@ >LFNΰM-K" yb؍NMB58j8O TriHF˷G>j`TK;jKT(3]=Ɗ4U qλe?G@ripd^"d(車CD&^ Ok 1(F2HzFyd)@aXEDiF E+F0bqOOZOj'ۀ|'8)MdZT*IU"ll`@hPk,1BH6BhTET, ],'[,F`$aPhGN;yKtl'|(aé]<~ JTE9 u= yX R!c@AP0d1a@EcHG "" D-$`5E b/j%eRV2a AUm8MZQN:Y(f6)- +PJm:E%5MѺJg¢nn>a@SrCm[1w& aZBД}"V>CVG@2T]@H&c⣑jYNTNH;攷l &DT^&QlBl]Y}QIUD-KIQƭT\L6E%+iaEs1V:>gqޱ4Dm}VNsB\ќfiiDx ݢpqo*eW˥b~e q[Wz}am\iqtEaoWq~qS}Dq-!q r!!#r"+"3r#;#Cr$K$Sr%[%cr&k&$P8*oHS4SQRJil  @2,wwyPћ㹍ue(a{uDc nm UaU[݀M=hU SE%2j*.fzzzzz{ {k\7.l$ColʾƴS{XET*AP!m$_ 1HWEptD$>F$Y;c{D7FJDaϝriE@7lh5E,QT$|ÆG۵LBz@ (o혶k@ QXA߫ TМͩ{sļWļ5>2L;wľdž{k[;ą¹<:FkNQܧ:; 09F|ᢝk&^k;9Bk|_=ϥ l8=EGйlC3lp=>x}KZXWƸ <>c E`ԙ3>ۥ-MLn6OS_;'X#eu ?/RG`O~eC@K ]Ι1tKmL9|S\6o@#$>q% +WcmId(DȥVnC͕ق," GD4 I&cҨ6PaCZuDlXeѢk׵iߪMkV^Eo_0lf`wcwYLibEE+ʙ۴߉fm!t=|s TR}I Է>C cAG7pb@Z3kJe@(80 )̻t@1zzh*t>D:'yG8"ƛ %S+N*lILVJ#$(*z '4J2 $2.: 5j+5*Ͷj*S=? TA#*,,IZQ{6P!An4=Ax|NM4gh T׉K<~K> |o>Bi7$ P=vfp zB9(zH (1)R?k^J&7J)'&^iᕴ̲ $jQM-9L*7t ,ؚ8;S.KMDN4ݢMYy矁6L(6,AN[18-K1eSAvygm֩)nQQtVL[V4m^w[z5Xb=~c@|| ^lωtt]\1Q`!;}r*r)I$XH"*ң64j)AZC!NAEJ)>b$Y+K+MEŏKN/9~BSb ꬦ-8aF3T*L _DPPmu6 e?|zC0}d?409@r qM rE-J'ӽ]#z#4D `n;+G)}XQ_#'< e]K1IMnEE1Sj H8EdU0A0a$y@$uJnG]CT|9s4`WЕ|; be`?7ƤB :)r3hG|ȷL3.\$2]R71|S#JPl䋶60!``B4^dD }fHEbS҄F.1hN=dp10RqFERxJc'8ЍC"Ԍq#`>Qg#[ oC&m6{ 2H/ l)a6D|/>$ש $I}, qdmER4zV"D"uKJ%MhƟ0(K2E*+I%BIhA^ő1[d֗SI+#Q=5yћPha5|j"81fU*XmVz$U8Ui?E 0}͉c&h;BVy"Pp1J 2gz"W$/=3$1B- 5GifCSg6O1` őd%Hn!f\'A1gBTy tB/̮]Ivd{dE/эv5cC82JɗKind]iQԥ6խ?b(D˪sO1< ?ԝL施p|'K9nNv_HO[₩ρp\>BLܒ\1du8kw~zVe?}* /Q.͙qn!=ȱ8֨C\;!{ceBډc6;8CdF5d~k0 :rUTv!lt$"ak X3D$Alb$l!g@dz*A/F"bkVa' b !6%01L2@e"@|`$Ɛʐ⚂;n//֬/i 1M eO08w ۢ@bbV@@F%jE$oB"A %!Ϙ.})0&tb"֦ @j*>, A^@9HL\| @ @@8E`0`@HP,0mV] 3?ral"*q`X)tXWf8y\9LagHDB֖ !r:O.<;˵@fc]4Z4[u"\ u_j, ~Do#tZA˨W^$4:!nkXg,?q[*O,8vEh@WFB@8S .AB6s,G+"ix A!KG8yjM)᪔rY80J$&m\W@Xt#u%w2,wgxl9r6'T.JA^go;NQA!4$BNOGZ7s>B0S H55ayw!6v"$ZTED9xe|]cX xIeG9w ؏z]W\aAB&9q~9%=u@M~S~u~rv Z Rϡ $ҞS<#S85C9t_R-@/uqh:g3,ZĆXw#Z ȎNiZVނ9$+59cA`A AiwZv"Z-W8&تx(6ֈm63dQ`)X/UNir0$ؚ$H$ZK"K%z@ksSGt^Yo~(`VVD'h rEZ Rcr{q`@/|dYJ__ utlTÞaKy[EgBc9io/Pɻ ڟGe%R66{@/kv>G]rh<@־bY;_ڹ8\28@+Z2drKB_`A4Ik7ĩD]RT|Ty"'n5$o F%z%t\`v/8GK"`7Aal;QS:G{z0H4>/R9Ey@|5ǜBȪt F 0* A39e}A £φ׼ozAAr|z!o=d=w\:`qω9Cɺ螠{D}FϺC1eyQyHa` N]uП8QDţ8łm4m=X@TyO-ݛc>}#Qt`CDVYD WfQ䱼\A\T 䝄;$PuWIPO QZ&^@bpʏ1t.apC=<&[u|\{cB4L*7a4LpzqA$=#P 6 nK5<$4]PsR\X=9gn]α}}֋_Ͼ޻߯?zɦuGġ 6F(Vhq2Άnh ($h(,0(4h8f|S;@@At09=\;DD. sΚq'wyghI}kZ3;.E|J ҋBI#Xx8q9Deka%YN6U꫔B+>ݘ8dddE9eaIrjf52qM;q+2Cr.hUlXv9c:♖䞳VQ8᳝92qŲh/Z8*WpHV3A 0%@-AFU fyLBL46=8$RHAkEpCTE7NVҲm騧^-Yz:P49f_~q5oX{eͽ{sD1D9`:1ͧYQ]U "HooUwwHxg^1$/+VlݜcRAx&$|@H~J'HAUmS`ō%QÌb=A/U_§cl(@M"UC*{'%clҠVmoW;FL񾘀V|J4¸`lf4Eg0VKtod H:ril8%/b%H !0;HAr%yj+nt0z&fǵ"'!ŲG]ec'٘bq2㠰|5zw@"Qkc iE덝4Yƚ)r0p&DHxg l.+JiHjR-$^DRUO|UJ5sCҕ8XV[q1GlP (4s΄#IR|4LJW wĥc7A ;0!AmE5Z5g6}d$BU`4ڀRRu["O3T:NV$Bc ,OyE(3[j2E4b$$F6:NhFGqT a6m#GÇ(45Y*klalA } "Dlv녷lDtc\G!X'rW uf^y3#8>3&&pK$lIlH,d }Xlʻ” #UfI<" 2`S@,bū *ׁtnPϊݴ(OR‹~6DU*ZNP%Tβ.K9?L2YuRٙ6pL:xγ>GMh-@g ͢VЭM-5" S%%4DA.vRx ǮHh>ɳ5QVjSP(&2a*VHM%Kv^zl@-RZbA n83<Uقy-TjUv$r= /snYڪLR-Ya@M@jy@;nK%x"-NͦWOWN<I K姚+YM{ +&FA jYe+{+s$+-bHq{Qm-TF *aupH-ZD1M1bww;:.9rYS\& ?epp}Q%x 'wr W7NO?%0xkel6>@LPl8۠:j<(W7H(+(EaEj'T6N]D?qq^V`؄8Jlt(`2{UVE|C Eq86<se$KXyT!yOy zrvA4DzJlT<=ĠF=ˣgc C;06 n 8uـ !VukNE$(I  Ҹ/~`'>jS;tP+ZT6⅏PFF>P9s?/YQ% #nP'l1 oF oV8np 2y+)>Đ .ْS3L2 rQWj *Tg+,x+: Z鄷+ژaqxu1[?.Ȳ$`8ڕgiA+=kvjXVI+ W2 Z @;]d U7a5V0! 1zJRS03QUkV\Kw;d2@J+-ܕo-Xzq|+~ |Bqy@ 3T uSS G3UX16RlUw,(S`@Uo16jPغ̪)l cem06q@fLHc#۹{UɛhnüZ9\\!V0ٽ F Lbt̪hW:逾+ G2Z:#S?QࠕJrT .[ l3W8\, v񳸐IU!VO sE4Lc,yZ[^ۧl <P= ܜLpP -=uqy5=jEdʂr݂[PWP}}Pj,W<a$Tc`#V=(b/ F=&Ƽ ,b2 &zS 1PC-|0ȝb*wD(Ɲ! iMtt>uC εR7@~%JhV*g>P"*4ra?QINfǁ\o>y"h0x=r[ lE|ݍ JLoNKk@SmQ]RK> ~8E4J=6XIKщ|2Z$y!VkapGaawm}WMQ"x I"оNaվw.ɡKdށ8G#:8*0X">oO^&wq1:8,(*,.02?4_68:<>@B?D_FHJLNPR?T_VXZ\^`b?d_fhjlnpr?t_vxz|~?_?_?_?_?_ȟʿ?_؟ڿ?_?_$XA .dC%NXE5nG!E$YI)UdK1eΤYM9uOA%ZQI.eSQNZUYnWaŎ%[Yiծe[qΥ[]y_&\aĉ/fcȑ%O\e̙5ogСE&]iԩUfkرeϦ]mܹuouWɕ/gޜsܤKs^u١Bvŏ'rqqʯg{ݹY#]I' 4@6W{ LA#02B 3.kơ>6qDKy'LtES !N, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0ct!.sɳϟ@ JѣH*]ʴS5QS3ӫXjʵׯ`ÊK,ĚucΪٷpʝKݻxEjm LÈ+^XsmL˘3k̙q:|$wMӨS^ݰװϱM۸sɫov NG׬УKN_νËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)pݘ#8y$5N:4s4i[ec4l 9yN6xh78xMÜx3P3 SN9Mj e t3 e0hfp.߬(> >೪݌3["9lBNNe3YcΡ"7:}9hfM9pmS)>LiAdj]O7nTe/r " D XY{!ų8 'gÐh[!PvMqͧN1ɧ 4'LM9r']epBoɦa 5fĪ@N10ٰy3ɩȳFP"ۢʺj]iLetI Uv]I&%٥MmŦXÖԔgu YǀsNhf4PƯ#f,ovm፨{麊N38c~:[ap9_9[4hJ=G79,^+wf,[v, 8;xt9GȱtzѾsb|ĸ%yL l`D5%xCf1blA v٧% g;&K2`jpʅK#%˗ELcP elb`Yv/pъHeu] M{Z&+XL5nTbƲ1IC7!G] *b3] ZU]'d]P0RҘ'ekC1_=K | gѹ-_(OCn*Vȑ>;A3Hl(Pq8$%fLSF/Il sQ`ЉFzWv:dit+aY"87юz HGJҒ(MJWҖ0LOp8)jZhf3‐K+pDL9T@CX(S2vᣐqzm ԋN/SΈ : 2Sjr ȧae%7U(a*9Xj)([M9@*Ub'h4g.6ᣰݗZۯˁ,E$[#}gA;jƮhg"Z;S-kqC7 mK]666^X\|lzv3:[Ϧ ]5D\Ja!C[(w#[y=ϳyGh߻:VȖ¶pJ 8(`Rqp D-XxG [|Dda :aPqی)^MV1;.H/|S h9H|*ƹDAjXo( l㺌v_4Cyәy%X{L\ӱ܃d<4bi;{(׻&a:*6l)ЎiIζn{MhQ\xOihfA>[>1:WjL7C MpB.ΈQnDICoػ܃i료{D`X r |Ľe:+%>qXY1zc] +lȚ@PBOjb\5K' eaمUTJ†ǛAօLkZ sX,XT#ͤ (xa!΀Vdz^~۬mfxU=O'&-us 37Y~0Z>|ݾTd 1mi矟}\\h {TJcyC `q%L>c<|c1`b\guW0hGx7v\qd Hft{'P{7}kqzzSC=0~ (tpeY&6WGY%G|F(\Ga1UP*S'&h%H&G65xx8q4ku5xȅoȇUs0za-ɲI{fwcߣJܐjhhun-l/Ѓ9\(gP1ϰU*xeq=kPQ+k8XxȘʸ،8XĈ8l'rnoU(EhҦʔ*87,3 0Kmza m# 8tFmfqLzf'9lC%6bs 7b`&҂xDžp)ex )w-@> A>wPvޣLp-Dnf>yz@磂/yV2L.xwdpb]c d'b)nPu-Lg$tyl>sW?wzHDp{ xzyÆăj'V䗥d&c 69Yyٛ9Yyșʹٜ9Yyؙڹٝ9Yy虞깞ٞ9Yyٟ:Zz ڠ:Zzڡ ":$Z&z(*,ڢ.02:4Z6z8:<ڣ>@B:DZFzHJLڤNPR:TZVzXZ\ڥ^`b:dZfzhjlڦnpr:tZvzxz|ڧ~:Zzڨ:Zzک:Zzڪ:ZzQ(XA+NU:MO kqԸ(*7JVE:Ez:IɬjwWcv͇k3jj`1Zc]mF OJU=V_9G$Jv-K7PA bJyE'ڰ҈XQvHd#Tڱ\!;Q2 6kg вϨiď! c@c @+N;K>cO`b;d[f{hjR<1pk1Ѝo .JA+R]"*kpRz ,~%f s;ې/|H_b6-wۡgs[B2 wzf1P0z6Ғ$Iz$Ѻ" ,绶g#:tsN{*(+-cݐh"!Kٻ K9ﻗQC;+@#fҽpč#+h gp&Iʲc = , ,1- jpw Z4<>@B@B=D]F}HJLNPR=T]V}XZ\^`b=d]f}hjlnpr=t]y+pXk2vm7~|q,ؚ0!  lJ$1" -ϙ lhhz~ {@o\ͫl_c:d'mٜ"Ƴ-}mi_I0l=l~_ր hP&z ؖ켆.As]M0iPL<~]ˆ(,;>^~^3l("ތs1P1Ri#~Xٜ=|1`X{ ]~ـ1>>G>s 6~- R2 pk:[ތwpG~JTx# jJn~xz|~>^~芾>^~阞难>^~ꨞꪾ qnBC`UHD7"5` 1R.7upNRVgsK"Ƙk {Ӑ2m-[Eu p뮵" Y>! ޵PMx`xqg`=]'2FWp ,0 l׵`Wq0Ŧa-8d"Plqݫ/Og~@b1&=. Ȱ3?iPgwd s^*p!S "ML4ٌ V_Yhp͖ " 7~gp.L~ξ8Q`@">t ݞqJ ~T :*DO}T$g2+F4 $?Ϡ/xnk` + ;d{a/ Dz@ YN)pu5 0bг P/ Q^@3̍3\6|Pvc.*|%NXE5nG!E$YI)UdK1eΤYMx+W߶|+4QI.etevq3*UWaŎ%[Yiծ͘("F׈J86_Υ**cȑ%O\ٲMnuEܖƢPqÆwiirU̺5*eϦ]mܹvXĽ햫6ܨnɕ_8]O^uٽIơi'_rRU}o 3_}[S\Mmxe?irځ砈B 3pC;CCqDK4DSTqE[tEcqFkFsqG{G rH"4H$TrI&tI( &6#Vdei9LJRI瘟LPqͣ|r˾jCoցpS eu1h``|q#0H9T*|aJӈW"QIa%F`4hO~L̊DS)5U8T وV\)ObQXމ`>;m#t-p&K[nP"q|āOifen[&TEQԏ`nZe6mJ݊)g|,WbfqrWv'W~wG`Xn珔Eofp|0J%k}|:n2?;eiŔe*ޘN:RY|R/YjNWCZ\"`'>k`zN#E)YFZ]v`<"L6`9?ڸ<# 6)跊꠽BH[ew[A᭄\YinOK-#bj!&戡E17ʈ,f|#"zgKmkA9Xv (d@A9K 2\ep!e FKaDdi+nv | 9rBU!֑T

( 1/ $Û5u#B`v/{C6!2OWU  | a΢cT94`c@> n*kE,1.kltªĘKR!Yv74S"KD9n2cM )OcQTM7JSl#SrWAL%PpK+hQl\mqFjGf#TfZ͈ܕ>%h6HÀ*Ta^astWwnc_ P6N%ÑHQbNwh-s,hi6S/Lp`X]vD>[p,(V$ ɞ d8vi[YV1哀DöBJdTNT!@j6*P䷥0E7zGORcZ߮~i"aE9 bÈɢx]Wื!&K1aVl8cyjMaa!w*6G{J^Wd4ByMKԗD;32v/u k[f^ta:ሚUcn+] 4yeP:/!3#I3D3=+󜏜1ilG]pfOS@ݤV/冔&b(A^[9(ahkfV6ƫJ[~;a^\6D_`7ņ,v|ϵ F!LJna1~h{Yh8AzciKq'd+l<BW@ײ#q4Rr}1+q:ܯLN8qri ]9m$4jl6t^DI c'vx[ n4+&5N".-s,I*VQ?z"F64'ːoD71-^ǰ%b2#;"E( ̰9;C7 79usf{ /*F^Lߙe{88;zF{(^kx~G|xClCҐ<Tlj啻6VF?8^lx3 ClK鈢{@cDk pP@66:,.@#P>ʞ@P'\Ԯ)DPHrlXɅm5A1ٲh>020>s6BNS+w򸱴H+*IT\?̆G.?Щ:ǹŜ Fp^DE`]عL1> l\5J˓.^ ?|L)_M ʈNtWbh.yjۄɆ1a&z+ZÇB,Z6-1 +$ ҼNOQl5li479U1CP)w=tIˤ$|HZєHP|% Yʈ KX0+KPE3̾pO3bs?uQX 2ūĺ r4L&mR'}3>hPp,r ' S11RkX-P,ӈ#p8S6]R2S>#Q IP#UASFmTG}THTITJTKTLTMTNTOTP UQUR-U3HU$8xUX큉UYz1U]U^U0YpWWcŇ(EUg}Vhֳ`s VY5XdmMXVՔVqWr-ה`: (dcՖzg4WzW{ڢwls{X-]E($Z~uc XXK]kXXX YY1mYXXVpS}YY(1hdvm׈UeLvYYm ʆuWcbNb ZZZZZZZZZ [[-[=[M[][m۲1H sEs ]=[N8ɤ&[=k=pR\\E, , MELaUU=K_{M_(]ڕ^Q[[5膆IJpU5k -4Q=,!UaR{j0ۍ_߈&x2O܊(0ܦ5g``БEťx\XɥC:2RMghahaKgL&jዐ1‡̕^a7: - qaƦq8su]b:^?|842oXỡb|0U%&2c9.Y@ip0ވ@Ȁ?nFGMP Pp ֜ZXdpd_Ϥ_*Y4ߢ'xO4!*g1Ž*0:ƺRESvYKO+܍@)eᕀaK*+#shapj 99L?q:z0撰DP4҈x] 5y ׹a  9bfDOf ^ ^Г>7 6(A[/9B^in"?IMbw E"$1P؊FT=jV ke5ώpTAlh|X<2kŇ0ΫeM"Z׳NėGJ;C"B)*ΰlc`<[bxy1c0ЈM`1QųO:`9la3. Qlq\|@ώln[ W0Pp@%1{%fp̱#/˱jPR^nlD6snJ\ފ%?Mp,Qsm3i8 ;C~݆pXK5Y膈舶't݊,gcHr蕠%/K ;5@li!`y׺.å,^:f3HBNlXꦞȧn5nj(qe*j5j|0@Jb[)E&V B(pْ bmp*iRЄ 77YSU>&`|2'k1Jf&TT֋mUtG1MtyiPP4A7q܋`ކnmvagXmN*)`\m螜5ngv8񨆇vmn$bЍoWп6ʆp!ؼ N,^%:h= 2~N$تh:Foυ%*Ҡj{mw}wY<m‡ v Ѱal؁ B|.f\aQ$.[„ҁ7Č"Gi۷$w%K2?,9Cx:/z*as|<"1nâ,bi*֬Zjv`nb0LTmj.޼z&AVZIѴt<9 }sg6]QIM6rI1]6%4˖m vƁvILeM.#MLoڔ&SΞ2>G>ae䭜[?8e3_5J'`*(0e j >ĂP:τ8dZE椣 %mQ$"M=')ze@]I8Ee-A=G-&2Xa]gZ5qodi{Csf"gwQw3GVll(g7&d3w1OTGs}\BP:ɼtFu3wNDr_~8\~78,W1S8^rJ*h|@.}s*;ο&qM6xDЪhx P{9J& K# . u9TS907۰ftI Ϋ5˪. ?<6baP!٤ )2L5$rBl>F4h~tH>4 Ecu( UUQ A0fP1,zqhJ:K>hC24ep[?!@&Dp]Z* HǾ"3C+MPB v0PJ+A4pb;Glps1&99pL&/ j[6ÜCSIBP j Y6>M@8;c3qq FB:GaDC?ĐFƂHB iHhCRӞl %rUwtEJ‴8rX%YrD"n<8(IuSlG)vSqtj %#ru%T7"X]Qdq;x"TDF U ;aNp$$)'2DT$#(H ޠ"9G..%pS38V2lxѓX8rqd%C FtC(wJ ݆brff6\G<#Q >p ^6EG$9 1Ռ#58](E#b\4QEhcM5FF|Ɖ4o_=  NO.i,ZtV%Q`G֎&4!2,ײ r>ۨ' -hN|\Gj *"L`+q C-p Gmcq,X! c1 h"T1?~NS,>%OY^a3NS9ݧPCP+Wbt|&>]px$zB*[0Ɵ/A08xChhu䦥 ⨨EӷC ;| p t!!1>zae ^uZ^EP4 '51I0 Cs#}&C3B 6k6!IHSg$!:b.1XzTbʖ=gC>1Q"é=-/boW>Yf9" =G6'u5&Z/ E3ٮ:qYv Y)d |?5Ѐ]Tn#9Tt ^dh}<{so]ьW3PAߏqKƜF)o>9/ʸp=(lf<7/s;5 y99K+~:ԣ.Sݫ:ֳ"UM=|NY*ሊRI\v;+|;n#Ɓj(jqL5bbۧ;s+u3>/Sֿ>~ o>>/~)?0HR~#b$HXuPH썢LE]$`DvHIh&VB !ij & Z0aM`IڂAIA `[UEN$DC ֎I"x,aH$BB\T8ĵUF5|Ð%!JG,jdCK^5#$%<",AMI%XʘeClE0`lH|ZX__ ZFM0MF`F^PAt!D fDf v[j&B+$GRB)H`F(`"n(VL .^^`%-t8r$+Vȅ8$UF`ۑAX#>VhcF \c3]V䞀R!+1>9ʝp #^ D Rxa9J4iq9lB]WfC,68ÿ@~'J?mUԑ>CeLH L_CI B >,P:Tm5@ "U C"& FY="D"~D`AvbM([Y">$B+(d+d[BȢZRC5.L/^h |tY&n!i0cۭ4R#*`#7fEf+869$UXlCDd\E'I- "RLM%D܎͒ȎJM#LLzzgi+CħH|$I]B%t&&~d1ЛS&8006$M98ܑlB"GPA`X2[G(F@mӘ"hdA'bPĕ%dڎTE{(9@N)ĚEw\R]wf U6t/8tB'J(@f(PƆtNH(@Ιa>ip,) {Q*Y<\頨Y-αBd,֑f> 鑘=8#;"j4P0jBJ1-E|ÙyN*9D#>U<ELCF T AEĉ!D0E96lK-1Áu_AExDقOA{"Dg{&zG*XgQ<,ABM-gIuG6h&nlQta$bɆpp\C%-sh#6}6.(+܍EA}Lr8d >>DŽ]6|8cxnœQ. [p~N C>C]6䱞HA8\ųZ\VCK4|E'8P1&g:G P&M_s6Do;CKC?zkBDrA,CmppuDG|"QppB|0d  008ԫU@Ӹ'GGPנpNu1F2EWK.N;W³@5j? u9GTzdg%A+/%Dla68]ewĄNނcq[${ +WƫX6p/9+r3y#8pIqFUÎp.7OY4ŕG_H,XKbXg9Vh4F8lA\~pH4BAl'$ò~dÎ8]@]_NK$z5~H5P5(FP(Qz145z0MfT[qV 1|qVSRsl&5BYݍ0` D\[ɫ&^7u3yP7Ɛb[\LWH`n-FF'|DfgȱB&B4.8L0UHElI{W8Bh|6sg3~ BCհ#C8~, 5`Ďoo0qV.CGMx9@O?NJ# "D"myKm4eFԑ%(eGFӻ3إ99BZ=02==rH2UP'(h{:#'O_dhRTFnG`2XA];eMUK,s68yg:x{MTd6_?-^KTqL-;AVlOj+E&1H8ATspWl> Eó 2HDX> ,Hn m 6tbD)RV8]܈Q1l9NØIg5ceΜ)pȏV3r'%FpޔV28['sawR|0> #TM6)-Z|hw;sC&́KD`7v^+T7s1QC~4pg2#G.a7!ܦ>,0e|ԭ[ll.m\Nw2މ.N.64TBN/se [v > Ģ +Xm-l8L0͒Ce _çcl ݪ2q&8j6<WL<E*0[z3ϫ2 BvđHL0g`ZE$\&|((!(,ْ-aLxuG|434L-:G!/=`2&= ;ʁ9mPA5LgH#Iɦt][)N(gۦHʨ*. aͦ ʉQ k[,&Ѝ"Țgw 5S /0t+!bdLͺl6)B4MfNg }} MRAVg{9XTxiX9.P:i.Q&0?F chFkc=c:C3FmC ٳR|4F|VAg!yNӝDJQ>|^<?Vg^NH T|?GBJGas)|,"(hR$Dтs%Nzi笯ߟD7@ph-ǭBi/y{BgxUɂ{&h}`*i'T YB1GeXCyM`phЇAXD#ITD'>QXE+^YE/~a#7F3iTF7zIX9BDn @.v&$IVE,q9 eyR5T<BM3i8o(D@#/%L0E/F7ԁJin;/0?%Q\R/x9G# sq |ܢ!Cp"1Q3nx= $ 1FH!9&l҃$$%9Ilb1Rʘ%G/qhM~J8>va`Hҡ1nD wN`pJ+brTH>AuSq(&>x naF| Ћ19mHI&ut,DDJ |Vy222.NuQRX]He9Z$T҅; 2Y$,G"<-t ჴnރN-RO)TF$xjP\bf9!Iٲn4s\^) [W^ѮhZF\˯3nicTo7ܱtl0RQ6mmN'F1CKޒ! ,1hBppDcEF]As GGXrFo$#J8C4DZ;$9mmR@J0Gf!QR~&O1-tzx#Of^"#d A\L_8b$#ŰL^\B =KoP !C/ަ3á "&A#"`vo l"-AlI #"Rt!( df=!|`iN N58Оna =- 0#L-#10,0"u(ā<0Eck </-`PijPgRRaQgAYAQg`jA)2`Ѯ@G u#vIK۴0 #!H!2ठ+\t !-=DbNraI`N Ԁ zHaA:SBd bNd1RJdA .@ q#<)bE0x/fQLQ3n% V!,n K\Z-! +a R@ %K-P O72Il H#=S$,΁F"k4.X2ƖNh@(\/!(oӊpm(!~H C06M"&ޣ$Iv!a0 Qr*$ bj0A/8A܌ =?;^!9+h i(@HrnDP \**%`!vrx/c0JF$1]-mB$-! 0beġXe@Xfg4.-J.To6_=4*#)~s A9&M SdF¦4Z0D!drpt6w NFcaXEf .}HsgqYLLJ!YXtK^_U_|0H_'"GZ5y&| 2s_b#Vb'PRH|.(yL WGAIyxIga "F(e[e_f+6yxFa=SchVhhhiViiij(.Pjkkv V_ɖLx"*QlA+`'b0U VFfceoCL6I6 TIJȄaq7&W"\AT!r#r3׀Pk L4\tq¢i Rg "%vSŁuUR(h6#wLU \7)(l]bl wAH3Bm'mn!'lj"5hIR! )m\=lCl4(FJ۹< I/s,+ρF3:ZmU3}x)Fu'0*\3< d'n(^PqGFa懧asZ]28 JGdzQs.#gEttzt4ZxA 6HKjŒ/2b`NR[u߁LceWJ! /ӓ6@Z!@ @u CHuy D{p7ťҒ̐šO#9rBf#.J!5Ȣ-rs~?0J,v[<^*ZC Ș &$8Dj$RŐ) XNLA^|NqKx-ܪyC\ELy FQ3e(؟ZR-nV]αjIMpx=g Kt g6}%9x+{f޿iR .* tM`w4n{0[E>iSƂ1 nl7^[Na۫=sӂf .{~Y t,??{5_}>h@ * : r *ja ("A"vA A,ϋ.(+6ވ+5@AϏ> ?SJ.dN>%Ԍ10eT^•tY/`M]ΚK5SnFxvqT1 zr JTMfx1Y>[iv@vKv3un6[&zpr-֘RrTCM)؅\umZJWr A{D|'߁,}V8s5߄& $,'8$ 0^$@/W^,cEw- 8K#72)V*[^~[U1Jk 6Jt#eՄ5/(m|JZ[1*1gr;@+Toq;q<,)EQ '%9&S5(_64&;6!+&=nbX'ȕh(" cIY}e1a#! qg;;P3|( m5I v'F8Ӯ"MjAx䵭|aΈ46SSEԶ6;Ρ࣎yGǜ&x A||;т#Y'a ݈LjDOu#L,| 5))jwR";'eS`6-l@6q$y>+sR'`do{RfeȭE:kK^#ˌW4LjUev,KK-Lp&ѯ`Q5yMplLp& qn"@di/NC DhֱH k-CB: 3!ZItәPAxIĂ@qh@]bQ"ᣊbXȋ[sEj\W ְud-YϚ$JO[el.QF|hBl+qɳ:D-a*vmcۧ^C+ZDZ-( ߚleQa qd֮x+6<I[ vmo[ [ql ps*wms Jwԭujww w-yϋwm{[ IG`Kx*IhB;Zb9eO[:g$4 RZ1"lD/ ȃM k-lfx q^OF2R^*ɆwRINt jK\*$WA9ɜ Q9RP>6/Y@dw# q, L-D.YzNsV$zҳ@ :.ie_ P9*_6ηyBwy+<ޒ"£36B 6Hlqn I,s*NR+?_|$H+6,\q@MUx5͖TlLX(1YB2&]:rߖwM%%mrlon4pNaeM* K\ָCk >q[*>p f8C]EtK ҫ-,btl:eO**M0V`.Uҧj\#ƋUjJj*`6Ni3@4FNNzdo.w~qޤ1"w[2$> f5_L+OR̰D@R@.cz騋 8AdH#7:y*ac/!H1_i I b5~ 9?N >%A7 ,Gqs)$Wi!(3VP nUfeHY7Q1zW7&{tܐsy(iN&`iM)q{$wqwgaLhz6A${!yvH &ti8qV ʷ*Qq;)_ b @ f° @ _q;ĠCa p 0 '\7_3*Vt-vG#bk0$&/`+iP7, -G/ng8ɡaE.tibb!=ᱣUh(.6.UqbĖFbIx0fے( Z*X"I2Ӧ  *jQV SY<> uSYbLszzڊgR#K!!q!:Lq(r{HJœi7 -$t37}1Aj __1ⰞK1%M`% 27bzp *J=!vConU A0`0EI (*bO61t(OP!L9iJj:}Gę  6ȖkX񅀨#ۨO~ą6ayey\^*py\9y};k!7soz Nr*j x۰}J1XrUv*y)q*|VQGzEG2gZ$*@.,"J[(ؿ39S0R{33-*/%c85lymm y۸٬j\vHǑ .S ' =Wܘ&K=8i!$gv~ S!@]<-B@.ji@ =BcbI>&#xٰ/=ф #mIf% +c 6yfGx䘛yQ|]&I 6 AH~D]]{APh' D~鄉9mcM$b}ԣHG9\htUG)!dJ OL~ :ȶ٣j6 ! IQa`mYلP~TDv0nxRLH$=dnfS钅UpAQ0mZPaiJ`ށPݰn>nN.bNm$.ԇs#S4 ?dll]O|n*QD-^ĘQF=~QR9Af\n* 6n;p[s`Ƚl>=̹\ҁkyI˜3k6*9 J1ദY&k 9|2 OXp^,oMP׷vǮg6.s鲥L NȺѼ5bLIy.ӨU|'mזO۷s6KezĂźP,x ]TbD"\WflP+n}ьo(FcGli,*I)bR3 "WE2 G%il[Mzmb k[6z,(|>;+fۺF ?Ǹl~PyE)cQq$4jzC@y ~6 Qj2p" !$ " _GL ٘ ,R~%'dMWxš,"9 2z1@HhYͥ[׬ذ'AB0-cxE8|$P8̘rD#F&GZm>BAրBjv3!>bCsU!㓒5y̆l1y"!'=DL%SJVҕCk$al*9Ł6MK!9ŃF)@|2EV9Gk} *N@A c@":!'ȚHhm3ZؗB'<.yy;4~ye$Yx,-"d)șc;OAIS$>aԅ@XQF'L (T|X*96pbèHAO2J8qA SH$Tbi,C/X'ettNYztø_OְEwtT h)٧4b;_f.قQS ,ӰvMA-FJp2XD_,%sOZ|F?؅4FQB"h[혡Ոr+fM/޵ЋoB)LY՛"=aD}*&mC UPzꁛK?vM[yHa%)ojX:'ɻ %\&FDquc h*񤉐, nt ( tǁaPC}Fd:H 1f\! sIN dg Ut0?pu 95P){|=& J3np۞1Z@}WF/%Dc BaߜBoH] FUo8ģ~5ǡD ȓtunlN3:dG`IRR2Sqvb{%9SRw=r%$Ok.ˍq|7h b)F6Ra& wCl)ؑ.pp[vx}h@S|l|(9f▂Dfdp3H(9R(~4%YF:cSGGIr A(Iec&uw^M#u­ =l4!*HpT#& \A˚LIsmwc7χ~GaP#"0Y lǹLzyH\|#J7c.rtw>ct^*X9JgP{tJY@"yji"Ñ[>Q*c ;! (u{B@OP6ÇH #=Z<;bIJ@u#DL"1/$WA"Lp0+¶X_Aw`{;;5d 0@Ԏ8 ̖cFtGHYDIĉ$؈D0{o[B㸥|#D[EWXYEqͪEZJ_d;PBFRaNa cDjklܱv>AEmGpIFho sDtTudvtwxyz{|}~|Oȁ$Ȃ4ȃDv5VdD0 t`1($`&(\B|ɐLȔTIq Ih1zڎwEH! A;tFaԎɣ˼"8X 0ʘ; B4sԑچfp| "|r5$(SRQֹ4(gHȉJx-\.<& D<$ lxt$ThN2JB)4M8@HN|20JR .MK:x_Qݐ E!t/|ZA *cI{CO$P&pp~q˺&+WMiA@"͢CY+VPg,JWфD%`ۣ\PrM@&Qh "`FERA¢]C+]||-RD LӦ9S,m() AA+Y`2qϭB4KMpa:ځګm0TTI%Pd-P]Ak!ʹ)ЏѹlXUU(sˆ>bxWb}jWpVaTÇUP̏0NeY`M#&P$pKTБ-JM9KDU*sĜ2T@pbg(VW<#R#|Uj80U [UX:z:B [#b8@ m0j`ÁBl׾n j&L;(3`#K\a\h5N1Z͟E$hՀ;C//YTY.սC5D5! J]2J*Nm0b&YOڭW4.DUB]߅ՐM^*px=DVKr BB1J_rʼnȆ[`A01*`a@&,F(Lא\=l0@He?k O|v$H=]ASlǻa2^HB#F& ^H߻Bl^)lYb(̎ W#_kQTp_rGqm__ AF0GKd& x`)N  `.e%ԸFh`b.U &T&ݽO]ސ⒭aPp!YbTK$h&8U'Yٯt #-6EeSTaQ0Qd6<,:#@I@A5#t&6Vאhr>a $~G:QƇS+h֙IG~Nގk;ٺFe xvĆE%ݮ :D-x=dh(xT³*LC=N=O.#vM`%L>+בUi[ XD0=U8U=P0UQ|WE!:c+5(`;&$Kcs}_x>>þ>|ŇD##PA;<]p`|h4 SQM8<5!iM92@CP.Ɩ!مY:; <%P$(eaA|@?Ĭ!_n@ AɕxYn^/Ά4D-iAuX _XD#߈loFb|%g6Zr`O&fb't-Tψ"f*uC,qˆ]^^X 6`]O7v"s`\8?-vl7h'? $tv p|L|PRFttSh9xr$O$hRSo~U"Yy[ /ix/1cG4v`x/wLyO?Gv`/w(Mqliq?ilv.zoD h(FSل !  !< {m]fhPWb{aP{P{xGx| | 5|&w٘ N~|ɏ]^0UMlKSe9Ko}gS|e3~hp /y~q`vksl2-;3΂8P=cBg7ow`> h'ˈ~dm):Bj \:p־d.sL! kY!Ɉ$Iq2$nj$OLre.]d&MOj6Ny2qDBfhRIjd24(>&V^ͪj"z Iנ`φ}v-۶n+w.ݺvͫw/߾~,x0ʕ&6C~؁#w28n)m&Y3smt n6f>m\e^x6cKzM˭]޿G[ tW pb%/قH|B6 apH~,TBǁ>a<<3JTF$tIbn$N;=/դ>Q͸F.6:eUUWK`ZD|K2٤OBSRY^%&De}db旫mgm)`IjYwqPZYoklv&zgs#]A螶@ʩ5+oE[t<w+t+hg bV`;ΩF- 7\#v$HZhmlIM)K*HTFAn:ˆԌM!%Տ>SVE\uVoW<# 3pa F yىG1`g5[i'tI X 1f:Y@*)rYlsi}4}ڙQM3 '9+r(+{D}ێmR-J2V24:$Ӌ.>ﺋ;/ģT"1WQG0裓^駣$e3D5N}kET8T}W0o7h["p-r h1}lsn563v߅~)QHCH@9 YȁP+bTkZ`[J^oJڢ}D.iVt+"sW8+^[\W0H^<70:!_|DJKd3MoBR޽L@jPOZ,=E6v( fA)*6)6.2GpV?{g`SB@ռ0/ 7 TLnD ppc@"e}$:G61| $Z6>Y/j@H)/"dzCA<0ز+Ȗq!NE\拔Lpьp.Fהa B~sWBs3\'a  cktA{&Yx꩖{zSw4%蓟x\G')]Qf587\7^ꏱ) ,EBz|d ;b W}kk@N۰j\'hZSᓶrI* =*Ajo@%Q|3ւIL<PY]ԓs13?ICxv]va ߕWy-R CgΣ"6],cX 򱒕!up6U-eRs]-k[6ׁ)ekTWKt3LkߖT7~mB7}R!fb37/yk7]/{7/}k7/8xآY̾#`xS!|!b(jU+ 8m)qȓ-^g|Hs8S\PsҀ7zUBtW P evCk,(o>MD$0_$U(r01p?r5'8 '\1t(KF , 3R-VU$ bC.c:KqĪk1Ywc=sts2qFn+8Վs Mĵ|S `E&Qj"Q[j4IZMaZҀFC301h..o%RY;/K-g-u+\arpI4f2F8+]8VnvnL\< 8dѮ90c*b0c:DagjDH8Z0 IZ=N2@B 1AkX]@8`솂ե&Aeg >.l!eV/uC [g&,wߟ e^du#PFӌT!vi3E a ;NLuP粟"61vpY]wqL 0=>1f8KEBp!P8V fIb ǑH qv \z =xw/12!ugCpEú_6ԉ!bZJQa݊`0HGX^R8 "g$E8SL_U`mNxX^Ku!^` Ʃ[GXelt7d%ɣ8 \_?U!&9޽L7JZXM, ]$a@+áIֺ} 8D16`3`V *5@յc F5DC#>"]vJD} E@<&%MH0 EL4K>dcrc7j >p,[HG6a, u}ܯI;[ͰȉZPKU 6Eܚ 8ʟy$m c#RkId]meHf]*$ԥ$Y]6|"amԉH,9-j`"أOd  8RF >0S7c2U(Xc6Fj66d["\p9eCJt<T ^6=Mlo9T<]؄GaՔD]9NVxؕ+@AԱ$딤H]ف܉lnCK8Ĥd)M,0dpGd++,Dpg6 pz93P`gt Ɉ5R,DFeac|ng%}e~rŵh 5Ѐ]F^l\iRw gfǍaF]=lp7B5(ghf|fDBdk.b6@A1@jC! bºC$B0Dm(("!+rT59D*,޼U犘R gxV -Nqr EXةѧ|f|%Zg8Q[@Cl6ԑ ҥN,R:47d&0>8p\OeD.Y9ޚ1a~V=V `@)f6`Im&""(`"*)BN Qe³Q`,sk f8*ę''\̠cPPWꖝڧg}:$S/:jp@.q 8]ԟ;ev͎=|DKplԫ89DIE1*!K׬dDf$ @b@)>Cڹ]Z*= |k+J VTJ‡"B- AIA%3*!A{@E{`+mR&HXz)B l)6Zbnj6x"څ񅽑n2ꅣX6.nJ羄q]_."._0_"oVؽ*oJRoZbojrozoo.z.JoyDP]@EbCY^U@LO>XSmOtOz_B"eXB]h[r0[D>pl%kFAR) ^ ίD/\oFK>\x[{8Ą:Qp`94ORXҳd؜sC=ՕT&I>d[Zaᚪ.p*MlUA#W`A$Kr nށ+a0]1/2(3V*X]7ԡ$ͤLcK%fT pq]4u͑FHĹy3[ d dTz#W-5m$u8Lj%DOi*sQoe A` z?)@C}.lBi|V.BOCDMc>;dCCgT tt6d@t0ljIS#07*ΜTlPCqCjO5G_/1 y4kYJ6`6`6C4±sE#ߵ`ԍGL;sZ%b\Z'v@s lC/Bv`&,E#)* lG)@{GBB]HC@d T@BCpB9KD>{@|w";|ۼ|nU۷^G{CK7sĈ\R&G\*^\@7ZGv c&Ql7*#9'dY~D8$ +r[=>(d-mXo&TfDrL~ 9X#vߺY$KD+ˇ<ؕk?s9]gAtCcG4`_3[ļD86PJ U:۬H C*0dF'>UA}ԫTT p 11G 0vɎYѦG *'ϸ9sY@\+7p`65!mƌUp K'V!AqeV$De"F$RLI|b`Ɣ)̚3[,)=y:t(I%"%*RO|U^ZkW_Jҫ֬fTm[oƕ;n]wջo_VNpD\|49>{}wsJn[nBF'l9U)"ԟt]ܷRRcV&I7xzpnX1^pX,3Ovp?:O5IjZduZo{9BMxYksd.Ld "/T@Ӛ5lg3O| UmAp75ao~wdco9iY ;nûad%) >|a@HⳢ/G6@;moԮ-! p(BJ68U#!0K;,IP'@ J?926YdPI?\ p$!xM.8`3m-ˆ;#81\LyB$ AzA1"ȸ]%A@&ځb,I>c!ɊJP7l-ɘW-D]Y<dbb"e$|&|iElaԖBuKaJJ,IAKcȚ'ΤSTZ@8aq۠FclÁ-ňߵg đ  S;3V!;b[T= Ole^I*B)X4s ASYnZIxӨQr,wJbZ;1(p4`ł2@#^xl:<9-L<1`T9 H5'!%^ >Wl &:] xq!|1q$8(\b.8I)^|9T"{+-[pѣ@y-yB&5Qs@t`%UqpVa J5uN uAK uT7F$,3X%%}mwA. ]la+-ž\ldX2D6]"$ !Ѷ˻rw ;׉{|[oR%7^ e) ækB0aȥ\d=8~vv+k[T{ʁd[NF]sϡOiAKEIiLv!N~QOLT'{o@\c(GI4#4YIܦ=-jPfn&gv&S`Vb>!#!4##@#(\- >6Ab\Hz+Eۊbl >M3`0InI0":N PtN!!$ Oܬ9p 0!\ /FP!lA50b >t+h0,+BHĬ!HB:Q:D,mL/!x(V/b :ǝJBqh!$rrAlgl$4GEs8 x&Fh6TxJ"Q\$ waOPARR vfPB@Gtҁt &-ܢa ? !@-(pPB"=?` 5 ,R#\> V20܈a,2*r' &Cd&OR&aºj ܸMl@ !ܺOpH Rʞ> %]R ύ +"m(r%?b%&Ac${!.#@&-  ŭf$u"'ub#$o+mo, M17) Bqbb|NZo@JL%Ńu :Xu7 AO\"ԑ:}7n%Hv1 ?6=Š.*fɠj'&0e!!^ ؈@1!a >}`ȠAAQz` B@!"1>S >!ݶA'>>^4B~PFW$m4mFTNh Brz@x Ig,.AǶބ  U! blIL-?#KT>1Ȁ@ >4V4]04TpHUUXE `PuaQBTa?[1[e(be$s",n N:37b4T4"` jK3;.i!F$JbbN!r%hz:mo [`*J[`ARB>pʱ::KŽC %RvS\P_泖`"_H : _ j!aN!A-tb {B-/(tD+Tٴk$UPL=O96"4e7a$fqV(6V3nlI#!~4$tƨ#A>hm>a,ia "Jb 'TBJAVkQd b+:P~v5ֶmW/h1t $&˘0.VU$^-UqUWq\/Z 7MQcf4`6p2)u5IdoXbWwcoH-Lǵ\S.u]O ywC^^K^ѳ rї_ݓ)XV>7&p! Āa}a2b5b-$2n{Pk?ؐ-oKd۶,_2hǢ%2f-K4/IE )Xc*íXAlG8 mW!wjMS XXoxOvUPb)ovOfI ߰ƬX8o 8>JF}pqq!7qWrrV.7 R3ɭs=6@7VEW-0ʧN |]vo8(J$Fj|&wswǜ)iwwob]JyKmyՂ$pzAFQ{:]/6u;[b*c̳k7&^>b!Z=PAن ٮzx !BCɢ6n{@e@CyCc8/xBDCCFOzm)܈lL'J $Fjڝx'z+3+W씋 Y)5Z#MV,4EaK1$Xa"u>5TG83itbO$2cxpY!4.8`RaBũ`8.$!(:* Zᩐ՛pJaآ 5̅8ײ!{v wj;q^sa&q&=J8J Rx3b c=q?Tr09m-v##{ C6 ²eGCSI3/X'[8;%x(A#I)*VLR-ǂ{FY!$'53r- bl)vR @*#)+hrq2S}|$2!]B2]TvS2osKaCK-$ā%[JZ׵Ĥ.zTAx(ֈF䏍q}\-ebiO֑$&ti܂%%{²5;ґU-kZ-/kHb2v+j j.`i=Wn;Q =-a>DCl;T#{ ]TG YȲaaleo%{{%X &@ |3GzƬl"] =U.6[9Qv6hPt2&P2*c}ơR(Qj/1l,]ŗ |ϼt|/*0*-<.$cƮ1pJ?.08>/2ZYDj|#l/)#AJ[8N/0^71(9ƞ0V#3p0p0?~yA2 eo<~2>~t. 0 Ԣ@-h8O0yO fk1<8#~.B߫P`p"[i-$K$DDlP_/O?{(+ߢ\Aݢ*@͟KFEB[9 =g=I xD] S-z 6.?02 + *\ȰÇK ŋtG G؁P#G(S\ɲ˗0cʜI&J5Ke"8< 7r:.ʭ(sJ/yt[+&kqYGv;V,s(P@AN;pt×>=ENrdÈm涫-q({_k>l81 X2aUv˜ْP 9ЛZX07>}ÔXq"+_μ7 nfVy+3(zǩp:&r{&[n"g<9N6T < S >"t;` 9sN6&TAfXҙaFg 8 A8#&K"6h\DX1XxOQ*Ok*XFR4ځ >I.h5%qd]X@gX 6 Fl%vlhXL 3Оaʙh u ʛ&>ډjiAڹjK/C_&hPV툉O789hRiЃ9Y¾4"[Z!A[\ji覫r $Pl]JJz{4F\p`)5U:kLCAkYzT&4HÂUXV6،֊dc,|%9Jc6LM7>ʺHҏ1  Ǎq$L 5Zb?sEP@!Lm36 @ĸ79.d6g3o؉Oӄ7rw99C gF#酇U (h M4Ejk Ά vsx"28$G4QTem=+mI+o{Ώk7cm>9Ż&bt/IoBρG7o As>r9yZ2@0<UEbBRD0AB  $)z;+ΰsg j`#GC&shP HO31J^s"4U|xLR]D]6s(7.n;+G5‚(b;! *Q#8иvu4gŕ$>I *HvA QxŁh Nń(i54؂ F=PҁJ8 bApD{ FD@ nz-a87/;! ?s$i^`\l 3i&Gkk@+׀D`&@: ̃De*z6ÑgLpd&j ՒsE3ib |zIJ8 ,>Q&ED r{^~&|4oK*Cő7Y* ʰNs! 2RbRIRF^)$&FYYS(2^m+Qa%=&}R1Z'3x@4Xժ C&[&ж}V̀D5Ƿ =&0Ofez+@q.Ȝ(A@{c m] BD@О#zL0ТݨH\f6å͈uarU"<yA[-/H$)}Z[2uKN8U)C) &ծ5,bhVԉC,^D;LAP\iIrɫ:vqa.de( #٠\8˵M6qEi Ԫe9Q:!>F5AF#ғ4[\_<Vup%Rơ6c" O `(@Wm1hYBz5ċIWHИAj@T ; H_f *3 Cwm`#^XC\# GT!min%H 5;AX1J gѫ^mJdRYWQo >2 ȄXsY6%]5Y*qO8\Ϊf"oܚ7K҇jӚg,ݛDM"'e2O39ԬK\wp;Kp'F ᎀ,NG<X=b,RHgbb"MF6잒PyQ Q4A@z>:׮oKeIZ ,tf'r% G9!wt02wax[6rx7f7?Fa5ҍo=?FcB G͎r+5g9 yC:LI f)Hr t_O gC }l.vu;Z>ِ :;$& 3=>jwMv68}Fxo>raqw0@ A1 "A!o[!(rAbyW##Aj" _1p=0#Q"q!1EiB %+nSv+&#݂RC|$14#sG2x='!~p&iL{~q u؃('q'M*|1ede Wԋ a*a*Ҍ)xȈe Ȉ-`ȁau؎[LJj r-dtH#ޒ&yƏwZDiUD|yaIϘ.*%7-`ǒ0294 Bm4QxEH>Iv.)TV$"b œp9IuPyXZMx"|[Gx.(1)e);Lhɖr9tYvyxz|ٗ~9Yyޤ9v921[I} &ysApKi. auyYtY>+Qh?iNXu3o tQ@iPl9! 6 qV;)V PW /([.a:djlx1D#%Y6 +'Aqu7QM> v'߲o! "=p44rMZb1v" ; sf6(Pjs9LH#"␤ ِ4L 1Xb  Qxy7Ҧۀa# [")~  . =jx9Ho ѩ‡>䩠Z6fq("Jĸ)!2}a7@+Z g 6u· P>"f{HKai9IiVr9 lJ A5n%%lu] xFDP$xCQ1v.0g Ei";Q4j9 :&{mP(t@ֲ0o2H($ګ0$4, ~ #4((Sr@&*8AF_ـ?"^ˊpY0t[[@r&K$;Q*݊+PJ;빌:`IP:Kj`PKHh/{31`6A+ 簯ѯxۆl1!s"P mjۂyHYA6@}J|PsJ2*K'ۿ'۲<-4k%a$~ƒ*"Z!2&\`:9°aѧY{\>%1=@9j[h+HLj+Q$)Mـ` A/S\\^,lY5p,5Q*xǥg̸[ȸ>R(Rxe=W#e ʛ,[Q~࠯ xz;0QAɑp%P  cKi+uml$ );Ѳ42KLw|5D|"pRqg ",EEj7G.g/>'ZH|'jg Aݶ\8PtAMgC_, `ɚNqj-2].MoTӯYzǮzٹve̺cN ȆLȨ&N9 J*s"Bye1 v;ʤ zt wEE *+J_'h<0k|p9$+@2} ɬL!}@2oܜ1^@6(vMMq#F dMfw2iR|!}iniH: $]k^KM| Ql$y]ҧ9} ꯾KdiTzԛ ~ >LǜԠc<\`6H]m}= 1q 8'r'ZY[ܗ(ʝal/`e mޜ+d(-}wO0Ҋ0=.n<ӴR[CӽP ᎄZ]̥c+p] za2aE5ڦQ@_Ɂ `] ;% R@ Ll+ͧ02?4C{q>9[S3Zٰ×A|!|̝30kAR9! )6>'XʕZT2)}豳'Omf.]Z۷Ą5 n\:Q i *6ھ$Hw2$[43[7A…+e1Bu\ycncJ=Όotћچ_qjܛ#o['^qɕ/gs$y;t5P1Gt[O(vU|6 u_NHc"'bv9'qaAR0A|!bB i P)Lb*R§RzH7|*6Jv^|4V]4ZGN)) b o0,(l2ɌEc2Y^ 5ZsFom"ll[*ˬj-37|{_x` 6`Jva&F(#pP $dQtIa@02T54,;x-lafsyg{gyJ*6hbb*($C!BYgyB*¤[vn-Yvm{ns&nfsiPdbb68mU{r+r3|s;sC}tK7tSW}u[wuc}vko}w{v;x+z5< JRky9*’Np.6"[Wh#hN?a]]1B !/([BqԠ= T6d0Ft 5Bt @if<.Đ l)aD&́X8Xd !c1!4tG5&*5qв$2dv3g{Ю!Axl>m""{v|q(Ar[F8b , Z$і.3&nvSғzwe,v5'jʌݖ&6ȔzU^@fe%kEu]¡)_73j"gZI051 ) c>+>L ~!qcKX[ ^c[<-ʰ]'Q[e;{ЖgфlW1S:ԩO> oo6& **lyz&LI2(:To6n*j6sNRczc&[:4|=ՅS!'y\6y7S w3.J׼7e6s2l-D`-(.]cpj2pi5 mq6v qLg6YldnvKwcsG,-G )lL1URnEeQ.[Gf):&ܜœ`l1Ew2{'[{hҺk+`5 ~rt[2H37+>2p0A@Aܼ{7ϻ.p)TAL9=a)3۪PPB܃* ԽPk>r5ވbp )?"c#J2\U ,Y  1;?r n؆~j;sΚ΂`ȅi;Z6DjS-}BI*#Hr" G:[((8lx2Uhs@q2/3WaćW3~ !t3hk3)kxEȒt0Չp`ؓW}h#iS2M'6Cf2Q8xHu=VsaAZ=MZ`&)A1$Vj Tp`[lMl([pZ$R^ƀO}BɆr65W@hlqUreq`ۼlpZa(F ˆgs M(WpXl mgmkg(flMkl偎mX :#Fg b n{SMd'Ƈ/Q9n6^?~ڭ60lHEi杈U5ߤk=9ajt,jYOనO`m <X`XDV xk h-]kukN-k  Vk([;ue%lF&MgƖBgq.ӖvxNg6m|@m}ffm׮VnrE푾mj:(hhOEj0كa{;p`1)Qn∧&GXmn9 mKXXDA@m8i{()$ R(}K(moYPQ8bR~P?f剐#Qs~¦k rp`4PuEmO >"%Z%nf念q?!ez^"7Znfr'_8`fAĉ^FqinzU=ޑӊ\Eo JdQLog 5  ` hle3 .e S]p0mav$aa9ۗ=φkq8uq{qbq_`oP_&Vwvwoh :ɋ: &E'u7WcWU'PE| Iz:oϊg}Y(iJ;d]?"s=U2ݱlx ]oKPr oO%ANRPplPK B k0B)D8!1.9,  3pְZ9qEPXCt`&H@RO|e\(Q\h%O,"8AAXZJ kыSjLJ@)Kl*ܸrҭk.޼z/.l0Ċ3n1d l2̚[3.I 3Lir;" soѣ_AF]f0Ek6ʗ3o9ҧSnnu3'#6N*ڧoy Mhwֽu۹5)F W\]7G * : JT"ݬ;83!^m{waomԑ| hM$!5x#9#=#A 9$Ey$I*$M:$QJ9%UZy%Yj%]z%Mn`ifV9PQlzE \Ɠ.q"AXggF;h9)vX9Dʓ.\8e 9 #3d#i*i\ps9Ҵ꯳ 9$ RO"tj_t#2v%TݰCx H*Wd >Ra#pхWVirBSQ\(]>\~6EuBAAsT'\ ^k<Zfۗ-Z:3]V88,WȎ8h'j\ 6# 9 o;+,U07U;YݝKKӴxM4}Ksi]#M.m"J=p5>慮#rmک'>Ds}t+rpq|ukI@ĀR<(Vn nt o_<<[naeSg.'Os|KP2¥x[ ߡǝ)qhbWT㇏nVbbE,_B)(U;0c`>1\y${qҁM,5x6ɅdKx/+)ƺB,ɕ6P7%--\kpfDemJ&ϱZJ-3u=%bu)P 'rSg*`/'{%Cv4X$3hi7+z¦G ΡV}k5 ͣY=Q[ 7q4XU㉿8 XS 6aj:{,U d[; ]t$Ulb >HX̂н_ZӐU6T9tdC5Ag,LUE4"6LNC<#ZAyVBiN@k@ ID U کd@ghTC,흂 ZLeJV&araPDlH D dyݽ4 HDEV4bRZU^]\$[UaId64UJ!Od89E\$Md*G@ܘdQF9# $C08O&V_RJSV(A(Nh2ƨ(樎(())&.)6>)FN)V^)fn)v~)))))Ʃ)֩)橞))**&.*6>*FN*V^*fn*v~***N#HƪΪҪ*`++@3+6G~<+VjƖmӱ\+v+^+$tG0f+g@!A,J H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0Mvk&tbɳϟ@ JѣH*]ʴelܢ;GիXjʵׯ`Ê5Bk ˶۷pʝKݻ.b߿ LuFe+Đ#KL˘*\̠CMә͢ ,װc˞Mmfў+ N0gϟ+_μIawسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\׍9@[ T8\@Ds'0@: >f8tF@Qq# 1FgT_'>35 Ө7mrƜQmchuƵd-xt*hx1MJ hP>+5x hc frMOhL!y6ۅŝy#ync@ZU%#ӥCL #00e"߀7#K5ߜΠ7UtMqq/J@{Ppg6y#X׃|1=p` kM}Оu[٘QBQiպf-_}mv]SO\,,>m *ή`/Vqn5>(Z-". iv]Pc @z㳍w>߳ 4XG<[͝q5㌉YC@g9>_]*2 :i(܍v|D% puH3P9,0Ѽ)N8G4daO{Br? MtlTGU @ H"HL&:P? <9 U,.j([$AjѾ lL9hrIN0يv)L 6bf2FX`F4!(8fA $7X48wQTX DlΞ/q<\|F&& ē9h^JCFU49GN6i$HQpZ8}iAɌ,OϿxl@}71QfY*!o $۠> SrB\  =Jr!$m0ݲ6 +/1->0u5x$lcCsr 1=8xRUV=PwBRqoҀPhj SSCB6?-p3adx=P{=;\UoX$q-1yyhAP{Єm}Q8$x1(qkt(T`$h@ x3_5Rv@B9DYFyHJLٔNPR9TYVyXZ\ٕ^`b9dYfyhjlٖnpr9tYvyxz|ٗ~9Yy٘9Yyٙ9Yyٚ9Yy#)'Uj!3O@OI@aHD;Hbc)i z )Yש0\lzQiIOÞRycpi}p3E\0m1))rP:X:qMd=XС 9詞feND@ @1Yz2E3IOJ-ʣO9R:TZVzXZ\ڥ2d`&JTy}s›Q)lb5" Qrl X,S #,0'8q* q*3hڨb"x12'zX= q N:G1P X6um1pC84\@9㪝7uJ g 4z!)$s0:0#6eW06A'ꚧ hPЯtr Z e A *4* LB @Dz"0qz}q< p|_rW?NH/`Ӓ},۲HJL۴NPR;T|G azRҠM`"&`\HصUEKҕxz5@3:>QՐu{>mԶSN{w 10 zl6lKS !W@Q%v6sRiY!!{@> ]ฮD!w4B pBE5MY+нC B Epk! ћ?Ѿ|sMpPt, %>ի93C6c뫿Fl ɄW{2[gY +&|(*,.02<4\6|8:<>@B`*$* h0A=\+l2 ww "|m;@ռ8׌E ʉ60 htδ\E΋lAϠE^8 'p  ͠s5q6i0Ϡlhsot< l>!3 }3LНav@q@\BѾ M4Rw K-3R 3@l>g)?8J3=7Sg-i gHזCΠ `3m}` ؖ}ٜ٘ٚٞ FbL_&4lwp6F~vv-[+=}{\NӼM@}Vgs0-=mˍX1cݝL;S k-D ]ާ Қ]S6sEi DDG /V >^~ ">$^&~(*,.02>4^6~8:<>@t D.qvMK^LAT, 1 x4T~  p d>p joL1 vQI zdە'q4=[ SjNB&=icd"XH Cd!ddjH(r0>_sbKPb2 kTdVC}'r! >@ ! Ǝg!V b?~ފ>&.?qv` ^!Nn CU` Zk0 _.c a    fk5BM`&'p*V"cZ ;{pϵ0_:Ty-Е9H qBCsnFcщw`2NsHv0P!*c!g*Gz`1g3̜ ~u& CU33)^ N] *M>tm ᛰ&)Y}\[ /AMXoq{2 u ; N+/P֚߷@&Ü3J o*Տh _$mB/۽T:o?D*q = Jt A *WwNHb65"Zr6&TSRn麱Rk}y.-1̐Kg\Jsƌw3PtѴ ;A#q)>iWXTR̖5s1:[qΥ[׮FYyei-Śf ;va|5exV|cxjⰆ,_i A rۦK mGtCMd>s6 +]nM>>X-۹ _].[5՜9/ztճWKl^:.k8,rȵ{wU7m^u.+W[| ʻt!F[Z%j: 2|T(dC BK;Q+>y@p$ű^0 s Grt<oK`IFT>^*BǺK0c 13lZ1U{.,+aL: -_B#cJ/T!qʩP ̀`b2.I L+LV[u5Lb="M2Ylݒ2æqf |uX < *y9g Lg9hQhRS!bưۿfkB Ign4gEĉV߶C붓.|ti e=oQA%%p^y@W[0Fs&gsw$ƇC]j%T[搜w~Z~ sF[ls,F|  c jTwD(d!2h &=&TyGp ;pejb#|r6;L^gQQk#7`+QiySDCY5V8%L!ʬ}U22wK\6r1Dh$P8Ņ/W75 'df)lwBB7ƓjH/eѱ{B9yL J(ROz+_.ϸo{` AFC[tXKG89hH:CfLOfqZ )jcШVHt thHS)}g~E'MqIS"e/u%Tb*4vW"!q;FԟUK42&*Xz8XV4l~v"NYP,JX2m |l(8|H/ Fi5F&KO_NJ!ĹdAɳQF f?;VR>^ &uhsqˀufHD L9ͥF)ŭ|vśJ7Q;hȓyT T&^WD?c9 eun|-[cb65k[d0ŽFD"3R69J*#ĥMkc7FLiǧ0H*C)~}dSQlDP*ꖫ6hbWı5mb7-!jlc%Yv eV}OB(1(I Q&Մ@(qsB(5v#KXHF&-Z F4fnҨU#7J֌ Պ5 }]2$ӥ.E.A Fq2E8hG/oD%<[1t|6&|ɹ!D*n0t./xAoc#FBu\&|Ya eA-C0"z<8l4&ǐ*  Ȩ U<̈́T4` eҰ&uKs!63<aDc 1EA F%D l_!xp#RPTF{+~W @MϱD5m~#[BKMS Yvjp˙Ax kA}_?ڣy&ɂZUC >=O{mlr_o"nqM?y_lш#M )&RN.v`E/|%uȶ9G[I M(u7`wc' >"4XT ҍH9Y g4x5{@/ @ h@Z( =m2g`(1fjo k;)% 8wjz!|0 59)`۶|4+|plPۂkXD|^!Pv8xvG,-pxpbCY0F )ȃ؅x|P5aJ8Gt ۭoZÍ]` lqy+41؍ސ*:u(:B3##BlCEXwK|p[h`Ez,lxwBDrG@ 'FʢG CXisL0 I*쎳tP'kح)y*._0wDʄN^lMGbKƜ0MM NNt2/IT:+N 3N TNN OW9N 8B0ɡΜ"OLihDNOOO cPNi=uxdP P P P P PPP QQ-Q=QMQ]QVoQQQѪx' 0cC*4(QxWH)PR.e/%NS-K^J(D E܈8A>(oP1mD40 (^Kq6SJ̆Ѕ;ӺyM;M0 x<3 TTu,M έʳ5Uw0STȅ H}PX_Uk<QdUωҿHKŽÉ8[KYlp κkR+%V`&M\..-MS0b֍$W`U+3-D>6u78;7{brs Y(Io"pn?i7@3XGقt؆pzؼb u3X|ЅZrb0 |Ȣh0( Z vQE?qhU,ʊ\aqڋ]AT/=E m=eV "֍ఱu&`< .i#/=&MzR`c~ Sa4XN_:4@عw%'KXI@oF8/E1@GO2!M  p@ (0 05J38,ѭ) ڐD0  Z<1H0H'Ѕ'XQl&!AR Ғ$!_sC!IVV'ّ@AVi}9v = C#{]%̅8i˽\yW܃\~S)>eX;S|S.F.A+.-2& 2.J.aT6nҍLa9F EҸ`;9nyLaݍ$FS-^m8Rhb `^bp<%BGE_}s0ɄȋB܅[ 119aV '/T01c.R`q`r&T(ۚù HcpΣihpҖ[c`C|(`a{kh 1{[hUh̆UQ RbyU(V)b|^/iTb>S@:8c>7Vムi9\݃cc؝E ԱF9Dֈm/[ƠIFmX|0sXD/@G1䍈؊)p v0.zEvpC 5H-Ǯ)=[_@(yŞP1_y$(kTfPʆe PV(Cqǭ98+l(Uy`AXb\f<]ڄȐW , ;z]p؄$|6>N*Wi iN25Vi#F26Z2隆cGHje_:j'EӍƭ&o6ቒ֚: Iي^#00^ fPQoXĝ 6qHl)"(wrPI1(kS9?ifDrb8"TPFm Xm>jk٦dԎέab (-C\#!2 . ~ !e!hzq0tŇ,&it.Nho.1vii^bEX/Ƈ| 3?W_A8hE gcӒ8/P0v4yރ (Z 썐uWF ((qq4`wbq-qO0`@Vl8g[V9ـ*T(}*k spLt~M4_s)spXK8MbmW~~hà>x#J))MRJϜX΅(I( 5()Cx<@˴b) I*L.$K @Q" +s=e3a6&ey&iQ"(B$PbMI,&M; OB4G78 SEh|5ZhCY*[;숏VNWު&hB<%6:u蠄fs5c3PԤme+x, [Og;G_j -AxHMվt30X0+ n]e_ftĐEL+dۂi(˛ >՜Ta/ >髿>>???γzpCZ 4d14!9MADcmҩ_-bka6W`){hCN芇P- xAr\%!D6.V~>^>z-cI#"F! 6Rr8S(KDXsD,BMA<% ^pFP q41sTCed9N[{c#?Moۢ\&"qJQ_QHjl8FjqF*{V<s1t@tD͛fSȗUE9ğ,Ȃ-CD&F3d13ɕ0C&A F%mCfϥҔGPy MUA43&}!=#_5JdQA6Z>pcU nA6t>k/D8Jʩĩ; .[PtP MD/4 YCFN`hs!HE4u`s19,q` I4Bh `?RA8dQ`!\Dw`aud2d.>vR2̀IeCV朇us5AqRk@L+!u$W-[|Pˠ@]d!O,܊vBr @>SӋ͎ %`xE(τ(2ZZ [[Z]Î"֐h }Ȓ^4/"ĕ+p➣=4*3F# _5._s..S86:@8f'88N#BtUK 9T "I2>C#~FdQ`EQTw|ҧ :Hjn G:H[QhttH|qqdgZQ4L hPJ * PB|evR.%,u<8,{uUUHVnMSVud)HhkY%ydؽ$-HX7'&RΆi)uy]rCYHa6ٳ1dnDNIx' YHh'>qʙgi('pMffm& kfMn6 _^`A 'b V2fIA5g6fctbr& E'.=rj'vD 5a0=a@x+h?YCQ9ph6D|QNCCT bk=C/X:6Dnd6@N`GZf&9Ē>h>+ 4![Jf#v! -5j&I\^;* CoVݱ`jnRI:n3&r>4bگ5_xbg~AO+دC7G.DiVɒN"0wCF8F(Qyk猓/MM5IH"DNbaekAژ9D/C,QV8L(@CNjS4oJ:MHDC;WB7 D6zB6AWѾ DZ<<&@Gp8f>/p$DnpɵwαWw_=CUapFBToC$@42_5HH{A,hkz"lhECĖٗT?Csa(@l+)0!tCĖ [>>\@̸뷾~D>̆#$8|YVQAW c@8]LM'0{]q@B*PD{YuHYME+̳Xbdvi%1p8| 48;)[;x"w\w|;gnb2n0ą%R<`n M> tٺIsgG*a_…J}y䴋%I#x䬩9ztJg6 ]|u$ٰ n]qV)Buhj.| ϐ(,rdɓ)W|A:t+ &6϶+83a-@dOGN7AF3J;El)ss0g3WNLg`mtdetԨ٢tKQH>IkS=~qӀÚ+`pf9IE$ YVIe 1|0L) >Ŝ%Eβ'=@aԡpÇC0o`E!9a C@#S2"[:0EC(8"tp7Ç|\NԐD5\E!U{It\?GSMiPZ"@!jB Pm oć XG Q )BmLJZeMDRQ/V(#=>{ 'Q${0ĤCZjB0Lm kn\Hq,\)}'sY->I=|F9 ExduZ6I/KCa oVz#nR/vq>4wZ8!JѕK9\q9@S  0@c@.x (G*T{ 񍽝- p=K+.&tW&-wFt]KO("̞U7@tvuQ DWTcF>/>LHEچA@ל6'M0 71%iH5*tQA\pLbs51U4Ii*xar9hB<X9kYV$_NkZЂⱮr5A@z- TAгRA;n"Z\NJGŁIhA TV |t]k![8s0i̽V:%.f' shw(& / ^U$tAghbdXF۫Z"W=ݯoA:|ۢLqwC%PRCF14!+_zx>EMC܍qÍRpcD,B)% gl$ӐIH)5m< m kܘFΊ|l7^gT8Rr/#a{ZVjVqWJa"` vЃdq17k mklGOD6IoDFDjy LJRb8Zs|0KXG6R L/uEkzU|Ojll YT:#U |ËOVm[JJ1LTAwǯL4\a8cs};#)3A&ADFڄEn'"KΉd  S.F< " ,<@p&0B$$&!ArcdH!C` "C_agannqZIB$ C?! 0f 媤.#M $ t!"&"N l Bʎ0%ގ|鲡'JVB̪h'=RB <H& &7a7"_6A0 "s.s BU4K7 L8S9dBzb!2P!B P{G2dOu QasۨRa *R;\A6*S>S=TBINu NuS% 3<]ph#b b2S3CWt5TCtPjN6^OuȤx`N#h-+iXn=Jl42HaVp!56@*` s 5WBB`6!&+qa`f3|A`U7`fsz6~MUn"PajD!/j L #b-ԁ"P--*sJQ^)Bظ'N"OO"$Qb^1" i I&BPaI%Pr!ȍ*AgB W(bjqAE\\( 7RkA X^ay%cSߑ,^[X5n+hn!o B< ⣖J<"YNp9GN:<9.W=ImXq2]IC!u l9ΊuFV X*N b P#~"]d-CsN3|^`Z6hC| `W|O,a{=~CJÀx74 5W| 朣YzYy7 lxr 4c[!,\vXa>cV6g~!gJ6'pU.eT.A?3ٙ\Eg{>)玣*z1 lf$p +&st32c`titMj˲]R)67BdCo J."fTZa- ' ';46xayWZ T 2l 6l@\pw23'bars!_ F[5VJ^U :62UJN.¢b:Kh!4z'TִkHr.~t^6K!AGtLg\!p:,Z{XKB!!Ɂ -4i+9PD)\͕|Լ, AYQ/F8!c'kd7 a@bS.;qxRir ò/NnA=sbZ†l^“dLP|?̵F`7 0T5äH`%G%Peu|5mima>bmR[h@Z`AITbQ Z!#5&Gml٦XTavb`=`%_~9 AQ9% 5d2P#H"$>>DOϐ +"-c ¸3D5AZ "1k T3l)>t6k(>%tRId5+x9aN}3fc]O TDPqUja¢3eQE 1F&@q։& `tb/bvcD6Y(]Nn(K^Efukvnfm7m8'> *u>,%e90ל-N.4#ٕs7A Y㥜{'t_CrMwv͈7dG~!Q ݍ8ܐ8!~c8pMGb`cX9J?M5\Yrs0]/a-l@U.lq$QzEY@| |&0O?'8^}(}P;GO;8?s֤>h&dO  IE."8ҩ`#Z >Z񿈔a!dE|4APyapdBo:H."+Y2,gI+Zr1Jӌ}Ov^Mt0̬ty&N6 #'{j%)`_61|,0KS´qdc0Sa =c* ÿ 9b/KM\MDI`3gq3iT<*ȭEgi$5(dCH)ڲ|<i7 p'9}7섇XNwCh<):c#$ppC 0IHÞ[Npk$[rHёF9*D Bt'1<&m!NCD=)f'8wP>#ɀ.r- d(hC{-DŇ^!  avt\f#  G|,88Ư %7YCq 'Ƈkݮ$>@v)~_x >ջ|?*~+f~>U  cM~}"WqHC}C"OF7V $t k0vwjOj}==r>QgQ|&2]5q}~}L?qXxηG;Yiwaw&Â'w1,n5 vgP dGNWyo'yK bz Bzp qS=C=G1 w@ | G! Qq5PqbC( tCW(a2vrEWH Dص m0[@"$`?u@% DE^F# } bf4}h`#Ea ]ǰFQUTUI\٠PQ?#]y7A װp*;8Ƣ74M `kiph *=d?(H)xwYL9I wx3DXn7!"xcn  gnw!@\؁xĀx dƐ ȐѐՐyyooPy$ `qS (4*-` )-0j@ r2?n;'2I`J0aT'|OA8ΰ^3zP!Vi9d6a m` u{=ȆG8HS aQLҠ;s?Yh{~`}84Nsր] c(tp` |.J{!}0,[֠bV4Hh)1GDqϐw0Û>"qn1t+q*?pnF@a` d?4(YdCQ(9dxظc It.qwn|g c6 [hXyG(1G\  gp \Co!8ijy%Jɒ#` V/+ p31Zvj>;YГaCNFi z@LJHw^pM83@RSOu>kN1si yҠli@zlGmw9X_[8f~x40ItQFDQDs03 <3f~wJ.A 0.C )@  Q71 5#0¸ ݣ L0hP2(b*h؝ ،Uw:mwўynEp-)~nZ!dG :1űxAyyJ (Ky+Y& o#Mjz4*/J'*x' >m ~rh.B9SғH*BGa t @S1e|M) Aq fJGx!RKfsj\pp@v4BQ5r8 mGf~[~8 ?RJ` [{ wN6f1 >-q 咪0C - 9S.I ؠMn, ˠ7QeC␋'1G]),JA)@qwVCR18ZxI 蚮|'g:Zg;,z+Zsf+Kۑ#ˑ' `%I&I!'22Y|3ڲ:ɣAzwU1rDIGBˀx@B}>۳WMb6!bdI{`x`ʦbQpdnٶjQh1tw+'7·^VчG ڨ:LEsP @Tۡ^ axF Kaúȵ{q! !@:QCB;+ɝ ˛׺׭KҸxdKؽ(:,ƾv{d` [⬡ l_|%!,ԡ49\ l%l7B8p8'_`Z!:!tCP>s=?V;S'{=s) Q x'Mq njqp~q0N~3!]^{lExa Q=K9[jِ*li՞_=$3U:.yW>0Ɇ2B* ` c@b l?#"Jر,+Pd˓cˮ'ژٍV܀ȯ:\ ʠKxzjoܰmI'  '#̲hERN'! &g|}t>ܰ {@Ҹ"Rk~MA/_* ?A3\a7 5 ri!$@!0!}@-0ۣc >%>(!8>CHjCǰ3 CJ`șC Th = A:3P wp>>eM0 -+Dbrk@媽(}.;q h;0J  K I[\MʝMf (# "=Ne@AT )Nb!= m @sET0lOոtQTIrـ7,m^ i:N& ._Ė{Q:$O]sa 2JT:j*?l^Zb1[`U0Eֻ︪[㚊Xױ{qX7g!L}mFwO|P>Q_eu @AXy'a vDdqx:gɟ 𫯑͔A+ {ɽ=ϲ!$Ͱ( ,ϺN¼N&jsVCf5i&W&&j/%ø5=gCIB)Ki&(b3k|†Ó8g/ WTm/Oo/Oo/l&`@ATf $D| 'D-^ĘQF=~RH%MDRJ-Akx.[F]M.r\TPEETRM>uḁ Lh„C~VXe ߹Tkϧ(ҁ3W^}XXfۊbX,o -_Ɯh7vfqϬ;f֭][l CCl[m'\p;CaOcEխ_Ǟ]EX͟Gis1"'޹g;;G=~E Lm<dAWvygރnA-OG$DO q1C4PFBj' ͫ} mD2I%Q ޢ|,23!I-t G))0g@k(R! dM7lE!Ir@8S,r+"ksQ.pOI'ң* 2 ݺRQGe nnJGT4'|ޑ (xj1I5W]wW_6Xa%XcE6YeeYg6ZiZk6[m[o7\q$%7]uׅvdw- S"v;ݍ_Np°suAm "&6W^ih%cX9d)'J`)5/"&ݵȓ $!3egxeQBqnm]'ZKshB13lqZ⢚iHڽ-ކ{ |>=vaiquli": 8Rrx'WqA*c(G!m/n膦Xlw#)Bit1jZrb\-Ϩ_ۓhPbN#E@ '#0 Ш/8X8 p஌5s*08jl&(5B]FHXlݬ (XEC٨RoXxeX.= 32J^ģ-C~M\)\mw{0xk(yt**lBm827qFǚ\fGl" ΦS3[<|Ȩ[ -C*kؐ9l@4p Yz;KLCj#SSC"1ƃsFm Q\ ؾCb*#|0rd},,-6`&xEArFx9|xTа&bOȷlط}SGp@Q7BjC<Zꌋ+|w*M¦Hx/q9 :'t$9SBq0Yʌ r sPCJm'Hx0 s@b~3)JȆ(m*9Wh`|C6Y(1|2C I p824/ElhtD0L$ ;z#A`<.MpŊE|*3hH2ҭtEXȅ@k.\l]8`a=Ks(9flHFijħFô*pPOށysa@,w$?Ý%|H H\@\&OW:QTl`QT@}$;,!ҭ8Ԅ8wIJOX9ۆdJ"ʩ$Tš lpgEn/v@1ܲpHr1& ùlj@lhŌPQ͆X 3̈UXQmw2ӟq8T8 tچŘ4L J(0J@M >P j:F)(xE3[:3jꅎI X>304j`H )#===԰bNLdOxB:RK\3Y>5{4U<1྆x'ث,iy,%ϓ,š#P3P k$HXW"-?CAW`;r|ݷXhlBIj@$&mB0R@` z ',M +g8.a"*+pjh/R/%TrCv [=ό&vZ"C* bQkCm1C#i1}`؆SD%Lb! 50]t" $zlB!"m\ܼ/چB6:֐ ɛU]mX|HoX 冠XhYF{4K3Fq$gȅeN[SËB=Llx0 mCfj0MXz1nۏ` rilPej|P5Z[m0nh%ߎh1y YsяHvU݋/FCmnOP8Vn_roJVoYI#P/ˠ6GWgw pIk .(؂S6%NTHDH\pqia Arp"'Ih9@&n'n(oUrU W.G0& ؆>H4&!p98-|p˳q1sh~ב~ ![Mg kV1H>%+HjPYQgqq~)Xj̎xiXhqDV gBWOJT i Vb*W&_Aer|Xw)wrwr|r-/g.$M4H< 8:sF"~T6R&*ށH]Hbs̢̋)P7idr]mp .hdΰO? RyR7`U_S2s)X}ƈ\wKvz c@ggjR0/SS`hxw{$)Ès!mn`aX"sPx:d$J`BMX^|(m3(yKP< |ok)21p+}y}yP3A@H3vTxWc jֺ郴ÒRzD,MxL虶}y2|؆?)MO0 8Qq<7VDp!> z6p6MI$r(.>K q&M,7})S&C|KG.]T{w.['|×\n֥׎g(keХ0I-ra|(VB;mܘqCѵ\Wf{3N`uf(T| Ǒ%˴Sg;r%ztj5k|_GӨo^=7޾.8rmk.%7V8֯cY(P}" NbgC!}wq\*E~vBĜp8. e9Xba~! 0?3m\( 8Vh(fX/Vы1h7 bO6j5ߨ$%5ۈ.#9<cLMex GϘD)>>,u/m V|36`UMSrc8MVSGCl6)i]K\p\."1Tt%\Z} p(1aFYe|*3&gv¸k0&l1v8Hsls% /}mQP=y)3>=™A$7Hn(9p_&ױ &`"f3. & 0.LCsS+Z"{^a۸6 >Ib|đ#Fllҧ҄CĀ,Ϣ|j$Ѥ3C,.߫Clτ0CDWCP뉶M S#ʔB࣠ >aV3Ű^"KaL N \L ;N\}1pB4"g L LP3CXgԌ&aVLZ6XĘL:p>L`|8OdvHm'&aELθ d:oӋmeYcq$^NМtpY"#E,Z8mFq! .Tňo} H#UT |)l䶂sY\<5gB}AXۥS2!8X;ev1>bEDxKɖNuSHDtVWآz 9AQ '+&1x$D1ծMNѪ[%NrB 04,^:1CO$,bF%|0KLMTy>.}]@B|D4-l(bB/& ]hP@P(FqӀ`:|\3q* fmHdqSцbLˢq$rWUPֻƌI x|3Pj`eJO*|& M`1&e\bODN8 yMi_ =~dQ0jҙSg|1z!LHȻ~S~LA rń%F6*l\M8ZLfll>$C 'ml\#2 a WαO&k/D]j(^66.N !T-Ъ]ꔵ*!~,+-|]ꚍ)\|i""ge松c g+}b8Gv?՘a#BΚL | 76a"ihJke˷"q4b=.w dK\J\nx˹) C||$H PUJˆkjnȶ h}bI5d Gb.#8D}h UwQd&Dt I=,@'a3Fm#o(`c-(ˌm)u2' E %I>]>¯FS*>4U!XZ´i-dqF]Ů(wL&v tp1p,@moiI$7zұf6m j߼g6^0Ʌ;~c/۠uX JQ(q ڊ.k嬨H9ZKQ]|t n.Qf#q&.;#Yy$aMr&ߘ%ǻ&~φC(~?Uq91KL3܄8BfāC5HKh9p9 8hׄ834C(L>H8P_,]E d4B QQI `TfcPIUө–iHLƅHqu I]ȸڍL2I xaxP5CGN;܇͠UPTXxXytP8R)Y"$Ga>^TPF~h(n((+a^G̈́LIT6P@Ĥ;CTּoLp L(u@O$8H>H|CT)H`))>F3hc.\'Eq"'j L(⃝*YXhIpȞh΅&0(p :%@u Fiz*"@w}8`phj(~r(Ȃ@\j*j"@ ^F!^G` 108pC7lzĻF׌CJ Hk7뺮++,DIL0æ-NҞ$A^ƞicͅ5kEܔ6NH^:uPj"B*zޖ$ut舖쪊L~hz,r茚H֨P*` {_CX4ՀD֨G @}BLLCz- NZΎv-yM&ںȄšn2ࠟGE XmFO=y)^"|MOAFL<jL]vΞ$f22Af n[K9F2hNL\,>\,'>h&o~no.%$>dBBobZBvGɪ*L^pl/n숦zop`/M j{؇lpHvx|DX ,0xO؆^o6MۺmȄ--Ќ h$ M@ D|,WҏͅGZoe\M2q;noGP3AQl*:(RjLnL\qn*/v&doq3@~qq@ q_Ct]/vNf,"k8o02JrL)|RpR@f3~ mE)դGT;2|͙-VH-x m2y`-Ƅ, 3MmuVLHD@(C`ܴ>@A <O H>q1G0uL,|H,T2CN02s2SJD2I3D ^4T,ߕB3WC$OmMsF2q>ץTtnK tk7h1FGC/En>_t?jGvnbtʚl͞/MKKoɞKoMp0~:m;\raOoOL\Qrb!vL@LAy>7zG,5>\L45H`xQw_u`|A€G { ^(6nA8Co^ dM <U& _8)EdseZn&n3kS\D(q9UU.BCgo.96sncG지>[u4rrgnEMvrht#/u*t9nEN#G id7x|7xL;:G:?Lx@(x~xuSGA|C0[+zC$mTx'1K$jxLxܮdxklSA_d3tgnq71Zfywt:4lw꿃H68ވN d9.z<+|H:>Hzʧ|ˋ+4COg^_"%]$P+eX4{ُqAsǥ}sx} Z\\l1˶籽#$*{wϬo*( m2끐*J fS@ӆG6МR8G~bѾ|xGPXș+*b֮Vb6TBvx"jD7ܩPSCB$,.3-OC]=B+4_.˄sv&4@z`A%TXL1aD!&СEA:(RF ,!J/aƔ9fM7qԹgO?:hQG&UiSO6jUWfk7vHX$1f8h ;n]wջo_˜:j`ÇÄtVYX-"uğA=tiӧQ %`Ajׯ2M)' wo߿>xqǑ'WysϡG>zuױg׾{wM xѧW{{M+fo?āK&2$/ܜJK( Ǟ) $0  0,Eì6ZZie{Qo֙|))3QvT|)) 0s22GpɽZ jiuh;'igIxB&8㪦L'k!*A!TA l !&(EmtSgLPs"2nєSUQq(3gɚ`lcνQ6v|~$q"򜄶iko~$  pt1!|" h X,3YsJIlH|5sXѮ jF?cژej0J4(c֨`YXsj&*yM Tt?E:駓LQzjVSM[w]3>=hp, ijv[%wʽ7Mw6ŠN<7!$I)LJ®(V)T郍);+{ݪ')wT9k6J5o˽"""!Pd^b"T1N Ih8)Rlf0VMΌs-/?8v!EY)4_yEФ΄XpH,`ij<lnP64uw1^L @^`C>)R$F4+I^ hOdwd+<eBob*TF+RqjzXUqQZ[s4=w:Lşen+29׺x1N( Hf P"T)6oJv,lW@ga]r'<LQ$ˣ̇`PgLLapddbQ*3HG(x+PP))Zrmk̊Lu?ąejQ^U>UŗLQS_u()K CT1q(k h@Er^)CSB@mX9$WQϩ1hx? qrc5#;$یrƁ2Y0l 6e ['Gٰe;d-wU{drPfx~E"?I3r3>~qx3flTĿRY1PFIcDh1E 鋀!$49f-ӡ^TTkƪ6eiO_}[[12Y4a)g?&rpu5q궩@OܩY+Nx{ d xC9T]7'Ꭿ)o,HVMl/G>#VS$`\IPHi?n珄1:F@! ƪcp,( @ AeGg?D&Hz$hS0hȐD0.!}VK&/Cvq"4ejbᶯ%f~0D"01X` Wn|<"$%^ d1*r*%J29L(eg).f",,QE!""`*2.4j.Q/!eBB&6Rޱ*s07 s.@1S6a#`".5s39S/|3c/BBई4iV(SSr$4es6i6m6q37us7y7}738s8(`<'99S3%v^9:y;ɒb |'`-'8U&%~0&HsJTXg Hi,v,s&fNq"Di vB#kB<ۍt'ӫtji1U&%NK֦`yqu£PLVDpXs ֞sJqhD|Gd6hi&Nvgbw+|6Hcxac@8 DL!zDE{aV5vf2 Y(E5R#U%h ?A?!VHCeTavHY!Hva~gVi b7! Z9`w`I wAv~\ uUA X:4/Fx?Ц'֫6l6˛cXn|_⚝+v1'yO_b&plzpmkgtXt:l]uCibf!^гp&\Yӥ*d@ @SoΑCVY60$՗G 26q!qI>pj ~QT*Q8J&&}=~BpD}EaCJVG5|p9 ']jr,}wE*:\# AIҞcc}+> (/Tjeà_gwJ^D.kVƀox@kkebET6a\2%1g 0XN1|*\ȰÇ#JHŋ3jȱǏ CIɓ(SĈ9V+cʜIfDk5S$I$ш&%K)L|EEٜJիXjʵׯ`FD n9m]˶-Ckⲍ+WLzNjH1ڸn+^̸ǐ#K~L:x N̹V~A&|гӨS^ͺװc˞M۸sͻ Nȓ+_μУK^.^b@&x#(NG( _9 X_"ݹg:w`&w|Y< szC*`h8S~X"> X)ANB: >*8\hQ7ZJ>$x$ O*i]^neBOl)'nޕ%I׈3PyY2ޞ ɟ54 A5(=Z G|e>e0ZP)2*N)&{6jAhzjɗ7C@|g_#Z7pM;KUdMA|CmflJxMᓍC;< еdK&(3`qJqƣC>6`ҊSmp=tєNQRFRg:Tf QڍYfh)EppV$YCY+Bhi&{YʬfS64yQ3(1I{jtAJ-8'+f}0MɇꊿB$0)El6v3 ;nB P91T)nB#t-/Pæ` 뛠0]Pp,54_/<1aj9ro|P0>ݸN:#2QMʕ ri*4,Ы '8L#&@w h_XM`}A«4?O02 &NVrNB`rA!eyP*B(U*pS " W>BfPSyb6hLqF(gšN5⩆M$A#^*"A cK1wg\8@â "I.q"#юw%4iZף) x܅/s#)jà AK*ĠoJ!FvY*Yӑ9$DÞaPo1e  R(&L[lCq@=il<)U|i"=Y2ipGW0 ۬քFkGC%%_ܢ8O;jCkUg4,ԎK lPPUU/=GT$$THGPʆ ?žNr@O`PbDGK i(Y$!}ĊLّ!ft%!(% _ZH,64NF'ĈHwu.Y^ƶFjD$Ge%Em\z#E9>@w k~YM[&i98T al8Va5Fu7=~^ٿo`~L/Mq]a+Nz0dQȑ9\|`#c܆An)' Lc#j+qlgc)™.[6}&${SC  m V) +zgw̭$0,W,4px7nc0=B@C-^0SdD( 7*ĔiwBBıax;G*/ 9CQk2E2@(R! `n]1+N^M6{6SJ5@? D Pw@r{ ({G^(Ro"B A JUSf'7 bH |h'1T{H UQ4XSUP&' NmHm,ׇU+ g8.XRK2 SUHt `f# 0. UGtW aЎx 0ӌhEDh-H,2$>PLtK#E f=%8a&h  AYQ*wNpӄ%RZTbO'%7a`d5&Z(<%TQP7}!ՆOuP >BbO55QbQ*{Fo_ Q9d7)g+05JQ,Upj)q9*s)FQTœh×XlI*f+ѐ}(&UW}(UHruu#;*;b-sfI7ḀPW'p."5/9=ٰIQ<:B.󙥙74!=XW<#u% Y!##<&r<7bЃ.IBk鲃eJ )'kOk3I9DH@p+T?rBQ 4@vUj@4UUQq$:dn':@>urrqj)jF_G(DLD A4E($цhI2v7x V_" "0%f8{Y0R,s!  Jv,J&P& LP]¤$cy` b` Pc L7k7<YeWLĿ{%|dp΄whjf$uQ7& Q,b#1.dJ nkf ٻhMN-J1</VPҎTV`(!\ H/i 4Ϳ6] )ض~9Sz&== VI9t&kBmf`I ?'mPS^CpHr<b9 9T lPX!ƥ&p~-<5PYJ3ęQlj ˻;boL64Ja #;NHȥhL!VM2Ý MNBc0_^ԍY:G٭$=a-K W~&|WޛCcO˃x'm}C8dzM nɇ6E:7vq$m|vy ~Nz~1XPkX,haQϖubsE/^bMh7!H݁ 1ԫ5 aPn V2;\_.ʋSeӜ4Is&{ԡ*՟xˈ1U "\Qt^Zv^xw@C( hh ^^ pA|cⰷبD-7M8 Л"_6.ɴLZ繏1Ac3Oـ GO~𐼫UY ـL~9ʯ>bnY+46u!;.J!ܝ)'AOD- R⤗&KzՒ^x@(o%N 3M|P( B#͐7f[&@$26G;AM$¨ʯ 䙷>Ҝ ; hܙЃhLVŔ V!wjȥˆp >c5s4{ns⓵0D+.|Hϥ:N*Z9@OYJ|À[rېN% \6FebI%2m7Wa"{(TTEhYeҺ 4l@IXZTLX]'^*Rgm 1+1E&]iԩUfkرeϦ]mܹuoO T.L~*4OаDfq1+4k4կg{ϧ_}mm\\јЊPn{xJ 3OtxѨ'@B!Qs"b]is1M8 MO=BpF[uUXa%4ւbqaGR+x(.E͌:]CBRA<өpv[nrA[ݘ%VP * r4. ]"`M+:*XH9}F&r o2TJ'U!r;cQWPaАg3]Յ]\B]-%Si&CufA FI m|~棎GR2Iz94S{l"A='][8Pw)T !8Φ9Sc$(И{7sy7R~Uw ]"ʘ㈲m{s;|8@]A?Gm/{Siv٠np^IgpnT0 D7z_Pr|\ 3zL*]{V7u+fn0govn5 ui"4Q|WW"ՓK>&P}st$u^&_5x>8.qH(?n qIŀ[ X@FP;䡖F6(AP^7m E<"8ؚnYXR_l8!bdpdQ4Y#/%XP)pcxG<"id9B1(;JyGF:]@dyL`A@(|UJa(YoPșS; 1`#RHXRp`Ft'OV NV "M.2qD kJN Y RY89l1$ޕ&oƍ Otd(Tt}Z$6P'nVaaJ& uhC!щֆ0"Nqmh"nc*E6\9S{jeIynt0F4Q2VXnsń,tx%R9<$E1#.-j7HׯHֲd!sAyPWI4,aP i+WDv1rsۄ8MhIi}$lhԂh)2)Bm륉A4P֒u*At()NSe %EKW(S Aj5"Awr}jkDfsu-`+,]μ:E,B=dZ (bқ:,<!cf1D%Q0Q6%M$EU(amJDzQS|x6L.T|0"ˌ_o}58N$|E`p;k"q|\x#p3ypqh~,S#0G\l)  recݯ Dt g@slǵP@լ`:^p3"|VV-5x-hל( 48$ q D )UB n4#dR6``$BYhE#H©h9 0<Ttq/zI i̱b!I<C ʡ;!diCp < ػ;$2t",(&apK(&0'+7>kˆu"L$Nruۄ {>l,l" UhEU01X tOT73-^EK_}ő> 9k shFF ƐFb]ԦC ,1K"2iAAXih{|2â~,@,-l*~$0qANZ3t\<w೶#U k0"pIn8$4pxF *t$M.d= VR" }YlPVpC6'aK⤂`;sѰrx;-X6>y &Hg'lQ,CEA Kt(Fn$b4-m>d?4k? ˸k?3M8dMkMSt͏Ll:E@9@X:@vLj,Gh ܈87;ꄍB(4 B2 b(IЅjpN 8X8w@T\;;o Ҩ*0< JĚy***/Sc16l5SJ|_QQ |uC6phKyɈ=bd[$eQ4Ep>uDOHYLxx>cx^LadQfӽ ZĨZ> |Eqo`>\ˋ2c-E?3]Yٗ _Ԥ?S58Ç)L)HDSʎL *8 `%{S-V{%K{+C *Q$/KpLI/N@h4q0HIV0%+Q]8  3\Ѕ*|{50:ҵH5 e|YUJY [cx-Q:6@Q,RM ㅈ)X6; A bF^-k^kެ@ 8x_:YP2-MY:]SMߘuNfe^\1V;ʳV_IefpNf 0kH xK.!Md }pg|֖qVvk~gxFp|>hNh^hnh~hhqgh*հhhPC `^t1kSxF(ALڐձMNa.*Z6[ሑh j)lꧢ`><*ƇUZ*E c*ճ Mx (%C`4m4 =xvRin@7Kȼs>wN#)a `|xY?@gm@4NΩQjiWIPyֆU1ĉBDB%tJApP^tH pWX6Dv6pv=U|=Cv5D>C;f=qiѼ)vJ =tYw7[uyrs01}O@W|1hTوþx ?Q 'P FϷ0Ox[ [y^[a WVw_AT<Y(k4a Va-"hXq & ~z'˵6.DfJi'{T@A-e/n8aE 8!˕×͇`<ۥٰAߤ%e}|Oyn=}#dJ|K@ =طe6@!1O-@7M.O94RI'ٷRKրNAOXU8xR@TRU#V>jW_)M:$Q% 5xE_!Q"eR 9#Na)c0 5Atg1j䙄iy6pRzymP@.ZzilN'UG v>dɝ'^LѤW6|D| DCQ:XSH~`&D!An!bva6$&lKj~I!dc:#V7[k<΋V]䒘 <0KyMu1+CE̖kq 8܌ce` N0ej!1xb:`cC Yʲ8d+#n)La0I@4e%ҍ8ܐ>~X3Nߴ4Jk vDל$8un(|1Gk] ߹(g7uP)Y22|"A\;N8SM7}}E٫&[TQi*N9]3gvEDE"(T 9_M|D83 LΒnX/>wL QchA&s}x &D s'xG:Zo"ϰ,>I6lXr!Q B5xm&E9 m3 gE@@N(|ܟX:)Exx!"E2|$$#)I9barð&]K$P[:=mV&ʴPe|%,c)YҲ auqIa0Bx5l8JPRJ [[F|&4)iR,Kl$jՙפϩu|'<)yҳ'>}'@*ЁN5<~"T}(D#:I4+OD3)pT cBza4&bф״񉽒zɞA'uGYAI2G*rTF'r"eѪs80=ammc!qQ40i$B^="!s@-R9q3Xuం x@"c[@5pe JȎjۘSZϷ̹oUQ?DڱTP!]qړDa'IJR*]g9ܒ=Xtx0r]P *5ePu ĄJ\,SPݘ KE,|9- ~ƊkN֍m2RELpkA++ lpJCPl+[뙘 ܠx9֝#`SA@3=m1"ұ QB>I#ȁ`ƈ6&EjWLshlb➤TJB /,1ʜ\"Vf\wk wOv +S5y{ojV9~Oi)-tYPK*Sy6tl6G J.=ы~#+ ^BI( ?©h?<"`MĈM#^d0@}U q9֋u RѱyjcGdF߰L[J_"ػ;1q9ɵhA <Ry |pR(1+UJ#myB_Jf6?yO@؜ U3 7DW tE]s]{Yhګl}A:]iRY$ . >4]*U`ɉCf} W `̠&e %O}y*)U eD h7 1 , b⡕؇fj\3@X> >38V^"4#AA IaACA"=Ʊ!߸-_">$9@g8 e\q>3ikDƱCi]NmD(m\7\%efɇJ* #A s 12>\ 9`lB=bNL\D:*D7н cI uT`y:AId9P8,$uJHv|W 22A @ R@/lJwuCh[I}P-^%@4P^[B]އbabaZB D" 2؇,C#.FA>iVC'4eQ()5X; țD-&פGW+"4^fluJ1~iƵ`q *J㱂{`>Ý1A` U@dhw#>6pWW) `̦Ԡ>E6]!'{L$` `hq>_dy~y,I8hn\$2%94F;V>eQR (%DPLJ[plRW&c%H"Y!%%>%\[eLI6%"Z%𥍂["8#hő԰=Fd@Y,^^dM."D*T0QThiB\ibđN DLf a{Y6_{{(mg;IF}JM=⃠+| ARGyAI}鞚vJ>{Dzұ8lCFgGV{i|6g}~7'.%PTIܠMRX(ꀄ 8IMD@ XbVuh['bbI*H)>lA≒^^JAJ莞CcTb^"+=`$](I6db%N),$Ji6"W #pl])B `06cjN9IAH{3ls\4)p.#IJ{TR4 + @4W6J:mDljZ˵C`lC` 笺' 04Yj{$0*{'Q)Ej&n8}m % E9M@Y6BMA tC`07$I <O贈,o>FА1I(KAԬI/^BL%: SgJ \d"Y/8E8phm,ɶQfKHڷ-w1I iI- YsxF*Xs6'31AL!6GnBաmj;;Oq&CR-ڙ'B+mBӵ.̲ŗŭ$#7Y@*..ІVGEYXM5*SwW5XX5YY5ZZ5[[5\ǵ\ӏE\;5պ0M8O'o[[06 8_RqYv^@/U:_ W`]kYXn+iH-"jAF.9P9X"%T[(CZ$t_TqñhMwgD_Bo 7b,nV+ _u7G4E VnʥpZZ8vҴ7 dìd [hZ<_k Z cI8_,S(|)j,>ܮTŋUTkc4hhc]%oΉ,vŴޏCul@w"HF97>ЂF,)'8;8^+,+2u˵w\ |G|[ ~Ӄ_Erŵ$ڟ;(8,afeZ E8L@Xfx+@ YNCX=[hĄ+E(NLA4$'7y͚H25B1eg3d;Ĭ^h:8d9_ǒ.[6z6@Be'Qr˾Z/3H07T&,b )?gU{9[*D'΅:KKM2bry2EmM2MI<{&ŵƛ}hBcx&02$ 6bܼ[Y,[ol}^L3;:3{{˩Ct`p˽ 8 ͿS&aBEAD\0?!nαe.]YsbD| C]m.ݳ?ħܻsѬmCgP8 > o hsi1 :|@'1sz^,rwB64n_(3Si-쾱1 '\)Llܤop[521ו :\9rOxrx<qa3vpP$w'=ѥ#h(HsY\MRi!Zӑ5g(tUs""p^gt4-?$'8hՓ li }Cd'sBJ3NPqCR)x )T!ou/3P7 x'* BfFxQD5) W&&A՚H̐Bt,8YϪDqPyyD$s4 *LqMHPЩ$3F٨oCr[6v&_e8 +#؆'ljra\LjT3%*=9! 3jBYftH. Sog06 /_ӘXeG/"zF6LiRӘFbgx3|P b bίQ/[V)Dq^2! `o ;Ca-F R BP|d`F\I ݪz'JY/LP &EKgӋSVc9!H*n3 }ܣCnĀ)}PҳY2G<"ؐD0QNq>̬ p?#t9#JWJ4m5D^XC"zXHXrWxin '7Ec "TވnÇXAYpxXj'a&4iMnԹ0)O2e"L JTAЩ:2Nz'GYe-Dׂ* ^w"&L"tsc#$~έNtƶϕ5Q6`!&u26(%aȈ[!nyjU=nkx28<(˦(V5fb;򂍽 h5Qqb D+8ybj&1K ,4~C! Z^ǐ ec9_coFFhpLRgI 3FIۏu1f{XCdI u7Q X" )lWv1aݸyqNdnS,ֱ!leE^9aLC߭p3%<=,Xnf2C>^J&v_Ȭ, ' sLt( Rn_P8R8pt}Qt<_{"Zz9ue3å =~:tc, 6IT•_,/9عra9a=XI޿$hSzMhw;AFr}ߏ{s7Q{?g V )uGYvIj^8uuN1ֵM%Z{ù[zg:Ȏox|o{mx@aXt?gxG|Xc\2Ax u#o5D&!րSl [du,ta}LyO" A"Z#>HbPgkGBlPw{v3P A-a ġ P P "C%  pbPBPQ Q#Q'+яl@a`;?CQgNJR"OJL1^zz{^`eQk(hatc'\HHI`HHF1 8~k@6b Ƒ#Qxn@ /`6C.-ڀ .!a@nc Qh :d!a/C#d j6XQT12@%"!¿LԆ ^6^&ueq&$t#2(guqzr)ko(1qGG&$81%HN L2f-ȱOb- E t `ȞLўBHF+!aۀBAdlh* &h؁1B"_*fRC2ʎl4*2$bU($e%4jqST6i60m17j!zR~273_Re)6FP0@mr#Q+3y c_,d Ad3!K6-(:=ލdD "1IA?:BaAaB!<>R @!V M-` v0dzEh(#s|`b@+R p!tpb2JJwM!v&L2qc\bRMm. Z/I{ DtHzN!|"n :+)!1Q"bM#on9S*Fo;}d*Sp>8n0*-MI(FPwcN$ZdJgcT Q<N5I@U+(ZmBYj7Q س,#BCU (p3C/c9'b9 *& tFFƩA%f A,BU^UC8;PS^a/u6 .f!B2H] "W LQjYx*d\OAd FnhJvNmA+O~KwD*15c.!,!I/Mʀ#lġzQn5)A ATlaSτL gqD+!)^Uq67pqCLLhsE-j݀Z+$N DWIJo?L`s1HJwָtW~u)@mtah mAF*[->%"\W\(Ԁ u]9"fA? tk/}D 4FEDL>DV 7ziZBsev/*#lV86LYBF (8dK8)Mrܤh b \!dx_8!r :tG"uL Llr K|V3DGV8a)@6lXҌ )!|e,58*,UU! JXkuvH@UeMmTR};EǤR8IT+!v:gÌcMRM80H䊿s|nZO%}Vͣ}!Bz ]뤱Ӛ["ԦSRsP/2|(7"AfP+wYlnkũZ!xʁZȺN%κ}4;p{8|ī:5NS;p2D;EU&#ʫQ{HSW9H>Vw6Pۺ+dK[yMcK  w^7?f9@BH;s!fA)}PM6 jBD тeKj2;'F:^QBc+¾; r-s,MJ:v\*tܵ9] s1xւRVmU:՞]ɉ6ޫiz"^:uq;{K!kH6AWoʇnJ۵S_ͯ_ GT8A 2BΜqDM>FLGœ+kG՛KQ,sca'b봹%"jސ 8ʜ]ve/+'B ڌ1,cBb"!f̞&b<6ԓ>7볾4& <*"žBdzEs:?8b [D%[GV8S-|vt4qܙ3) me_2mX+1I"mu#MN/m?ř~r\P5\vCx?+԰ s{qra_u3W T\6 $|XAˉصۼ%')a +%($D2VFlicĉ4kڼ3Ν<{ Tఄ%x(~&-Wfv5s鲵>X{ |wN:N=[/EܣEv%|TԪ-&,AY#ws8ѤK^L2UFk_rM۾-3lRv;7@(kQM'qbnޥÜG3!tȝ; t2dECШφ!Lq2x̖E$  O @*0Ky6:D GOn!>O%'PH E6 16hM Dc:ώ:B(&6H!@D!Hf8R #{->)>͔m#I#%DXX}YT&Q^*(h''ISGnƙ"J٨$65R EI5iNJi^ini~ʩo爱y8BAh_F0!8Ed,+ndl.l> mNKhQꩨj:UI=xMV;(w}=$6[8o pLp^l&n DER] "Lr&r*r. s2Ls6ߌs:s> tBMtFtJ"$R/MR@5Af=xt=쫰- cn 7nye|[ O}7>`,V19W1 ;09>:]Z2>Wޅ?7uA G/ DqOCM玏Yb52>\9\ 5-'Ʀ=^?S&@[~AftYݭ+hsU3⏻g/9ͯ/뫉7$dFZOJ_[96rYr77n8~)$ '9NQqd ynHD O:H O 1I#AXd X ,p@񈧆(s~\{I7>qy#u0#>d6)~ 7QI1F DE΃1My'+_"n<4 cÞM @(1& Ƒ]х@.gK;Gfѹd3 3r=8,8R<lg;NvgxRAY\[%A2U0iM`ET1Jb t@fK.Aٸzy? *  ʴ+a0+IZjƂŌŢĈR lTU{#6>͈ ;‘l$( IkmkurtMCM/pf]}0S%ƉQr oL]2w}Y|Ԇ~DsL`1aZ "i,'89syjkx6"! ̝~D$Jnŕ\87'"P?p (D3 HpUJр |KB a1Fc olĠc0p}a@ ) Xع.$kHTEj\W=VZU:+u֚okZ ׺ yȞ4PWLŒ\Ow%k24Y+35ruN ےHdP~2M@;"> PZ&b='>9΂y;wۋɢ1݂˝t vҍx;Sf!:P;#T`!CV V74!ore{`>WKjf؛_ a*'T]bcG wDGaǒ63CBQTy{:ddɧEc*Tk/`zqjh#njAq*A%2,c#੩ʪꪯ *Jjʫ꫿ *JjNJɪʬ *Jj׊٪ʭ *Jj犮骮ʮ *Jjʯ +Kk ˰  +Kk :! #K%/UxD PpD&+3KBQ99;f1[? A)[7,+9:+K˴MĒcUkWkGx=_ B{9KK]>i;\˳gq+ip` |(9sFr !Z,2  H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0c@swEEݻs"JѣH*]ʴӧPJJjJ(ȩtນçɪٳhӪ]˶۷pʝ۶[nEf&LÈ+^̸6;9ޜ3k̹ϠCv.;zװc˞Mmv⛬u NĻ[ʭKNسUh|ӫ_&][_{˿ >>߁& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6Rm>HObVSN9CAx3*>Df謲Xb@% B9T)jA$j9l| k*Velխye-BȷTNa0KAhP Cja`mbfexp!8S$tf?4|qM!Gy0=sBE ݴ;<hP"9sP>∱AlPtH۬aT]u5Cx͕N2j6l7 -iF5͜ދS:4 >;TS;j+#v'mgэ8 zѡf,l]30y8dM-WvnZM<>w/o9/oIүi8q , >D |`ARp` A8 >BX@zDM8E`Ѕ"9%V 6!>lXD`Ї"bHXpO,EA R1W"_\Bg CЍA$b8'$ G=#q@HH`Oߤ(>椃jߤG$,'9xP'wvWw?qCԃL- 9J K5EH8E^FQj0IL+Ә'2L2Q eG6\XnD l!1 d-oRŃ$=9c99&H ɒ8@ub%8sBiCW V4/6 :>((7\"d JSZ 6ӥDŽiK3>Ӧ"6Lff 9TmԛgR`أS="dU>wgX~ƏdhDkٗ5|1@&c9I*99ܲ5@|MF! ph_;nq#In(磞7}jg hnt[3 ySN'Cjs>})6tȡ"9:/ >䃍"?XN~/Ë,a8t5[Jo5ǺHqAzͷ{=?z'ߡ7=lkS`fuEIT}8j'j'o7z[fHfWZFzxX( sgt/(3NGz8(pǃq;hD&8F(Ӑ PIфLQO(WHaU]j[(a\8rIkHj l #orI8 |8x'c 8FzrhDwXx؉XH0WkdBWu"c(3l\Vςr̂0x/ рcrrW ۠J|  ޠ*>1*сH{X~/ Ԙgэ3HW('َ (Cka7œX<(4P0$xE5sQv} `U V(40إmP0&WCi'B11XɍQA @s0'>xbMQyA o=`=`}" A/e xX5wy'}. ِ g6''YRqǍ}3!VԐuš|2ٛ9Yyșʹٜx ڇ:TypI wIOE K'X*Yq } 1BRHP/nnrў! &,ia 2'܈** x>{!E)X]}B-H)z1dw6c7V3) 1֣@B;D[F{HJL۴NPR;T[V{XZ\۵^`b;d[f{hjl۶npr;t[v{xz|۷~;[{۸;[{۹;[{ۺ;[{keX"(0BO xqy4X.2h 뉗+hFyWIۉ10b&4} O뻉KR: {ѿe|4-+4nL\>"pyy \\"w+By”hI)F"k 1 4@B=D]F}HJLNPR=T]V}XZ\^`b=d]f}hjlnpr=t]v}x| ׂ v}pGI0|=ؘmr0e* >ߔل=QWC|ڪ cذur&m טP"b Cٔm۫Tܔa +ܨmݕ}-a3Mނ7Gu=ו߂7aː#ؕ}܉Ҁ!~T~ ެ My܁&(`⡘ 1.]4].9Ή}?w Cw=>IމiV~XZ\^`b>d^f~hjlnpr>t^v~xz|~>^~芾莮(Bډmv-c&kpK[ `ѩ9!J3pE]Pz>~[&c Rz`qWŎbpb00=ۼ6}a2*dZvqǾ&0 }f>ByB .b0| -˲*۰q(Í(|!N/ ]'-yx+iϼ ?=r7nol&C~| +@#9 Uғ 0*:p#5`&i1!sgb "< tR[*@D/ c _!ΦJn qs_A*R?*Li{?/L # yQ ny aﲢpn  t qxoq  q mR^dYdDPYy  1Rِ i O >~xDZ̯fBK;pbX3w>%NX1v"G!E$YI)UdK1eΤYM9uOA%ZQI.eSQNZUYnWaŎ%[Yiծe[qΥ[]y_&\aĉ/fcȑ%O\e̙5oy&rYLsM6ϩ8|S]m܂AK(kȝǍ[Uʍs_y+ץK:R;w[U~xկ9:>qYL@!Y";&絎=&{)ݠ !;EDd~z*hLmn2zg.jvmvDt#-qA!c 7%x';oz 9 ?|sI7Y,q"i"tmBlqyӍۆkω Y0)+[#Du! uۛwy裗~z꫷z~{{|7|W}QK)#g~|Ή}mBo3lSOM9E@ `'GLzt G ` ieDdzL"XsNj'x!0`Bj:F kd! Z/xPb1CЁu0 Tq[4#ʠAw̮2rQD(nCh|f 9⃎Yc/t}W6t!5r2]7c#HHFRd%-yILfRd'=IPRiBk,^\;))J \Rq5P7mhfqȭ ٨G$-B!UP B v6(¾EC#-l  SX(IE^|Ϯi*>sDg!IG0B#9#gTDd1[06EkaVв+㐫b.+3DncfZbա.-$# M 8Qhci'dZyl4A܆Zي>i>j@3~]2hB| 0A~"& n L&M\(+qq\< q)J1qM~y_MS[< 8c⚋38*^WBC,Dnt#`'1*YQ'fqOBZgӡ.cy"a'Gqv]'.B=;.R )lJr EN}tqk -/>qIY騆K\-_}H $8QHx 9D,"άsl`C 5472bhm~e+o!9#>30\# _s=J_jY`W'&쵫ם`V50GA E 1$X3&@Jjk"?!fd+RÛ+q*ӑ{{88 0 ,k28cK9sK9j8M0\ć~#V`#9ml&|Bm&c'J90&s:W9SC4$::8t1:;:W CW:|غCAtʢy*;[;8;F<;|hD1I;\hRE@h:'!pp`<`)X¼3.2:\`?i^{k8#k3-/=Qm=h[DǏ4|7؁csY4b%ThWkˆjd859WXM@zU3/Wc0eK,qm@/KpKGI!b')%XMHkrSp2|  ;A  9|%sAÇW0[8L89+8|pA#\81h8B)+l9H1.ĹoC CT8DK6b:ub9ԝ:x:xSP>DT`':BD[F|j(MghDѢK:MD|pMgDLDxaE8` <І8- U.C\ǂ8P  J,@yT@jq̆85h0%P6D$@$G$R!5l)%Y&pRVR|R*uZ|&AmOT ꀆ3 fZz󷮁S<B<98|JˇA2#K8ڡ30O5DuKkTIԿ.BLpNDLPU2T1UUz U?LCZ|;JM]GTMLDdE]Ed5VSy"qV6QlkݮlMEj"/bNEFxKxuWwݼKNQz͆Ϩ]O~WLiX5+8-/)Q5s s=-PG|%YK_5 YeGk&"HXbڠmS(Y%HI5bPMV⣟ڌ!A.Lgx)*-ɖ0-IL{'h mVxj0n/.Jd;=Jm9m"(ʮjⰿ,8C7lA &5af~eF6acۿӑ&hi ICReErɾ\rl/Ά0:.S[82A1c=&Êe\"\9Ÿ 0ĵdZZBc\ldK, Ü LO[тCT`L8:4;lOuVhWeDn3FUe-\b]&4M 8GYʈ͆ij|Dk.lɨG ghvmy>*:Myu o|p>#4UPzΆ23PP:uxF㈉#BB Bb`|U( 0 p *$ZΆ7S%]/dKh[)=+ml]7 g@ؘjԄ&vhVk8"t6Mck@9HrYr9JZQӔ@LOH)S7QVNzHВ+ K0\ >9(gӗIu$&8Єm6QcPDJ}Z$#5ˋU*3UJu[UTYT%N2fZ7u @q*]R4Kl^1rEm@#KwhGfTs@Èj"-Se > k AGIt4l3 Tu-mW:؋6ALjC=H<v8c6I],>꽧}4y49r_Hn)L׉)v>t@=N~uN6ր3a 2UWe'8(C2u 1"+qՍG5"QZ%OM[Js t9#GLِm},g KҙE8p6lZ U#>Ck^Ғ1 Fz,WL(}AɍY9 7Gs̟޲S0;2k?k9Ŗv4zR{@lA@q0;Pq9%kE4ې xx LH2qwrc1ؠ@(qwV"@Hȃi<*DjX MxQ5<A"(ш&1V#ώҠ-m[܉MΡTj0ʼnY@.N` |-fۚh5M*T1L" (&)hꆄEK .-D5¥mb]Er1&Ti*)aJq,rC'Ȍ C"TjaTnF=%.hP!ah$$Lꁅyy 6/IH<':de3(. 5] A<êy[(E">$kU@ddq0Fj(=y ̓K&watȱ*IXO_ ԦF8h~sFE )ċQ8!2*P3!Fc  8XP&-*I15P [TRSZxDԡDK.8*UH\F)K_)Ĭ,Wv$sRg(nkIrZEI*Ȕ +8@NP61 d'B2p5+EbVqPkI<J;*xK X%ɆD L*c 0` %I W8$Q ?h= HBRG! TA%.!KT=vc!II9Uťf5U11:!VA ^%cpek (KvӒŔDl ¨XPaZ"QY %|nw C+*V[2C7R)6a sX"("cȎ u o8/~8ce"&Id y.eeS@)኶6*[fUx:MLcu-G$JգG講7 H]cj&o8.=MI1nٖN8x \]lo_NON9Ɓ !桮$ܪ&ʹ+HEV9ʪ_P80(c8ϩ#X aRhei}I){g q!F u?]#6n f &>!=B* }Q#NJQ4+dFwNHW5EUQA T , Q,\hȍB+ V)M6tElw΀6Re l JPH\&k[e\ qZa+KD) Cn1<V> !8Ol=MȬiYkX}NK`Ҙ ͒0>h3h!`^\@U] m^3D>BE>8ZDBMDDDOx#bN`tU*Ȃ(;#q:Kt4P; 13XtBNFzN-uC<U>4:J;E\ZM|:dmTKSjdE yJuK5"N<@h DXTnRlg_I2eCᔄ$IO,EnGƤdD5qHpDH#N&RP.Daf(+!$eVe^e;a&gve Jg[J xi&lƦl&m>dnYm&oŠA74&X^50y a"ktN'uVuAuvwo^"^BJx~'fF'z'{{'|Ƨ|'}֧}'~~''((&.((}FRH75(Z&+TL4i92\4 kU( }phI0b9䆎T#Ȇ$ACD)04i0|B򑄒ckMfHP/D۠h7yˏ8xXBJ˹C^\(B7IPe_-܈@t-D@ l*hL\8DdCePPLHEhOp6*' 8Ì'8bI DS F58()C~ET`I[lC@ðrm@[[jSx >jhęV,On2i?W5)> D+͂\ˀ@@-KB\נhZł5JJȝP)h&lىZpGn~+E`KL7ŬҬ̂۔v^dmКi 8pe -Ӳ3$*ƃQ0"k<:6 /86H 4 PnF*Bܚpp08m]b f DR+(JHN쫙z‘nDt0Jʑ"DB3(e٣'xBk,q?qpDMt*2AyqP3WQ;f;.#C"C6DZ*@I@ 7Z΢ΌZkI72@FT26 _%AiȴD=D2IǺ>D@4Uq-K-7B8t4=DvpkCWuݖCfKdYp4#5>.7ߜXpU-&x;3qI:K6P•$ vq6pe33RXD4h菵&tY68<f ĀpPǢ4q5IhBk o%2G U DQ&5CCAaHM!hƼUU^V+D8mTuܚjD\5!p4[*Cf #nX14)4Z!aBbs%q~d?k.6NJ*x݈DSs0"fVohT6lChxt.}!qoٓ%.46HBHCOsߛ'CE"*Q+20L-;|_T-SB&J”FWjX-;3١4SD&|d‰Ȝ=/]IA S۴sbdzIxI(1x6te?e4bDxAKw;AE1dw:ETĴ8EKT鄆Gi;KTj tr6`w'E75S\Az@D6OOPc)xKc#9U!,Kķ@l:D[IK&=a*HKAǛD+0C/,y~;uχp3'+Zf(O8@ QKZ}x{a_a(b c&B + ;ӝ)1`ރkUK|&Dqx&>1q+ ?dGk6d' GNI*낅ų9}>l>5*i;HB"AsPQԞ#?©fwTo$48BGm+Id:L@:t,Q=?7AbB~vٵ^ԯ-;Qtٚ3ϚwfSMw2QC+&4Lʓ_Ι70UBx+%;_/SAH/La&kFF=ç(-DTYѠ^ig""g1(`jI[ ǐ6Z}VndBrFas&!|!ggjRNyZEI)]ϋs`ko\ 5rpe&ϛ. xYi_&jwp,Gl½HwEKlf#b0|sX9/[ r#~,EQA|H{[>Ld%ZZ2| eMY`B&-4K΀6grA\Pi_V5]jA6#-lSY%-mNT5h[Π&|,(1f;z NpΝq].Ġ!1AM^Z _¯8R$]->ڝ58E[ڙ-F6M-}"&ų5@e92L%#y35$c~ 4Caka 2$s.QsC L-Iٺ` dVq^r^rgڸs2t)`4ĶIn[x2dElGo[E/Y~CIMd/ H#;vã̄,؛0E Sp B*Xt1 ϽH=pěBɜ1ܓ2 e!6&,F ,XP!,5|Th0HёHf#ݎ"MdҤVnC|!mk o6/܎l h=-By 5 Y1jVb!D/h,-,ˠÃ0_q QD &Ƶ5[׷-s53קpQӐXmi,b抡#cNMѠq2+s $ΝV=-CIEtm~T 6\c(CHԼqڤCO '_TQu+JOV(X5 RAdҽ[VCl0+Č!+rVAۚ i'2p~t$ b 1@$!U;B<Ṋ$$ Y:$45&ej{̃&+J΄:@RdW8B&rȇ"DCaCETȦD݂lJf OF[ L gt87~O#$nXj P[B[–lMXkl݈$D &O BD$mm%B_8[jITg $^~ngN4i,DɕD C 4y2.p {R: b T vrB3 Ni*;*|W 0t T|ysi&Dc '41L:L!l|D|y Z[IED(f<#8&R(I@J;Ÿ~qJ٥g"c9tJ*874A+n[`j8:8ej""j R&LZ^hT*Q@1@%^)8ed}-bD׆"8Og$Ar}V:<FW1-lL!gRAC&/*Z/6\ڮ:6f6n#0:9#$gD8`y.@ !wfm/u/t;۳$ øaR?۴C 5z;D6c[gk۶os[w{۷[{KƸ[;A;X&y.,--/Z&gJe#N+|v.b 7"̀PP|[*!R%:UfgrC)hi=fP v]ŵ¹-f%[ A{) EVb<.G,-/X äܻ1Na;>8ƯDʡbnVo6n#'(%}\BD@ǿA.I KM)+xJ5[/[`hD ;UuX nb|Taߢ{}-SA;,"*=A( B`L-ި dL0 P U[Mt}/@\ P0(b("p\y">wgaOB_ ^]^`p> {AiSQ% $Q,A,؉6 < TbmAeT !ơEHL-xbF( (gD`x&,7N"VERe "ai>;+4!_4Q"֘ ; sD=Χ뵨$d$ߢ[M:Uc( f =/Li^k^"QApc"-w!t TB :?=}O׽@2 .fu03,@  6 >ubL  2F-[MvaDsF 7w!϶Yeu#"N-&Ό8[hg)>>| ܄… j‡Wɠ;z/Ȋ"K<92dI(S| 3̙4kڼ3Ν<{vFDr<4i + nҁf.n; d+`֮˖ܹTHM 5svU=Gl;]!WXM\s傜j VY@܂V躵ٳھҏgS̘fدaq?<9g*6Dpc C%FKOzrXrٚ4Qezz6YW'ZWپN{*/rJ}@>LLHj`VEl!8| CB_p) f@@uQ!Bc?·@:v@HRK+dJN*GeV^O@[Pd &pxL9AHbÁRbU-Ɖ[dUVIpX+"7X!O` T8xvW`aYVqw~UjlQj}!kZ۫an~l L@*ip3){7D#+` #Oe98O4!35z~DmY_~en\a"JX`'1V^x+2n_6IT"Da)iW'+)d >jɍMQFJ H(EɤJ,FHPtI54RD1gTMT#]HV=F Y䨫9TDi"ܝ]]uF5G'<6H.CjXjH 9k_`^jʪlM}a#y0քSX\X!6ώ%ϲ>ĵWEs!BĄM f8Wsje0i2#%fJ陓d|'xёheH&i6p`#+@t4s&d1T6~VeYɆ[Th*m,/ ]iC!nc1a-5*=x*gph ԑ*a"}j 0đjC7j(rx3GlBIp@.\mm2a"HSlR<+GST⣕$9lCHl6nmt(\ T 2T eȘ$^)M@ sdoT|d# G60ThC,\6N 6 e:Y|rh-qw{EX"E*x$ .j;K"ZFٲю YDړ]᣿JZđ . Zh_@/q6"H먘ZTIuᴐG5hռɣ?t-m"> =nN&d)(*xP*Cc)[.oIG}0wnƮQb/1%o6DY`s 'qh@P3f@:O $Alge: % CE&BH WD7uq&O임hRҮv\z׼uMf` [jMOf7^LD [.lk{V6 pd6 S"W pH7LNh|{T0 {.zdz#nk )qമ6/k|?|$/O|,o_ޠFo| VpHE*!b$XI\΁ F 7%@,1H3` Mno4gzĒs A{|{.&opd)w1u @boG5K&v^r,hf:S7.ͬ$ɇB00$L?wd 0-;Bg`Wi`', (jW94sj wMArc/l ̂]O9?q}iM'>VYF1)7R Pe^&lPVw0{Kg{䖂RWfI|YcIͧzׇ9Xr ٷ}8~?6_a{!rarEjCxKqH4r1ie'@7|'E kaiCL!f~!D&_fRXRS7>GFOPPBb{x_fY Ht+bO TV|Y7Tp X 9XpQ&U52 $ MCS6EX7DF#awhPFF~hLhCF۸b>1' "1XI:ȏvŧ}9~gqw _NVT'afty)!`'0V[tRR[EQ` 0('f"%P 3%[BVf#X!S%np > q@xr_` !xP{πYȌ8z55'(z9s ~0X(@ 8 Ϡ7PV?X;%p Ža 3@A&0䏿vAH~_ynEфyOP,]!YȑʼnعbѝO "@#UseSoSDeq@7!DcDBKCyaaaޙ=7L6Āz)Hc t"i tXw!٠|IpA ; ̑C° @ X 0Pe# GQ;.)"g"pQ8"Xj;1#[xP]jMI9(I4 QF1ቢISx =Y{  9PiO!P9_a'x+be |'kNMIq o :2 P )Ea!J#$*'H$Ҁbp? Xِ0Ș[gFAJp]JФU U,?(xI/JP000dZp/Og d5fZhv+t/Q1+IDuʲ?8 0A#Oۉ6}qZ7Z40=_)BjrJY5Z5J*"7E 7FgAdtJqa! _3A ZHتZu5Ze:P0ɸwY;Uf z?T֗} ⰯX0S>p1 ]{M55jۚg?B>?S>'({Kk +۲s/:d6k}:G8JD;Kj pKIPWP˩ZQ5ypP'Yq1lQ`!Pm-{BDk@~pQ!  O~ 42KEq!0qt Xp QG:T p??  [N*P*+lcW Qr`OW Lar!X %9ƩTY;+8'A4a $Uϙ&: 4FQ U Ġ2i\5ɓ(g#U{QS&/ 1ٙ1Xb៙VU]$e(pg6|7\Iٰ\z>A`;HH( [`uUI\es! 8#œIU昉[W>[XdXie=R[flѓ9Ѧ+m}ȃl.':btgA@{xɂcxUGm=Wavb(ò\h3xmiB-yhfkfdT`12Aoޜ APfi qԇwgBPf\HUXT$йXC (ȘDk XeF-`h kݟnXsݻm֥pL>4L7 -/D39ޕLS =,oΠ-CPT-Mm3sG}B .Nn 4-n w_ZٿIQ*3fe14 >&!i< 73 H #Kx-`W^Pxْ f=wF_6yvy`DاkgΓ 9} 0q1Q!T>4Н ΐA&9>@N7cI P'LUFq~X~V~i Ѭ6+V՜YE`܀2Y/pE2^NTȱ;_Q 48<0ၝݭ@81N!n.!ao)Ÿjх7'@Ҭ{2$ 4_ҬG# XuNX^ `W(JAXkX}UVn_VQ1 51!<0@8 B@)!*f0 a lҀHv !ƒ9ɸu㣓Y1^!tl-f߲b$q|Ȕ"  ).(b!-8q]o'8lOh@q/u|1]lC/3|LDXOsڽ;…MDRJ-]SL5m޼9\9bhvf[n$,4iFTZҔ֌&i68QHLjeKz@̍3JU.swet܆򍨋#F?Ls 9=KRT, #8h6kZlQZr Y۶ Iқݖ3bp1"AR1;ʼn+'nwֽ8f t'ݙ|&a2Z >r| &l$m"bç7$k/B￁("mXsW^W1b^0pH41sXIM6 MsR+ T1j'ň~)Q,3 &##`2 D) 9&M l†J+% "O2EWVamRi3* Өsm"< -RI'RKW;|vچT$ i(V*s@,ȤZCb,.R HJɠgE Ri} V4 j --q҉2 b7]bF-X5NHB$+gᝪɮl+Lyfl"d=L5Nb l e73i'r "41g4Qy?t#\dEpz汈YRH.O2$`s)qLF|8ڤvIW sƇm&v|Y,jo.(ڼ<"Is?ݦ>#r 0@)bJkQ#PNJRiwQvΙaxBpp8A",rfKL-yPCTR{l|{q̵!h{geSIq8"?|!<։~r'Oqp,@5$ &H 1P 40] Pql"8t0LdYIB9MiK$?t5W3PfGB0$-#-_w-yKSw„b#>$4akD R8yTIwÖ(#+$FDw*qHǕ(r+sCe"&:̷JVRO%H %]Mev'q[K3| /xh8GP9GR3=#v1R(Ɇ3ff|.q* _-8%R'v!rUkMZ)G:ġ { <퍏XZcp fD&$l(2C8ـ㒎E_7C_TRlLjA18P<"%JA3"xx=A;ҪnX9-ۥ9 +; PC;D:s22><1:z+HR”;|, 8L;SZ./CII24CJ r4-`$rl8*3D /A8@DDTEdDC,hHD`ϰJlCL8̩R H9\ˀHJY tCl 7,KHNɢTd P&K/zJY!'` a)y-I#Rϱ< 8ˌ=@t-tK{݋ :B[&72&HLx q*pQTQ|&+IXE&A^mb$%|X)\*=fm+F\#"m0 檦`l]N AgC^<1>CVfvnaQȄ Ҟ<˿޿ /K<'`N?{^ ~fN Do7q` TI Cq3v l0dC>_Y _#i }K| (P rx;kmqiA*_zD>CI  ͔IJ:2o@w :3s|h2(x? wꌛG QDpsk񑎉N( 1 uR'u'Pu1/INGNH${&g( &_W})dh .Y"Ё$iցe_v|h-`gu\F[m'qtpnw&m N *+LtflM|8,〼N AMi vLns;sɤl s:xWMG:*(tkMt!xz_uNTo UWu*Z^Co 5+^_ _ ;-̈س|t  pn 2^Q҉x|Gt?Gw`Ol_ H\ J%(Pg<ȍ$蔽ډMXz1~bώl]0M1ˈm1hӒK;Y~NHu\9qy C1 Bdh8$ŸG|IˆEf޻s,!w\8~ 1̚|;g* Lc"H@f+ZҢϦl)J瞁H]Ӊgs> ٴ":/G%k˫ږEvi7{CeS|M NYrYjZ:BJ:U>>]Y8l:|cvN+8t˷:8gO~yƏr+ŧ'/~<ϣO~=Or 'LQb:@;ِtn2E >r@3U㘣Qb_:,xN2bR.怓x8XMLJ5P0!G0I"O60bSRYSƗ[b6D {p\ff9&A1\B6r)0m$N*8$FGbf6JLT1x3F9S)p8]Q HRZP.B=$QIьB!A9L7dMP SKC2e(!m:GT)OBdy* nhXY  U!(AVh GEԤK)6m#xLk[QE`9)FʈAa \+SA*g5(j6_UWٱU)E&Gٻq%baÚx%b[KĪc JT-پƶwAc++5%ϖW3΅6(/NC&]RK 5"9EoI m%vג@ \0{k0>z)&#Hl\60AbA,Deͼ78xQs{'ӕݨÜ:SJ*d`HU zAG IA8ʟ 4 |D}`HJ46X& G7䂦|`\tDVJ EJ68}ǒîP8JԆ1M=!!A!)ޝUKS=>l E dF6K5t|VЙ$a35B-!Zmp8*>Y!5d}Lè!"!YX" !< "DC38B$RUС+M`1:ɀhJw=GH:8_4J8h{ I84̈ub5 wG.3v4R7nuXPS.!VXbPwH~ΔP@ G$C C61MpRpzGJQ  RʏqAK 0$BdIBL >pXBpD6dGp dIaM$GD}4xKYt:CneG(Uތe P_K +;UG`0Fpl|khQbGAXes4L"w`eue]b8^hfۡ絙E'pOez5hh}{hW&(hh¨(dBhBg>B$y^"\Y}}"i*2i:BiJRiZbijriz闂i阒iM隲i©xJ׬lx'yrEL樚j2p Gpy:D`LGz8*GD:cwTT4LT|:; CMM*GDå6j{w$rJ#"jxƥ>FqCr뷂+O<ÙޜtCJ螊gONz yNy鴊ǿi|)n.ڱ*® 7xXCApYC6p>p9.XÃă:C0GʂCIp 7l錃, 鰃86Dž)70Ghj,>%Ö9,R+DԚrC7~J&;1z٢-F{Ξ +kzky-FykyM:m*{0yȳ7~H(\yI|u^ywtxT>u.EP-xFrdED EQF"kvD~G(Eښn`TH3hmx )$ OT뢐`$/oG+0\)p#l[!b0n3jAHݼmrÀnjdӲv ّI{h[D.x#5u[x` x0p kEGepk@욭񊫁1G,S1#8XA]9JUJ4¦A*±2-xoۧ r"'l!+r##;0$iAj1E4_麛zdwr ({H*'S^|.2%GԺKX1x2)ÙÌ V&rEwݴE+x 8< , "*.`O*1d~=. t@NmZ624$CCACoE%&D*ѰsR)Ga1 ?7r0IK=rS6I6.SrmwGm=Gֲrk[3GvDᜃ56S7[EÉ9BKIHJ4Aϛ3=ֱjBp?4A@}4"'t,4b'BCc#2vE+*F[6bFtrMGhZ|.QWG-?^9r9vdG$ۉM dEs'X69aVww$xsD֦<>><ǷT_1U9F~fPw/Z+Y/~z׹wG(__< n(.< 9OK0@$_<dos~{>x=iݦ~þ~Gg}/+3;CKS[cks{6-zʂ-G3!ةyйNUxݴ_sz@6@\wMw➡ 3H1†u$g\H'2wF-)@A;p7^lBwʃfF88VR7Rz;X;lYg7ZE.aI|js5N> 'm_TCh`xqǑ'WOR9r:A'5ܾ[Lg1ӻ8⋴LzȩcIK{ nި&6j'%S$ڴàLfl.nQIƚmt!lb:̱MMqTS)Ho)n uZMf[KfTqm]ĞYWR#&H摇2qIr`b3b[bD mq2Rn˟BV@3G<7@dC^xv BrQ"x% r ;ΐ5flQd!&Õ+aԠq7yjP60uJ9CLQR$7"%M 4V!  MVGmf{(ʼn爝W8D7|AZDMK\'-]+3ͺt!V^Q1΀ I$[r&L4,1$mK(1ÞW&%`4ݴ F3 !_F!U2YqdK[Uj,s=O0 FBQ JT L "Vt R#_ƨjTZ|t!Z琨%F0ꀍF)P1|<+Z>U)MQU)>-*RK!RHB R fGVLBъ$$\ z6p[jZU5el )b +VJc__5$e#`⸦e1b2scH.PSc E3INs~Q=}},{`Xƌ ǀ_ǻa \/d=rIwO ,L&\k7{|$< Sf_OxB|E! xeXK:člBьS NrVRIGEwt#7HNs_$$󬥔\K9 S @S] S g``:HA4uϸzfӌ"H3!6 #.8`U/!܋`Ivb/Î- 2D?ѯAE]lAyMO|gzM5i1PɯPSPF*e0"=&ݡ}S5"_F#ӖV'YHҬ7+/ҵofNwaV_Nt`Fh$WZSr*fb!ڄVNFz\!o *O*.XP4H#L $bø].!GXl*!_%!`:2F|f +„Xi ħB He(ˌ6e #f A)8F }OR 0Z6̐f pi6Blq  1j^eq}!GjcG|P"|8n cEqIMQ\  Nbr|dQGjq#,&Daafuaqx!2QLr.1q+nؼ[1qɱ1qٱ1DaMrW`]$~$@D@|@$̍u},̂0PBFML";!9 @*8"zMK B~@~RC B'b YaCN&$pjr*)@(ۡ&7J`!QX%!L`kr#Ta'zG`.GB "0s0 30Ay3^M*a!O!B!%3hM*+*!c")7@38X3t@ 2##"./a|LKRK%a2&2 *.$O'r(8B>8L>P\pG^;QQ#<*D@ 9Y:`!r@rѲXr",jvAy!=Z:qD ZJ ,0tAXh#dA3*s62+2'W^8!}3'28F"-9ZS#{7$E$7q77/aZ * ,-(d#~ SKBk"bJc)p0!3^ 2L j MAjD N`K}/AS (0"eQ0@U&!4\J&gvg"3إpL`A ( /KLT4`DDg_6t$q#A"m4'^j2Vcl`G{N"n``U'/"5S48#;i%giObQh6YYoϐyYT]5\yaUu`nS7B \^ 2踚CyW_9*jY%cYf)!zybYT;Ý;Lc~!I{+FX_"$xm 7#2xփe +A,,"H1pp~n1 -"j '(/qqzjZe{R*b`,w=$rKȢ"l`)o[V XLo/cǻ!&|&߶0z1 ýdն"3"bv8k] H26Aڮu[`ɼ6W|`&z9!8k 'MXʩ-LM%gv# a ׀+ՄHdÛ,BܩX0ūxE"$VGJ 23ʸ:̚wR:_Zf }ȍ{Q#\sCS*zm~bl^8") x%;Y& }˜Y<04!EO\Is$^zXr9`)w("~霸Z!% -0 m&r>Fgiˁ`%A`osyPBY78J)k=OB:7ơ<`:*AN::^MbVʧSz@  9j!!5!*XXx,ܡrjR&%BoK%#saRp!o!)ov 7NwT37Y,x?t"/*4["I4 +Wn%˖ _9qeCP mA9$# C)RGGOXHo5+CPrHF0'k5eZf9p "OPE*L6l=\T)~$*IԷ!.-S'S=b:5SMل]ȴ,F]̸ǐ#KL}*:|ȅ0Ԣvk;p2فw.rޝs}̷u܉#z$nӉњQ:. /]6>Ϊ;|YM\'EX—\^;Nq wq$Ȟw"a ~H~dGjছ4hG"gj<HV i(RȽ9!(ƀ9b9j>QJSEPQ&F Wa=Ԅ>`Hj.CC }>| |R6jiCscàyYU MPI0u~$TFu|*ĒI>RPY[[)VلJWVDR\BVU]iYXhI'>~ kqy(TUk'[ VVEDECCٞ(k覫+G,nb9bI\Mh{.nሗM&MѬS)ҠZکdP8^רnuMV艷D*"j6[wȨlw6v9ܥ7F;e37<SiY3ۂ^.D 6\xtcNnġ>Nj3OS I`fSF9hN)T?) F#S1vY;BmJ!΅CkLx7ft&̰@բrspX^'#ppc4eo8ȡ8v؎(Pta5&,X/E"~iPqK烏02`ʡ11><7AaPt``Hɳ vqsJt>c<$m"S"(?rJ4%g<#躑nc*9/A8SI4GLcAq&3%k8" 7/"pIRG!ꟚbGQi6c'„t TrZqjmlYH'$ XA E.Nu#*w(O6!l w#h-E4t|/=*-e$h=݁N3:2;ܦT2HS]d kE&DJS59YMV@"f#DTFo$Ikb3 `%u$D*s 'l#rA,]g"1'*ˁ3(oEU˜%)7C Dsiؘ l|MzӍӰ.8$V1:,bGJ2b®LFa$tt)z;ˋ(:`­.K2,\2ϩous\*i|ueOn!rȐ&̴ Ve2( G8) jT'_: L̫n)))HRXJAX: QJ^Eα/N-P^Hzm_j,^%jvJt-Ņ`cgͭ ,dLlĠ6$)'vxŷ.I3%%v$l@2dɦ>Uafls!x& :0RTOa>Җ݌ j~!{H ܭv3|^ nI@).E{dkxNw8i( pRdcx!34$mÚND^')NG:m #^y[uj3z~B@V 4; Gh62Q>Al0@ yW@$x1 X x'yt0` ڠ 4M!zDG JzKNvpWF& jBZ7(=&a(|f{i|gsB9k[1q-@f[xطH\t=U~KwiiuSW<,1JwFj x6(*.2YSl>DIQ2NC"(> ̣XxG1˨bİ@BW ݠ;b? bL C ΐQY"qrNՅ vr&dXUPfH`&2qa&@E,Yz9Ʌ.+c1g'gs\ua? &t$E^`^r 8_:9" K@__UgKjؕ"I.h0UxKA>xEx > ؗ b 2!֨M#0ca^)QXڔM2}H,0!D N' IZS17 <3i0g|#W 1Z@=QVrRQ05,}.1?$ :Bu*%j4l36jsT3"9T3 [X9YG$@.' d!SԨ?N8C |G2H 3@A9"O7g= ".0NWG5OW#QiCB<B:DZFzHJLڤNP]ӑ3(5PRZZ.1Zb*[5,/!]PЦm*nPs *.}b9ёTJ .f1}Z 3c?QF䨸bal34HKZf#nx:n&Ɣ2:fE]JoU_lq"3M"! 7!  "$z04 ATP^PS? h0&}dM6H#|ޡz=)Tz9 ~P _ QP"Ƌ:1fGv~PFLVjEݰ ڗ0Dx$Fr$nA "ZXK gb@ .`+ *.juXcA!3غꭣ:џu3ʦlˮJu 4MD]d sS0 QemvxF9MA![C\ [[AV!" ї,"QMTB K_K "1fХ]Z/ $E$"*aTju m;Ktxޫ/ $U˕\!{jNi0\И,T5ҦN%ӦMP>*Az}$Ok!y'N& iP,;tA0J,b F7Gi)0æ86 ;̧@|DZ*eY4Hj`{)~iQl"^!Z5 Tb 5eGˋ&E &P_WB] B=_$IfbM ^P "t,ϙ# ĖKB`딁ty7?]Nkj)S]#c|%#PƬ.4Z HbM<4u+q,:c/|\mlULK| KLwD=8fBHϐ!ZJ}l1F Rp%U"QP `ᖇdYbG Gh+ftiR̡S:! YqRE9{vk\ ^u Ô$ٔR+<,g>lvDkX1Nw$n؈Ln}t]$Ow$}/QŻ˻aut]4[]@ Oǂ=$4{6]t:ދz@}FՑLߜ\ə![W1_] Y^mS7kzwzrMlͶcqk??ag:^UfRvz$ci|=l;U ͩE@ @>E?08&{ j5"\7s`cC%N8q7p;jwKG 5Mӕ0Y3M|䙭Oq;qm8q|=r4\=jJ36leZq}KH+XdvcGnk9M6&L+U #Ҙf) M17Ʒ9sgϡ!:iQ^Mk6~={pEܹuo'^qɅWa3ȻW=nHŰDZ"GL&Dg/yG8a .޷?Jݨçcsɜqj k#)"bCrΑ وicB ].e=^Q;c;gul( L!H$s^Iҏ?25H295Qa`Kln|Y@wB{b(*|݊(81(H<4ϣAK ¬0LEhhEb{Rb[#SV4a{|5lh h6¨1v[n[pw\r5[!Uw]vNO( 0e*FA|_ r*ݥNSva#xb+b+.Ȍ;pw}Рwϣ𭬃5tb(d{gzhݸh.B er8owaEik{l6lV{mvm{nn{oo|p/Î;Ng|r.pΗM.RfveHuwm@0"=u cH n֛U(?bp"磏!hb7-95:6h3ǭ !i(J$iI$ >hAL$G}a8K>:Ϲ\+$:vuVqfGN6ȹVnJB!qB19Nc >Jdȁp$.X^+Zq 1^J )nO7#wF4>T$A!!D| ȭY_  0$s %g.1U.!9Dt`:7k'ԍ V䅰 JP&4@1"{C0&qXIDzp= 3xrkr_D耡sHPĤl$b:q3BG"%b\ĐAO|擞LۆHL^$H3@IҤ !73N%9,'|* GTtQ!SyґIjU!Z 5T aŠL98׹6ʨ0 R= O7C,rX?hF|0+5R*:&3&S@K3+WCRpjšzBJZך+,!R!+fVNdLk-1&r Зvic8/Y&c-@Saƌc5iQD!Iۀ^q@  $}ޓA<71uaZpK !h1`W]FL*g%!FBZ[v~IL$l6Sw&%cAզY)llSԠ&,M2"1 nSEF0 r:-UZ'FaZg3ZO5d]xBj8BiV9,a- #Aw1L6+FD#혵s"ilk"8;уDnMa@0ats,ƅCφzf|<)KwwuyR<cQ{/Lk^7F]E.>3 CkX,-N$ɛǕP?i:Z8+0f8|Gk0Ɩ JVx9 -ipPqCZHou r<#׸"~L1(!Sfוe-YNs]7Ί?ްp87%8o$.)58;y2d2orcNEؼk,>vϮĔiLkZeC T'Aeˮ>leeJC|a.`:B56Mӛ}DX;1jtcFU0y+VmN^Wv],n7amlJ7D2ma^t㫕oo+yɪ-1>cCxpe&3]!E1J >ha7ؔm)yNrsuR\F4y4~? MJKk4vA$:/ʐTÀ9XY 5+0+g1°A, +<; ˌëڈ6l7w몬*ۡC+}k2c+1uAl 1xKw=ۻ {BB2$#72=%})>6<bʆ."3-l88CdQařDY=l3E yD9D9:Ka5rD:bW4[ $s#5@V5ɘYV5A0#)|gS0a;lLÔлh{<)*(,B#=C;yDB27p bBy7By#2 Ht0i)/qCs(4ÈA ڝErC,*&J:t;3>)#A-Yx0ďÙEL1nm(; y q\ȹkEԹb/0#(#Cʴ/J;$+@Up@_ĺ` )/kB7'[gK|FA6<66ʋ[0[;#p62qč88I|I:H̐IDtʹr:[]IwZJD?Kk5|&$)$.19 &IZVF ](y(ȎwOP P̗lj4Lm4v{$p< 8<{GRr=̷Ľ%{M 7|+K%*ݴDžc/CS2Ֆ~*S4MS5ҍث5S99S<ӈxS=S@ TB-TCU6=TE]TFmTG}THTITJTKTLTMTN| TR-US=ձxX :i2萂"SvrQݍ#;xlBUrK")-g=Ni3kPuw@( ]h(z63ϱ`ڍđ qnJq-FPm"4%O P8x |(B ѓXFV톩yU @;\`8LJh  )$$_ VpXY(VsQ١he%5H|䈊tuq#HqaʆnpHDshs`ׇ34:#^s4ި X eUہ˰yz PJʄPű|+qEuxu?:s u10y 5[$Ѝy@,遚]$ըu ݷ=rQZI֧ ^%|U߸4އ}^>ؿВ[ć Iͦ604z6<0 ;8Le.mQ|FHIME?r[ 안J %]u ͓(qZXedYeX :iȀ \dXƖ`' Pƀ C1 !2PÆa^ h}(mP # @Z B^ЗL`hH aR= A㣐 % ]}b0 h,> j!'v[R05%'%RpGHơd|-&VD-ȳ*"TmZVf-ĊkeF^@,i`+-I3 ]Us8=pbΆ_Y8S <2yJØ'9dTaB@yk )@چzᗒ5 $paXMkݚEb4XbCݏ֗2 VqH㟕)`aH .nC&fgp(-vA٬c|f,Ur<^bq(N?*ZBƇf,+&jbb=;RBkbŽd7a2v V~e′*&b⿮-!ߖ ?hHh(uf|IXk HLl쟢4{Eg3W<h`:p4`E L+h| (nThY ZKs j](&b(a!ԝʆ |m |a2o2o؆-=^:&p&kbդxo%0e(ju ºJ fƁ蒘s`xnHn|bN Tapbņ؄*PvƇH5lawlo@Z$٨2dbZ&(v2vp7>jPj qCYiww#%^wLJz`pu3(1#0% ed!1׸ǻNx)V+[ePybD@Fg#w}][Ty9CK8ttmK v2m(zfLEFz9 $f(YY5Rr߱@Zka_`5wdgo|剭q↠yo|@Ym/hwT w"ޢ>vΟxg.wlwZe}LJnԜ7(d痝N$rH$҉gW y򒏈7y_yl6.45Eês>kBh.r!hbDa\HbucbIpH\%̘2gҬi&Μ:w^Tx>e5KҔ҆:)Ԩu!L!(RH _sf\YxEH1&}=G,CYksH|F9z ܵ0B 1Ȋ1`b+GlX吒*WVepP3ŋ3x×r5|DVnvnC\#X9kǷq a6l,WvLm mWf)r!I)yiGPms9\TAp " -a7=p!P(am!3xRx"T"4b18#5cT9#=U$XPq8RB"$NC0jq%>pI8H7pC;ġHE4AF> Zr +)N6+!A(&>dM+mQ7B/M5[v9pk?z)bU:tQPjTH#-*Yf6j|N6V*YY eky>NBkuVx Hݴ3xdRu-bf [B`pjr&>&v)U>2T&8UuOl)w8sofJ!C Wu&>f>mDby,N[_68cMOzSDr,0_H~`FtZ UYxToXc =ػ}6iˤ%Nzm?) q/NRSq% eց:kBFg"nAP/ԎgD"#-ڴH"'9sN=I##j ?<ڽҼj< 'O<<]Hª9!0p)DeZ{9KKni=yyMvNo|ov 0pf>9B7Hb06A3rk:E`g>8fdq3(2a\x g4a>0$B5rpC&e@R@@<9ڈNtыmQn܈FX~# )A<䧴%ZKc1bN/߆l(uh(|%,c)YҲ%.)/m|*bn#b q! g]05dLBKmp q<':өu|0סy5jSvk&-agEi,b(BЅ2}(D#*щR(F3эr(HC*ґ&=)JSҕ.}Kg0)NsӝnqÒbӡM*} &u{ST|art\q\ʼnWFt)+::ΫqkXVOm$DL TW!Uqx=[`#qKYQKMڛt,-rD͘Pb0ɩa% g?a^zFUK*UdSSjRW4*[jֱiek[K]uku{T[CԧajC`a/ ֱK+`>VWB`'+2 4/* jS s0i-]S3L|ݲ.~1C CLms U#{Lc&#.Y]&'[[EQ2>ZQ}c [03B#bl{fkee٭`ŝ3-(톻 +щf40}4!qlALS#`D%l@E::ɱa^ 9OMlV&u}ЫUasuYyee/!QPķ; 3B@39bf0nlbwUgs ,B/ʲwzE'Zp.϶ / j IyOF B553nWG qܙ$xCtoMHV+`wQɢ2RW-#=-QmQs&7_;Uo=oig-hB/i7Gݴ ^vvGXnWõ-ZB=r  L!yB"_uakՉyUcz_+oTpX)џ+n{%Ba*$׭;; ;>$=u_Kw}Z tlϟiZ / Tj@Q=a孜MdW5#Кq鱞Υ]ApMLi[m չۺ1KLAUum%uIZa֥]ɖím_?ƨџ~!LI$B(UW>IvI塜ф9"YN͑E^ΥF$\ʒ]D_`d)]$ &>]EI]-߻YL]Y 9jأ=AL-zVQŝ2.%Ba_9E VW"FvᡮYy;vW9F ai$-C̞9"ǽa T v%Y͠u bTݺ95).բډGV.D9YLmᖂ|3֤MR4$#VFWVUS5BQY7J\EWANĜc;6;Yy9 ڣ=cY`"DOƒ^@Sp%UXp"^_Cڌ1q"/a&& a],΢,d cMExfVl}AI m%M&jjMH,bl>Ji&nn&oH dH:jaBdo&r.'s6P&Tqm:u^'vfvn'wvw~'xx'y>.|0yL'>'|Ƨ|gM=,)}҄~M=9BN(#-{ҧ>(< B(=@TاRV-XDy<''ćN|#}N2DhI)(C>ԋꈵ̨N$i.(OX(bD7Lh)v69\<)ÉÅࠩ9h:92BiB)-ɑ(׊-8<.mzm(JIA.'..h<,=ܧRjm0~-~>)2*20fLpmRm=LiD'((Z^jDn:D/*+lE*/^ٓh<&/(k:jԎھ^//:B+pOdpގJ k:8̂ o W5` /ާ:p!-Gq_W"20?ž}>)3~nc0nf~pڮ1D/Үޫ-O p: s.*#`q CiTC\Zr?.BH&χ$_ꦃSq+2,**8jگ9(,=ùi--%/P,q/)0>/0s-2N317K7~KW5X}s:3#O! @CX5\ +Qp\^5__5``6a!$6Tc?6d'# v,Q`c/`B\WM:527 B  zJXBd6m##(R/7F4^j똄#.Kx[x-88w88p2+,F:lÞSX8v qUyNOgZ,tb$:>$;$,3#%\BJ\>L{O;>@9yUJ@ ܂WzWO#uwH4<#<ÚT|8OƯjj'91x[ʧ>'LOcӎE<~^4> }ڧ`>θD tRa-$tWI?;p$\Dg{IX;ٿ>HT(Ű8 ӽHOD"RsKmE=zK-Huc.8ZaH!%4ysTyJVJme@ztCF8fy>]"2S8՚@iY} TKtϦ^n\sֵ{o^{p` 6|qbŋ7vr۳FhѢn-HE/cTܬ]263HC_hmF\f"h!]K=.Ǽ?f/s5vs죷]yQha:iyLؽCh"*mz kLgZ2%( t(|ZiZ 橣뺲yg&Bm #| "<$\I Jx`R2㬻hʢ*$/un%L0=lT 2)8Z撃:E(LDs(=֛=.!>?M1 P)P$H4b[iũ:svX=p%^ZJ1:Ӫq滊ܲ*/I 4&pr=]^曋YR3l6UŇ^;w_z^8#)rU+>+vj0*5{ T)k$NMk)]p/K'D쑂r=Zo3AhAuR?zdu$كA W|V|)*Z1';7ZNZA$Zj'Z~IQWY3XE ǎ>lnvbpD aK8A~!4,EPs// &~.L$zKs gӎ(I.FˎDF0WjĮ [8zg<,e!$[|R/rH2Ưc#CDW|"z G@ 8"+H >1"$H d fcMA:tca,:Q!a#.yK_2. Sr:6t2:D`s1w4YMk^Ԧ^9L2^iEL9iq*% nq {L7qĬ!@ ZP MR7dDE\ D!Q%E)kSF9Q~!Hl' IYR !U,`  H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0!h1sɳϟ@ JѣH*]zq&8n+ŴիXjʵׯ`Êl]˶۷pʝK]f3X3wݿ LÈF0As"$L˘3kެl/nLӨS^-FY|ȥƺ۸sͻz NȽZ@bɣKN kgmËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dAtNԹ9S|7O'L"BSt#)u@:y祘40xS'\07Yg7tNJYxJ(>(x*8`i^@z'8Ć'Y+@ =   fmFY$,>'pM9g*8\>4Et 'A>֙ltkM1ş 5P˾@։R()rzKLe .0oۇA:8>ŧDmH'L7PG-TWmXg\Gpg~ @JЂMBІ:4=@ЊWAE7?@ 9Ho!JWǫgEm+)|P2ͩPfP@ԢrMwԫ4N1X VrUl(ki_˸|8pc1cYp,rscMvr+b[,@08ccQ[Mp\g%JUqc/F*ۅll9^'cĖn*mgb@fǸ#ϼ7{GOzn`j30|C;f6T{utNtDnD0۾7&ec  #O:VqU2D">zo4gc p$_ BB@B8DXFxHJL؄NPR8TXVxXZ\؅^`b8dXfxhjl؆npr8tXvxxz|؇~8Xx؈8Xx؉8Xx؊8Xx؋8Xxcxzf-vҀ v},hmQ6c{ )6 66' 8ۀ  t# m a{;BM p tR' m0_ ''/1 | hAp )P%  ('#dp&{э׎1)&(5s9+Awwz'82 1(ybgP }b61fS_ǕHtUi|,C>l%xq6It ,i @R! }%)xy5qyzdtQE6\w 9YyyѨ!rZSH)YS5ȗUXpf)5i|q I#iT#ΘiT| RSScyٟ:Zz ڠ:Zzڡ ":$Z&z(*,ʅ``Pt 4a=" P 8g@ p=E͠Lڤ :Vpـ`*q ⠑n`V6sbz'`_wTG }bݗ`G }1.B.`/ 4v(b0 /KuKob`1tK) lQ6:낣 &m" Z ҪCZD*`xS3 𭰉` ? 暮?z ڪ"IJC IG::K QߚjzP*0 Ӫz[pXz   du`+|t#6n&vSz En|ʧ5h.pw ) 2{ W|oz };43a&0 EI+.SDjp"Ԩ*b7(D+ p ȰkQ*;4 񳉳 㬚0 KzLc= 0㪮 ʮ@ Dz K[  +Q [:Ƞ `ț P&11nB*Z3n12 ѳ1v8tپb3 |1 q PEV* @1/! ̲ $+ htcpvcuq (YP JMh 6Op6 E8N | ˠKg*S A_ p ,ʸ4 ?:KLa\aƺߺ p ⹥[ Ѯaʯj2Պȉb<; ȐO: ;[L :఼ʪw@0)1. (l-j%pj+;{ff,(*G ֗8#X"Á[p ߺwi<Zvkl`,v;g+ԫpKp𔁂(d4:630cIe+90E<S8+OSyK gŝś  lɟ,aȳB=*@ ;{ywq8ΰѢ\*]l}q ԍ  ` ` M-: ;L CR+D2E- qųś ,} [Wl?P0ozLܤp= P : 6my C]F t|@QM8P=(bme cA Q*峫rסא|ūʳ T-{ ܻ$jck¿ ᦋt̳zXfɍ ΍h ̘!8*PI, `t}΀ I*=vBt1Mf]8ݷm4MgJ b`.-kI2Hz BLo1fw08Dݚ ٠ Sܣ.B P *y@g-z `޻lm' 51 K Яz:SmT=W ֊fl=z䰻LO R~;T.TԀ=^tuM?~NzW ikNm>RQ 0z%[lv ݳ-̫j}#! bJښN.ULve;Jtα^ Ξ+*0 "(j) Pr(Q*L.1Ð OM { |1` a)F9RbK8=Kߤ Э+=M f?,x P $O A "4haCM$&A+kl"FV idC)UrҕAW1!Ɣِ͚4#μ!5 n،cӦ0sRInWaŊV s1r6kѴ N.;wi;.Xv`6[;' 4UƌA5؁35 iL/>7ƌls]fqGtɒ%^r#mɕ/gxXrĮA|,ػ"CƚwkĹ|K!V[*U&&6 6fG.fGeZ1h0|3ȰhBhe&xiHCy,!&hb6a"d_3H+ z16#ѫmF$71eǔMl*g%VPI$g %̆6ѤXrͪӨ:rgi&(O>.B%Az7?z#JJɤ ]I%҈(ZjEHKobTZuձJ+-dxI3|g]u+o+ Ƕ=sFCà^یg9GϰNִhۦ4Dr .ҵml&YZli1͒_{.:;lF+RnbdnImVcO=0C>v=AX[1>A>1hig+qiBbʙ ?bćL &\LElt l|e*r3b\ bGZpǹwQi.DrL0gJPRNA;wKt>07t $/ՠWZRIRG'JS5' SPAm)VY*{}lf@[!]W`a@taMہw9oM{x?|o,"[{wā %)()p"FDGID+#NT(ݜۭw]RL@\Re/}K`SԥDb&5df3{yIgFf5yMlfSf7q$$f9IBS1ʪNxSg=لp3g?y ("hA zP&T ehCPFThE-zQfThG=QTa"GzRT+eiK4dcEÇLa!=JsF) 08M]zT4S >.͊+`ꐼ!0(ւ8{Q9y|05s\ |1P+^銏]1H AU[sC]ghԢU@cm__*2 (V[ 25|cpǔV1 }0K L񡳘$cMIg:i56+e,&|,Q± FǫIeo{I-BVڼ%K"G^xh^,l513{4s\%3Xjb𚐙 ^9R\tC[PR|4ÛlL`rr(0ȶ^܆3dۋ&pq㚨+*VR;ݲP]VJ3UyAuKs Cqɫ2_AZ,yI"LJ68tIF^YQi#1h_LjVØT\@Ium6#2X,1 Y.Q9;Z!2Y26/W:1)rpzt'M168XTn\kcMɪ @ 63Z1$#c38M4ɎU.=kghaBR'?UL,*jq`F8p^hDFۍr69HOLgy` Y ;:K-H vWdArȫ4@T \ l $ ((8L;eX8TnЫk$A$ ꡁT@Gqu4<ҀB|8R8#8)4-Mp6jZHJ v.A/klۄÇN8l)DI8 xTԊlJ(ʣLh`@::TKր `؊JKK@ȀLKH>0`6t6TƪPT(IHӡ&5Y  y\)`6jhjəB*4:11"/HRJG`̆A`xMɆhÑ32)80)IL>c> S1 Eh>hq9|30KED:M@GȰ`H >iq6P 5Tlq;#1;-Rkh1|pmرK_EC 40 W}(:mIBmQ sT_eȉjC YK<B.#!!g<Eg<( 11G:l69bghS8)b81B,8`P&;h)éWNSӨIbOeSFHXpO  >ؤH89"*ʆD@TENpqʾ2hп= I2lX@ƹP 0PWuU5wY5؊2٦ZʆӒ(Y)Dӛ1QvH5kmʜo5[P*z]"@zb)iH5A4aW:4Br>BN=X ]]%Vi2y $.ҝ]ڭ]۽]o:WVPʉ,!]-^=^ )M^m^}^^^^^^^^^ _kjdbV(u&e/h]TG䅄==D iFِ=`;+:,rX l6`|O 5PϩY|Xźu5˫h,+I:Sa}ZXK! W8(y4_fR߮"7L X8,ͱ(搤wK 1'ߴ0RH 4J j;`VX]&dĠ3=l dvJ;W?90]0Ѕ#=ndՅ:1 6TY0RV=]ʤf"⭐R 'F6&3( )f!bޝr_.>sˆh E`? ]{نͰ|tGv `6reYc bx:KX@|)pa|HhM J[ތ(b02l8nR `h lIۍM@. )*-l`_V81OjHػ +,3m@5TS`̫=]W@BP@@^R)knkfnfzfEjuDÕr#D0!&gp0gtf Vfe5ݼαvAoto xk^)>Dp9`NXDegq0g>sJ?5Ydq -,x3~t3{%N,d[0(=bX!~Փ+qvbPqY$T&QB ITG|Fܼn5<%ɓ\V3÷hzꆨjv$&jݳp^k~GoB)ⅺFDH4HC܊ĀkLI]6> g>MG ;xƠ`ߌZGjx ,qphelvg^]b݌ Uc!qR`H1ȼ"'԰8 &\(Lս)SÁDBbILg$kteRIHue4]ʄYފ$Xp`;hz|7.6l<vghv8ZćfoP~Ͻg{Ae >gƀ5p5H oOgv,>g ];C.]6| 2l!Ĉ'Rh"ƌ-h`‡%O%L̨-[VMaHoA[Z9|R)0ZM¢ /MfژVVZYsXu;+,T 7=&`^O m->%US'X'v v!1 Mdd|7k0BTF/ ӨIF رavp6D٭m{nܺc/n8ʗ3oBfV`5Ji)h}Zogpjjo8+z+Ցt 8׵9%l/DBh8֐<8eD%->޶x!HFa~QvkNCBL,10+ekÌNAB΄\NBÔS3cK*xN1B|3>4ve[5p`N:SyI'^W ֱ|{ںp_Bl9-pf)>e 1\ڢ ߯lB멯1K>9[~9k93Ìg 7Fö(iwQch:~;;{C1ycչѬJ;(Ι;=k={=qV#V*>ճ>?????(< 2| #( Ј5 Fl| )6'xVΐvת +bQa 9`K: QD}(bgVͪE,"Nd">Ґwp׺`p iǓD/x] ZH:I7֑ `t0K[B.⨐sD%$EE="I2"ߪ* "]8 bG BB "Bg HXBf&V2(WQl%Q>Iub䐿!GT' )wWL!E\ÊW '6@)NԐa3΋0:ec ]|Kzs)Y6H0N|3LZߘχtы9N ;(@E"Lj|B-oK>&- -. |`4MaE梑$#fn$ *mDPsl"5bsi5 J '>R!˰nrLd`Suuh!#K""qT!)IʜjL㟽3,nÅ/H6cZȰ"h35yj6TkM[{*:'xAD"1p+Di .CT..iHB& K&ź؁9,J'uq135F#iOS cUb6b"E8Cmc (a`wU[r$>|!,8%q 5= " &eZ 0`!c5Ec@E%א*㙩UD+P㕡&R>@,>|ټT$(0rs$ZґiLxsK Nuc{FIQ,VÚw5,s5Lz[F@zҡp`糠e\bs W'jǡZ}ja F5U ]뺞3\:}=Ӧ66CXfb>ڇD3JTEI b <'AX 0>X] lC*,9!A&XHL+ 88EaEY3L*x,4dC 8Y!܉b5_,Y60)BDB078,æ|Zݐ&L͵ M xJEMXڤxE,oC0ī 5D1* Bf-)j>Pqj5DA7SlQl:9LCK@9Dv@>x!AC8рuB]0Q]ByɜӀ>ąx0<#EG  HC0(ȂC."˚5BXB0Ƌ=L^T9L4!b@E5D}+4&+X4h=ݐh]B,X.mB,Q%+ ѼF]Z D_y`'%5H CDwP >$f1vbH(jXe1De<^Q+rCT,,^jF5Fk N L"mf.S6_2>93Z99.V865e߳0gQgCNzhMUչQLԅ,@OIEa@T^wT~ʰBXչX` XJU6HUaER \d(v(Z%Z ]^_j_B5t)* 3-⁦aZM,`aFD'+d梹Cje$*$+Jhި1D,b*fk~kNm:&8 ɞl̬ccf0pښvtc]#64vV'8:]2ngr'3<&'C 8D$X4.AdTAha A +`EN5&5e2kD%õ,t Ip3H|t FAkͅEB ĀʼnXdUd:CF-H8 I%*D삒409we3L{${h )p0qC1@,l)ܯE^&Dp`DO mn(X$6 -Z\׺[lm֡8dܙk{m1I>]E Y.^u-1JHFfY'E\>ˇ]м~ +O1KA3Ŕ z> zL10I&|X68L tYM:0WXBpK!y1d@Fs%-*l@ >M7 M(‘ŕ'-leWJ>FLl-Kk>t|YXY?/P.D_פ +38͈@23܍e$jB̍R7nvJnhub,/f)|zZuf2j*#$<ɮ'Kg(_P!k*bӖc?^BC"ǩ"OD\ގ(&ekh].:8Si6k6s&8@ke'GfrvX԰ٞ6,hKPC.'rj s?rԳ(5tWwrogXPj5CaIvowس@G(x爂{/B7 :Dd8CT6DħG,,Āq5xS7L;C#tsC/ItY3>܄ť38>ЁxB-F̬fHa(F4->iIDB7DHa E[`P&GGĂ/M_FK,x8]z0뭅73ɇ?Dq%1 [D9B!B1Ia"H$ȃ2M6x?8u 9?TzFAEXE/ss$ >`{lx[yʸmEdgjċ5{FcDWDR;tLyX`pM! $wBzt7:N8Aqx+XC"/GDw&_w)AJN,8C;LcT W6ET~z|Ё<C%;{; <}FHC Zu8NC11L* ) x$o;C:\{;{ xp,8<[gC):+D`Qxb^%&H&%Bр JE;~ĚCGM{Y} `s~DPx<~>? 6tbD)VxrUژ #C> PBsygΜ73ۭۆ).۴K=[t\K>S k+L$IknK&kٮ5p[vמTV7̝#,_}lw.q 3H0Ucm-|B 3NkEmN'65՗>Bfz+¦/qȯQ\qX #,6٨t7}zٷwᢥʉ||d꼶QRzȎ;Yh=(J[yf`Z`'nIj&Pta-iJEXt%`J"xr΁is,^tTK*+6a-p4 d PVM,IıcCjR8&pIz\GV2VT#9U*R0iBՄ' n}&&SRq aߠ g_qٰI +r, kWrfhPiAjG9 .$[$³5nwHG>=}ƹIPCyII xHjc 6o~({h kT ʛ\GPCzc("IsZFY W.-L 8! $)@BfB~Dks`㵂^a+R ><X$(Q:bZ֦L퉗zdѣf4fJu8"`5xH8 >7fs ɔْ k4slɫe\MK) "Τb9-$[JVUC# OF2VԡCѐr!HW|4(FB챓K*p"Nr1cQbEtnC4`Y.QH684h/"%b C‹hcEcAV=4W$" EԘ'2@#Bh5 =<ڒ453Le PMqj"c8e HQmũ^闿kYkYM6JS%63`E}#G8X1']L*(,b~ 窼*rycbu䅈l(OxqH mx1Zktݞ4zK%%G;ށa\ a$ >NB5G0gh3>Tu+P̱h46iۜY$o!1<.%y3!]LldMo N-"aHV)guAÀf3Ex:޾׼iJFcXe-Xݞ1i#QtJ2dȳ;3u9f,pHMTЭ BZҡ$cn*|a[qv:(mj{6V_l{;F1q}ø6OoD-I^r)W#D!,I2!iGtSmRRZIWҙt?Q׉a!IzR񧆼:\)8ΡlC.^wyޓr4K۲MC MlBNn}+`%%@Y,bMUcyڀp, ͲH$!`*"",-AFtHRu&% B!4Kġt/p!`–o!zpD, ԇF V.XRTl"F^+K!kf!$$J!&u!"Fbn+5Z pf@gӪ!`"h|6NZh"%[G!POq[l7D!V P7*hq~ H'\ߐn""/[1qdFUl!ʡ!=/L! e7  #!rf!0"!K"`d#BIper~o!L!A&RKbc!P!7A.R 6lA 0#* wN %b!ڰy("t"+ "RZa!r $jVg!˃74Xa}, y dHq.3|2L1,2wd!hq$cR%1,θQ!/"l6017w JkNb ` @%) =dCtO`A/dA $"-<$^mӬzd!@DD0VB&.KdJKӳ> hBha HR Ox׈q֮Tf-תmp #mZa-0 `P!F2$(e@SOX/I/ q$o=a1ij:A&:a[zQ:S;5"BATG5`BT HuTD^31!6!P!X|~B ^<6s3UYU&uE9%V5!bsmSXUP \]&W/hR86{UoLD"@ l?[#_"(dp.Xc!3AGF`}I!80\BLB($WQ@ &z!|ر&1f̾epvvpBƜޢlaEH~,Khcj= %V!k!b BrbvcrFF+bϡ,&HMR('#*"iv)~#',H *H"ݸ>q磋"(MHG.(ԉ4S,a`A/\ג+!"9q%OQ㒉G{lr5&6.:R?STUTgJ5 [{bRuUblLʏwY,^{\Y5YaC,fR𑧲U6B6a~305Ros5|~5,X{ 5@A_!_ D(B>%L/labRDC>,!c{|hv! F*${|DXBaCVBlfw&d` b8lByԠQ@ʆ&l!d.%iX&{G@gZE-qĶKPBh08D!>ޤj5x>'DV͒9$\hzBPAdm @^f!9G壎V2RxQksa%S-_B P dVR+HX0O!Q.Pљ06y13G S3!ze;bIҸ`*b3I!XMq:A/jAGrcDx0e$Y%Wpzs%vgXbS[cpA7X .,W%naB=9QMO@_"@ IC@_oX"SQo&4dafb  a4a9"^L=dqbZ`Tvea.Eg׸.w)QB t"q֎ s$"Yz)#`b/c?f>riF!aH$'qarw/48c#qGQUVphMBʣP6;%Yj9"A+šCRJB VWVɔXA[l!&iJlRa;R-J%@S>\ NTy$-B!beQ2Wĭn`oPs3cRVcMPT7|#w㰔(ca\]6 Cq§|Ct:/8G͉abQ2Y!!ڪE=6:"BX.EԚ|f!|nG }xs%r%mD`{Qu%<ɘ e"z%X.0ePBlafr!>ې%kOj7$+c{DFe!rl'{qp69_gT{3pMn߄!{y{G[*p a߹/oiCR+߲n5vDUB=L!:,6AxxkRy;%>15n| ePNv5:TmfNTG!X9>Xa!6"Zb N䪞}3e)KG"O!ZE%d|aa|:8uڐG"\| " =:s$Ad!ʒ2dתQ r),%"`Ed򥡔SBdAճӸQ٥2aB Yu$s رg JD"?J=a'F Ω$M>fda?d!F2d0Zeʉ{ڳkM+_*bk8eLjgjH&L$&+K\l̝cFf6|1o.b;uٲbtHZQ6M1֭6,KsϖɬH,-4W׮rneS禬[f XNd>*N78T$㓌YQr爅7*|m*̣F%M*Oǝb hĊlBsX_T ιE_ "tjܻs*w~%&xWs[ Ng /\|KLx H`` .`ba2ZnlƄQ 0&hbE&fF6Liv38|^04vc΁ܱ05L@3M$b͐AqL"^&b)逃9yGݴsN6،CYs-ٔ 5#,Hδ.E-m43naj+z1>E Zmaz /Z4:r46-C`FQ473MÊl6 >TC QkP--e4, 1ϸR..`^mrIO܋JI3R=SgpAIL,khcg5SJ:[5P B#>6!VRӖ[Eԕ&"U\6v5sK|r*9;94dTFfNKO?|IeWQjS8la }gg>poEA׌+fR 0nM0-J*?s48h 9N[hu.PV|;y}EB KY4ئ,o<#8O;4@UwHG:Սu#G6H}&K 4HCM:0JPB9/O2`Nl{ҒN4mj)Lx|\Eb5uM6qCpB:, ;OHpXh>W4l8Sm<i΃9`6+g4%ltHq-ItnۡC шJtEi刊G? &n5ֆD:RZuscA*QMn2K%LYt<ݔ- Ӡ uD-Q?nLI8Q բJ!nu\ץui*g3l+*4ut]:¤X 갤U:v"_cSJ6Aoݫ81jvg? Њv-iOԪvmk_ vmo[6^n w-qgҮ@\ Ѽ4#N@C"Td'")nuw'FQ(uj f DBShX-\bBmƁr(@:jX#j `< 1j>x_0aUQC%7p4,櫍˺k1< U5 dw# >}ɂ %! Y..fM,OA9&ephZX$h)Eı.[B$(yћޤ9[/y* /{ KLz}TWA.02z a`0@ȐԤ0@ctLAI\'cFqk5iFG"Tk|D[VdmƊڈgo[ӝV0ssC.C9( *VИˌ 4/M^P2A\lWb 5q,gG^ĥoyn$TTo")\A.p̬ abvEC0ۖuҁp_-q:>g#1Q:e_2FkoA\^Xfx).>Ғ]D E. tŽ@@\6 Pα C9xP WDI7r,p&6wB/RiP@Z"NzGć0H\~'(>>m$q)"- Тɱr~y+K{9Z JwBЪh"0>!"VW"F"luUtm \W'$uq)u)ˀ@j lcSW$pGyrm_r)@~ t($h>G PvAyXC=">:GfzHpL *a>@#Փd*&P  Mq^qa|C ;cӷr$rAi)Gq~8hX'TPP 10!@ -,W"rxVZ1l;x hb]X53rːvgU kwr&&=b"&-!fm9Fy7CA! BhCs#Vy0fI ĐHPQ/|&wRpS9t$xru;ct B - !'ϒ -@òW}Hi1I!*]Q H1 X('0E5js'p!!x;͇_Hk6a"8+Blle0o3X!6g؁k{ BcQU2f'=xc 舔xPЖhr ䷎ IMpc# b8\GpL0A t(QGM- !^Q,ppD 8/$y(1hp4 ~rme`& xT kq P  BWWB ֐*6qdB?w TYT $5c-I`2FIAEq"'j cb2)H' bxAѡx'(a>0Hwy˜8f) qh׋$*q'BCq=gLcph G, P'DG gI'Yr*r -IF&'p7%"0 uꝨ]0VjtՂtw1j'eI YE1 B"!1 ֠ ڠ B8Ƞx6?ar9*c 'c 1ycЁ~)JfYeIp*1fqWI1D:zyH3yCDj֚^ ) `ٛ բoT}#9')b:}*DuTQ"2 `N;ՠXS Q `;; 62*ܰ lz6UtuU'=mb7l3 qi;8x_)zթmܰV T @io8lR"4Rs i(Q*9@97Y:g3 7pR&І"rXQzyDϠ -İ t}6&})ao1Sfp_ aSLW "{cF kUWP<-y"[AZv ,+lI@DHqlj =;'M,0=3TM|մDaܻ^HeyCEa48fNKh ە Ȅ  M䭛OCI-QfOPe ͤ/|;׺ Ƿ, w,;,hr 3ه)J3CS$3L5l7&!Cds6H?ULHicMd2jxDDgr>VN362Sf0 oӰzTƋ @>D44Ns 8J >]rn 1~ ߀XD@V&n^?-E~85@SǨەG>97H n My1R˻~W3WABUFM ]~#݂ W1.w޾݃'A Z`}j0: !8+Nc ېFSv}>&_)5"> c@'N zY% UY(Qx ^ `ܴd;^ p51Q7 /ZBLgdx8MeqW aT1a'|9Pp'-QU bcp_q&0T0R5SgaL5[S1 S ^StGv8*"D# жڠfx P o'M-4jc>9o ƿ'>QL3PR.̘ i.47b8Snc o9w$$] m& U5 @ DPB|0 h 2ĘఁncxBfw ̝k9b؁H[tນK 5s(eÇEM՜LMM΅rKY䢚.r頵9?xf[[H@h ޾ F<8bƍ  !:eJا( ٓMyL7ؔO&y20ɚI|'tI3Ma>޾Zr8 6>س; MBq|lg4S ->G C%|yO"VȚ:` ]Q҄?|)BӤм):>pD87MO˪`b¥ ?o**A wJl|6ti=afAnk__ › !f")`O ъA Rcu7NrMLA(S9X'9+snⳔ]:ԁz64 ET#$BK=ieoAYRЁNlmmeK0d CRe ]NEy%>W((O'v@erC*RO %+H3r0u7g';1L-tɍz+ډOd1lSPe$N-%N~bPJ6h+jLB)6 R "KR%XTI 8g%XQ lLYd@2PXun8TKeiY>y1jq8#x!X,Vyz01c6^Ql A)aUP5|XysF%r2r3U?76BYGa1hM v":-Hy@H-(Bǁ=wq6BMiҒq[6 l`O6!8Ňm%l,$H51:RE|u[ 8M7 Ns4k4G9ϑ f|Cu:4yשEZal՝'SbbCPr9>܎ $`I6 ?/z.w8,K7pf7hC=V'.FS7ӑU (;*w(9Eqܗ^Cp  ƀAM;)Gq<w5kKj;]٠|t C^Ay9:g ;q1x/PR ?C bt}3æ !)Q@GYd}#m²b 4#B@h?@l>B4C ĵ,[Q6YN@ADĩ8 Ń(:cNTUdVt? WYřz#PC 1;{ T QM܄Le|c4԰[*i$ Fi gdmnFWpr4sCY0F{DtZ?v4y|}~Ȁȁ$Ȃ4ȃDȄTȅdȆtȇȈȉȊȋȌȍȎȏɐ+nh1gVC`I=yƘɛɜ[@p F$ʄl&n(K,ʦtʧnqZE+l ʰȅ! |@>D˴TKJqV䅭6 X˻4G.KҨI˿LsV5DWK. HDŽ4DFJrX6s¬ .$EXKL¤h=ӤM͌XpYTEZTDtjEhN /KAn WDT鈾dcN%5EUeuMA$ u jL0(-H hsd(śMSFkі+sQE$Q$Z+xiHJ'";<|v<8)R|@ChPl83xV@ '3XC6mSutp 2Ԁ[GQ(Is >p ЁQHԂ@nʰHq%2SS|5DNOI+JAⓅĈWmZ IMF[H=fQ|Rd{ =>VMIԁa{=;Vi=`=1 pHEL B!W=$(IYS RrxuHeSxi0h"zL-ڄhM8T|P hʬ|9 rְ,LQJ&'I]% 8Qn8f]me|hhY;(*1ጠҬh]0`타TŇ 'Y'fflim4 ͊ ez rmn`\ o΀ n8 `biQoΐ=a 69vP 鑶 JlY Ll@Tiq ia&0 !bh2VAh!&|Uj#U1-N|'NU'rƣT<>O0bpZ0nakcH l*ǤmkpU9!W5̾ 3I""6ׁl9RfO)etH Hmd}@8F^l ^em0A?IQ~ G$2Y(fn{>F0g OfuK?LגF..|ompmY_hFgT[N: 5{)h/ǫ!f$ k pP:Av lv 8\hA_$9vxgq|7q0#Ua8$8-VϊW FiV` ψx@?q('[9nVp`Ap&>W.çi7q{Qq%TղD;r羝c%Ke̙:;L(nNebF_IY"NBW Uxf[Rk6zWm۶l&喭YܞAY˕ٳx1ƎC,'2n<*ՕQq"xֱ:QpNJlm|atjk7sq+6QΕ ֕|8fl?iR|dV PGr~phI=SAF%r,Q0ءWA ΈA(F T"H j 7x[ahw瘒[Z=3T02ᢌ0x+/2Qe{U6e4SZ\\B%W6TR&W +PcJFԖN03LQJbF?[yڤ>% )TZDCP9ҐHH$EtU'hI&&m0 cHDS^!596Wp%S\NuT4+ i8FV"LJ\cy\"S7w"W碛.xb Jhōp.椵ZӍ9N8ڌkSc^X38|9:sJ%s/cWMÙQgv!%N?; եπLόz\9 |MvWWrU1,oFK(6*SNH@]w#{N60T8()0wc *dluNZHD'x6VD\Jj|Rr@f P :m-g$egSDVTe}UMZ|2Q9dmcCߏ)>~* y$i$yc?t\j3[3ZQVW;xm֥l2 0T'|JF I`$쬊iH i$HA xK&ȑ0k<&i 7F-ȋ ߲E:"Jc(UiEͳf6ǒ]+>UQĢ,%lB& eCHDC c P( hŘm1(.RH!s8sVЦ8r/q#3"%1z;? y#M4RYb5Z*WU4_+YjֳFG&z.~feTj׻5z+_!V~,a ם&!V1f&VFI5,g;v,hKkJ&o\'j[̺6-mkk6-o{7.qk"7].s\ ޠskb7.w;kW) ͆C8F}㸶3fĚkԄ0b^FLy~A/zS8"C~UU!GSwXTE !%eI}}3c4h1lųcTW%v^g ד%t0D>a+HF9OFP2YUzծ^g U}1cUIys͒h$۰Hp^_Ag7NJ=OqHG tҌh7i`wDUK _0$aˆ.a-G"<7&>Kb@q/ cvIQiunV%VC IRKxy7TRv WEOyi ?(gyM#XG:9I1 ~\  n&꿉NlBdDž ͑v>)`E8BF>HYRWHr'P ɚeΉ >`\^}X W-CŰAEЎjí@ѝd FIt8;Ҿ ̱pD5lJ. = EEFR`Ν`Aƚ@ f*$U|݆YWGſՠ59Kt7JWLX$GVSn ϼM6Tx>ܝh؀<GGE!d6a_`(dDUWmÈJy9@^ C8>@FDYA w&B*CDSVd Sx$bČ`rx6ξ`Յhg~n 醉 ;N@pxXG)MmDN IgrWWdN@NRl&"ɓ =BzRgv@PJ4'ֆ]+0$C&DOh)CqE(T()ʵ6*JnG[&>ɥQ*lOpD8:gv9j#s2r>>&<=cg8:h*K8jF8 z9A'Zy)gDΚvgg~y(Y`e ZdbX$.W| ٥BdGGW|0@VFH*WX&,@|!N+RSg}V+dTKJ׌fDhF((>(&AJ{-" CT)`S%Z9aT&ɂ,AdC^j),M))R W*[j\IpF9šN7I%8cqcr FΥN7Nj 8`*>*?>D6+  .+Sy'>+&${W' vPp+~sPjNtr$ڤkS&P l3B5.WڄMP>L\M,+VnFLe_aR.,V8~OĮOA<ÈTIT^A\-"# FgMMV_^i`$>Ca^T3NUCfZre^.-2|(ϛ\mUcnmf\(> \"݆9QV0jcjr4kxgJNKve-N T daƔͽp[EN3'O(O:p;clɰPs=ovbj;FnD*1K4Nz'3qVP)3ڝTt_5 LɀýV}`SH{n}X'8h%(ܫ(_6nj8))QQV*0cZ,TR)QV~8@r$K ~D6XnrDmo-N24+w'a ?DW=CKbUuԇ=?%Z^[[4ONae+66Ł#}N&p횮2ղgskCFzl6>cc'B+a ) $OA#dB#p7ro,s_Xut %uƒZvOƥywkpr77tw{s7lb)1eJ<RdDX⃉eD; ム͊{I]Uc yoPd۹Ij(bI:od<9SYcb2+x'AJ<\ {FTC1h57\GFZԃH덜 K{_t,a}a6F֡A`Ͳ~6ؗ}-4dIFٍLAXRE TG?@{wΗsKMAsҁc &R0lLk$"L7xħ[;يQCȁHH;p%uɆ8f#$%MC <')ǣl.H LՁR.MtCGgּIrgO6B|Yмzvs\͡u}Ca4gc Uԩfukׯaǖ=vm۷q&>p tĺ%PܻlɏXvv;j8IN8ss#=PqbEœ|<-e09qf"Ji;4( ’(̰ Ȱ? 1>$1QL:bZnwā)0yL RlRHbr$m' 9,' Rr$H"42?$ƒ`-Hqy&r3hFL⒒$ɏG,2*iG}&Hj(p$uL'BbsHBB5'liSL ,蠄j(_ "PkŇ|kC sfl @ҩ9\ P(cw5'gWV[`_O0R]5X-`V[aEd $rgZXg^iUڌ a'ciQ` ߤTCUUlVc"RAL6ǝyo37 0Qو]nBKqW3n^迲Bؤ_ppP { 3,)D|n,Zqv͌oᦦsqXqy.2)(xs!qI-,()$&L2HREwU(t0R}upDlϓMGU&l]v14kH"j' A'G2Kϥ,hv$"&<$mG/O=!\b>Bn(FaJ2ML.)BIclD"E>!H X[0$0+Ѩ2C9a =%;b2|zBVH nF0a]&,cB f0Ņ\Rј4FvlhQb7`8R7fuұ (|֞et])ШJq](]{$Q`ɯЩtMPȓ2' Bj+5T$#\w#R &5/`;bP6 ].1=lp]mcuO"I%D=LcBIL)GDPIP^;|OӟDlfgLSDJMHR%,II/vs& '%(+RV V2$ 3  :LxXHt;9Ԃv*<eNJapfONAǩHТjR6 B(F4kQSْ (UkD,VմOTu*`[+BٰG[AO *323,8(|kSS'X9KƢEkaJb@6i hZ 5ht6*rad A?E5` f(`@ăO3$h׾%j>@ rEWR[qQ +x!5uBg"埑l''KsɿF?bFQ9 ]ؗϪяeg>ԔE\Y7ҡT=$gG +3xHXJT{wɀ%)k0JfCu8਀U"Hwe8Y xoe`B!7,V]gj7Zp Y pྷx>Y\}hnn.lq# g#8Mڭ7$. HKBR .ۗ0v>zx5q*6 =@^$OJBJgp F%P}"$%'jlDo 8 4XL%`f3cl1A[H aָ4]bdrPJ4T)%*ʼ u6 ) SjpZ 6Y^K\ Q  Lf{YCM&!8A(a6F%h8CFb+81(l!^#bl80(l0C:c+ 5E/fHĖ g2 :ZjܡFH Cqs`I$ DM KQUOƄD ޑ@D*/HJnР%/P0q"`SĠց)0 )T,D/#;L2X.T 'v$e΃0@*#]vn;Q V*6r-fF+,C00ή$_h]1(}1Xʒ*-z*fTXa( _##*Ԓ0؎ 5!#K0.j/35lB,q11s11%s2SDQ|2-G):2>xDR Kp#L5yDkT42}F6i6q37us7y38%2-3733o 4@BUH:}363<ɳ<<5D3==&4>>3?s???4@t@ @ @4AtAAA!4B%tBiS ,T(C=CA>9@!n6B4EeC316X465K"(,BmcZ g}gm&5&}H5tqNԏ@tIYbJ{66SE$āώ&hBTD*hC@EY&6R;M"NVQE"Q;M͔-:d?P4$hAm~͇Ԥ!P50``?J"RB 4 J6^5LW BFI" D]#FcF6t5p6T6X5<)#XUKMBIa#IDtJIBY]YyDK rJc,Q6HZTZ4_#L+gP4AFDrF޵a^k#*i!qV&"Y4urnD6)H` C>OE&dGZ.D!XVb"H@9R\T3Uc "jG}fWWB}66556E•\[Y6JY[C\Si=V"iKֱ6]I!aទ=8np8Xl͹^>o-2Aj4E:C(maXVl]H b88CvOg8f$rads= A667 4C֣8?~)\>dDx=P,4w@`f-9stM HֺXumT,TNGv=bUrv7&B d@@%Qe-r5lnsPϠ{ !yF {e'2%{iK׽WKkH$~L $Dwkm&mґ'_^FE]ܥkb.]T"$t VaHb;:F6k kJSJF呟!')ڄMYEIXIii"-kZcLѩ#DC؜ e q5Ft){OnSq^d<$wqעC $oWn nɜ%#뎂o 7G?O`m5fbt10?{2E9#H  @ px#BAEƖQx+yl IxazD'{!v  W paqB)ya$^{Ʃb (JHbuABNjLvGX|yGzuIšdǸ)ՠWIQ(t"j(xBWM0GuRVKJ)zF '`v"'ph!UU[+zmҤQ$FاxxԈqڦwQ,gZa NAH:6v)AAjoj<=t_<x ,iZBmIrW,'eę}Lŧؾ6N.~5f 6 `n-XqCH_h˩HM`# ɅQwK,:)E"DT3ϡ6eC3=±R B(vC_ontѡyR]$ *vТTA J6Nk=IJ{]\HVGޤ>׷{ e~LOpJO_ĦTړ=uꮭ'j!ӝ&ٝ!8kW? E;՝ݗe.1j-\iWY ~‰8ee^ዘ%~6Jm{sT<^dp86 ̐K (00[k@aD‹1؈È6Ud7vpeF]ut$: |&s t#h".Q4'𜦃P2C3jʵׯ`b/R$Ml6JaʝKk5$ Tx B,fy[bv_g1b6r岝N-_K6X 1`n1AaA}%Ԫ_C l$^w|˱:D<1$vΆmѮ?{9AXFCg]U^DSA`&ADITQE T :5bDb =# ;e x >?( ("XĐ, Xđ,AGPV:XYne_>a9\Yךl_! BL \ J"2>p '{TS\73 F$hDbPfG}:hO|B6ؘCF~PM7M`3N6NbP4D э5Tf ͚3g kDi* >aVoaˢ(m見QFecj6j|N)f9fToY#>qNcvjaZ61>GmX,Apx "ly=Ax#jM.cs|dB3s㡶MzZ}ssfPOY䉺̱ɱ[MxNlHP.RD`TӍ[M3wK6>Ͷ:͸=RFu}WdNyWU):XZy&dku$sL\UѦC<{RF֐c;dC5 _|Vl8A/TB,_<>_LC<#;};`#wc)B,||a #mqT1+O wA0`Cxo1ȏ(8,1>&!G60T Fz1ȈdLM* ;ιgÜj,p AKaMČfB =*I?:QQR@P9$B̆"j% 춭 *8B?X@ kl0wUV+`e9H#?W>(Ke. K%|Bq ,׫a*x`9=0LZc(Nfۋ5# ?lD-,]#H/Ջ'ZDAE/!Y-Dy9u%OA:ZOB'Y‡Bg  ^ e#4eFwyj(GnvQWAU1ox'y^&ygy,T+Q$!x.܇<gWgF"/2iCFqA ~ P0P`2@a^>&At[?q hձcMa ֣XVxGWǃ՘W\, V YVc {c{ !i ZTDz0QS^Xe %6"?0Bo0)|bhyx1kda+agt"LPBU7u aàk@c]6iRzA3?8>al4 1w(xxƈGgȌθH +!\XBɍ]y}y(WFh ߰]ȎHc T 5S3؏5a3wc0 Q;Ͳ}ؓn}ƨYbA~^أG9yl%36wwؙq7I0oi7k^c!!fP %wVx&.,pxt gigp?~pyeFxĀf0KUTȏ@ eR_h^x~3WlٖQJj@s5|B0y+'*j-0vuA/ P.N 0s*&2-vRǩ \`)"(Pf'c:+1 H+P dН2(0\)TxuZH-hg/-zhFAi{e@!Ķ64-*=)1_Q.jV6( kZAx󥴹zB;1Z3;a:+!0BQT  ;~\aۜ4&w&uඔyndE_ct' X:$HNIquɧ=1~!=] ZYBBe@"Ai<ŷ"Y\˽B]|5]Ra^6`"60P:0+bH/͹$ lJ"EB$\qS/5ߠ[ sU؇y]r M29ȉВ~ٍDbYRy-ϸ,Z2m-XfiS0t;Ғ/p/Fia;3T#FD`L\SBU.UA0eN۽5X6a׌ t"8jek -6xL苾 m馜8b@!֙YiɣnuAHXs+RA28܈g!nENQQ}V]..l>ޮ,a ^ k,><:<'0@Xg2er;/ΰ =~x Bzı7!}_C [DYP싁KT?ޱ[͟dN-=noe? j_h>k*A% Dj|Ok #T ěiNn@$`X:.e9'c] ZP}^]~ݩ1|_QX߁PvE0qzШ@b&gR* BRq .-RLpN餴K UgNݓ:7D@V MʂYM׍gzD)XvᆛmMC۩6*܂lnR"uUrͥ nUlю+^)'lYqe - G' Tc|^F+fiNKETfr0;i1$/'!ؤKHR6BZ?źht|M2}; IH #?H}@"e>_b(}n cDD3n/L(+eD 3H:,#)*I16leZk  8R(P" AAfT׃aLN4||:c6Jmc6m(M O:ģfHL1~f$&BиGK,6t ȞQm&VLE鼒hhZrjB@N+B/wK`EХwL|STQf3Y" ؓ`zG 4}j _4`>tsڬ8,%18&S$%pH7/:B k;_/!%9XQMph]o\Q15ƣh!_H2(}Cam!*0ec_ 1#B10$ f^FUkt4B]nTq3l 0đ7B*_mg!z=t(5HK$>9J6A*d%(2`$'vs]"Ub-Mk=6%1u$ ӵ=wL- z5ʪS8\՟ѯm2jS9b~gT93/(!]@" K8bDQԢ[.%~GJ͝_I~&>>.+1MB fX,F ٝb}!HӚf_6> ѹ} C&C̸ HUcVL#n#S!2t.q2%:ʌ ,>2>ji 8 d6McX3O5yᙹ;d0tz[F$;Ҝ+CLR˜JmRM{n]WJJp;۩ .WOXN36+}䊝?|(@_}6[ Pz==ٱ. E8*4,፝@Za]gt(VެHXV,0#84pF0ʕFdVɐ9גtE&:䑙{TIWS%Rtn 4Shq\4LrN:̳"}@%ީ]ڲOڴܑ4k1 6έG˸3ދ̹:0;VË"fx ӼV1'ka4ㇿ6 dΒ HA~Wҫ^QWTZ+)>NYIGo(2 =*TAS1UΐfjiZGd|X5,0j8:+XPJ9d09=.;2:3>;,C:X3q;c@4"-Cr4K[C 0S {!+EȨʷ 8A bA9/[g1|,Ak"ވ s9P%p̪L4,܄U3K:Pָp3HѳH$̺01t$DCA+Zěлc;I$B4;g$TGAC T^bq| xdo(Ib(C)ӻ@IYIp;zkS1 ɒ|X (ħœH𜎉l8QD35PlJDDg> Cᩘ P "!K10p SB?E:?%8 +b+/* i3RMb*⫛!:pD )U,ZHt?LYMЪǻlBt,N;rȇXJ8I`W)\)2C sopuIq=ἐH/g=0$CMq8J앖/53|x@Q`@`xĩ 8^Q]"u[(Dg'p!% !K1lh̀K҈"}p*5"FY# F/HF|@:'‡#遺G.0%q QFc3Yd: C$̪.,M=%K1{GH%p;B!AHWΨTC5U_U5[ 7(\@|mZ yͩ+-r\r"A&`Vp Wqaq&gHk8T:CִєV+;$j!WX-X(!eyAaS0c|}Wn]LO3XX YY-Y=YMY]YmY}YVYYuBъn2 *Rp*z NPZZU"~UPț-Xi=sBex @У @ DP(el9@}[w(%t1QugY[ t% 2m1NĊ9ڪY+W.YpgZ (HjMEhZ rI4ڑg,|P핼`jۉP(Cf@ԻqA5n؆1_-^P)[(\A`AɁ Ù$rBWЊE *0 eB CfMNEޙ=$<ڳC aMHJ@&" 5\åth=ZqJ㚫ĭy뚜u=)^? d!8$ 7//\GsDЊڞ8HmFќb% o c` sҊ0$5N2jCc.+8$p1d&5"CNdd1C0Shf>#KNQ QT2ٸvD^k Np Aq\.q٠El:9Ztɶql@ʞF.-lAtd2>솥=Q9k@ m] pr:!'eJy*<0KX5?6/j T,_8p‚Jj6HC?oňt7T锠8̴>MpdQ$ pfmHd~R5M/V ] XW6 T?cUV;CSHl` ukQleNaN _rvU#JrBFvO|ثWb^9p0xX<؃}DKss$Ax"Ƞ:tE:pVB*6MLJoS!SH+H+?TV?dX UU:/e@u_lmib' cGk (ljvtjʍ mwSͦ(q13u'v?w n-NU{4|}IBs& 6|i.'}rN=! hܟx=< EdĜ>@Hyk !)Uy@tmoNV*p\(H)YGu4%EN SE,seN`n\:b b6|jȝ#HК9pAlɐ#|MB0nL_ '-jhOA؆3f1Ȓ'Sl2̚7s3Co 36s) %mŖZjXOnAp L\}9c6oYOq-;wn_ܸm{Es.Yf;xVLUP5L9Z5nMQ8TH%fSb9",bO薍߀MlCL:UTn99]$I=x8x ZM3:@)88aM;<8,wSN;Wb3qWA#1U@X3Hi@ZqUP5ވ >: hEa#ՅBb5ܓ%hJXa*v>5vz+xC8 [ϕP@mb>[HVweϱe<#@;<3vgܕIβz/ZCoTAc M~KP},k,-4M9dESpX8`dla9@">(f"6"7|=’MtٴtpJbԴ%Ͳ>VBu<$2A:BCtEjf6>x]'Pt}ڋTNomhݰJGS\#Lm$]en> *b9ı>;~;;;f!%Puv=$Wk={=?~P /<+Z'vֈe˓688LvX< ~/}>НB  Y &u C(&!(!#"HRLR(P369-r9Am<F2:egeE8qqć.2|\ R.`Y_iȇt8de \="UbƗ+U+ bgU!NVE//ͲDЂ|L`|FgIs}P@CvQMdHG;ޑnk<Ҝʌth02@"cu6A3ղֆF&`[`.dzhUȈx*GWjֱ極[!c9FD"mD z (@6x/Gh&_ddj-&KvҢ#Fj+ hl Є#̆(\|Y_UfR+b@\QӍ0)G6Ҁ!;]NnlJ t%%~ V)ઢF[@:cg~Q ?E7M9,H{^IL?+y!Yk~Cx)93yMkw9C~dYꍭ!=G"ck[T: qAQ*pYtd-Lr|Xď,@n$Grq@v$94X6JÛFAF rzQ!v5eO!9C}O8cD#__5aZߣUG7Ju%R~%X1aXI3RD+8%DHT\d_e !.A!`PZ-M[Fc7PLeݥ\avg">BgPb.fS]UTDy"Afzi&o~3܁pMAoOj.杴dLTKDHhF'wv' 8 'q.D"x$'XADBRt$N<ΕH ~yy'ɣh".(6>(FN(V^(fnhGb~(,.f$B"hyj8I6Ng4D/x(")A)AI1BVifiH_$1" >D~`Ih(: (8XЂ@[Rϊd_Eh$fDj*bj&)i)䩪C"lr4,j_XiPij#7qcC>pD0C/Hx-~k:04G,‰Eò-$| ;vF*g6īV{`ԶBM_`@gk}xj j)Ω.GASBD>R:AÒO_IȊi"#X"B$SQ6, "V+,A,W6B!CɦЂ6HaQ+,ȄVҲFAKڴfE4D0PC^͂ܫ:I(Z-歀eGm+MTx/ JN.V֤*).MADJbQځpgxBɕO"-x#P+elI4/@A x2(VhimyRZomB2"A 4`ăPM(ãDD@WńIdd@XIdߙBHڡf@LNI+A*FR*m.]  PNp>gp!"lp㞙.d`늧x0ynmC&B9HCC/D,ɎhS<#`DS$BbZEV/j"AG$m# fB6)D7C,pDSTA` !M8KLb"p4Hk׭/^0&C'.20'+)/D*?%n0 Dz fj000>H{bdps~l*M5{-4-v3,.1Gώ11AU|pglDre4`F"KA *WoSϏ30^(wr({b4'.H2.c.+{ ,òrZ2 2/!*ABNCFJx)y58<_ܛ)fOled6;/8{s?C88Gs3;mSHҦ5>!:koC8TH8|38Hd[TəpĎȟf%:Dmb(7vG{ccrF_*kjvaJc-_6LaMN6fC@ P'lŜ"u Fso3"8T,`TKAP7SVsX3[vow;5!ЂL9C|%^yx_@OE(݊ s>Rp_FstGG6/0ew2_(p2.72ͲhNKZpv6nkx>,lE8#Ho,wUpR5V;wGUd,x:9470B^:Svw9~l-ć$>HLDkXÔ`'s$FJr$dEW/7d+zO6rf˕JEYL+ x6vqG8AX+lwuRi,)1.BD+dd,l>$:DWc9zl:=!Ŵ >9e4)@}^QF. o.>௿:GktotEg2F[1qVJs8vp*8:ŏs':"(e4f_wsW>'/>7?>GO>W_>go>w>臾>闾>ꧾ>뷾>Ǿ>׾>>>??'/?7X; A˚CmN;:~SD>q4\vt#|>'t%vcF9w25&LÈ+nX#H!q4RŁqH45jTSVzkV[vlXcɖ5{# un\sֵkV j\ۧjm-g7 ;'6GQH0b|+kpV:m@k6C9יEϔ(tԕW|wÉ7~yr˙UsW~{vQ \mLף= ic7v{~ѩc/Q> C@G8f>=p - 5ܰ|EDPc-R+O+5JJgpVH= jƟy,^Q<ہ"iO:G$)4IJƎ 'yrJ%$\6|+f-87SbX0r9g +t tB'FPBb1 LR00tPKR/qӏH}4<]}XeK-ΙYuݕ׹PLqEGKN.vʯ$,3$&3)vbGS 7aU*pKmYne7^|D}`Ncm%ɦ 0 Vغ'aa9tC,l%Ziݬ83H69<7H]DO&i>[$K+g.~jz)L\7;ɝl4Sgsl%&i 2(xfH˶-?[n;B[#ŧ;x{n/jyFq3<=Et@3:-]e=ju?. !Y,Y H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0/vk3tSN٠KULXfA"8@miN98ekӝ36`7sUA8uK FSLAE)i93 S`l* 69Y'*-Z@nJhmc5m2 >rK6{c´Ն/j{)1n繨Yә 6m[6I΋3GFm扚߀7kƹ*1<׷n6mk1>XL @(x%Cvrʰmkjpk\k|= ߺ`f@ɩ@dBԈM-m۪6pĝ-{q/>`! D />t D27(2l92=.b=]3jh,S/ K//w mݭkJ:̛7$a+PӘJ1>>ٜ@7dkMNuǻvh;(Vo HL:p(5H9ukT99l2( ~"A|mDR94لaI+ؐ z.9R s-[h@ {Ę#d1\"7PeEDE*^_rS#Q )#>Ŏ:޲!B*q#p+ Q Ґh2!ɈV૔({^H2$1ك0'jLB")KZ5e1KC]$\R~ sh5c^ْ2Q #?ԋ.J@;*1'Ô9W! b2̉!1jT}¦BM X33|ԑ6SP&A, X=YRF3!ќq `r;h!E@ F.NT%dBΡAnp7@$nF!>Ǭn~wbܑ% SK_t\ jZBL>јWq>XOieH7Uxͫ^׾ `KMb ih:)&8^.D F&/__.D B`{ KXBGr7BWtvC@S?٩j">[+f6#)7K MA#<#Nx;D Vc+"(.(L7B.EYFQj%oDy {߃x| Q*GJS*`|5hKm6q{ +n/]C̥׌Ks mqE^bИ^ / ljOlÙ Q B:΢,eȠ !L8od CA l"x!zb@gbv4+s%rgLgÇ&iFȃ!Afx>| "I[q+ț@nZ"a4j= fXC4%BܚC8)O+Td>k`I F 5E0?@0f@}Cl#*~Uj]ՓHmXX8qM=9= ϸ7{ GN(OW#È8ݲTO X{وHE_-)|q*Or@ @8+c,ץ5)j27Q'3 T$—c=j7ѦCD9tvHS[i0ݏvz>` pC [jQTG^{QT7Ϩ@B8DXFxHJL؄NPR8TXVxXZ\؅^`b8dXfxhjl؆npr8tXvxxz|؇~8Xx؈8Xx؉8Xx؊8Xx؋wgs@g.0T.h'.~ Ę/s=ͨ^U\`V 㸌W18(~Eqvpߴ{b@1 m4qPǏ(xI=epdQ'"y:9I2WԒpEW* -Y'0 7iDҠ 5(Db(~B. {VI!D P J cA)8b\IaZK \ Tcy6Eirٔ Ր! (k E | x5aEwE i0+89 Fp P\xpEJI aJ4q.$<9Y ٛ9Yyșʹٜ9Yyؙڹٝ9Yy虞깞(b)Y) (yDipD0*)Yb\  j٠ECj K ck)3j )j`8Ha5N Zj0g'NHb@8H:4:;OTZif`'*c*@gjXj"MM L*0zJHKJ]䦟ڨ(ʄ5zϐ c:Zzڪ Bp-s "NuL0ʫGc/ѬʄT.!cZjI"`߳GXI1DLH|ʺħK}ط%K ]p K01B ۰;[{۱ ";$[&{(*,۲.02;4[6{8:<۳>@B;D[F{HJL۴NPR;T[V{XZ\۵^`b;d[f{hjl۶npr;t[v{xz|۷~;[{۸;[{۹ '4> [4>Kp( AZU QĥQ5D=I $ 0To+2353 wwG+ қ.KQk0*Aup딿˾3{ amu(Nٰt MLvJifPXҀv` y=` ˾1|5\8,q<(F@sAH .S֙F¸6L7 [rVkXTa.2\b7v)<Ƃ<Ȅ\Ȇ|ȈȊ A×+ t(hu4 lT%N r t@ ; @{'`c $ S˻@b)(H…z 0G:͜ $1m@\L̜ $1O:Q])<\|=]} =]} "=$]&}(]Tq/Ys|w! 0;u` skQF[Pd! ሎP 1öHŤ  et PF IU=3 4 vej bmd}p! aQg't=> @LHMǀIeDaأ;Dx@ٔ d=ӀMm1c R4Pܸx{w0*]y܆]fY Q 3V :` th; Ұw p= ֠AYܖ Ȁڼݯjk  !}-y[1cȍ:iu'2[eV`6` -ݘe! <~?7s2ǔ02>4^6~8 QB^D0]uΫ p;^\àQiB~R ڵ 0  ! |~~c m> 'QDuh{n!/z.l~#1Qi}'B ~nnvB PaB *}kkmn얾mPU c.b@0 peyiԠ GPNϠ>^rni ji&t y*&$~O<.~ )3 "_ b aBa99^68:KIJs4k@h+?G_SNiuLa\r=hB  s 9ηPn'0ti p;)s?ػwђQ\ٳ= 'D~o3?>o QXBءۺߦ\2jqq YO}kٻ?-v TޟAg 'Ket=$XA .dC%NXE5nG!E$YI)UdK1eΤYM9uOA%ZQI.eSQNZUYnWaŎ%[Yiծe[qΥ{Ro!3y5recȑ%O|D7vq8en5*fkرee& 1 oAdxqɕ/g\(qޝ˶ ts;Cz/ŏ'_yK[jۿO5O@tPB 5PDUtQFuQH#tRJ+}K!HK7cnipltUVʔrTm_qbHgieV`jB[j8|PXhmjXCd n[pꚂaV\  QVt㕗k1wDW^)VMu_ Vi{CS} ^ xI_T1Vb{bK6"54iN͚qƶye{&HW1h<膉vizjjzkk{l6lV{mOmjJhį=g Fn;D#szˑpɱBSρ7sЭX1*mQ5At{ds5<5 6nqzI᡺%wx7{| RjZNg[$~| +U/OJuU}ؖQ~ ۵5#'AhX H,$0 rt[p_}VqAfP`=AP#$a MxBP+da ]BP9qCtPg!8T3qb\pji႔\zT) ~&kI6%6{օATjt uo!3c E/|A`sb08Ch@pHfP& (Rsl-SS 1H$u$1c( T_F94 EiH>bGt/~1i 'FY j@29~HĕHrL0VM^F;JYAk146@AP@ 8nE,w(0|kJEm&@GupDS&αėT— ;AB\Y2%8NsQ=}{9NDGZЊEF|1H>(F`imn`-v!RP[M0Y; .xiLy˝O*fQK>A TEC"3ҫk3q4|ˊc`X3j# "}#: ^ CL"ɷ$F.A.|:%qh> P,2_(O$%t!bإH 1&{΄Տ bwۓ&`E u:jԲBwCiK2Y=qp '@%Qȵ$ܫFᶡ t_rE r'n6yF+BB8HU#JPYGp \lG_vs ?t _`ԐTc>んJ*OۤB(p5PdeT Wܰz$8E"X^8!qYAļ$dT`s #EA'>BևZ)z$kHT|,O/DE/l $H5!uo\'x ~p'\ gxpG\ΈC܈l GH\O0@$ F +*P !9Sj1a :1}M<,5*ڴzV/"oRAQ6!yÇE%!vN4^i:˅ƄLTGa' X1D6.'(D 5X'1He#Π=GPQs q*p. ;ΝRC$fXRfPݗXMLB 44Dm}IW*T)"%R63+w6ҴsЯ[?ۈ,C+*`+,D&8x&u4RPT@Ca\ Od&f%gj5X І؄5Zu欑6#Ǵ͆gd +H]OyG4ObhjESGpuSAGgVkЉOVe=oDɖrBst"lר}W>Z ף @W]ݡ!2J{Aʊ;i"Dޔ0 jʑ$UC߇ˈK sY0-(Y@v:v k˘)Hjh +h`+O@%e00Z84,qabh(^LܮC<)9VHܵmFߠTlbTh lЄ`$61|T$6ӮÅ ku9"(Sxn U̝iefh;O׽V=`V]]g ւ(Inm=ۅHOeIJ6IKWȁSdWW'D]BBFTFl‡J(<0 p@C5I>3^gF\P G``XUԆsre@Dv\- aM"4-hPS6&Ӡe OT=abpe1TOD=E=F}ňT|cgMj[)0(q8"/LUjbq݁UMXfg$_ccܖAH@FAn:P։t}FvdgGn}PޥHuPvQ>WS (TW 0q:kI+[d3$y.ImHdCʃˮ2(1 YNTnL@:5n|~p ؾ > 1L<=Z_X&ui-C艖N]ehf\Fo\bg:ΎxfYp\U.ʆfЄnфeL-NNH4D9.͍G];\v؍=F֕ǬEdeVF~ȚKW%9vW%exUޢhX(lIPqh_k:[@H+w$Fotj0ëd|lK <*Ř &g؆nX7qX҃@+18\ޅ} 8 Y g GPӊZ]xYר%Zو_ynH[٘„X6$1Z!#Jas&F > nxPZp8xPb6ZJHnTM^4c* ir(0NYgwr78|;WS)L0jQ(Z/1Y Bl)BϢuO' S3= m|<K& B < A C52%uklcA檛ʫ+E*[> sk@->zmھ͠T컦y/>y.ˁhA82|V"xoFMNAN6Q ϝ sA,wPw K@S腺puWĸ0T$2aK^egEX3 L8#b-Q&j!{EL~g6U>ѷ3丣w9("%1di8όQuO\rAL4!&`%7>m&*r'r¬E|#N6$Fc6!_)6tZ >V|rPXA%-j;a3N6ACOEB>'!8|\K~SL=Y;Hvu- ,Hc_AG+\]dAm_L f_O!!B 8;X󘦂s"8» _rņ>,bjG.F9eh3G͊r3' !@/eCYִ馅FEf "' FMr2(JxfQl&k#ouT(dL H-pKI6&a-ŭ% I ApU`L^U:ݗ2%0yi*Ae 3 67|K9J"DXRDl&5ͩwS.b@A5F&!7Q&)Vl{ >FUEt:G(F|͜v.*,9:C6A!Sf0"`– I ]Pi#BLŇ&ڴ+^qJ$XbMš s p7iCo}GT7Hpq$!n@R|Ns|0?!'Be=&?yONLUE-a0N \|2yD!g{#:'VpR2ӻd6ն>3g,<RbC_o<ءTop E4/aPG%C"}:YBzQɇ'otW(70[!G1`ST. W۷40ALb {P"WT0"ӑCBs\7>41o5AMsB*;t=N*c$6(wQrؼ{JZA@HElBUAA [E LT)HXUϝPZL >WE׸BDнr Bq]q̟\֥+M> ]rH[ p0!Dd̈́WPV6H<8KOz| MX7|Il1|8aR@| BdCGJi" 4`6ġ%8RI77 8"F/I NE"81">LX;a>hump`t"{<UCM|0b6PA9XCY8(܂!CN'@Đ8:8"vCZZE5DUfYUVK]@!~W&PLA4Ƽ"C[(fYN4pډȮ*dñkb׉L#5_*܎e6=Ex#F;m#>gc&c ;g:԰XHK68 3'hĆ. ejD~]S5O( wgBاydDw~Z!荅$k <IZK~" t(mE s0AL3[("X4%k(ezf)&jybdD-iLFdLFj`iQ8'o(PQX)))ZkbjZCIf)m)"srnXC)L**&橣(>*FN*V^*fn*v~****ʄ Ī @jD!*FFȜŔk*AdR&Bijn)CQt Y ȏ*KlIRD \YXD҄Op@C+Eಉ.B-S.BD.&8bnV%pQ+D#5&6P&vOdMϿJĦemCP;+B.74ЛĊIJh"7lMYT@hG:L R Jd"JOJ"o^.ޔ4f< m>LGLQPmF-R`-LhhAl-|mL)NْnR-R8ȵm߲eLDY(*n.*ACfJ*`nfЏZ.>q憏'.Q.DnF.4"[AKGXqCRӦFx+UĺB`1L$@DIfYd@j/" 0L#72#E䁩 pDxD|r|+- :`tES'eFl D,7s*wA D'?հS灥K(_62 ޵MQKA8'CT8IR47>e['gLdC'L'ټ„B ?#L(zBtL)XTPY\s<~j:8PO,@L?C eDtqk6fwonLH1OFJ,e'9HMaO/$+DFx+>DrE4\AB 6+2 `,B.,r#C#K2¾D&,Mt*(Sұ"M65񪪽D6rLb9DaCp^ֆho-: E<$hlP>?O6 ͐$Ϥ6 L41Y1n[/V Z~f+T q9y m`3uOvdk? %LC5& i|[FzRK6@sƪ?O#- Ä R lw ]6Ht(PEc4zPX Ыu:@DXК8dT1Hn'14N0' QP+>kjD:H)OxlS7 (+@,oWDC Ëp$"~ɵ^f/`A#^50,r)9P)=IN9IKT tڏ(*Eb"Ĵ֮KpDqh:1 j-BA;STI0 )pK\$HSDMwg+SC:zzA0W 1̖Aqͤ0A@Ԩ}Lٖȣ@mPDJ~[~Kb`A+DR=4g(AsR͉*$EDƻLAd&Y  nro P6D&W@nR;;aǏ OBst<85˷ P5\^]b71j8Da&,:1;:,'C*(kxYХA3cA ^ Hݫ>z;O0=Ic3c9Ý& }#q{ U"+% s,=-B@ [\W{ְ! QXɻ-OAFx,n R?k |T\*pF{3nO*}MX #D+s{ZK8Ȓ\;W>5tp|ȥcF1"]F ri|tXB70+49aC5;OP|LiiRK.5S" w9S%Mɖ5{mZ̝d$P7"ToH"A+5̰l7!a{f$3cVL-+|9VMf ^A}6X=T0OE/^z|[WA FZuMn͒넚} xɯ_)| ""_QćdfDC 5ć:#94YIUNQe fH0Ʈq*Yq lmI'a?|b$v׾p8Hqi ΁Ԩ|~x'󆰁eE33>]5wV$52$h M3OB >V2]'FTjoP,;wF< ō+ajY_U\ 2;$ʈ\Cl`c(.U@RCڕVg}egQ Ro6 p\.pTs㜇 Ĺg"ё[n68.0ٴ2@VH"9\Aht3dž ŒhT miJźF%;EEBb^ʙ9jԟD0fEM0dܲA7(n(Gq1},Mo< A\DAvh' r\[ꔑ—7@|Ä/+4*.jRR(v3)qg03|,)N9o V(ȊRܕЌ%$ gWE:n2!J6Q=Ƹ8b !$!bP&,V!X|g$/HӍu#tyri,4 joE4a„QaeCc5C&p81D!b'#0|x?ۄԄ%jT^DZ1F2b$>ͪE:եF%wMP9AlPdz٫yhPcCىNHh0T>T2De2JO<*nhUjET*G[]^٭R]~eX*4TJuCKJo[૑N)ix_~w)`= cyCc0Z15>pi1da K)]b1 ,ceA `9n{\*R+d'?Q\e+_Ye/a\f3YAPsf7q3-5BEv8H['ٮa @ ,B78Zll|!6^ jGˆjB9RBgdAB{ dFk#a1G6)"?90`56to0iR dtvC>\NR8MlUO# 0/e mڢm cp bbB !%0`46 L*+:g᪬¸p, !h6 _JAhl#<DAkl̈́ B," 0F"h .5q1/: j57mmEʫx2[0/L眪9"@@hr[c 6. hZՏ;UfVgWZLB BBf!jt@LN-@Y TR?X`!H# a`"}#bx1D&Rde":GW#~crD#4b,-1W-n+g6R~ F6=8X;*Kg,h9 I.h|-="Iy8j6ڲڡU,6Rlp l?-1! OLO)7R~4!6PHB `I֎ !qs=NY*! - ^T;7>Z;c%-u Vu9~`wv " P!v3tW=C 150N&1;+ W*΁3H Mazxc Xp{Y?sx6Y|73 ?ˁUWYԳ$ RC;A!ٹ!'BGVS1N_ ӕB#LS-!tZCyud Z[X"*!Cif h#~?n@=~ Xht!8@i@Hfape GQ@LXp44ܶ$֌D&Oi?oۢp$DW:ˏ_S3/\0!ZGq$<! tt-ypU0Vuq/y@*QYXcd07 Zxk5W11!R < ;A5#Y!Nm@!y!U/9*8&~`Ѹ+C(cUg!91t'X5D.;\,c1^!K\}Gkv,X -ڿ#̃SFzh kÇ_;uT#  <أ|J bgs*9|^vu&|Z"Imْv}գxx/ o3b7S5bkv0T Y{6%в1/`ђk@_0 hY,;"P69ꚠe |{^8g/.aaμ7㨌jJ:2/5w{>cX]/>>Vh awZJy>ɇ)GtBAFP)`2){aZG}KBOoËMTHIۀ̥cb BBݓ Vt##&@.f#X5+8ۢzI()$xJ 4ST*ƪr* + [tm"~j@f<[ljoFX`WG 1[ v!ӳs <]2 Xs c2fPh;r뚎5 f!a1/:Lї՗>bM"TQ8F77JLum)JHhjk,}d>!NG@fMhE?n?ˮo{B;ȋJ)ϺPߺ0Rlì+k.*)r˟ <[l:|1ĉ+Z1ƍ;z2dE$$K"yʕLPt(\h/kڼ3Ν<{ 4СD=4ҥL:} 5ԩTZ5֭\z 6رd˚=6ڵM6ܹtڽ+t,Z389"u;`~lI=ƛr"]:-KL:vEz;dn#:qRI'ğ>h4Pn u}SX\eܻ;'\; ܉cwt3Nu 4C<6>8X;Tfݼd ;"GD > GSB B 4.AWE!BAf{1PI=tGMaf5Ȕ>VbYD&G 4DEVFFКlDy[oF4'QETq6i8 DZ YC7ߴsNN:^鄈OS߼#7݌ QJaO ֍@x7ltNF𪨐jR`*`j1}Pp#9# #X 8-MAď]j!T$gS6tZlCaztpGe0D*ũi6'Gwd'Ĝ^PByn * jAЕC )?`: [l@\ tʼbS&<}.-(=BvOϮ:59 n( Ivv~suEDf\x3sAØ(+>(DB(M q$ajx6dA\ `][B#Pd'6eyٜvfI>~پN\@?6<}Y@&>쓤~O 4&K+1RIyӝ("5`mɁ X  o>:dqaBP+\@LưO"3 wp2deG3"3"Ѭ;Ѻ3q>(Հ6scFsы&RlR2:G),d} R83p@: q109@ kl#o))$8ԕXD9eV-jJs  C L^J_7?~|IpO2O\ ;& 8*#(B*t B9n 89a [RУ#aIRP,BsU9Byr9!e8EAAcC^KD6 ?(IZ`5ֻ+OMGdf6?]$T pG>N@l Q) o8QHP Uft|YL(۹4R1 _>.?bǺw0rlL1hrM{ۄ@ >cXA JWD|zA ޷oD@ XCh8t'\ҕBB `yHq3#VT TpG#*͈,6'feAb ^`!A~zickɊ@6N\*3)*kvH.V7Ɇ F=2[9o9pfLg MUH-ic. ᡣ[q"WAL'{Poűjg&:%f9Łui#>γ}yK1K7c64p  7 "CS{0I ; spP^0 ;69]&wx&fFZNP)Ǣ"Fimۓ#/VƲ eUuYƑ2RP]L5$kshܑtt>r҃I]w-MhoISohUc0k2x,]YMےեiv[lf#$MXpb1XB!]$?V=r7A j=1 Қ!QZ' u'!oJI )`K% @q{ ,ω6I0"  "I5ɡ{ [B>PʰM= qԐ sC=b!I`ib2Qҹ&:̼ jQBd09п ZDKX2xGRbw1K aH1 Ј=-$ˠa\`-ٗ$ڧ m> -QFX QF̢ ?}^j p2Dm)Z]q0 Ut0ձҰp !1LG϶׿p~ .һR$ϴ P$PP'>E :rs =`;b Lӹܚ 7 9)Dy3#j):v:>9&>(6~HHLԳ]l.Eۨsd-ǰ5)M{ {!11ݻ` G-ݾ*~M9­,]0xCި!x4a}[k PNLѕ^DFo۵HG!LΏa5DBH$ ubJQF$PFh˪>9dUI!yL.U-E LY 1VUTU EDp@ UO>֜ TNH-`~e>񛼝& \q. |Net aaO2[ʌʎ.ѓhPNE uW =9%yӥ~ I Ȋ?-=7i&MξVV:v)q7n+ 8Y -rS}X-A8K *ZD fl X!sޫ= NgRfCYj.P %$CI%v>k |%yT!?>tP?=ۼ -POD.:,GIV/i_qaeW>'G2mxp2'> GBlC.]؁×H"nv;!>I^yPD@:çH.5JIpQD\D$ECD {STU^ŚUV9|G"ŜvEVZ+VԔ+ Kp- apw[9q` n4PnoM`aժQKCHSKQr9&>x.A EyB⳦N!9iQ_$س Nw;8>q 'njz0Y OLRӃ/}H__~0@$c0p^F1צ[ 6ڈm2J AHl0x x b~e&kᆛo.J@!$*?lH'k뭸B 03 ¼X 2 3\335v[%6q%@rڢk 3vGE39G:|M z@O+>(UoH ҂l "쓬+=(UZ>R>HTXdYg6ZijnG'uf m!s\,ksfFnfiv`~Z]|nᆜwydƒb6cڶowJB68oāKq.Ġ"̿8Lɦg#/2M7l挊@be&b%9B5vTɥeIzu7]>%:J>sz _{,w(^QTicϿe?=tGJ|Z|ہ睿b}7&SƜҡNxuo]vta$GJd Fr~x(ǟvuxj!?†dwLʼn.òX&&E -K´ MpRyQ=s]6z PvrĄe=dP* r׺Sau`27B%$Lt'AU>hGiV7!Fn6.}kB\YI?.vы_c8F2ьg 5VSԓH YQиG>яd 9HBi88ZgO6;ptR$Hpe(E9JRҔDeJ2wC@7XgfLe.uK^җf09LbӘDf2Lf6әτf49MjVӚf6Mnvӛg89NrӜDg:չNvӝg<9OzӞg>O~ӟh@:PԠEhBP6ԡhD%:QVԢhF5QvԣiHE:RԤ'EiJURԥ/iLe:SԦ7iNuSԧ?jP:TըGEjRT6թOjT:UVժWjVUvի_kX:VլgEkZպVխok\:Wծwk^Wկl`;XְElbX6ֱld؋o|BB ="wAXT$ ]|cp]fGTZ~:R"1p^8.ѲvňR[xK52 ^ q% ֳ)s&oz ݳi'!0Jpī^3J)_?9) _@ $%phx;a%qQu|Ͽ¼5@SO% 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6 X;#DPR7  3P9Aa'Q8`ٍ.߬Oјiu38%ҕCK$DLE[1wD zfp#k*g 9$2л,LBSL1L9D3 ><@|phL 'TA^@oϰTeNCx Xx38bd24לJ4LgЍ_'pvr*PN@X15m>5ڌź [9OJǽӔ' eSl5>߁38Ѡ 'ꚬU,P/酴ܘE78lex^5jͿ6ˌ6d <& IOB{/DoC 5V@;mc p62Pџ.cAD#/KC7([ǂ/Bdd[Vê1l@*E2ˠJfUp.S<>(& <8C ;UJXk@g;CW|6k1瘡H"HL&:PH*ZX̢.F%` #!pA 9;%I1JX>A*&~AXv58ƃr2CpO誕_l\ᣑER7 Fm Čq6HJ[:BܑJ|Iyep]\yiRaH\E+p;qGI9˼Ȥ8[cԅ 6jsɱ+񑎆Sb N` BT@kqڅ@4<6v1@ c n1&xt0"礒:fe'9ޑ C2|S^ad'wh<s'YJB= `q Fy!R)Z5]f^J'5kӬ snvh l4^+t ƅ >(8=8@<84xޓq'AAsӬTnPuOb`jiY(Frt9,:RJ~gx)5T(H&kOd@VJbfF|84ڌh*G5!cR v awIO?k߮UwF)5 qOB({ j G 4X6-8Vrq()@QW%"r[I}NkQ膮ʩ.]22tSva 4}?vC^L&;PL*[Xβ.{`R9n2DIy4 lE D+%Ǯg?Sdc69 Pa,aHmo9!0r:^faꗼ|ͫWєN\Wc+JsR(3}s iǤkWC/3r F 9FӻtW Z l5+bF? 4QҿN! jEXeݫ>S/nScFN9Z3s˴tsRovLO [}ЌMjξ˙n{'֨Bx5rH{̓R_}YW λLRw%(k4f'NđP|Y4:2r|+lj2{l} 6hC":t@L}pz^GU^=!&;<G*xHƫ۠g;+]ds'?$s$TtV2> 屢yAG;L{OO?B9r?%-4S{DtDPGUv|qkg?}16L L1f(2 ]GP`OC'tw~Uk#F0u+Re-h~5wu4fgUCL$(4hGXS_XX\CGU**uqq+7+u1S A='և-vGH/ʂgg]ph6` ЈL~*f-lH3@ާ"zj= _`Pf'6Q3H)$ }EvdX3u[%tC'P؋8XxȘʸ،8Xxؘڸ؍8Xx蘎긎؎8Xx؏9Yy ِ9Yyّ "9$Y&y(*,ْ.0294Y6y8:<ٓ>@B9DYFyHJLٔNfB ߠ!)찇P9Vp?/g,!q dY#A?v-R0w𕀹z[F @B;\6;Db@<1OPF+H*Pմџ4 99醮`1\GIg;$jY6z Os[:)P`x9U2;{1Ib KuKES!{c!Q 7)Q$˺aĴSX.˒'"P׉a~:if;OP;[{؛딥zR;|!Hj֕0kq"Cq$ۋi9k $.٪ZXbKL&Oؾj1Xp1FP0z*9m1eD30N\P"c4<< mH$\C(Es+ 1 H[x)2%az-k( VU Ȳaj1'k\:(KJ-b,өJ;.3IĐIĕ [ɝ{-I/à ̤lY4يʮʰ˲<˴\˶|˸˺˼˾<\|Ȝʼ<\|؜ڼ<\|<\|=]} =]} "=$]&}ұ*cbB]Xn!ti5+~H~@QD=9B1 B() tӱuZuL ~ &MT҉b+44, ’RIip׌?J1gMiMRq h6ŃmEJ*-w-qҐ .Π}&pLP Kt׋@P90 Cs.&gpHUW-I$R [[j[\l\ ƝD,F2/Yɱס-n\Y,nIa a߰aFUnbnf$EDݍRbۺ"@!|2FN$^&~(*,ߩg3] |.r Ղ|.0=,*BfI hm,M*KNe5^Q-%WeRMj :La^eQN}VPeތ\re ݉X6n+B@i`>^~阞难>^~ꨞꪾ>^~븞뺾>^~]WAp=_'Ҟ!Ը)PB H|<]мpZx5+ˀ"9r! ?ziNFWwӰF.풲ۼ(b֔RNN~ ηp4 DpuG"| Bq_& hڬd~R "-T!*D". qpϟ܋۷޻qiȴt6ZI Lm?tA#tPmZdxf$l3NnkÎ!Z|-kFsQ( Jdž3Mq#a3`bN*I.K0Ż)!# ҥB&Lìg#dnF43G&lnmdrNB 5PD bL/kiF'KGTptUV[uUXcuVZkV\suW^{W`vXb5XdUvYfuYhvZjZlv[n[pw^ L+\u+{g9CX9xyYx`+hŅ@ZH?UB˗ljc %K&݄0do["ȖаesxK#HxC(DtֶE0!h0Nqj{KHuZlllE#n񈙱XԵqDDnfo@%Aqc&|rsBc~ʝ}ܗjNǡ-~Qu7[!FbWME[i}W~&B{'Hl捭ъHs~|ut*V h'uHg hP$` x@&P d`@FP`-xA fP`=AM@8]| n>:")+^zFXt~-KSCxDB`!4*Bs`8!071$ ȑܥx'F 耏'dٰ`7E0Db@% MHHPT":DtcIp]5 e)QERʣC I8#AlB2[Fv1$;+LsLg$_H6L(!|.DH2ԐDL5#`sfڰ^>'T8).D؉21$%M}.Bgz3HɠvaB13Yn#'A&Y&@eԘp!T'Npq$S[FXBi%{8–3*K)r \GLāRU{k_WV%la {X&VelcXFVle1998|V:`&@% ]Z&hcDXa Sv!-C0ˊk nq]rFr,o$FA1&!~Ha]1PKϥ?a#쇐aT_58 zGЂA*!Drd*Lڑb hg펦2`T)Bx4ޥZ |D)Mm i:@NhQ,$#} b/-JE*ܒYb.uMBZ䂴k:5"h'>e"Ȱ2Bqf43dya2܋F1t[MM Sș o&, 4}%]`DwS`=!q4i-IsWyVM.e[1@8\#`Y}<2d,Yad7z߄ } f i1EP/zAsX Ȃ̾>] NpᆏBKv8@u2n,ШVR؊[Qhz4[[j{0+PZAd yr 3@CAtBsإa4/dksC"g!Մ&|cv>̢]VI2-e7.[0wC2 ޢw?q=%l&Ȫ˱V:;ϕ0d]\jPϐb7)@%B{ ?R >"Ir%P5tohC"Qt(Y7/""$/҇>4բ D?IQ=PCW"1qt0ό7bVb.-3VafSVHlxnpuHY蔁x2V?,nH0yI̔&@/k1Fi}9KSht̆ :zS#3ZAA|X  D Sk&1c'|B|`xA؄5M`2e3 X c܄_X A L-$@D?s5qH.s5Z5:<|S5S WˆaE08DBZI m |؆,&؄&>VA)9lvX$@k$ʕȆ5+\['K#,KAKM14"[KԄ4Dm8ɖ;7$hCLL Q| T=CIpIb,A͆́7숒Hpt޴CM[O39dYPL;p-|0T,EŪIEbFs.键l,hx4M|E\h Fa5е+[5PŇh=F ;0iƲ?=3u$i@9#{L酕hM1|s7AD 4\QD벐D0:yQ"|`TH>T-+3ZEJ$2|+dÎ$H Ď|zA1ć;'XS1J+,M`LC*KBu+]-fѷ3Rb˝tBDcBE6 F)3ê+R_ VxlЄĴ _KŇĎP̝SMEcP`21SV$Si};--DDoDئp83zI՜p.W$fZcƁhEWjZDX=ʨ:M`\\E/# .@<[ ja0aO*RIݐP*)GHׇPʼnbz |lR$vњeD>kPGSI$Q+Fz ! Y`*At?Y -d'=@T(22$?<0] |<#Q$fb-i&B}'![%::\ʈ3eh}a&MmѵЄNb`aUAj|j*3e]zTeR(i[UpAHVOCrI;`_aM\.YY5&L+nD1]K ]($U,XƇWFZ`DW@`PIaX]*O[F@6`6^ؓ@ cć `Flpƒ} iYpa6=RP%f 1͞{GAZDrRH$|H%舁Q/&C4 `uWphIJ%^=^BcT@ڒ]P&%Je }8%S$`m5ݹ--\8lDd\N\<5V2-͹|Fݷ]ӵ]b厐&bHjbބ"-TRxx޸cݷ:CNM%_PfbΆ÷(rx6]=n%Nఆ3a}VW8G!A`ãׯhfh >EyN^D5`: aaDjPaM:p ƋKEC/m23 G٘  m^*#lHjj ZGN)~3 ;&xSR>#SdT>հU$3baV03ɠ_=\>T<!Õm|"\p`UЊBzI;fJÃƣ83߾_o>psONae>wC]aI{}dELײ1j@&o8tnXj^¯pbNj)q5bOZ,XZ32M;P̅υ9Z->7i;?9(V`H4ڢk#0&ȾF$Js7jФl(S'll]`JDʶtMpǨ mQ]"zĎ3l؆X˦$ˍfGܘ|?Y]]V:#wCXfSJ%WE5|х̌όgˊ Lv\ beFix[}g7dG#@ֶ_Mnes+x(%0?tGݒEBahE`OTmNVkEZs?MY(M]OqxH*/%^;q·[Zz$'Ep6qKG<=:x 0 wKiIIRPs%21zR\ 4|1i(2O( v8ȅ@kHctbg(u&S2^^|$B/,[|٣A< eRI Kj,Hm|&Ⱦ f/7]w]h2ǵ0܄XLި+?#3y:OØf"$AvP*h_AQ̗sDK@T ˜ŎH̚9xґg\-;Ҥ2&˚FꬉR;qh'ώECrQ<_UJZrZ*j޲6Xױٲfgت5E/.l0Ċ3n1Ȓ'Sl2̚7sΌHF#ܦ4n8sCyWDSx?{򴈳U3oør:ڷs;C-HMҤML:Ik׈֭/`kf}`u&T&E(X&XeFtm z!!8"%^)GzD16|19^. IhۉE8WF*$M:$QJ9%UZ~h%Wz%a9&ey&i&m&q9'uy'y'ǘ%V;3մ P 1Yoff}P!FLVwxJO&r+j`)/dє `]VG: ֍S*Y ( K0(":= CAUb/uH)m ӫ!I6Pp í#)-IN2O+lEן%ΣI锨\b`T:.>HS=aĸ213Ml8SJM+sJGנ&AtlIGG'5KC+QK=+Xf4i-*aݑeSg*dl6^pw`bfEފO]NG80( H 9OEw,3NO߰37d|9>Kr7; 䒣R:4wM^ wz;܍ <1G+Ȑ3^Jxaw1i|h'ia{&/iL,!+B&׳,AKD'$HG$ґSP8ŧ(Wp9\׺6l$G[ dHL+4e+8\51*rGlFBsYd(S#CTND90@x`5'sN &f[Fp(HوT;r>cUCvy$4 Z.>kdG+ F`9FINb"{uA_|ۿpnlZ[d*{nGBLTɁ10ƀ"b'[ʰvpS%`ql$^EDx|̎,EK[Ȩ]cf]U$n8^ f _lKiMy!33Sp٨ )hөs%GXH+k/:$)S"yOR 8XZA@Nژ卐5tEHx3]֭~FqiAgGq@t}NzUEDX3Ě#.ޯ #)H|Mk½mSAɍPsWhHv}N 5l;DQ~#XNL E x@{m9 ox" L 0H>fmcF5(0 ^cQ QB58%^x]iTD\OT‹Eѭ1$]d V#QՉadYDy*di gZ(ZUȌDj͈5|.  C6^G (M8!L^D6 lDCZpeCUa&hH(9*􄯅By UŵCm[)lF?([~-!_*>_*=T- 9. F9CJ[9X0.m a5ȟOeP \hs5<FXp6@ MLODdCEQMgYQ5iTQ\B9c}$#qUbAF9RU`@`T]#젛D9(9Q6d92Ԛ-CMo9LRMFM^lM!>A5Pq0oF=oZ2Q9!L %S8U뵚Uyʓ&:k*dKZ8+֓2'z( ԹE_~  i2Gei1NXM‘9ITrlޒ&^N^-f->mR^WY t~^DMI)j-g۾-ƭMҊBS`ikJR..&..6>.FN. U.fn.F]ԭc|D tDȈäy+"h<c+SXZ]nb(tb|WCYFȴUH*mN.ȟbcbA.L aK.7$S*T;KK.-KGj*>o90L|KG9 8QH8žXD"܄Kfapx@HAG\>-8pMGii*`@ 0 'F p ۰* e C@AnBHq,dHt'`.pDDb ndox81TcS0P2LnވWSG;6Vfq/qJ *q g ɄSGc,oaB7Am k2)? f@E#bl/0`#7At>|40xZkT p*ijX'aO, QrbP UCr&'2@*΢1 m {O2KbqT,^p80A8 p 34 4&Sd(t8'qqZ.CF-`tfwqHbqTVcL.cdN,d4'>>BsXlm+py5sg:D0Da'MrH|i vjM-H@AH԰ BvG AMBԏES/bsCcK>ZY*LLGL_WAZd64%x7xwl1k1&CxE1>B[D{+x\O1CVE /5%ôB8>MB3 rDtDS:ubKMCiZDYS;/jg1m@oSx(_ϳ?DDH\#AhRTu`b0DKtÎ'v3-*du; 0:87bvw;~FR`gN_9cFCàF5gv>'z iij6k{Y.B--vn?@(6b8B AMp sWc8wG9o[w6 3x7YdC\ECyw9{Vtw\twgC7V]&>kS%r-xֶX6sg6;ǔoiu!>v;2L.c*SGtՑ7:bDQ`JBtu2l]:(WVTmOL?WCUXD$e-T6E|ϧuU zI:+2bX]62fX5V㬋cCM!fPDb W= 8؂rX;O:sAD6moz > w ; >dкG٧YwSq&Tj*h#W\6>$pFQWx~+xE6Hmm}.P?w|;Pj@4l{H'yEE;T^YsT{ķvJuc95tbćȥ3w.>k8vV*9x0j̚w&\(f̐JH,XG:9b1BI웸Z YfÜMA6L'lPZJ)Wh\|\_YMPT|uAUV˦ËZXnW^*rdɓ#0-!cʛ9wE>qՊs aS_/mnmi3}(B4oD7?7 fٳgf=7}/_}#71.~rw0B?a!: Ylš !K4\(*|j)'01qq$XlxD!Mk ar2 #yF$p2I6|Uiq汜7x McETp}˯r`婬4]=5Fu0g)VVX}Hb _*`Y|Qb&֑dŋ^w0sf!0<س L0AEbE'i贘ꫯ!J܀i)Spv!6ɹs({ړs٣aX 5 Ld ZH(B ((J@7!!RyP0"[ 4:= {þ#2EYTrJ|$9EO#3JDbQ)rHOS2H|`0&7)سM8Ntԓ.SP@-ЊgM QxzF*~ c7MfikIzhjeAVTƏXm'6wZ‡-^ŎHFS C/rS5*͌&LRTc2Y0Є@aU|M_WaPIaDzA !d3L49XLDD#8WiF-A42.IaڐaTC 5 )cy3y4;TDXHC>d=,!d^B:D-T6&u,866 !HE@ɶn" DVy&Jچt1r8.w"VtDK0=Ia9IF4ni: 0%9[ &V&2ul]099*NcJܔ XD*P!TC%s4OPkMrlh!T +⩙Ψ01CZQ@e^9(r|T'ZA"'%8GB"_jTh/\ LH {x .ȰZjMCϒr6#:UƤ*"dU8! Xjg!MCtHCzD1tYgcKqY )IHwkqp<\ֲ}TĞsUx,rX\̱93`L y6Eqp[[H $!d?#փΖGň.Gx&b#d.vDL" Iz$4:2hyfzt T4 TٰsiyͧJpS\NA !yb.nlXJ\Qtx2@)8Q׫\nhb(J?{ВF\獉 O XkT"1gKi膴S٠c6꣖GV%aC/sHM669"Al><-i@z$+q "`]#и,>}z}v u0K j]Oe j{%;ccHHPPۃV I G$. w{#b٤" Ɠđ!r\]D{E(p֡sn[A[ 69=!n%J*b!ecmQg:bBOcdTu3r{j=6sџCJ_㕅 99\fa<ܾ5ig<=Q_e7BjŎ&g2;!ӫWx?|tQfɼA.y=qHџWYz׿~TzWTC|`ͤŽg^q7iɺW|?}o_}O&o_uJ_~W~_ pr:a:..O'Λ=cS?s?b? &dy`0G::)g)+΁!*@C+ C+2,2!2Β šֲ(Sؑ.].R"b`!R/)(R4{<8&9d de%6Hh9afBD}kgӱ)(jM\b4]B;8Oi3&`j'eL UQAUlmԤU۶DAoPnEbDoEJu7aB#AYYU'Yquq`A@X8![7/Ϻ( 2X\wwda\ u;#1"-M`2`.aˆE4b4H,İ~1uH#+"`a |  Tv~)6 Af}'(~ߪ_o~V2Mu!\%>d 8S %xy ' 6X{_ iuRQ s4gPPb<0!rX=?qqsq1pZ!rUɹϨ1s\`jU#HD iX2d@XvW]aaP` Ҳh! !h8$v B-џG7a!  9&-&% $*Ԁ s@4e_.~~C}i6h"pG5c |j$iv hcg!fӀS6"QkV6! x 6lO+ J+^!0n=AW0W$PioYuJ? U ؞wRY_Πʢ!! baEbKx1Raala#Q%BFEZؔ&08bRFA2ʶa` 0M!7~ʸaI}iB Ԁ BL\ԟ  l{TMYOq!R+\8l 79-7|rR4DLv]SjB.SSn J(SPq%*E!p+.{Is4p!Yי(&uՉQB㜈ĕ12rPfD@= a&B(BA"B\Ay&?D!PPX09?.>UA$c+\[8ٝ1B\ϷU{*p(abt06! k<1 -[3-P b0}ሔ x>)8!! ld &rA?D "`@y$!000eVN*0řjȵ{wƑ u;gHjm$GΤY3' ,3MD7%$Є* $+hUa(T+4lͨjͪ0O QE%-\nUZ6竼9MH¯\%E\6g:~ y鹄"[W9|km͝#8|-69|*T0CN;p(؎Nn2g"L8w.05Υ =2Fq؁sB{OMy:ۻ1/ز-#g{wpeYn4jyg=PY>A҄tQMI&唓0#ƔF518H)RK#L8-u(#B?^Q d$[N=YsmdUT$I_IeVX>W(&Ir]LhXP{ӄV0'ic > 52Z9*5:⡗V怓mݤol"PV0"%BZ*n=xB)>ބV8~kqiązOVd B&Ff#5bH<á9fca7^ZOqi4pg%O1 5;!+,0h:A򂔍/2Kb%Gå'0j 1'\&1%I|)ј)plk2 YC5)e1+XV 0!qӭ| &j5T1$Ұ6D" &ٍz14$_/NBaMf< ՄLabbFz6ȚdȆ_4dx]LZ2/B/2Ь@SG CZ# a5e2kF;I(<0X$0򸍨p9-kQUC5$8WX>Xь ) UN,U!\( 0xFFBPqJ0skshn9ܘ^qNNF1q׷A3W\N#l#t4>ЕFtrT-(,ZCxBS q@ʆEacRYX/$&S1Vz'a hRpw˗搨P"+2cO#&O0Jkj,\(Jdm" fjMYʦf&K>HZ]Ksn)u77 Bժ(wҶ2Ii#[H!0Pk &uq,`L$,ɪ@X"A%0{ITu~%o{U1^t~KQ|lPF,^ $T," dK9Py Caۨ2uᱏ([ \#΀Fb6KAT򵶚VlN]V"V\YP$Pj6DNs:"qlCbW?;+F /r%C2MAB!/qCZWEHfm,6,*F `"4u#u׽vCnt:m+#86!9hKN7c*6nx_:z6>@ jט TbX% ❍m"rUH{^%K :xICLW<_0_g$'1h]3CfE03а"8_( &GѿкŹ Q;A+ d0` 3Hnsj-CaI^8٬GB qD`R1-rhmqb?0 #DdEL(uqΥdk:Ӌk|H]t_HEQ7j>H sc;1]v?oA0>z9%EpYU>@-!ޭJr6͔m Wpp)v Ȁvv+1l'4P հ ۠; &sw'' t(d0= '28"4(EGR;6 @ l1!B/cM A)> G2!PqS_2!`v! Z,+ Q# ֠ ڐ)ot"Cw*BRBdE {gTxD~&pED mOD"S0saia!cP c!31ei))@g>BXt2ZӄY%m!ZhZZkɁ$'[h$η}e L` 9݇DP\'q\F5!c#%]ӵ ܕE4R# Qr9P8%pL#qp^]\b%  ޡ iqـq_t`Uaꄐ $1$ U1ڴ4?o!:k Az&S# ;o A#ˢ'2+˲-/ 1a2i7@@H4b%R&$%O Q+SKU{mO 1KJ$? |1j edf]`[r6Vkwy{˷Q PٷŴ˸븏 +Kk˹빟 +KkkU' *Р%9i51-h1P%L!#"(ьw]TRBA+2Sс`P@2 Pn `ڬ>Ns# _R( Pt/tf(Prjx1S0aEŖ14ZWXX s!!EM$jQies Ǜ QWɫcaQWk(15@r1a5tKa^b8[7u ls1:/'3[k~"m&"1v#.$;5,s -Y'Q{|TE 0P1p a 4Pq !ܰ  AQtHcHzqBPA| R "Ց Y$pʴ? QáȤ;MBf1W;)"lJ|˱V<9т!ƂEC Isji<%uma[moQtK36F G 3skM:S22mR=Hqǒr{K*R$k ՟|#MM$qBEZCZ0k͓4٨k%&;/:c:P.)-A!d ' 2)>)-  /mSVp./Wtp 2:׾ȁ"܊T/]>CЯ+!+1a r,Y ;/>1'(1Q%%|Q0=SCmR #b}"="l[Gtq4]iLȯ!p01 \/cB&׋[H &_&)TA@!nc$; v,9!FPݜaB*Wdd@X y:PPgi2@ƕޱ)kcMÙJ Rq D:/,[BH@&-Ma5wz'V9kTp$.92C 6dWD^cNHHcHةCk+pqkfV[oɃ!*:,ػ̊ "ACi'"dhb%h0s;h0$(,s̕<ՈHW}m2&f6 8@&wIMX۷a3 ""΍ -H<:!AӘt–Cf2o%cšoȁSclg6/T9\ϔdB&"#,\y p"2OLQQF"t?QkoQ ˡQ1M4YMRQ4Nd'1~ Ǎ6ߌ9%^+1ac.9YIPh:93Gyb$! D"چ&rJH+QF[6 \ $"F'O4ɢn1Y>$[A6*o&{LFDTIM `+)*G1itkA8n@xbVHVr)L)Dy1,*{9+Vq`IZBCӟ B++@h68]p@ߙrB>6 b 'H0!֙Q.ZYl6/sC9_ށG8ɻ` rlc=)'nQĠi6Da@p`á11WӝfխXCϑ gG&9b23Uq`D{4!!W d_X|"fiG5|#"fO0E41TNar%hc5,kx3v9gC`)!B""mrnd&#$V17URc.*a in21)&p WMH3|:ęHj6`1pdcl *}nq髾Ag9U\^:[ r5[k*fq<}!Ԑ :YG;qYQu>\97w|.1<MnZ '[Yr6 0,rpp2n`PeـIf]|cO݂/$_4vo-py `rϰ+#7YgHhN$Hr6;%l.D9K^z rHϴ~زȄ5zea:2W0-N RJ?P ryt-2]s2 7V PHrbp'VO]pAspnHKfI$uBN+aۉt0AR&WM03B:WPX/'A2U\ modYysw3F\QF>tԥ>uWapzֵuB:JbF159;όӉ3 )F!Ԝ8!zw?x7L9N 86a qL:3%;exǧ ͹&(\"w<',|UzW=}eWSlg~V|?|G~|7χ~?}W~}w?~0 5߭dƚcrDQ񚉵!A s;7 tHo8qp@!'@>S6Oy‰pgA2zAs[Y8 )ӶR2&%) q(;&X_Ttœ=A%sM58$3#?SxADX%{\*/{/L|QPP 1 T Q>&aOȻ6L(0k8|3|xę`h(qHiFk>nRn؆f.,nh/N[?`&BF[ i4pbǚFu] E2gHrThŘx8<:?sà ";BI$(#Zƃp ٌ4Z,aD'IQ$EXŜPERSćT$S$XlHT"pF(aP_bFhœ˴\8oԄ0:t3*#K)rO!4%|dX61;o2O9)/빾0(8ФIOB_ QpMQʗ3* lJl#ʄɆ$TBz?|<1r2MĎ|,ʷ\N"A|[H&!a Uђb-ۂόG߽+\x]NGW@l@<+!ŗ0GNkЧ\2O2O|UZtowؗ٧ڷ'7G{× M4 ء姽$O$h2DӳN=(b^!mu?Ah`3AwkG9|eC@޹ap̵{Π>0hf!7\UL(X&9Za:a yd#V+ؗ&ݼW\uM^}eaX916ԊAʶ$gLgD(Dk(m]Ygk% dC&$eP;`@WDgPxyi@eN_ʹKHhR@Y3>}δ ɦgFAnAϨ Ύ)hHWvlQX̎+RݔĞ1`B47V6 yFR~`g$k,8Iೆ~*eAEm|m|fpF0oۗQ|0 Slh̒śõ%Yf,L%!Ot+qƿ+A0%E -|3Y?K3ݴO9$12@&0M]uPxd8^(P _4`ŊeӗDr9GW;DgXqS,RhP#[&aL_bhW҅+L;6@zc+ÊtcP_bFLA+->䁳'+Tnـq8o+&.1춋{;/j5웄dIc6ARWڟi&j A\68G G6G,8ns)`Ff9c/!F7jܛ0~7<Վdø1(8m;jõmtȎUBμM&K,LvG[ڍաM1 pu6sLU&fF3vÔ׷R7)U&g$O^M^A}S+[ʮI3׽MNf`u9² %/K#-.2~–L]GUF9Y֞&`F6Ӵ\B7٘!3 U)ȶr?39frӑ6.N0i5%"`ԨX]94pETpV7fǭl%BY‹jzGr S24%0BvԃMƒ MRdH >pK hB2a.vIXj ԰~kln2CdX8Ʀ'TNb =u_"DP}`&ܒS9Np5&ҮeGf/s+C7xr@G&6Am!z"1@ jDxb6) %88@.?;ȫߣ+Nz<+cěv!Lc`Lc*|ppPLNPBnC#~GJ= =TvW6Hƅy^U66+9{1,ʯ}|zB 掟AkP'f}Ɇ3?6-j3#S\F)R fOh~/ÅP-E^hGPE"_{ސo:@GG3"URO?DNR| IO #ng%+@wMT`.;Ďp414aJLTL :48p> ̎؀ ˏcݚoi lBX>`lCZ[xfD$zCZSIIa y8pFY&֎>t a"5K:0 P MZaLL.Lڣ2jRoDAA.%0ND?QaW v`]p PU>"E>ze%8F]A0QbŨQ&A\ƥAL$$Lpf|!38dL_"]o4d`ƎKD&a$<&AGEd:AID9\q(GKƤO#N&L>֥\eI fi"lej VQU6l7vfWpPn]pQLZ &eA]~F\Ŋ5(GC+x9'pfHcVdudH^f}hGëHYRCiRDiȢJkh?*P%En l >J(L8ğf|hD>NX(>@(٨('Hh>L`IiRhe !bL{PKPBC>Yd:2~LijA1d%dHDbĝ)Ý~ FRljrApd$G2jHjb$} A>*D\jBjr}Aeq KAŕfOͤCVm*L%SNjWRP(DS6X܎#mࣱ s宎6πIq+$+Be#%hjdC/R@Sae@ÑBA֎2P0>CINC"k*,&iBijL`rlfj[Tj*F,E6ɒv"NɪʂfRLfʬzj|ve*7s6,f&TRfw耖fuīchK䣬]+T':JQH,vG_4ܦ| D6-ւSSl"Y9'ZCł~HDN9dP"H:Ú綧iR,Nl`X4f֮i~d~ʡR"*ʢ/}2K, /l*,>̧ll7#>p-B=Q䭌歋GO1Pp-W.fb(HN uf"TїǑN)\ Ɋ" B~Ơ"ꞩ:,NN{nc+b:1ncĦ6.jbqon1}vq/LVFnˆlzoL݄HMfWe"%BƲ*bh?N*V%U9-,p2O/m6-O`r&:&B\fE8F8Ŏyby .蒕 *34A@d߮inq;181j,1q;3_1;q=q6F5(TBVmE$¤n :-lTrR Aec?l 3+br>FKm֭>TDRN2&2/+id89i=! 3R14d"%`1A5Pf3G63[3Rc,˄Rsl87q^qvo<q?kQgJnNrXN4(#bvfQfOvO݀0GO}1hrk1 '>Eg˶J㣵.okd6O)[pi3ws)6eQ]SU:)X{Xgғk40o.6f@Xx{D3V16{+i^#^cF`3xӳ6l8b366 5LHH5E־(XR>Q6'l->8wOxO_@Fvhm(Ka-ok 8h|kStOwrSĔc9cgbD`$QXl"H+^_T).N%0Ca}|#(TI~n\\)d5CqCWR[DW3?c3?z Ki@awR'EZϺz[):[I"o:{2쩜5lܩ{Q[Kk;c;'{{{{;,5x{&.Ĭղow ' )#K*EH|ydot|P|ɰDSBT@L==%8TH@ENCDldJTDskW `e{OwLԄ8\z,|"&>|C*0K~7>AARzӆ]~#8u[APD~R@hhFD`WD<>>L>śp~~ccwqt %wȀ($QǃO?,lz `_hCH܉SćtbP~}=Ri;3`\ 5@Xc.HA|&,h8& I8bD :ƌEB!YǍ"ITAT2wNJvgσ(Kl!ОF}&MsROF: @Ty+eCgC02\sudx· OX.|f)PȆ9gڠP|ikgϟA$]1 ukʕ{g&wZr[6Ka#bJP11&R`;6lcx3h %'S72UfUi.׎U؋ w| )O:ք 20h #,ܐ1FpD&*Nl˲KZA vFhPm N4+M*󊙽їX` q?dg~+V( braBԠM l*L{rH()/ (i ʉ{ND"@39!0jы&1/NRKH")Q$>PgJu;Bވzѳ#$0FdG!FF\K.&J& Y)d$ \/%FFɔVj/8):iJsJ%fSp  _C r$}h)ZE c P;qÀxѬh!ćlpn@n$0> ̳ =5 ԟ״E9ЈrDwHX;0'>{apXR|X93tOzXLz3cU el^!'iS4G>)iIa<#biIh a :SD(] ,U:a\y$+f>lc]$W(KWIM}*SɉGƒF  &6l]%HD+]i!|5^9Wuy, ;⣫d~kNQ'RB\,,px>rJ}20\J:{NJ.v.98`.tc#(ds4@&}oB&%rP:Z Y2q'?)ynlPiST95dm<6ʑ0Vի@lP `=X;IQ+/{V+&\YTn2խd[ Ȋ!mn;=lure#+OEEXp&'ʡbrrerrF\"${{ϝo&@O*FP|5е87>Q⭜8IbjC0r`d7*鵋}‹j .ݥf @h0cqrpDp Dcc!x$&,$G ŒŦ6cYLEެpUM㢩QF☐&.A%[h{y0*/=aޑL9& (|D< =hOřD=iLN>ؐ(?1Ys|ѥ<͛GJMBaaT`"c_S]e'8^nr H{ErۨN,7 bTpFwG`Jk0v.>~ Ukb"-//&b}pf1wˆ%_q") 6Pl<|a3Q0hiKˆ3 86Q!@jKEnHB=Cp#D^nFF߂ίmf"(<+~o4G"TOrJps.OGOГtrxGBoufxNx0 .$N'XC'B MUd d.AIaiV8A.A A'N4@!-~EI2d[ K)  JL$ 0*:4<04( le 7JQ:*,!c(!kG;ʀ&L6@,&g/T>Xf;?xoDh@h4$d@*pҥ!M(PدPdPFDM$P&Qġ$r)bI NA"e{dSq. GѴq1G1%eab/X1)#1HqM p Mm+#=#A2$Er$Z#c&b:xè%1#&.B"&b'G~n'}'2(r(2 5#%-:C&gR+&+r%+2,r,ɲ,2U%@-2.r...2/r///30s0 0 031s111!32%3(W$3f/!6s2=3A^d|C+C3*@=C4QI )a6 NB̲2"*!0S*,iA.$e :63:S)$c@F)i=%s4$ƓS7;M782$b/Ra!I8%3@4;@k@"^6 A$`+8=s+ L..,`$7!R d~v!`$;9?-AmF!{#Vp'4.G$`/ZaB.TCCCkRAorJ.)sF 32nS̭FM0u4|M;"CN9 8Jd 8 OIt Ps"3DĀ >Hc"k J:ROEuT-jTU!s&R!P@VV@ .@QDzC;FZRg .,vȪ4}*:Uu[2՜[' ~BbCU'~W\uX-X BEAK@ Z5ZS5a#- 4 UAc[LS[u @%. ]}XRXρXQnR+)0S`9 uamfAKNaY #v p5,EdxƒQFsF`3"cNcFi^`gٶmK &Efe !#>o Kȵ+(,D #iF9{$)"c0Qmm5ws9s=7UsEwtItM>}tUwuYu]ua7vewvivmvq7wuwwyw}wG xmV&(ZWH2FHzy9"OK% r)@#{ȷ|kxַy7w4?b+҂~~KW}Dm ~IL~U*cG0/ 'R S6Hn3_L6 -ՠC>’Dpuf"jTSC w!B㌒|w*}CC}}!}:nj-~1Ρ!~+hŋyb+H n-p! CXY9ɳ=8Ba!˓>"#`8V7fiam$ bi"|@|}Y̕\ 4xA3iy" 8t~7#.3 ȜbN} D!A(eRLey89@ @yw&!,ASd? $/Rue Sgifiv)z B` H @& ضNYYx"XT#d|j l§#Bt@2necFu?xtl%ŸVm$8ޅ3ą\-I7RkjNKYY',8 ™;S(⠝`3j:L9JaJ!0vr ԠkvzT2sD `9w$%(`7D1GФO7⸕|iڦz}e+ ە4Nk9WƘUɂڗ~{*o*OFL}$If0B)ǹ4=_U ;;)E\4BX ZEgBGv?u>g=`Xnaj|Cöu{šȵ┗@‘ɉ۸s<[uڦ\ۨi{Dh۷Ο} ,N6'͖X}{&=z'4&0:E!|: =)(?|f;\=Wa=d&qu&0,4T$DzZ/D£ٵI"Br!*]'=הEyQ,O̿\̍;ܨgY@%œ-q)u/ ;ٵ'`e'(~*_A'<$}ܤ"\c l聯A0a|A"F,(ŋ!>QEUXL 9s3O$aeZc~Yn MfT]UV#1ddbQ5XjM9(>M;Cg&tijA' OApZ(>~J*gtTgUЗwq ;,E74*N+U>bm >bjAc_*z { 6x΃)k{ Xbyx/ .bI&F!,#4.,C7 "fw ,.(2,sAUԌPkAYG>d4PH'L7PtBk'pZXg7d8+Sq^UX3P=tD'itmxBvZɯ- 56l=4s.Wngw砇.褗n騧ꬷιx;v]P; K$[dLo?<sF~﨑ړ x$8^T%]pm:_N+DH:A^` .-A$(ԋXevqfȭ1x0Mј!NxCb&5ψ28j/zRX}C!M DD9րʸ6 n0Ҁ np!5ʑE tzΡƜÎhLמ$f}tl 9 P{4Ʀ81,rҋoD IāU]Pvȼ'fR%.q(M|by9`H`>hEQ(bI6'Nzs*Ǚ)-$>StlӚ`v>IS'{7Y8bV: L "@nֹ]$\0+*P偉n>VXZ_=G.$q0iJ ( U\Q!H9Fʤr0}؄ʄa0iQA'ԪYK#>OG*A՟µkŇP{Z*t1H5t >Qh (vH8 JP69XjnG?FT(iĢ 'r4 |mT4ف6eg9IO0/oÁxY28SNr5! 4(+ݼmPPDVRHt6w(F3zz&-OHSKk|=&]9am#Gp( ({V|%w x"Rᑎla6S52~L} 1eY!S%@ʰU[>-PRk\RFTN5 wBXn R8-5\(z:%:1}+d `ǖd`0sC0 ODt~eJ|@Mzً:5(>@J,:v!f] #; b@ mE+#m9myD\j1&gA@o2a#yvj |(:h{s)TQ,SW|L4ar?$ݗ 0v1  XjQ&T-VV&"/hAGSʬgeOg`pMy~J}fD0 =s&tޅ"Yр2DIGzsprMQwwx$[%kA`ĂsPx.P*.9!Pw4!xJy@,x=+E7y'.HсZyz*5zlzBuVP6 g{w{|TEVⰇR}WJzȇA}psp!}tUggDSC~?ƇnV~~$"Ð @ Lh> ErPπww!lH a"E7P @ Ũ ɸhtX> 8@؍Z7uhyA'bj'n\<'r(*':09 X Hh>a&YbFp6 rLЩ cڧ{0 -Qݚ5Cf\(0 ԐؾV9.] (@(*{1 X܁ljr&f㔎:vw Ā`-q<^>n l .?t܈ 2䱸K~P[:!`NPY*9zv+ITLE;?F!j,0S1}>vA| b>#*ו𣣀ђ  5B t꩎i)p"%ݥ jR 5Q0a c,͍%~Tjq:GeFO gk~l Qփ&p[;kX+`O!VBjlP^0,z5MAil3^2r6XUUC͂u2ᣳFSO9$?_ 7zQ?O$mmm5/Y#t|Z3 _ʯqRPI#C68ܯ_;!AtPojȥ{k`n/>9|ȵ{'.ծoSw v2gZ:M9uOA%ZQI.eSQNZUYWi%[Yi L7 +V=R;p̝ke Ҭmoa*춄Ge̙5ogСEJbiflwț@|f](-YƎ6ĺb7k¦^uٵoit〫c 3qFkFB| O qH"b>":g͡}`k$,#K0sv Bkf㆛md! k$e(tkDr$ɺ+pflZ$tň :EsRL3tK >@t䂼VP0"(@Rquy)|)_+#XdUvYfuֳ|YjZlh[pw\r5\tUw]vu]xw^z^|w߳⊋ {j6cÒCHD"i_m*J.z@eEEd!e)'"mJ +臛sKHf*ق$"Uׁp 6vJ(":#v!GFlHmp(MFJnAƧEme#?B \m|,2+ybb):vcF!l!@[{ l Wf5ËqG(,"HD#ep/`Atҋ$pC!BF'0HGΑ pU'I n$b&ZX)[%o|!@$b.(U|rOp6pHA:G n)i^QAA92Hԃ-Ad! q:)G(.FbVOqlɳF|1iA +Szo?ˁag0nV2|n &x࣋@BH/L,5$2ً`zv5Xء9\V(>Oٕ'N0y[T҃BPҒM,Faۖ?6",<4^sGry`; vȠz`sZ,Hg!\8gN2Eɢ[23w6@7x FÍ0wBAPP Adh˶j1$}i\͚ Sp6Ʝ%p6 |[#h(^ [f m$Zq:%^h|bS;WX? >cғU(wb n|㭅ed7BX .br.YHPX"*Yor$tk 刼H\og9PqxqlsIvq#}S_-ti24uͽl"+U,R]t"RaDM|7 >j|UÀ@ߘlڋb LxqbDŽn|EQҗ^coϊx3jD{ӗ>š x}uJU%lȈj8E_uRE's.?NI]3nH"OG.#!?"љ4jnG9}5 ^[:os3#4pȀiɀ ɺ @F{(;%4$% '|M; V;<#]["S<ʙ|k+22ӏ 3IQ?KD0ɥ]r2m(qsb'![&)=ćسWYRЦ$+?ai `X˴thLSQv' \P9S|XS,`  H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0#F;p1sɳϟ@ JѣH*]zq& rnF`JիXjʵׯ`-]7vঊ]˶۷pʝK݊4́;߿ LT#W-ǐ#KLIϠCM4nR>gװc˞M!jFͻ :s&>+_μسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXrƖ[ F7SlXcNfj7u8L9 >S0@8Aw9[tnBN; Jϸs3`ˡ5Tq%>f@pT79p4p'AL1{ 4@r78u#)OBŪ/ 49f|A@mقǹr8@#N*^SNQ Sz¾'`SλvZB';*iԙ@N:,F<A;a^hzlLV؊E['j A_|h|a U)u7-Š*z2~ >|9oSlg6,3&Tj M9g%L*1Ts >;mOPM;3@A{)/S\iZ6AͿbV/]jx+{ߤx5{[2R30LjqgxɼN+j$Ի[A+07@^4SV8a<M/І6" TPՊx N5^ d_*G+e| c= zPiaK<ť:tCܸ8D!GU25Ituv9f:D!~UœuM Y`bkNpCn&=@R!6[R:q \@̔wd}@\2|i vSF Ii !dLc9qI7L*WV򕰌,gIZB̥.w^򗺴0`%1̊ġ qA$ f3ͅ<42 pfΩJ`@Zv4xLorF )K鸧Qa6);L*0|l:J9"  anGӌfs@#Iϡ ޕ)͆Zv[F SO6 El"+؅eqcǥD PlMdh5iӚZp))Gj ,I]q &n.F#*A-4X᳋Hl` |BNpʲ+\UX#Z!^EHg$ qCab/o4q_5%QkRa -ng ce`3Il)#t81wxZL#r$6~G? ZTl-WBzƺ TC7 N1{? e]û-z SXqN9~!(&6a[ JYAA]#v@l6-DnCUl9>4岑^z:Ɠ4g;hؘag9&OT.YqlŴMDLͯCQD Yf1ЃW'j8pdD+4˛Y4apNu^.ꩼ@tkVǺNhO{Wt=a;r+~a?x+q2DO!1aяR&m¨vpw4Βy>/!6=dW>=ͽ!)e֤y AĆ ̴Y P*7nqYSr_Xb ȇCHsV  I/1Q.;&(ς&T`nfgeDTVo6}Q4PzU4~A'v'Ґz ~H=[7x&XqO=8Dӕ (U]Q0ZBVk҂ wQ4f h6@8g D0>A_'`(xTz8*j1Zu| V8(t{868w^JRXhp$ \(2ah$z.q9\#,fPP][͗iD(Tㅻ҄czmgp 7/"~gQl؂SPkѐ6jQ)SYd0s hqwdyEvD2qXqDn0aD]c]qf%Cg:P({Q 6zJ("Ћ|7hy" yQ3_jq~&,Yy*$*qv-2> RGPZRIRs=WIwYq VYyٚm2l28xv85dabIș߀P`QUɄYZ=Qb98 zjGPsy$j**c+|] FICXe ٞ)]F|U_c P ù| yE@R9bUPǷY~ ʟI=hB.zUٟ9$9"\dmRU2E]wEʡ[T+Y5X5oW]PakSA5*7'=:: 7~? $t9V9q@ZOdQp;q*FG Xġrڄh4 |aa$<* w OPc1gQzz|KB2 a Z`u9yVP0 UVɣ2 Ao^pXԦ8CO nP— UI|&ojo $ GːG QAmIЃzQW VZ>ʢ< ck sG:[{ ۰;[{۱ ";$[&{(*,۲.02;4[6{8:<۳>@B;D[F{HJL۴NPR;T[V{XZ\۵^`b;d[f{hjl۶npr;t[v{xz|۷~;[{۸;[{q;.DXЋ|br {)gC OUw&*F|+̫+5TX Y %*ۼ{5`BK|&8T;8Xπ`X;25gSΒa 5b\|(n:" 0 L-#ָ0<""\q".d @@+@  ;÷iH\PYh\F: ^|K5{B' W) &r4^6~8:|1,.>S.Zmn|U8\^`b?d_fh?Ի+]`!Ҟ-Bt-el "Ym=ҟ-wm!s#m./f"1m]u겝lW>_@ܦOk֡]]d{m=*fKo>١~wך9&\atc'_7|/"ę5oSnckرef8sΉj'^n6ZXr?^uٵL>:N`Sc^kyկG\X{%?adoo?tARixѐ"CC%kit kCEcqFkFsqG{G rH"4H$TrI&tI(rJ*J,rK'0ʼn/,GLs>IsN:\i0\3L 5a-o';UtQF%/hBRJF/Yd >ltTRKmtr!UUTЂIrT4V\sr5WAU֮Is uUvYfDKqV3Sǚ[pm6iZX J|l ]xo\i b F w_Crh%5 :4`#)u >SX7cCydK6dSVye[vecyfkfsyg{gzh6hVzivizjjzkk{l6lV{mvm{nn{oo|p 7pW|qwq#|r+r3|s;sC}tK7tSW}u[wuc}vkvs}w{w~x7xW~ywy裗~z꫷z~{{ߠ4O#kx;BövÇ/k^C~ID}FS@xc|`8э%|P܏.>Fp99ޑC a>"j>8 P"B!s&a .|nTCO$ԡVӆ PtY"R/r!EPǎ#%Ih;~>2i@fe/CC&:C$H1@]6їO]Pe"I/)q s:mf(yOD5+GstCw::S =yQfThG=QT#%iIMzRxD>Akc|([R~(wX5fiiQ=dMԚTd"FA=EjR)j~H% j*\3yUJӖ3hZzZnVKYSU8d">A~V O-kX6mɆ%-OoƾASH|mmm{[Vmo}[W%nq{\&Wens\FWӥnu{]fWnw]W%oy{^Weo{^Wo}{_Wo_X&p |`'X fpx]9,[ < s -L`|C=1b3ą\qG.qBA[Ґ1=|8GϑeT,cPmFf) 1gA|01e63>Dcd8ce9-6W3 <3 z318p0h2I M `5p ȺFZz!P$0PbBuN&Ffρh C4@j`,YOD-P`>|. O&f&!EJC r j`O.L0vsnbx$M33D4hlL¦.Hd pHG!3C3B98s96Y\"t/79c/Llr)ksTέ~ug][z׽u]쒽Dfd#?Pl{6- :d "v+.P}8}ŧe`5rnhތ   8r C/Up~<XAQi {4j|*Lp{̫E{WB‡OO^1 ~8?ˌ#&7)| {57ϟi7 B "s@u6~䘹xkS?08x3s=ah>p;6o`"<+HɻL? /{6?#/;p3?rs14&J5xt k"+D\shg`sx*+$ س@81s{"(p'؅#?|Pćz(CIDJDKDLDMDNDOL 酁h g9p|0ExXELO$3$sCɣ<W<S829| 9l[QիF@[bFbćlX{FX=3k5m\ !G(5tGX [2GٸBj՘0XU83[~ HP@aVyH|HXM+;w<<7 jADjthِƘxɏ|HII@t "9E`8'q[> ZJ@RG D KrHq@KL,L92-؂5Ga 'JF0NpM<]:d=C֠ X e ĀhtGT1 \4!σYshiO <]ŒrϬOŌ8PD; 蘆qPh@gς44A :@lC|٫C|m\'&#Q"0"B5`+R xPh 0s) Lڥ؈ "񫺕=Zx{$T},l؆㠿_D9ДI@怡x ALTXVH_`"b@܅Y|m@>;*80ܦ͕cȄR @Gň]%[q5%;`]1jhȆ1M[^Xc?c@dAdB.dC>,ނI(FH${6JnK>YCdd^{R\*UV -Ж``", rө峲eb BQl\pfF >!]C#I&:jrбfTwZr ,(I[j4{l wgghh.h>h劁ؗtS1qHEWɋ$@蜨F@A^sΒhpIҁ%~hڄo4霨3aiw* < B!\nI.jo.a8:0Nj9v љ2>%j DjfX74K= Aj k:*Gl@>lNl^lnl~lȎ$AsU~)(sH RV'F~"8z+;Bt@!^]Jm ye$T(Ί9K]YƁ`_4tmnBֹn1yΕՐ*0ltō CC}gh{3n9o@$%֍iPbbPb[)n05B $.(X&zԼ![e&X%Be$|$y fޭ*hr_V ~'x 5 1+:(<>(9֍f27:'0'Y3W3G% 'sp꒾ͭZߥ^Yq ܞEN5(%X'v<͆mnp t5t&.膿VUtGNXyv\7ƒlpwqwr/ws?wtO"Acuhyox Q("`" .>P(x wgpwhxw*#&gVGԍgX|Bpcl=?paG0z B#/y'`vx'wW͞x2~ &w&xaP P Vh@R8S7@{PWhhxPz4/6 Յσ 嘻&XnMCn@ pyY|0b||m#l֏FdU4".% GzI{xO{NS_Lj0|H| |`aȅN4 ,h „ V R°w;Ck .$*Xg4C!fB2Kp.p-j(ҤJ)ϢA JP+(KeE+Ӱbǒ-+v`9qʁ\ڟbMKltˁ$-m,nSOO0t>m}3ݹl^^:p[n\a&WEˡ6nܛpdH&E!w,iSM,m9M^buSr}r4Nr&vPﺦ4ʕQ >x 4`6 A2!D!Aj8!>Vh*!B)xAf&"5ʨʋ*#A IC >QFZہCACQ&1PNPfJ4t6qb@B SzT/㇘D 0B\p3%xz)GeRAlQW]PUW6W_>%NZ45g:tG 7=s AhS7NAT{&KDc6|#N6dLEDJJi/xyݵ-wζ Kl6V7酫_u~YQ%h`>D ~`(fab(#(">"Rc57HP9*QD͖QBdRF|Z7m㵣Ăl:e\PZR)ibT(ܨB"6>D<Nh4ԉ+}FMmIiB^RÆ3{Y{=^pE_c܊¸j]^Ĉqdy%>k>Ѵ7ME:t&oL&A Al[qX\s_O5pb=X ΊYgOuʼnmy7S#cByOA- ~ȃ6әOHlg4J V >[EEp$ Q!0$*@eX K/V#iQDB;,A b8<*BHI% 0 kTc:ң0uv XTӺ8^b-"HW  #nc䮚;T33!H6X1DT +_Y\IE5YM l68.a6 a`v8͗6*7sS\ !4'8-r_pM1tbA{sA0H lCR!Z"̡H\4Pa{V҄Z%J K &4U (0D%E52.D'I)*Do&:g)P\X!{tA˓"–VK\HCzBt1Y^-fM Bj!ױͫGnVϲp3} JpqN:ߗGD~:7 6]!g:C cٗΎgd!vK݃賺5Y$ЁTf'<۳Wg;B`kWEBgB828_v'䮟"6AMC^i>LFAȍlIVbIE#ƴZ5lj{-8ڲ(J-)x6!Р~>Y2A\DVRլZ[e[ ⫍8*%|0 8s[Vhio{5pF҆|$@kb\F36fkBXz=G9WIjt:9b_|riPKW!'4SQLlzgi5.U4%i)Ix&zJ'5B] &fT( S( óJ.19%v ɸ7~ d> `xtՀgĈK\A@:_A48thGr3D:\FfdGpe8]u l׉DȾQhR SR0!N !!Ya`8H8ZNY SWQ!""&".!";#*N%^"&f&n"'v'~"(("))"**"++",Ƣ,"-~R-R"B!"0=AY#2VR(I DXBXQYRRܬd*XI*#NY|$* .|b)}=RĤpnA9@BC r9DAF3p@P9ƗCJ;CPy^:*-A,t M,"3A`rLP&,%A<4:6c1J1J-%FUQp,Q̡B [eA4D o AٹeD l#܀}z$A|#Qҧa=%E8Hd#8P%&> 5aAB8:*D%ZTpx Uµ&B=&6ht9CAJP1$BP$;7lCDN6 ]DZGɈ5lٴQT@ôe"[[D["A\0a~p `Rd`ڇp&b,$:OULfTf;*N,Af˜gT%BE0T%A 8pBj! ]lkmpmDYK>d:9@BpEfPcfmEP#>N`)I$y ]H<*f^C,z⃉/0LCjy ЄDP@Yb*+6lB (B!>xI0}Hj|ĵ\ A軪*AgmϊnOP+zCkrҮZy}BFq9fC'L'JԦRa,*>*z BS R-6QBx6IDP,ݨK@Pͱ2")G@,/(8Dn.e3/]ZqfÇ%4K0D3FElFhq0/>2y+3ʩN30h,plA4tTEXq%8GlA){,uGxO0(BS>õ\D|pQ(0Ȓ(D#HKhnYK4H+%Jg6-TYkKe *t*#$u]S7=D/`  F޾G0O:@N E~nAأNG fSc;J}TALU.FL &/&B.D.!Md)nh$}I,b3dv2>%1]Ae0#A3dh2D1TrunaO'OOc+741TqBd(;,1Us7<NJ)mQ5i6iIgA&,WP5Ad@O$B ,6&g6#[hA0g&6gtk<3\h78qwt5&s[88478 Dٶ5N@=bD3>qc;9UEyA55E;lQiCCLC=яIzIx|WBHY=1 :[)|v~w+ :AA5PD7rkv[3DhCk3v A om +ܰ3sf)0ABo0+)T7 m\zu֚ft)אiKΖ7/s爽r 93.ho׹k'Fٔj$W떚IxE0Όṻ -'.X3VD-"W.&O\h %S"8 0Q$P , c%B:<ȗ-8۞lͶiW4GWL5H˨\l<ǕU\S0,Ɯ0p$6|N8𦜂q"Ψ<OOkiw+ 9K-2⠥g΂Άe9n N8$|a.O4250| ڒA14t5 АC(HYxpBR6Ι*L+H |Jk?57]vΜSiL%S"1g$eŲvAv=̜Sxwx }fg)&Z' X1_er3Nǻ><&:\xP^f]q4/3Q"fbqgⳍ"4CyFB頟QPARNFX CV4D+D@\{{1F[4N:A TH/~lKYm]w L3U1(ݝmu}|RTJxQz쇻>"*Cc ?Vlp M?N,g qMDO4T]׀!uoHAw C9yCAXD#ITD'>QXE+^Y&@N g)*3.ui/>IIS0 8/.`b< %@  9$>,vp<-07Rp`[6DH!ScG3U`%S<#0bgQ| t*yrcfAC87cԧX]i9Ps,d[-(H|6ҜCpЩq##0@<" fFy:DtwzMlN:BԨ|UTЩNF8&1*L1Ä&V%*7aӇ\P؂'q% aRmtt*_UZ;Y9r*Swz(Gt;ᔤ3$ (R"*YCvuho)^ 0>D3ATyD*Qޮbɪ9a| :vfv{$B wdEAR0Oh t^ESZitRE(WN ]bm^HOL2& ':c{_@e(qdKS] efT1SF%G"WACkq f83t*8,$ Ec#Lx47hqw",L,Do*MĦ쨙FiF8\Ґj!M0t XNV f8SD0t"+:'=ב^b)SS[KRvRmd PnVj8G夫0Re4(| 8:(JlTK%~Ȧ\& OUd >s.ʙTRQrQdԆʒ-d&?d3qL9DCCe7a0F u6?j^>W悺'wv S5OSU6< cNTUǟYHܑ0-C 0F6̤/oi:o-΍ R7Fj*W}'RYWҞMԧMx>&WWj"cPZɠi6(5ʇwt-% U70VٮPT'Ɍ&-_wP3 &БT8aJ*Rlڎ$8*3x/"XN~L% X :d1=1La؏r#aH1<\0뇌.=4f$"L)V΁NHʮD  n|N&CTAd ~ʶ c4 TA 2/I~ˁjפba'sB Qm/#%B/%.*!&"a,^<{/1o# µ o*8 m֭]@ ,"mmt"J})p8n 32" Sd )svdK !3A:"5WRN$E<J ef&J/ Av0|# A'}2)3l#*3!6 F ?Yc" k!SE M1EI!CQ9w Z "ܥ8 S08`:e"`)*">\XYOjl7vC8Q8Ρs*a:K ^!4$;~,:- | Qp2T50 ; <@l>= @ lTZT*I> : f4% i`Ӱ!pF(rD pA2! 7^r9Tm$A*ρ?3q=D IJ 82&& ATشI3 §ٲk2LnDo[3"4Uq V [V*gSa!T*J ``2S6hˆ1I#9,+N1"`P3D./.. *x6+6C]lE ȱk!@*~ bfv,U /,G@R,"/qAi@l ;aH.a`P=/SXܰNN-##Cvo"pg+j%ztelSf3%PM&U 3^K00 W MըNMJpT"*udM|8j= @8ia+G**+2"+7-$zwfq"i4"!a] @[|q6(hV!ZR"Stf%j uUR"u4@`B k6˞.`XH(R ${P8HYҟ6"RH-TL%bU@fN"f^&מFh2w1p.RH/ &p^fWiI*G/|9, Vw L'BI9HB1hXv ¥!|Uxx]C02-H_WC(z "nD7y**Bp\xe4e!⏋e/0I'%xB p'Ƶ(`o$Uy~#`%2h8Sz˛ٝyv\y%gȜ(O|ع ڠ*yMg(]Z+ڢ/3Z7;ڣ?CZGKڤO:OQڥ_GhBocB M%z.2-<,Iiu7h8* Q ȵx'A'"B 0= vN)hO!h03’rUMH&"ںMIb03 [d)f:x7( Z%t*'id ĔlmzRVS"pN u=#_@%ZB[_+ U"b)"NM;<;*-û *%k˱d%)m[%x;"@ʗ @g v35"JW$8H*zkM[*l%­ +:.* Im7}P+e;N+- %+"L@k L E(+ CUB'ⷝL.ոN[%74?{( *:.ȃc O%:4ۄm'|*wܥez] 2#d \^RWfD7 @\ ^2#lWAfST7U]lhCN cq8 > vGB;b|Bs:&  ! ,iDlȣa<60,4Ѐ=$*ƤTj@\h ĀQĠF|x]XP>vÍYUHBڸ@/ƘM 9V(`fB`bȖM[5$Bte^yA8@n@@Ig6B)0)`yO:4 90Lu.(A6 =0Nx45=i9tAr&B㊨)1P8)IOJI185>A4l¬" 5+B-zв-,GtkLODTYlne9 XeeoYC5¬ +qeL^yc@ dԶ%1AELȓe_sjS%c">6,+ =;۲; 2)'rқ|s62˸4tG5BuY9xr=4chrM-ya]a9` Z(e;3N/ 16h#9^g0jP7=VۀiG%\6NNafS&>f)'>mYmtx9y&MC럷 79|F⃩p吰y Da-@ $Y?II bED\>a,a d {G\& &}|0TMPzk^6C\Ea ̈HXJf!!.PZ l hj F0 ɺ$d2*Lv30Ha@B/Q7A2F2~&1b#̈?ڲښmaWL2T)#-h 붂ved6efʾFj.ԸdYnМc]FhM)Hz,&hgh@]9>TCѰOٮҨoݔӷ2hߔk鸑 MlG ͍f 6,GMNAā6.Ă%((.F{TX_ǾYNp 'Tlwpݨ'E)V ~51oXsEX)@iKrS!4ҔMTe tc]k)U|\ U"Q3xc%].&)I. u'v8P+D|]m_O556c7(=C5K;[;8*-F7rFV6ddFA,)MvPx!Bu?Pg~UA@ % Y <S@'2&@PEa0"Tkvɘ "*b6 :x1 Z 5*:Qf .1*%9%  Y8(AxQ#6UxqN<^9qB EzY"u>; 9*d qCOvيrx@P£рB9 q- ڒ`CA1! #Ҩ*W ҡ@+СҡF!)0sb"o, P0 : 'oE)!dBq';xEٰѫ瀓A$dr%&RV;3J%IârN@‰ Pf09h `yZ{ej FaU)g6"X*P%BHPC{cd@T@Fpvk?"Zz=c! C1-sz6Ћy:h-؄ҘH864e!X 1{)2IdN+f4J q'pckP v P%j'*e[;I[@ˬ򬑅Nu{bvہ{ZM#PJ y~oԡD,oQj&B bx `;J:O=oa*7ᐝ+ P #JRcK# !>$AZٲ:k 0\! U#rgeâ0j1kj^w)gl!}K v!Qg *- #=Rn'P*X#C"+-~3.){+ b G/;[w6c 7 l'(6*ʢ49h91JB?Ba3=59U9[j9 0| :b1 fQ<ʤ@,*+H ԡ z]"F&S=B*&ZLB!Ny¢኶LqNji#rC oML8v\Frd*Ȏ .kC0r%7stӨk02%OVQ'C?IY`䉝H`#֭,Z4iVMw ${JQ$Ll؆ Ys0 b]Ѡo!HJt_% p:N0?JЕ-$} pRu,Ps f- -XaDe5uy2i,%jv֫<3~ \{ WE7آ~j b\{mWnAg5#Ym?qqs PRә9Onjq(+bRGжCq `HMDK]WԆ:\ OJq&}8\5>P^#*gv~72ڽtDEbnz0yP:MjK&| L΁Y裂z>YS{z1j&FMa>wz nunH@}r8$0nx.H#L(#8fBUTU^ŚUV]~VXe͞EʖiݾWnUk% [\bɪ/Xy͝T6Jbs?Ydʕ-_ƜYfsF\ΥMjM̯ƱWk]i6I7Т7\pōGln k\t3vuݽ^x͟G^zݿ_|ǟ_~_j D0AdA#ˢrFrFr,K$--1DBI**$^ "v+h(*@!Hrȉ24r"%z(Úҩ*r8't (]yGɅ֙(:x,S!{7B 23Un>1/ +| 'kqC 4)]Vƙf; eh V 1*(*[qmJדѤX(,aGI 2H̲+nr\r wrBr)65 tq=@O<niFa0Ϧ|ɸyE14Q"] _p0Я xj #CQ*Zj̽*̪[i.piޖn٥竛<2[pRwt['cM-@gMBx *L>,?%m" 4!Rj󆹾(: Km(u D5ݐP%fk6%TUa-g(#1t9F3 @$ZqwT3*$igd brt&qsAGT¤ -j|J^6t w#`v:6. K`7 - D@|R@A&y,^7aC 76řgLțM`{K贝>pJ1ŘDZ+egdLa\%Is7@զMd%©h.CÇd'HtHL4d*uqlFW@axI`FJf㒙<&́Ij.aBN(|/FBۄfY[$G/$"iX# Ҫҁv`YpIniܰK&-°I2! O8:l Avt)CP"?|D|p+V?%a1C 6It4["ᘢbԅR5 1(-qc֒7Gf_p 2VG2cD)შZ$) ue+XW2 VٯzDB)Q/%  !'5zAk7iD&ID1"%R B`_i3[: ?NuYZ|Z[Y`ωWSyOsm ʵrP%(ږ \pKڒD ]G> l8|(ZplI/VTʔ@5Vw7^9M-H})}~*X쐪Ԉ QktrVy#F242o~ɛbI,’b %a?^E,MyV$A8Hblz,>`(\KbSd孀ٲ&@cVHW2EK>Ʋմqu{o9͹MAah\S*nU1ZN4u;J%~?Vf XZ̗)Fêd >GhFrl%"وQz3QTPp0* #e%DjhC ̰îڻ{p}*ʼ HCrs8Y݇d+k;\i 0y(e>HM/AhLA9#q(+m'-x-s1M\($yLA)tUh2cHG[&ŪZeVj *Se~tW^)#=[R=!cKu"ʦ0RsHhKUAaqYZocX+< K:+v|lկ+c-R pਲkB[eHaLf|0-S(Tbθ6l!smsǼ(rm\E;y=ib?ւ4@s|1\#oh7 hfv!fcTY-Z  n2?aLrCH*A*;ND# DCb`qАIq&Lr&]rP*v&n٠+lhcJ>AL9BڹL+D"|*9' :"y6 cG5@S4Iq?(N̆ p3 /P٣\ ,9 0b|Il;|+‡1㑱{%W" E)#&rs*)+$i:A as=y䫭 E[yCٹ-؉HR㳴7>I4F>K|DyF>dɕ|uyCɖZɞɟ ջh\rs !|@LjJʬʭI #Y 8ʧQ 0 @KXK˼˽tx YLTdtDŽȔɤʴtR DD@1j85MiUL+N,&P=J0I0ͯXN*̶}DXЎTN +nM O1Os"'|pO0NqhήωA;UN-"Y}uI*NC%B~CadgBEvv̜OD8US)IR;eb"4N^qZ~ {a } 7J@-Zdc> %f8h押AuN&WL8e2Dp;i/X[Pzmf+șp1<` %Dݡ;a`5b0R /Q"dV"b,mfZffn/d%̼8țqfBU[-R^<ؔ?Ey֐@Z[9c hjzhz8vh';.Hmּa)fiv4 b~fp٨O5u'4]BLl댍jkS2)6j(\  Q*p胠;g45oMk* ~m:!hmC~f2i%iQX}=Shͥ^ #6$I@y$nn/2oo}#k˝@*QEbj+QRhj`w`4X ii0}EMhn@O.%j /l|iEg~g\VȐl簾oSo+|aȆ(%mۦ.mƇ1'sGpJfȺx >xRj@d`ofigLsn=PAhH\.`rl#ўU&oDZFuT,/nr| 3sN]?Mc\*9kX1LC[8? @q0w @fo[b"p C"8e7udnSpTx=ܻ!/r6A\0(hrF.Y\'s>s^x( er ENїeO2h,%vs @NWCnxnL?b0@z|0ڦ|Eq8?z^m.|+lHu(h0Xضݹ.?*1a/s3{0'GWgwLJȗ̏` ˿|U!=0 I8ӟؗ|4ב IqP:`N|oNƇGz tMS NOaJYQ)pxW61~Yh  *T(r 1*rQq9im`n!Am8vEЁw8+|+NMG,,ݶ>vw\8tc'[m=`㦘9b( A/cQ8\ՁL֮_&/+g1g=DDTpEVi񑌭I9μ};޿Y5fhePÀZnr:[C 3{1#_Ct>U`P6 ThP(|& {q!_qı+>E&7lPgS]bO&c%6Ad>r׃5O:cX#&=eERd oCLW`Ӓ.j2ꪫ٥ :܄ʢlCjA[SXVy3{`à^ִͦX40RP ݒnScΥٔ`YU(Z)r4"Jfy(N>c95_4G:6&)\#~oMKȱbhQ(^ JBl06"\ho"f+W%h+:ʛ! G,5 .&Kȋ-i[8tAXt-'C1!|^WnQ)]FO4q' +G40#q^d76hD|Ds"Q|qT&'%dM@_lп B> rɤЁA@T2GvYVNY]z%n v7PVZBofӛ|vU<3޹FЉь8@ }08|u {>!_Hd0 N.KnkA,\<\G8mYr jWX"n3Ue֒n]Kh`mpz#!9JB8aQ h"a6-!18Jm"TdBۓ!|1a8hc"3sA‚U$B!܀>-yJ4# !2v :XpCIڍKbȁ-)3$܄zHCR5R>P^%&XlLELs 6,SS9W-va_l-ZL>!2g&YX<$s-J7q*oڒz@g'8D0!IeeC"ݎK=cܱ(@%đ-bhtŶ!fO7Ç06yCfLM;oR 9% Kp >exFVqyDru &G6+j<w݄Vusmc=Z:׵3h(%u3L&fGoXқʁ9]?\n=z߻]v X,{؞v!tC|;><+oy]㤠):Nӣ>_=[>=ko>={?Cv5en󥰑*@!ʟ>44N7iCBEP"Z+nnx>FA& F#_ʹ~&ŴI͜[|L (DqhFƩ_TtD䍇pAGHAFD `LD uNosV!1M=†fEFLуb(Ɣ UXA 78N3LFiCDZ|.C; L9NBfYC97H xAG` `8 nDuU+VRGC.aUDuP0mPaacaaq`@|t >lN@5DCIcFCicCp`@$YL܇W@9cq` :63#;VG̜d\l(2ё\EY%,(=?6޺VJj䝱@ECF9l>TaErZ{TH<)R8N@-D L$L,nSVbQ_q0dCp Hc,caD5WZR6Rė8{ ;#;h4<hB2e18d9["͝![@9 6l[:\͢@a~1`nAf:,CJ ݝH"#lFf"fD$ 3܁h lAM ')D+DOa%,A,GT٢QZ'!elC0HQ Č%aTNcOXUP\Yr7@̠J6PG ,jR2`(ƪWU LF\Rh*>\YV$*2HGhGXi"k9h& 8@AxClC+CIj߶D.ҷb-܎kodr`Jघ"xs~LPN k.Q5d[%lT,kAK;6z\,r 3D/54h;j>ͲlFAlG-2ю(E @®h@gr AA(k6$81@04CdAj2LA@)>T"+qNmHmb).!QnboijUvYd5{{lE6,Q*m1T Kȥ#(6 7,thEo`baj@$RC8¦jbV E\&n9 YA$oE!,Tnn6|m&ٽ$opƭ n)JgꭙkuoDOJPt+(c(_ެ$Ľ[D)ш(Λ[ ٸh/崙EgWP`D~ޡA]H,L1CJ6ЁA@CBZ%qBJ8\5䉭H/˱Z-Jj$dC!f6diHn n=TZΚ v{⣀0nGR2/VcF#SVb]G[ܠe%7k i<;%O1Cc@t8@d^4/<Ht{#kHgýI軾=vçf+a:q I`jzdrqظp @÷ܹM+'Nhü)\(XE0@AQ"Cb>CpJ e[157mrB?cZ*X&dz84wPdժ6_jeDqEa4|=%h3/fu8sڰRPb&:rƋN %\dʤQqOO/:"l': XŽkɯaǖ=vm۷=8Q6(pC 8.o؁{ ]:>QrWVwÃ.볩![:s Nǣvѱ.9GIG:s9P$ΑeID0iDHgCMTq>i@lFq?8ԐO=հ*Apa??nlIจ@#(K|J\ .*|M@lΗK)CjjXhY hrQTT-%bP LeRp +J$#TbŶ1*P &F,U[-G:T#KR<#%PXGhS O23ԇi0 5!VR"uT|=a3&]#5хVYtZF}QbՖPe!ӡg7۠X2mVlt|ݖ*,a}Q>لcFq;8_KNf*Ňno6s4駗o< b*mȿ낮n)H)ĎnΫ B Ip>f*+.o["ՃsY;ś1{h2B&Cd󔣼V  sL[1S$4D49KKu-@fMz%5{YT$OJru)J S{q>ĥg''D]H+" gdEjy%Z08%M$_3ҩE,.`W6.hJW6'q$P*_יX;+$fw\SW *S琘ϭlefh\U38N,6i3ŝ:F7!D&:iM(rKa7%: $l<"E+\) #H$ AURtd"ӡk>kݖ٥=kutǻsԉg^{%@xSI^D@XD5*- >g=i{6r͝t0a6ʷl|ּ6n^3d3B D,0)jU18=E"9m )=/5A!ėL'2t/ΔH{^x,(D3Cy! (q},Mq*LP &C3$ԘP8I3 bx#@ #cA6gQ èF$!6A)*6# GYzB3dyCy#hTigCqdZ]Ԡͨ9ͩ# 6N! "Yұ րbJWbO4W  dT;No9KV aêC<|PSjT=L!3LAa4c|2p잨n Nw0QsA\KV: :BpEc|zCWZ_=.E/NO ͭQHo`TEuoҋuOXtE1Eϳ%61l sBbX$Ft8&TTT \r4#<_6X O2{J֬q>7! |`k#ԍqxlX.q%@fnqdE8A,f/Y.QRhVh< L,aUe=}~z##msh>W?vcAb NE! W;RlHZ:!!!-5;mAՏ`aړ kRR\&o bSFa~$;/_N%i;{ÇJ{uF_"@D0@j_nP."2$"^O.(`":/%+LQ0U07Vaбm &BVG2XՒ hŴ)i ."XO 0 06HAFp =5lp2 =g  %F&& bʞH. ӏ0pO&C ðSƗ̋ 16?g&h -115q9=A1EqIMQ1UqY]a1eqQm`х}1qPKΡ fk/$0j$AQgI`?K xQQP6qP `6$A 86tt*m@rqzQ<ޑSmd6 H4r2L| RF1'*6\"x'qIo1=8LwH 6)K*4)6taƓT+@ +LA:\/BĒ,]oDz,Jj+72.&6Br@0ABQ2Xva2o2#2R3m/(N$2 2#5P A\e+gc X $z Ԁ@6NRڠ C@@7F>5oJ d:!#NRndbbc%0->%A,o97l \f!*z`RZN=# OZ. P,!l@18*z@)yScKNQp="܁A!A!ƓF_ kc5ddCt=&H+<$k6)k6raƊ .h iN*N;P9&d:Tkd#L-::4EBM*C"d=@1>@{z2&TB,M*`,@E`Z$#0tKC1N}vV $g_&Ugjz OxU9V499YYW`(wKXmW3N~@\$K!q_? RlOe^ =t5,U M6t?:@,`kLL6:bg sk&'B4k:d<Dna|WrEedj0a;_b5O@K$L@6,,ώ瘌k'DkE%,S#0TVb}>j3eh%$D"}.?TzK!{dmGVK(m_׀`o#Hm:l4{cu>A'$hq"2$@&TGczׄQ8K7`U h 8ukA"crrda@H84z'CyYy z(zRz{7W5ÚY Y#SVVc₰VWTtY3A)mmXCLnm!`]e#Jt ryA3! boi Ssm2!Z2 نKrxq9ׇ78\%GhC85Kif*qϪBI9I464s5OhV21S7,>FiU0>59m!B2j%෼(2'}*DFX᷊cUqHـmbYYosY*sC|:;p r,DTBoMr+ת3sA8:6j*Zx¬88a5Ɛa/wڌlPF®f iSFd4m  #ERb{7Sm:UX,ӗS=9!A58Tk7vTV ᫜B,9nQRtQ{m-> Nz B[\z:!ralȸ kBڻƻ58*'}gcCNsrNA D;:῿.6T%C *BH{zs!!X}o!ڣ/?AԐ1.omjW!0#T;&`9"R pCtD5J,ZSÉKa{YJ =& r=.goG}tЦ(\缹A!=%ݱ"N8>$@3gCn#0.}oHyQ=U}Փh7,h>5e18ha%y}؉؍}2JIke;3m?_ЇQڱ=۵}۹۽=}ɽ=}ٽ=}=}>~ >~!>%~)-1>5~9=A>E~IMQ>U~Y]a>e~imq>u~y}>~艾>~陾>~ꩾ>~빾>~ɾ>~پ>~>~+ uSf ?jMlDaRfHʠA0# i#'<$;A4pad?pÍP?F!Gv`7d`x/  B ƊNb@ƀ:?zŨ$^V?J(! R4F!>2kzD$B ;7 u{N A DxRq؁CPC C٭>nuc'tY[Y3ifN<2NQnR6pFc5*>Xj5JC9.ۮڸ-lq˖C5KpܾKk On^M`:bRՐ;s*:ntDZ+[s.-4n鲙^ЄkְQMiٶsͻ Nȓ<ʣKN9s-R4ڬEe0qn{ڣo|si{zA16A"1b_:xġbقSH֐;s98^}eT= B'ҢXp5>nEF?N[l8P+DXjZlѤPcchFX,i@cdHSsτza3P#Fp9RIy$N晊dB&h>%sS睇s#ӄ.B瘈*Eh}bX։c)j*Zݬj뭸뮵=hb*IJv.rY6iԬ$]#gFG!e`cP q!VVTCC8W?FщH[@cA>}Apq3Pvpaŕ`%C؅ȘHS<Ři"0li3&X )M\6HɖAM K I[4>\u\4ٸd8`5f v_kx|#]ujbǎF39ն{ # }Njg6 *knIR9U=Qb-t<7#JAV E$$;󊑦Jg%B92>Z\̏=cG XeA;7L '; VG%PyAi) -f`cloR9cl, Wpp@"0$9vkqd!BC|\+[HGG؁G-AsnCQ.<]"w|^\F NfFAk"bLU F-N8⒕NiA` ).NЍjM$#4AZSK)Vi*@*U`c1.ft<b 5onzEpp;L>΃HV8Nrt|ޢ0=<&(U<x-]EpT!Ɓ/r> 6 2"IFł4%ɔJ j8C6~$)BBPofTSV#SlRj sjlRcЬHz$jT$řXDHs1m=\J׺*[|^o5w?3R=|C#ԨKa@-kA 45;0+Vؠ q#n+}TcHo(x@.*Hd!d[Ac@ʤMb P@ඤ׀P&@xƁH|p!/>NЦ'&EH~ 7sJ [K 6OgZV~ȃ$T o+g^E#p<- ,*H$2dC~c/,EɿPöMCl!8Ebqr{/da>tq _JN $keaWqAxAT&-+qrx]IJb Amiذ*M 8 WKu-%f7jpdz H/U(WT T֭~9jDm1H#[QY" wS 7BV􅾘 HH9gL:|daܝo];ox89k):g'`թ ]2HRz-3d 1 >΁ G(:tX}j{UY:ڵfp'fpO^r6JEκ rZ` g[P۶0;| "?w{EڅVz7yu}Q^H^8[%OgG:Oş50B}Ͼ?!7,3 H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0c2Mxɳϟ@ JѣH*]ʴ4ظI%wӫXjʵׯ`ÊKlQ۷pʝKݻxŀ/g޿ LÈ 9V#KL˘3^܍CMӨS<\γc˞M۸QM{ NqÝ?>μУKWyӳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\vޱa 9G78l$ 99:y8 S #8S`M9'>$N4 A٘#bΚ`VJ.}mcM_М98.߀7SSdgꉏ8$Y# o~QɉzkӀx #*5Ps AWg9A7$G6mNs >l0jBo|XI9*P [U(+>Fj8ƫ1`bcSN,c9f0Ë)PāM=VUrn,]r9! Y7⌑0>' S ǟ{B עc:YCWpl7`0 v+Y d fZ't9nGVr6Kw b Zw;  Yc (#/Ğ\.VZl9~g8P7̇ )3>v=sm#y{Z87M7Q9I'_<@F3L/ڦv HL:'Hy>08 rP EA~!UXB0 $\H6D kCP?ܡ 2 o E%* hA@8LWP zQK+ èфhϸ2ьn C9x#hD>*яN%QȌXc@8DtAHEtcوØ!|*Q%dD7d <15f0<䄏HP0`k[ƴ˜ daۨnfpf87q蜣tщM$A&1 A\@E}^M$4L G'1 2]I* (>.)\T|"n j(i4xƣЋwfJu c{Z4g~3ti6pLlL#M39I;ܣ;>$"~Ցd*`LФAP*NdDO)Q&}_%a(M #P,Kwě d5&>J#: I47"CRڧֵQUmVibZ-ms[[&zշ*X "ElE IBGu4y'ۍ{D ֎tx )y9ʡÊTU֠]w:X`V:k7<6*/ B68Pu%,[ O歆w۾S WY(CCw ?PEH,b?x$KjR+d!ȽNϑ 5jɩQZ><Uɑ SI6i ̰p\a6_x;+CG=#PO! ,>kyRYLP{#, [f7>:_w0>lќm<3&1Ay]HkEk#F mOxq9As 30Qn1r(O{Gg\ kTˈ7 sB?2$Vu7\_0#N(W`-@ن@cX(ȿЀk6h HL*7NDmPNw8&"MP27qwp|Zt6 jzg{ڋ};nG"Fv=l_DNHݗ);( o (N^Yۉ&YS)Qz0@^dM=0lT^{ud{`Wcgg·l$VH_48 { xAt`|q؂_t0ǁpq"؁{dGEm EAbhqDHA2 wIH8NLM8RTxZ[h`U(\H)gFlj(m8vq/Oŀ(8EXxq؈X!؉8XH9Sx1=7X4'xKswS )dQ&QT>dS$ =0+"u5sJX>XuӈvY%,_):Q=!RFr? >ࠍ#1X^CW< 3c8ш!huYmz7") A8T ڢ b捸1xiyiHH'ĉ蠈iP@60)c$9{k A)u#Lؔ9hHɈdtY?#poiQ:Bj頌C A62#s3&b7XGbᑅy#Ht.qR?y[7B6priuysќyHi8jP s>b =LyA` A˹K{d6֙Ɏ Ivc #^Y6@ِ)1Xe‘1)@XpxW93J :t1݀+b;V'9Yγ7J-Q-1wY&i1<3 :IY<'&5(ـ <**1Zxڨs :ښz:Zک:$?F&@~!fYQL60-铩LW፱%p;w QzP-z2p azȸ NJڬt5yos/\=8suO()۹;[{ۺ;[{ۻ;[{țʻۼ;[{؛ڻ۽;[{蛾껾۾;[{ۿ<\| <\| "<$\&|(*,X1}P3c&( {Í qs" F0Z 1Ӳ&G (T?,z\ I Zy;L}en}10p$yi{ 7xƄx00"=j / \(q'Z 7q9+kTɖ|,xr01#/0ʨ\.ʪ.üdm|Тn˶\˪0brZyGghȜ:J/L$C|<\AZ HL_<&>2mLJFLS*5 IѶSSu蜒и\I(W)U&\1;p4˃29]2E @_3L|X!A ”mjԨt Q̸ӡ7)4q wf0`8]1Yo.PՎs2 @9AH jP Ր0.9P a Qz0YlL95R Pn 9c2ܰ lڵk5'`Ke } b =]}؝ڽ2".1"5LH%&" kZ&](Cz4\#qt] ~\ ƪ=#P" 2,L '&>>ɔ&n,,NF6 9m02n4^7-ANȪ<-`+-Iی*Ъ%q8'0RF\x%'@<&& -oz|~>^~>@Yp`bUb@[A鏎.D^DP].TNONQ<n~]<^ >鼁 c@\Ӟ.#>.q팊\ ώ_ ~.~L ?ϩ~^>>~^La5OP-ߨezA~GqPL>jAb07O[n^ OVnpr?t_vx-L2lٓ}#p єbѧ22S/12(A$;{B =}1-@,,+ sz1{'&?ᮿʯ` 8 L?}oϿz ۰ LTl3T2  Vgho^4g|ؙU_ "lϡUouH\f 휮sSB3TC hʰT 7$ ܛo g?y'FUm!ʡsu꫷zT;{|/B[`w}Gf~dG8~v/Pw@&P d`@FP`-xA fP`=AP#$a MxBP+da ]BP3a mxCP;a}C QC$bxD$&QKdbD(FQSbxE,fQ[bE0Qc$cxF4QkdcF8QscxGAФs\e+pЦkK1yG[֥#iHD2Kdfkc2't]AulgEq8DmC86LVƶzJ=hՔ Ô}*[W%nq{\&Wens\Fי B_IK+- nyߧGDLs2pk^/xjT g," o[hHH~{u5kh_!XŸsbUaLXs0{7vF&F[1m].Y(bX;q}c YC&r|d$'YKfrd(GYSr|e,gY[re0Yc&s|f4Ykf\f8BkE,d/栁bI{BAYtc8c9Gy1ę| 5rCq a.zy!iʂeZҋI4&qI\: ipZqu=X{ F<msb#p48qEKtraYF_Ƈu$_(49>!Nckn>HQEAcy<˳wU/$k$.A?Ԍ=gy_HΈqRcя6B X\|aRgֽ dLe qtc҈=B@]a h08xJ}W|m 5L= I?J @@,@<@da(r|>詑 Ŀ@ki# gA-Zr;xa 6` [P-KaV4((p@h*[p0)6@3(i`y>Ȍ0 YtK 8T pX+`IypxpJ)eA:fh ,:gpvjD4V0O4M0MER i1  d3>y1ұ4 EHU<za<lVWYćctgx lkx^1v!,JFdA8tAX;xA{<4Qlnx b0+#"TBs(<))B}.ghCrȆ(3 AHhÓ 9搅c1I|JăXDpGĊHLċĭ)R4ŧ+>hELm@Wh)Fii,JdYd``ML bTc@HFd.EkˏFxGdi^Яb(\lLT ;hk`@wG>/ЗT-33@dlBۼaHspc}F¨lj[PIbΘdd0 @ MYy<yh`@(DG؄Kw;?σĆPAt\M,m8LG|XjD4t?jCٔihXLFCp0E| F }18q2K $Lp}a)ш#=E +೏Ex+u2=JV)-G`HMQ+A҂8Q!K~+aK ǥZ@q@d=L\Ȱ= M ͱܴ44`*yM0լMMQ͍`,ejĺ9zI9\TlN0NsЖPДjl?qx7dhV_r 1`V|OʔPqʬLT9gW|scUDyP$|m6ǐ69)~KLҹ<*pPV3<ՋPjihQE͈/S؈Œ-]7-E !e-Y@Xȸ$QX0hg8TטqڞM+Y>YgJ<a4Lv>mE@GLyT[Cu6 qY:LMtl+^O;5wp8[UpՄJ?էp\phpSzUVe=PTiwPUj@ &Ȅt4UxU0EU8PbttkލD|e yW؄uRRzb[  l9 ܊hJJT=TTp0\ Άii%a݈@:|HS̎ka{`)[q -#Fqg0>j}KFX[/ۖ1Y`čB`1tXD؈`]U)f < ӅI dg @l(a)FVA>uaiiքܔ0aP|PgTn\> PyŇg*M+Ћ Qb0>dM-FTxu^S@䆐YyVѱt\y` NXFy:aKuV``P' _6QV (vF}biuN,_|xg怿h i!(X>{I+}fj^5MW/^VAXMw ݅A6؎=Xɐ ?K5PB * BA+v`j oVo+9k R S npHr N$&藭a,}?[hK?UG Q.5.}UHb!]&[`h6a`Vsq܃pmh^~H)}Q9cnuڼT3jhMrpRq%rlrS}]8 k(H+?Y5Nl䗴N.fV@}- v+d@VNeDYΆkU$tt|ht7a }OmcD_gfŚ}_Xqn&嬮R"=V/fl]~]rb8}^}j} sPgkYcΎVw.gi/$g͎r'`K,08[0>alu[8ϳcv)N5-P-Xpp-QՕaȿ=14+@,s `>*RL)X x`+jFd星\ gmXqfa0&ewkhl|؆rHjm$OJLJC7Wq%Pu M_?MHQiauvYjhEH$lHfXOx MÇoH?Lj ,U`a#Ev}:g /m L׈)Ibpw5)@Q]:dqr>|pLZ)0^vE@mnxF-Nx5ZF3\@rV񕒿,G1btc„ gY#4'Rh"ƌ7r:x΁#J&KV7D&n&͔BM;pec̚s(V+šY֤%ʑ6ƛرvi۴p-#L0de'Fo9q^U !_[VVRB}\[|/37ܹ\Ҿn}*Р ۵+*+|+†N],ϩ. B$ܵ7/;'^RpPi6;iyY~v;tLj'PK'+UQ![5qwle3MTZ)wy!!8"%x")"-"1nTW9Hbܸ#=^n> 9d, I*$M:$QJ9y%]4y9f݀M7&m&q9'Bec[ҹ'3| ii8(*(:(J:)Zz)j)z):*zꎭ\͡*:+z Tp~Fi|) ۡq+dQ*:-f%f/dy+N.8Π`jYfQ/ NthXmeLLM7.G14>e^Bf9j2E\O۪ g;:rl-Q!Up_8WsR9Yg?զĖk2FcO, /M7HF6P5sB9Sd: 2;7SM 9l&;w^D;z-O3:3AL 2|$d O*7&#15,E|e$!1g7W!4R i^!W d6<+ G}>!!J. ]&a%@\9w9v@.tHgS ͱ̢h8621!5[@΀g$ YX#'JI*"s"8$"Ep^Q#EE^-nQBLct"7̈́IVXD I Kis&41W`,5k(1PDS+0RA^c8Itf6Aa| WN )D@r}B=!BΈ5,rTr"i$zqx SР4 k@C-l05nޑҙջ @Y8D|N*N$:1GR[" ’\4A2YP 53 t"-(%hzU"| QYbH@p첗#5& r4&RZdB`8HE*x^H,,c<Ѐ-“U!EB)q"*|¸Z]`I%B(DU[}D-'Ed4)D^$9!3 FRдRD@}@tVF7_#8X:R{S\W!j8( #MNxILZ6Ia1 mbKy2>+BK|eJ)m,Θ=N3*Q x…VLN 2Apеp#;;=2!rBT {#ZT(D0#=nWx"٪*)'adiB?HY t58 F`ʻt ypwP6\.O:0%P 'yGF[`r qAZkFֹ Ǐ)ʋ* D- !~Ϩ0&1e4s1sTΆ!6dAhmT^{(,=%l}FtYnNb CĞ6ғ#JSrHEY Di\Ʊ9GZ'e7iFtBS5ՂP s1e)ax#DbFeu;T1АJv8a*E]$U)"4# X_ފ5osyhEz@ar$H|pڛ8 =0CGAOBAKPCNuQoc&FQ a\D/X~AHxȂ%ʱG D d@A/0q \5س9II!e]qx[)hBDHUI`S(A[E 1hMY`%1 5@*+쉙5f|^_!Whqm))B3EU2ĒfeՙBDB\,=0,Nic!0]vȷweĸ80GԅAP[B(((b"i!`BBt6zl 0tD-uO6HV߁+/Z/JYC5PAB`CQ0-*^ 6c7FUN}\OIe%Y6܇+&"ÉQ+!8O6heuF< & 2mǙjpHU1F *Bn-7L÷_5W<=MJY#"$On"b`ϩ"Tb`PzqDw}KGHBDU("LA(8TJͽ}}S6QlTO3 MύLLeo ھ S] !LPazl1a+pEWBr>|XH, vF*e1 k؃3DB/9Dd1%?8-_ Fm8NC!SI#~ +&Ma|j!@E_S4@vn'wvw.zkehm G|'{{'|3ޟP̧اyVXnƧ'W0 (&.(6>(FN(V^(fn(v~(DLא4TH20yGb*"ި܁U0)$Ѐ"0L DD)BAC&}N)BȚt4XI DQ l"I : >XAPLi&̕ ,0u9GF/"Da(EI9 8m&pMNSEjDjȉ)D*DY6J*3ͦz\*2j ݻ*P+^x"D$0<)&̪Fdm+C EDL9Di `~DE[*e8XA쫙X8'QEDlE&pSlC4@E, ʉ41UYI,ũqH' ҒLDeDҮҬf|]ng,h@E"脎M"؁h9APB3m0LbBQV-$ě ,N 2[T+ڊN` u؂VI,27AEK -BuZa3&S,30SgRh"V$hNMBXS9\+D+n;RMH7!jf2nBlvBnJBGj:GroOo_L`/E]s RBo^3/cTn&$ؓ4XEPmfU"0d-BT>bO ڱ(m4TTR!G*X>$lR)F>&+ .ncTQꄢVVZngN \DZV OS9H1- 0 XqޔEqQ!.nd`oi6>JnFR$w&n5׀PjjuRlO0,M6#1܆`e\ǜ6p8LHxt_RO)EXB2 p!'V:YD V()rK$Vnog$%T5Pp(G.BY鰢])O끉 WY(ws`L;C,=h,4,;{DDA\.߄ QaEldƽ!rngQ`8FQ4P68KZ+JVDhZ&xI&՞yfXC't.ry"wSTfur-eR +V5!E5*uuFNR%,$6?IBOfZO2D텭9-'JR[6ij<@ 9FPDRDL*, P84p#P)9Q%uBX48.X,$I M5 KDɍʱ(IfBz^0Kw΁3%,ZY7P uf P/@*BsGM`T6rf6/j~u؄Q/zPՉ1upuM(ܭf88 2]W^_DRD;]'DbxjE_@  )3B`AOC84 kW4dEۂ7pӉdWsWs+f{81WhnDy9réyDy7t&+xBxBS7ntطT wŒ(r؞B,(zj5do:QYLUS ]gV_u5x>8 )D!KLE!a6XrX;7XC5XOmץTcMTBhA6KyJwDO- w Üz}Up1 5A"x4՝d^8C3LF&q #+3E0QFyKa183n༦gu(TuГ"/(XxV[s-*׈QfODj/R3r;Ojh| ų& 778Lp].JP>Pc^K8=S::{fD;o3c4#;8|u47 *ķ+[h9;Xy0^$_)7w5abk`ugU0;qlu-nshp(WkAĺdSA\7\13p9 4|i0"'iB|aF'\3ZYEZ$\zЉM6' GZp@"5|HBf$qN6{u8J)št$Dur,&Jx*4u㒻vjħxNJ=gj3g$*DJ-L5ݔN=PERMK?oGMaN?S9';\uݕ^}`buY4Sk2EYfrVZGd:npr=]LE%t 3eݝz|ݗ~ >^~%Eƛj+ޘ=y==l %2)]QԘT>/Da7-090ZDDqdB⫚yzDND" Iot^ܬd zl9pHxΑnJmPDk|gG |p.#ty,q,֫i-q0ZԨBB  uvpW\G4ڪ-]BjP'-Mt=8đ5c9zR9őW4hq [D:+;p,MGiR9Q@(7u /βuY,~A:mRޖ"w7p0"PRDwmFd \H^uqe^8\|Fα pG:.EvWhE%( JXK'򻯤ODac7奂yB"= Į\AcH\~h5+I+>;h 1YD?x^3ʐ1 `Hȃ?KڰRt&< 7Fzջd|@?@#rAYTc#K 9WD`e 0`n^耆6FqW ]j'Q!4w5D b Ƨ`4J'X'`?c z2yds6º]7$E=Qޔ4w=YVPvRdwѰ6dpaUGN3/)Q:0ƀ1w?/ͪϭb*L?\I&=%f Z?_0.Rd@lidT4oQ.E'X۠6 6"tfCI6 I&d*ϸ9W&g1N0Ѵ;.bXɲBNP dP>sXBIT(v6+oAKl׸FHXƬv ,gk0!#H Y9cԐ5!fv0K+>p W࢏ _)e.%F쐨"$(7.rL E@(cm,&B+fV)a4"X'X>x7#@%WǢo9X_D 2{hI/X3`Mr!ۊP C; B$[ 'r#8W7Ҳm4m,ҠeE4}|J( o\< F6.w,庬n>' c:!d!Co\ (lxO:mfm{ 4(,~[)b7>*뙽I)/8aL4mğ8{SSKHؙKc\E!5͗R&q \0 6и!L}yH!`)@`&<,E?~'f`kcGv`6+hG +XD&wl OPpmAvK$zK8p&pF`٤ZťJiMm`/G OmBc~Pt XlI~/mCf6DBi&-FFF@ BO h#xABЏr!Om,/$KB+.A` s(p"mA C?!,͝0E @0) | `T"JAyX~Xhb0 i|9[jD:10l0F2E /fdO 0EBl;gY &&SdfR0rpR'-$f0%hDbܺBDAA2c绊{_)6$ ^llaEhl;fRAUۼ0=AY0naDĖ<|o[!1"0A& 20K( $# 89B|C:M! J95}#!&%\ R^ubo"0bAj<73<'(9:<'Zњ8L%֒%~%֎:s7x__خXmxb-y$)\]xG [ {z#=WߚYՀ b1di9D[caKٔ_!ntT.̜)9, +bLEBjJ΂#B?J':Aʹbx,*.%X2%W!$ƽhA($}w>QG \*,AiPDC{zA'6 B$D3KG20DB{ 僺\b d nKG⿨':Mt+nZ苐%6ABzͧ_EE [z˷`{`SuHMB̼!P!`+~l_wxiYY:Ϲx)NA,:]aa'y};A1,.]ЕUo'o6l/.BW=ݏd]vҁΡbo%Æ+ς+Q+Θ?ay|*ρ#LjG-ړ#vSll<[1ObEwSfP6! L~7<"[|M:vcIr;Zٱ n Fe`cc ߁{.8p-;貍-#nlw.QbLiW֭ldشψ CZ?i ͍,nUDbwnJE2Ɠes4ZNxߦN'BNBUaNHa/唓ld7̆0bas6s>9n 3 >Q7Xc#-de$ ҁFV /n]r /8OD3 a閉ff4X5ペ n}I9=4~*t\cK MFP&4i* nlf7刳 f1L)b)%)AO5ڗF)%R`MO'( =iyFz.4^|Us_~_y5e;vj c hd!lH 䈏`ٱ 3F` 6߀͓|$>F [M0W۲KE(X4 Ts%M{I5F@49 \ DqpڑJ*9ch=bl;I 1jD#+gC+ +&Ll#I5 YGP%ZS #&GKDx] +*?k+`)dcfaF`敽4+ͿRA06&9"bC4&G)M"41lhRTMQ! d5lje4Ao̒f8ofg zN3E3xP%}B@RqdCUٸħ@>c~ALji0bFL6ЄeH48R He nc$6ƙ f|CV2¤(i\[u[PlH(E+楤nՃu9ªxIb )E0Pj3'6[O1Ut[M7 l&բllՈcؘLtmNy#8}sH Yg?/ bl;3n$IDhs%1lD ޱRϝ|S<وK;'~ , |s ,]!MQz_&ܙ}][Ҏm+@j-P]nN-Ռv4> c|cI)L 13Bj}{#hG5Yz3R<5xPQ3E{gt ILZd򟮁mwsJT͐K|/I*Gw&qvDM6a e'jsל6e0֒DCj|笼.oD/я+}L7ag:ז9%"Lac)+`˹ knj0i46Rj?gj ~/t6y|#$ųNw 291.Ч/Oԫ~o_%o~ /+o `HBү>z!:k}< ;#!B1v f]*ºuoۏFٱ0Oe;q_!CybW 4Q}jP!d99j@.b)x@$ XQm;` qb}b:ח}'M3O>0` ˆ `]҃}r)a*ǀ=cRg~ƓiF nU!@G  E1@1w WK7/2@y!c`;y`bٱ :P1 e(9hlN2QCOLqMM L}`M$MܴMNQJA8!w'VqNcHMZPv !Z{姅c<^!~bh7d~s VOh/W!!xw.^t@p|X1xͰS7aA:=$P=0w@br#(0T=6xH!{6! w8t`$ 1`BX aA`V!45 v`` LH! P):-IZ^Xdd )!V4H#XE(~f)h Me"e"_&f&rBvexivV>c4l q ĐD`M\NMl4oce VO! M'ye8Ud$ǰ_JaYЀZ4}S  ){)tgsO Bh) So Yj7ӘAIE FRu #S@v*0f D4.yv.IY-(wP1B1ZI nIŇf}8>y4a q`O$>``&Ґى{0bO2!9ΚOP! {`kx/c`2IqIv@ l!jPA2%M2@nP :`04^t%b eb j{x8XSEE!k_ K =3C&)B] +:Cji3{ܳ$DxʧvZeODs1vwsU;D̩ EIYe{1Xx0[8Te{Y!.Ey`0 a}}yk4!ƚ#}'X  *$ʙj1F&A1qanuPUrwˋPVy2JaL:vhHMʹK*Dj0*RǀKol@b(̰'′)y0*,*b*SB3t [IDuO fa5@!kA.YAXQ1T/16f ExᛅV+sas1_2a 3j/ |z Z@Z0}#""R=` MIxPW}"}|9~3 1 *b)(Xn8ny@TۭS &&~,TT U 4Qˋ1IŬTcX$PzN׼fE7һ)k VР1l&lif@ )+0*0 k:.B.Awl 0L`pʿ4.7g!`0 ,A|%\IMC8YjU*͑ 4ͻa')<+ckF0 ϸ\ |@ ZsK1"}{P ~m@qD!҇ 0 Z"/\m$ӭq@~j0r hzkj_ In bxE,cRԫ ɯB@ "3݅!]me@a *)eͲcV!ᤇeAĠ1WҊuQ!B+Dך PY[4aWq.͑*Ղs£ڮBJy,J;t`dN{TqOmC: "Mv+}tNܰ!,H$D0Hx ÿ2 VJV$ @"Up"9 UuōSB]xOUA ۰įg1m&T X]~G!I#²=j)K9Ja*jYu2&a>,;[\hBC|EPr'T1$֌.MTղٍ ڞ]wEel£QjE] -sz!4!e;m Sjh(F9Q!zjk4% @}Myl lG#hßNMY/R {=Nh^;lM\OWCəۓ;aw zɗ{JDR4 Kp ^F4bi + ՠs!u]w}X㳞 6ٱ<)UZ]~VhثNyeY:OuC:!|h#-mIm~B0Aʭ7& 1PF* ytWE~PD| aXFB2$+b5 H8 @x(dq8LF2|І1SY\~}aO ~?mBŊi+mU2J(s# H4D @c]I N&0CDv1%mnBVD9{EQBn i84Ft$QRP1̤*;X >q눩BWn7dU*d8*S<[9SK#Çpz-xq3nTړ,q<3 x H6?~wFs`J@?RHV(/ %jTRt-$V H{01$PBr!GCaAdNy;ć^H ZF&mp%zۍ6cJNNR82__urt[#U. ܦh3..7eWfͦ_HHLCŹ=ёAnyG*W>fl芀^fѝ%5Q Hoҕ.G0MjӬ%HRPeka%En_Ld.1SxuG W$y7M.r󧞡`E/]_[ȘEO‹t?fF}R 0y^b}o PdP5x u)˃(񉇙0QZ<ڃ9 ;éy?Сpk99ATH# a>YJgx>s)*!sp2,j&Ⱥh2 ,Yyia$);A3"Aa P;3|pAC)-N(<84ς<-JLqN! R=|:Tp`={=ߑ=(.kk 됦n]!>`6oq2|*t@8y*i|zE1Ex_E\H!.Pd?e?~ Y) <ȱoP=>*![q(Z81-r  1A@{{@!K̓[42!r@Q LDŒr6VDtz![ `4? i\Țlȅ`d,{FӼƏ@^ij`9Q  pqȚ`@v< ~)) I'y)x $%8̪( !HԘc`8)iDꚱ"<O"dt&̈)|wHܓd |NxB̠8dʦ\C>Wʤ@G %GCHC9>$VC@;KlDz5Q#ڂKիK[޳XķLRLq2S-.&/1=YB1A!5eӚh6lJ8:;e!%.5B-TAEeFuGITI=KmSENOPQ%R5SETUUeVuWXYZ[6m\^_`10SBq+B KTEnc]|o3r qh+s)סH6 [v1ϱ@xx 5|0؁@،PxG؃60KuX7? up''y q{ ) آ$A"g#H[c9VH֙39 (픉Kfuk.|֘V4ٵer+q0o!9%4Ws=Y07{M11xLyBH0@Y-mǍ\>5GЃ]%l Y&ѹ(| ؅ |.%ݠH=QS5c83'=S;qVXU 뮏^nJ%tlMq@x6̘Ⱦ͈YghpB)I•A|8Q -`~aȥ;ȍ\(,#PuB5ZAfŏ@18a|4JYHSߟ(^U^m8QpްM/0VkamnMVb|؆G>fVnn}6fDA-:q `_T r0 @R{;=~~)rN ,-p`-`?* ̭G7Sc|V'y90,@ ŭ^x.e#]}#ޟf:chAH_xYMblnbYYnٰ Y$oXJK47gԜ1KXwq?^WAnE.|s DVdQlƊ~S^nM 55Y|27:neY.Y'Y) z)!).g 9yi# deVތ/ `.; $n؆Lbpmhjp$&kMhnȅ}V|Xkkv|g3}Nʛr͆dV4W8-V> VX@h1a1= 淈dp/M"͈l kбsUe|1n*H"RnhmΠjvg~+"o|pEk޲j`nykg%.Fg&nykEq@^n}vKJ<ɦp_W,\rM'@ۘ.n>|((^䠠nˆmŊaQ8^0a|D)aN$(">͈0 *OrHoploqLqs,lXq~l9?3NeI$ϔW Wt[$Xߺ%3(UUkA?!YP9^'IA^ tyH@ U ~)[W].vˏaˆ$XN7"nb$~~Vm7'wh*@ k=srwW ˲~6~JJCD_MhM0Wp йMχ P? 0H/6vNtnƛ$J` ււ ]e?.qQV mz|ś0H.Y0H^d]?i- {g4?nlg..grbH2c|C&it[lPϻȊpNcU]s=_|0uc$'9YW 50 Pjg0y#٠pP~ W]q"،lԘlh/אf2pƤa(Y)$(ZGO0o)ⱊp'b@b('0ۥe×ɛ@q0&Z9q1lɦM^*mr ć!>Uɓ,o/eK@~2MŇ(қNB*u*ժVbͪu+׮^ +v,ٲfϢMv-۶n+w.ݺv͋&w0†#Nx1ƎC,y2m!VI `˞?-z4ҦONzc=-{6ڶoέ{7޾.|8Ə#O|9ΟC.}:֯cϮ};؛4yDx^u;gjj`ȥ |g5u_WzVo'xU7v8%4UpM$.߬;DSA7SbT. Zp',9L9h‹iŰ`;U֐ޥ5'jUcX"8S" ZĤY%^ DX[{Aޓ&uuZ'Y9*T*Ζ/!UsN6hz8NR]%/jZm7#.pSkĤh98$V#tÎ8ژ T3;V> RA6f LekH5jf-ve20]8azEXHQi]5&u **ߡY;qYy) TtH8Ѩ z\$lDKO`0|  Ӈ>tSΨN}$+He ŧXіއ1sEѳ* rP{B5=jRE-m,^Y|–_d Ж*ƇIXb\ŗ鯂-FKd}g"NncP|= `AP_FB]ٍQ(#f"(mӜD9vN75 E,IFJ^Rmhe(HIZaA$%ļDeK+oUu>Jg3'3Sɳj};J4by _|:sܤPL7-#*x_4F %0J(ЋWg:[ZNFfVBQEw8 ew)§V kWRXr2.@5)Rֆlb~<sĕpsBICJ) Us̳^X"(KPR2`K˦L>D[ j#Zd)o11-+Qfl.QWC-f8 zHO75oN%ded?MUmX>)2ȼVc.0N3t>r VZ׾ACW(l|L>;*@)7`mj4b:J" j&rmc Qwx˥ )NV9' ^ n70 #KNdcG@'p 211ce#%oaJƻe1 ZQr[[5 `-z9k6#l@60*_ c<G?KO͋j~i+9L`gߺY(n&6*fTnKƊ5jōo4#U<8`VXC_-QKPUK"y t;H/߳l!b 5m*IE,M Ut"Ux$JPN "Z NMU| \]jI!e8Sh\;x 6J$1|\--+OXӿH_ݍY|PWUumN"]ٖTC7<1 ~R˳2]Z MS5K9I7S8<8‚g%5B!b=& >^+ WkŖ%Ra[U C1#$0j88C3ZZ#5M!:PM$htK!>aNɑx [8TdP >$ڲ [&^.t34Ux%>LH_VU)X`P~3ΌUQSp\?\9HLf|4D&9;J̹ei202iH9 C*|:lh Z`feeF,t3H!NSxdnv:3]nJAb&r S$d"gEZz$ P'rgr+|zeMZ}g~N'mfsdYƤD璬~2h:胪eF߆k'sXCEWt 8L|bQL,VT,BlY|TTBrEǾZVLd*0ˢW,^ >ެK K0 oB.p6\)&؎l–3ɟ*dqjVS(qK)UTDñĎB(Bf> B! 2"!;2! $St"L64\llXԮ&خUj'ǪhBFC/tN+& aŁ*erP1 T8 +HJ"9=RԠx/>81\`3Q).iX舘/HA:JEzH/a AsMFrH[->Xm3t} 8c-asN Aј FIx0~ϡVbIJ;7t ".1qC&#L'{@0|I ';&2NqGtEDßpBs)jc1_Eu>l6JZ3.q5\qvn>2!/2"!^2$O26%K]WKlS|[trfn)ӬV,Or.>4o}KXeEh3ج9b:Ζ4NElB=1Kk|TG}ƍ!s?˱ZU,"A̔hS_@@AUD4QM2sIxG}D iGD%ȂB3>P4186 B΢4)40ƒGWxBp2_L2)\,* jU' , |EXuR8,XWS@l:(BN$#j`u_k.T`##SŘ2b/6K!'MXpE.WX f{gC/`hiJzK9o0K KڞXQ3WmQ%QDՠQ-h89? \=3BYs}8Ws,@)|wUMSV3>왇PY\҉k+TfD_ܖNCDDE4A[jHi6X+)L.g3 [8";+`_x3h;nSFґ0\_uou_t5; 459[+[;?y(@cߔvy!s_ﵘfǚ9y%p4\*ť+ CŇi'ؔ&SȮkE*/WObX:g:|$xn1f3چ5wg>V;ۥgCOXAYC)Pw6+O-wzlz~h%>p~zOD#DEX+K3{>CBB@{4<;K{E{#A8M·W6V@\Ws߄/nT0y1?@ 5_ACDp!*TtD|1BqUUzA'1$ys"W P 3QFh(h&|6#B$:MI# uTlzTXmW*r 5C8nyoڦV+* ;q~f>s{jZҬ=ost`ŇrW's7$l'-g 6GX/X3H5 U~cr&-7eo"\tUoa ;9dŶUP0pߘǙ *_rnL6Mixi9R'qGoVim&ːEv[gT};[%wqaݶM,hɾ!&LU8)s5L]ՅSOGOSNPE54ϝwEQJҔF5Ԏ4"SMQ2&L4T\ R f1fx~a*gǫxf>&̆|#tRqv4fWc~A(/kЁP(.5@i"fڰ+t`` |[ G%AAP?$=I3$\.H}^>(g  y Q]Ob2ƺ4 )ۃ&ρTSȤlD1Hqd#ҌjBFt˄&i" b)ep%>9|oFA^A&4tmRSA5NrS'ݩvI(tBNP 7N !u HNR#)2MT1I'*D&?Pe2fP. -(͖9l6I0J2nD&Cݐb$EU:G!zv-uKaSQpFa=U(D``2Q.t)F4&$U:U*n]W_E #t`5YJj N״Ε@*ZW}_X5aX.uc!YNekxgAZ v@b'(3xȞ@ |tk1`:4_PF?' N8Ww]$\ٙ/Su!/nvr^nl[;)}[_4crD cҾ9pP'XaAB3՘@X !mnBb , &ATS$$`Dcf#: HxfaM|`'->|+*$ G蕅Kܧd Eos k'IOvKfVljNe3p] :&RLD©FY%u1}hHNu21HI 2O ^5K)W􋎫7)6VV}uR(ʶƄu"L͍K[9\ cD-b4[J16aI1lpQ):BӚ6&tO\|pc4N>c>HaA|Ce{bۜD:Z or.{9eL̓l:)[*VfjWӟ=m^L}IXa*Ǯ/<#-/^4Apg Q76l x|i"D8 ?,=:SD:4 a\EcX OIX_X )%wPG#=Mn<|Bh< >1"6`X  ~/.*-P! !Vema Cp,@~$FC@,@gB$ː arbdBAn~!"`!sFx)q#0m5*'2fn6`A a;at RXA!^jekbac _.q2Aj)Jh&I6ѰDMvps+jzH_j_n>khO\6_cMv5(!+!4fP! 4 b P^_APc-")&45S, S^R\jS(cv*Cڎ d<'b"-`6F\A1 9O;{(4,:`U'f0@ 2@ô6QـoѬb5)T,R"tb~1ro||$$F fG.!G o%W =X!GR4Ha/O"JVAa* qF3G=ȠDOh2&oA'2 4J?ChH

,f#sunC2+5k 5T4D XU5nU 6 NPE4 {L6k6F88Nn#؞V Yb4VmL* zu;}h~A3P^Ns(c;ѵB_0 v(͔u'">bA͵ ro/$\-0&5d3?t>\XPLEsFCH, IaII/>rJAHi $$LE!Gfh ?iOLł &!6FCQ=Tm6m= NXP8Ӣ8$-&F=opARv5/s麞 ë>*S,ڤdO5:? (2PU4Мbj%-@ bB,VU LÎ#fl7QP&-V <ߘt9Z?*bu\ 5'8ڄ\?`8̀}oû|?.'@_fu ( v_/ƕ\s,|/@C_16z' U, LqlFBlpv;VVnf`IPfHʣMiHYJ'đ4jtq@Dt ֶP /b yk4P`Pʈ*nTЦW  A 8-q=@/ lrs$-I6:7s?wz4Nw+Ԏ,R_7Q vbb63c77!X9wX{ fvZo5\bu|O\cϠ v\cû<~Aڂh]%/V9,B,2OX`Bo#*[ b-j6Z!,."py7XYᗴ/#$HG4`TH$"3;ᗢ8rZ ETtjIrjKT<>KcFD`@.l0fpNД UzuX<&P CsiUP*bԣCnrJsU=r(J6w:5 nCCo3:?bvNU[42`WV &V6 T R}Y}pyϋ9w['9 r=cubaAg]EXe9=e[*X>4 [|Ӣ|}31{`Oc%c鹟r'~t.bF)(%rFrHT f"rj sG1!W^rH@ۆBozk,h`,*&pN=,,،3(j@ح+PM1kl kAV[S}] [VF6F#Rƛ!Sݚ$˻|h5^JQtBa Q)D=$&^/'5h>;(08{YfB逜\?/hdd`V|͕|/ڧLv|[ o@{;'1`>05"<($'h~o!?vo"~A9t'20h k W|o 8" '!i%o`ImB 'mNq7 Z܈H>@t<,0 Wk &xjH3Nȉ=Um$lA( z`Pr`jPoPspu% 3KaKo4l>^M7fa/gT* R]1f޵.>'ȿ^}9cCwCgdfrN:V',GY" A}+gbM?j:O.ym': ?|???|P5Fٿ?? HI&9ȰÇ#J/5o(jȱǏ CIɓ(S\ɲ˗0cʜI͛8Y"Ϟ\0=ܹM%5JҍVM,!&`L⭜YqPY2͠T!"bۑ]&LҶ+EpႆL|I!Gt⤈h~ϠMf"t̐c=UoLk=X@9n.8k\'vQfs`x,.Pj0>w|8bL9A~wz5P~jA`72$r5_! C׈sVZkAoΈdAs]x #EEAX`8vXaGJ6ґ))dP29mf\$ 7dFlM3Pd|9`AR(Gu38Puf34PWui{oh2&$89JDAB# )AbH(~$MPfxІ멀!P3EׁBkB2wc_ TIKkSCeCdekoD5Yфdj/mNDfPE5ILR70P P@6H(ӄ4{@)eIB!a fZ;A9NP-P `7U*P-PS\gӫe %kZ%P=18 o]TB55qwA`o9e4.ٽҪx \`4"曛%١X>"*>x֯Q9$f{xѵ>L>\nnbHeF.|߾XK_ue{C>g磟~c812L'A1&a鈐ADK?";Hf(wkkaiXde6fI!#AD=ӆ(GQhXc'œRJu%!:4E'k7- rۜq)ZЇ$ YIB'PlpdĖ2NtĨ6m.L ^$Hω<8YPǩ[vab J-]dH*PP JyI4&1Lu1=U2>eӛgN @̲ H@A%wcC駟J  b  [y?Ft>;& &IRD;i"P'!0NJ`{aNp]AEH3) 6Yf:ӳeA.sy"?rƏ!ZkږPk'Hy1dYbU }`AH؋AfVlLN!m{ŊhQzىo /?8&*@QT H`L]j?ݢܦ2oI0B(nBl*rE,5lலZ):9"!EpaQV|Xؤ\5 5*F & 8xb$P )B'ql\Flhe&i9+%27OJ[ki~ٔm>~H$?ox_QhXAL E1̬ӀICc~2.zf*Bm>ѽO1iK8ݗ=kbVDt|86،.#'Y}0RT~$V9@:3 7h])CQ@b V` ~U=M)MC+oφT]T`[Zvv0j&0Ԕ+_i XWtl;.aq򋬊܋b9 A:b,;F=}gr$X211@!A@&]a !Q7W2"A!E 5 6f焌dht!䘂!CA318E^5\ A;]T~Ce6z79rI`X Fr7 AeP!8sm e9n(cga Hp|,Hb;Z =! 7@ F#,T܇r,׊|&~rFlٖnpY?#1Q,D/!(RRSz/m]91a c9,!@u-~Rs$Y g[Iy+16T_ay dŹٜ9Yyؙڹٝi/y虞깞i3(%8a+x !I b``"&V6w9"n!O"!W e3᠗eڞZe! T߀@V0 &!E2!24ufH8ʡ#I aQHN=P=`X=PU!QbPџTQshZVzz%% 1065{z BW"?2z *(Q(ܰ&)j/,&䩠i'E)b*RB(0j2 u`fNV=Pvq !#A sJ o wb.2캛 nШJQ01"s(!iJ7*qA ,Áb(d=]+s7,25C  AeQɚ+)`B40487ϰ)h*5c9mj(cl $H4h;IS`9dIt*z 9=YiGY6 L+4m!'K68d't,Ŝ.MA ]RI$`(Bac}i0ba뼞2j̪'z?3,.DFNJ>۩ǫ33]٠z˿rk:N(i7iq \݆G|FCa5[* n4bÉaSi™†֒s#0sNWtFCyK91x"$)M0!յQY3{\?n\OyR1M e#ySMn+' ֺѴb_ Q+:2 V{?-LJ] Tc* ;H iXM=jԟ K"d#'}+O"?U"!)1?Aˏzg j??__>$XA .dC!!( lq@!vXG$MTIAƔr% :ӦĞ<%ZQI.eSID&P\3kW\"ݹgZ(P +LP.> x%kZN3f\n/]6|}"g3v\`v{Cʕ/1Ō x "g*}_͜Yp o%>%YCa3ɞ+&_yկg_" [_,ruwWB BKϿ=ni?aGn&4 /=cA B ri O$bd$c6ZI||HTgvKHK.Th4)3c"j7sN:N#%)l3"HPҿ8DȌv.MOT[M0 &V ħTt1*Yar!=߀g]4Y|=GT*n<S 5&62W z]u^|xB HB| X`X͙N) X'.ib|4I^CydKrAcO u.2WӁ :H ,+kj>8M+aE2K6djl2HhV͚(],E"%,iنtY{ G^8h;\|VE\S2ޝx)O'r|:~c ]a4^;48_87]c}w{]khO1O昑! 2!|pЭ?m 21g>l^w|p V gBhb|Cҡ,g8s[Ҩd1@8K* Ҹ2q-&9|0s!`+N00x^GCd] +'QC$byW|x.S̔BG ReS¢=YEGda&{F;A"ьHxMs2+VUBٴ,Y~d+\[ @Ħ5#)!I 4WUxI꒼(`NsB2ta դ:Άáv1 ީxLd&SAX=fM,8l֥I$BT͚RCIk!XVyMk.wIkgn&6xtXɓ !ZQFvcO蒹J6rn-N$JÒPj&OfP"%8L/TRKr/LLeKdN`0Db;<0i` TKe'!є"LfW3@hfV3sP60ȡtN;T|т{5W4`u(&tZӾ5tEb)Q@ЁOc3ˠ qƃK)x륡,Q7C[a.)Oz4G=*~aзkq{\: bD++&:d7ktK8)*rlp1-A!dcn?"V. эq8[iU`dK%e\D8J!bP-APb4] Z+\`C&rrIT%s2Tj,zFv,J/zs!'vQD q/ # g C׸5[DՊ*\K<یϽЖ;Q gr%l* edaLJZksy1\\j٢Ʊ%L[K>Dzwnc]nk`[&vt(жL'|yVM![Ӧv}ml;fϨ lڸ6Q]@!V*Mj.g ԆhpghCI;} <>6V >@y5"$H!-u # q⯞C~wO>*|]!sH!Dlʨw^?Ҟq*EP8*2Y h%6S??Łgҷ2>8s)@9(;.H.P +ˀ:HDj, ?(gȠUٸd,9ma;iI riɄ?Aoؓm@|Ȅ"|lr|"aXr =&8"% < C1D<#)w`!Ɇ^ȤsPPM:),atC9&:>CԛECԽ#9SCiúYS Ē 5Po <DAJ4l l4T _g,Kd*sțmAc|plry)=ƔM=qj|gT"q`Fj<1Gr<+i+ +(KYL0RZ?x\?)jv{?)1+s)3aȺuksH.06K; @x(S)Yb(p)ts # {TǴxǂ82#@rCHD(Kp0~ˇ}sP>=O?|Jshc'LKL54>s8H o< H8ؔ2,qɌAdJQ f0Nq@"B%R-݆ hΤR"-CI4OP+f 'S+s s?>OE5U҅,PJb@H@|Â: Q! Q1SPKTs9q8$(pLe*>0? Rpxia "UZ-3 nȆTKpنURLUNLV,/b=GK0žISÂ^0p?(CQ!MPN̆‡ QI;+PsS,͠S, ԫ z|XE0*0_5#u0ÌMe;ܤ-lm$'%̆Q+ćWMBZY<ܼ ,Hq|@dRj}Rٖq<$mjM=1ZmH(C>K㸃P/qH)ٍ | CtypHYҧր0;VJĞ4,(\Cl^J/d%<$\Bq Qkć*NhY|X\Y\ ]q@>A]a*ѝ]ڭ]mmʟݕ`%6}Pmٽ]M^]8^^^^^^^^^ __Pu))_}iP7h_4@`U.K 39=p(:DȖuix`v`a;L߇e҄_&_:ᰈV_֊Za V{(=9 88. Dn0=|8(#n` 6Sv aNa/++Di'_*-=Da'<8P=!bsA⃀-p5g@69n*T Uз $ Sd9luT[$bO^2?K?$cQw"'5V۫;&b;?M<Z9Aӻ1#{EGF$Nd IfƬؘ\`Of_/'*vrn)0SP.#{s]va`汓l8Ne^PG ?];|$Pf >kC 69\n|児l "{8FȞk<l~-PhN܍I^nh = ..kOAv...9?.gg@d=Y8ho8dK!E+TWp]oe.0S!fen ~. E_*+p3/b`q [iO&.X$D~gPװ+DpgffIFĞ L6\H[-p(r)r*r+r,r-r.r/r0m2 s4Os5_s6os7s8s5;s/wlxjc=*8AT^)Xc%ґs %3 7SM$$2  >h@ v;`4NoۘbbbѺ(xl 2tAoAW DGtC?D5F:GZtE@"@‡i nOuwpw&C<&G/& |0΀u2vYXgExi*^ _c11xn x4/tvBgi7kvj Zpw}>rmzwmxYAc@k?5$ "Bk$8H{-p{-Ђ--Q /bxZBJ;[\*dMC@G 1.PIM\}gwiv8]9gDw7tC_}F_t_j5i!U}UotfB7kzj k.z~sqz2L.!C1bX3iJrD|H{1b-[$TB|'Rh"ƌ7rQFicn%̘2;!nl̝KeJt&vI #,r[cS"9|ٚ{wNm>sbZYr2]*UTჭ۸r֮=ȷKW6'x1>!ObA2cY3ϢAy4ӛOɓgҮm6ܺw7‡üV7D%BΖ94Ns )Gp=)Őq%vF3|VAb0Hو `B'8( .2D)q! ]c )4l$"DA8`'\ьY8P3DNdHOM_VZ\5\iW`Uњlahʆ qjwIZiZj睖YlŸ(:(J:iƕ81RutywI^ymD^y%^Fb3Q/u&/]*le>2'HTD0- !>_hnbjA)E[Q%Q椣 Jl$EΛl;Nص$Pb7<j5Jq^di&FmiXahN$r_rYv)hg'jV<=A =4E}nG MSEiXy +y}z58߽Q]Q1$, ĖxP m->Dj+.81 NJhőE leɲqܽRZylN0leiDeqsu1r1^%ؙoIq\Xb'FzYͩ݌g h:,}>$ft9~'(TE P)z(?B3&0im<7` K@ BX -ҒHP8`aA2-qA <'!Fza mh-С i 8$"0H*@:(T*=A눑0cPȉ[0 j4-bD;cw2"kjSɌ7IzȗN۫#{Դ&6H$&3Mə8М@jRϩ'H`*C-NV ܅M!l#( >kKKL `?e+M % 71` 6a9i8k% KFۓ].ʺLuC_9&lk~~R2vlxǻȘ9e^b ɲ8eܳNr{3͡񅶼=/zӫ^ lX/|51xa Q gQ0Pd%cE+ކYd|3'S8D}FfU"PmbhyYnW.~1k# Ǹl>1,!F>2%3N~2,)SV2e0Ȗ,1KDJSʲUzR33Ҷ= |s~U@#*EVqK"jpoɱ#&ѼQ#Z|;Wծ~5z!&ԍd6a: =DZB~c4mm%DdnJ".2KJCJaj,ws&5-o;d֯ ̉-g?׀.8>)!'zɢ+"-/3b႗;LmHE`;lX:!W"mx9ǜtٝŊ40"?tV݁`<׭'>2؊laaV6WH~WWX>0$D>HR5<Ӊ[I4 _pQP]=SC:4S*x¼ߗ~"(~b5.aۜDUYe,ȂDJ8[LGᥐ|lh_&‚JJ  D܁HR 7dPEa[ 텠N+З( #D$J%_} [=X(AV_[b\ۈFU-i5 /bc lQd 1fL#X4\؜ԡ5dO!ޡQN`"$S9BE:!#p W_P9$5EiJA$[eEZL*2!ҮED xHtEd&v˱\v^am. j6%EkUAUR p^eA;S|AAtCmiX'q}'z)li4G")FۆrfΒ.Kpؓ^~)Vنid)zD))Ʃ)֩)橞nY̞)VijcL`h&%]!X@ʄdDd@@FHjMYl*nˆ aDFTa{CaCϪ9ȏ]Z4<7lD/J}JD*<8KxNGmJ/44Kh#nIDYL+LUԡ=;2dCxbM\^DA[&84FX O0*8ME,dDs Yv6]E'ZD3^* b0qCTCU,I ԮZC;T\殤8JČK80U>ǶjR,HQ@XdîTmYZļ+םޫ:M+8-j%ˆ "QN `j\*nGBOYDBFS-VHZ Pqq DfC&8xfl/h 6F5EDl^ DD(s%0`8FmF4FX_DE[`uOUw0kxWm ?lEȆF 6 GldPjfL .ns* / K,0JME1 _l3q<)>F,iyWTHbvin i$[8C]K8,c6:UdEgBg"CRHo/>kV ka2О~/.G|88$+rBȚ6hڲ-CFþQD)EdC!'pߔS0s _P` K08ˌDF0F1MajT Orz3q=Sjs߆> q3<׳@/qeqV|RB_DLjpE<aI HJEzb jLK(A BU-m ۄ4X$%sC#_6$2Z,rZD DZKIp`6X`t|GZ 1r$Lَo4ȚD%O6$L 5.`U700P2/(E5ZO%84E(,$aD4L67F7 83#EEM=g3>@tB{jnjGl9F?s0oG,j4l;pF8q`B/loRt!brJxt:4pELtDc>H##(Ƅ!^EA&kE"alJD$? "8FQ m 4¬I5|Q5- ,r.oaƒM152B8AC/F8l8Mr20G%c+6A6WĦp˸T6'9+7+ȀF%3yl"F p lclFj;pjÙ 4KD_jm6ph0ngp 6F@q"nuE z&e@@d6hwwoAe8Gz|o|c}78}$Og$P[,N& FB58&U28*6pu8U rx*x݉K,knUƸS8g3{81r 6Ĕc [p?8_SnG:Op9A7;KFϨsyN;os _DD,nSdд袱vtofB0Tyoi)#mL`VEȂbD"d,fM/oMn",Bzu u7 &y%YD!@](,|.@04k)uYo/- ZqB)/k^3uCE 6> s90W7yϾ7;?φƕs"ȯkp9ojv|1(ĖDS<7н筡K D#9xE4=v<}R!.C."|4x D4bDVxcF9v1tນ;@kqkQ7qȽ'+eN;yVN\*oʁ[D(mP*%↖)RbPTծV8۪D4[-OC芏X=zZ̦ q (2J,(*ꬴSPK#B+=* 3R}LUŰh2U3|j:^4]G3o`(7tmKe-vxU8ks.l7e7<t]v}$z!.#_9:ˣH'Nŀal ߈mtVb˘=E^+$#e WR= sXtuhvڸ9褕^~zsg0%fSS(]5^~垛ޛ ?%_:!r̓fj!eFJ'ycu1 []؝Ƃ7:]Čxp߅P 8y68^Hy_HzÎ#;RH ,کrLHc<8GБB@ >]bYGPA+e=Ax! Y,\J!O`'; wHPRgxATWDTozgyO|QLIhXI}Kה҇/#'8+F8pC y$(A Zwpd ۶>rn1Eh-P89HYû"E%pDD{EWށ':]DJC%.E}[H8/}È2˳?5pP4F5TrB+cG}qĂ /Y;A9Bc`P>ӞA3P4g sVyD0KVF"uUBZ\'Yf#Vt<ܨr<)$y*1Iw6d&d GmH2Iϔ=Uҕ{xNN5,2]HX̰VJe1aG̴g4Dx5þp,`F́6]ćbѥ// dI'>OA2\UπQh6چh̀AYЁNlZ[ehE 2=h<3”t;ѩܴNbK#r g76vECi +*QMN0 eJJ$J"-eF=1+r,2#dU_Y%*U ,IL%bIf2BW '\4WN vydž ]z9esn 6)&'ڙq@9 De[BEWQގ8(n$bu rņFn㺮4RGfiݜBra w'^Qǚyfz^hzMFR!_D_uJC\UtwK*:x/:Xp^(5oć7+r'V,nac ؝Re-lC>|ώvmnAhPvDZT˾M=*:X̌0ZsQT7 33gyץI85F筗hڡ#ڿjňO.Zo=5T>F8=q0G.,kho9*бI@q-įSbƞkHexD yNtҮ?;lVvvqX.C-Ƣ x;x"ۢ7e-zYZ q~˩]gB<_^Ɓ:@l0F;"Q𤭸jV$!/߫fu͙/Kdї>[LЕ:DކP9P f`N8 &laC@*y]g= ZP/?Vjx+#mY`U, 2ʌm$pY77c@02wbP=<8$~'j` TA^/z#r "ܪު#\ӌL2-I hO\ #|0"Nnæi ohʯ邭I*"flL/`m oC+@ L M.z * :ϭҌ 50͎źhZ: Kl!oJ~O ѫ /Ĩ+g:,F KF/qM]p]Qn IJ 0 P,ȄlڲUF m@>P"X:t4ޤpCoc,{"d2Z&s'{';b~ro<8g%ҟc$\6mSmXs'ps4S8s0!a (:|3eSf!#ajS';w5zSN84@[E_ԅ.tAV3D@4a;!D46U"H@E)t;1"JDG}"GJa|4b6i3G4LBKI47o524By3#4G!NTJN4ǔ6!TB1D!4=MPtM"als6C}tOI(5G5DKiS5S P4-FoWsp 4Wa  SA54D DsS55LmU%B XY"BMgNY}Ls;A@HԵUU95D Q#X5NUO\iY5DߵZP/B:t_SX5>vaݕ@7=Y@6GtZucU5]U``/V;t NTWogsofsL8m`N $ȕbTiUt975[Aj4V!r!#s:vDkk9;"|koAV!ha-mvn'j55!Ak2==Ti!A3sQ6CoMC9k!#>QtiDSkl}s#Til+B:uu_vf6^4A[ÔG'HjSmwjQA5_9s-bw-l7m#t !LOSo6wqM6wQzL;#"{Y4մr)r5k$~w!tB|zLG}3vXh4gZQc{sz Dxɕxws)7QAyz3XpwzՄ"'5uaStysSՁAfaח| "5NdN7~3ÔD9gx~/Aa|d{X,xzQOSUeI9Z؍_z=k)w7XP6M57_83NVl!LWBim=V#*cUCut3wA5ZIYsxcQ8>ُU\AtCUviY\tySJz8rCiǹ$UcsLDy;yR5jCTtou$>Ly$SD'xXAd%Z7BE!4aٝATd5A9=Wb٥_yiuL遠U>?:ԦS7T'SI~wBNAD^LvtC6]U> Or/U+Us-Ty7rY`O:!O):G8d'N/#6qlV'+\4}-͗ C ۲C[G'tSOS[W[۵_c[gk& g .N9ᶋ۸'sP{#x[3{=d{<=rWe`^Kc z;D!ĤGzC+M D@;zKN#m3Jy.zaL"|9$#a{}AtA&{#MP'΁sȏl!A|N$CD<a dɉtAʏ<aʏyl5@H\A@K|iƁ4:G$a؁9a&a& }zEJҷ&H$fixŻOȁd?=<̝0Nt %6ÈK<2ʕ,[| 3̙4kڼ3Ν<{ 4СD]'鞑F;PD#%.@s \vBOeXNBķѢJB;%|zEQ`۪A pE7ٸ&CdQsqD{#F.YG9EU,hѤMÖ(7]asNxρk(i+x悪'.|ęVV禃c9~dXaNHa)-KVDPU`;2;_:ġY`&(Rf%%`6IE8Ob1؏6DAf8,vm0xlyYۍD%\n2Uw\"\A9ё{^'v y-yqb^ǸR|)U 7Ph$jj kzH"9HVkZ>UapM6us\ui` K5j,EjA#C0Yc 9eBd/&_ږژo5"]ⓦn[# [!SIy%ǧBUgtM\A$r9ǜ.!3|Һq&P"0̡:k:s> tB3d9Hl6 lJ.UX14XL?0oI䐼XS͎xؐԘ.h{X1ݦZٮ9.mkuڴ־>r[ yR!*Q"eAM,H٘l>3qwv-8')RE{ r`k[KCTSp%MXՈR{ڇ?bsD [1 s^ }\4!dgZ^pMمgэHcAۧ/Ƅ@ sթV<졡JR:܁#>I# dp < ㈓,3Id!qlSXF@M y8qtRecih;v˞ ]>0! ҵ>2R$̣$GR !ȕ&f['g 21d&=iY#ȁTdFY$ 4|ѓp\ˮ#GgKj| 'aI0Nb>q2pBu["mra!T -[< <ѓM>Ɓ!Є*t mά澆n&AN rUCF1M(uIOҔt,EI"P]|CpI>qO&9hř֔A2TdȢwTn>YLSҬju\WeүZ8EÔgPut]׼gȆ_W3u-a*vmc Jve/jvg? ZO 9ځ҆vmk_ SkpnhkvoV)p*w%wJwԭIֺ̩w ޜa-yϋem*z wavCwn2(|-`̾uA07Kx6P@!9, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0c>4Ćtk0w2*]ʴӧPJJիXj*9nܶEw\:p O;9Meٚçݻx˷߿ LkYs wbq-~˘3k̹ϠC?i8bqvc5ֈW{ .6kѸsͻ۷v&wnuBe/o~[سkνވLmz7Yo˟O>JACFmg& 6Rx'cj B5&P9 ($g8\\B,Y-2V8 9tN:S`Aq@ҸEhhxSN9]8' O9hAa758c7gr{ )B#u38mg܋@⤂5刳t/ݤ#[BɢHml.Vƾ3sd@l_]tg`@0(&WӉ$.֢ɆW`+TRh s3hy9+uusY-ws&{+5"|2^_XpO( 0ҟ \)fMaq ;UF=;M< 8'X7u +2 tc4|< QMlswa#Ix;a6!mt>:m2Ȁ  ͨYoP/ mvSByѯ3N|AOmfض-;3Rb KǓ2|`FAĆ>ʆ 1["8F#Hа @N B. q XA]<@38.Hk_PNp,;ր 1 (anz 8IrL:vuOg@%e%:X.ci ! I6=ne,'87|Tn&hB0+T$~3:A@ jEtߊ/AT !;R@N= -3dQWllX)l^}hl$NDQI؃u_&ӊc.+Dz8p| =Z Wf{ME7rS"9xcu_Cu5l0(PxYa9  \ݕUZ{55ⷦS YTU qpC'C~ciQCz)5oX^C= OuJc&|:w./ sEA sjZt{*2Ee++jL^Ix ]l@&a#ȳl\5).>+<5p zU^^ @ > rM&ügF{ *: ۊXq Xt\:9I.^~Ac);QKԜjenS-n!(lfbJ>N+^H8NV̷u}:2N* ;'N[g8/*{9qm|c jCT^|6K/UMLjsa=NXb 9Nցtt oʍ5*UW(\8I}RAi?yk"ӥ{/8k&,oM<7S1e{]Aw|s'Eqv\bF;ށ)Dzexk{;.ZW~չ@B:DZFzHJLڤNPR:TZVzXZ\ڥ^`b:dZfzhjlڦnpr:tZvzxz|ڧ~:Zzڨ:Zzک:ZzwXڪmM7 vi.:55R:muAZZxwc!"JPn! 5za1WvvW3KjZ; LJ  a:z۰ѪqXPKz hP˱#0'{Z: Hk& :VnQ(K+.BT"ppW{ *PP@! [l۶npr;t[v{xz|۷~;[{۸;[{۹K_O qCn f1'a SxP( qHk8ۻCh!M kskbP[F؛D{Ka KX" OCK O0yC<\| <"11.0 aR=)"kx$PjlgDc4* *` R䑏Gfj8G'2P09g;0q$_qpO3e< !!anZ L,#A[ [ [' Ć8$e,3z|m!K#!!Fs&ē'/ȋ kJRے 00 %ƍlMIA( }Ml<\|Ȝʼ12L /0 _̐#  jeݬ{w 0 Q!KV{  2!l,c@ѿ { qk  \Ѽȃ<]۱AI$&-*,Ӹ( )0>=], h\nSM}P\^`b=d]f}hjlnpr=t]v}xz|~׀؂=؄]؆}؈؊،؎ْؐ=ٔ]ٖ}ٜ٘ٚٞ٠ڢ=ڤ]ڦ}ڨڪڬڮڰ۲=۴]۶}۸ۺۼ۾=]}ȝʽ=]֝1=)5h{RÌЃ<@en%M׍qD3b5 :a..UUu ." 4| ޼ `aWG m) @ۖ3 wwpq5P9m8m [#([zWsgu JtP5'Ι U#@1>R݉7"u;1U8k9〬1U'JKP84P Da9^toPKd.vph^F^1pf! snWP @{ J.ΚA {ʸ t^@tNЉ­onVH gt`n}PRktP>^~מcPY-G9m ˚\d@B?D_FHJLNP+{w 6]g9E}i1 m}F3 G67ӠVo c  2T6򍌾]5c-p t~o}_ɽd/PaW9s3ȁoO]?_$Or= ΀ oo vjPHoq|nIIb!a-i y nmEc$-` pQ$XA .dC%NXE5nG!E$YI)UdK1eΤY#+b9mu[A%ZQI.eSOM:DfeuFWa t\q*2Zp%]]y56|Ҥ6kjc"Ln3 >]m~o μ;wI5u _;|w ,q=(N`n&4' fPL|Ո8t<^n6g+Ue#pv{ƺtFxr$I;ںa1ĐV.bfCs[<*+1-^q Ί(B eP܂$1TrI&.ĵJ!l!. {L2&[dLj>pn sjT{'idk\:uhS|qT~Sq& .e5bp徉+>|R1q(3wABqɉNE'=Ϭmr QpV|Hb]q 3$ki=_ gAtB1P;dteFu w(6#i"k9w_~פi\RP4fgK˒>I:IT-s %?2WRA7-G)RNM n 0_NrPVl^33E٭FZk$nQ$Ub(r{=}95h|.yM@tl͆yDk* 9J-yqql:a*P +JqP/gKvϊj` w* jۑ6x䏇]Ghfz| MDD&;63q՜qfc? >'N5Р{b YtKLcqJl h~q1a%TNFza! U@7h3,cK "VB"5hZcؼ:2?.fm.lR r<'Oۀ8o{Ư!dD-bf pP`RAG#gBKFW:G@ab렄0TxkH gܱ.ՠ WUaGZ"AHFRz]"lT6"E`obw0I&_A5I9dTZ1QɖuejZ },fH]Smb\ W&h&79ɜ5V:7U6 t0hp+T[8C^ٰ a@"=#IP*j ջF [i@оmc3+($.Q Z- V1!@|85E <'RcvWBR|Baq\^ZBo#>xB%1uK\*Af4 $kY:FLUaît^LOX('V^cP4xpWmE" >%;a_#1#C愨Ryr}!D(XDZ`I6vC a8ہ5" 3aVJ(>xV4`|8+h253apzJ0qM <9҅FoL*gF+tXoBǠ[.c(`=8Asve#qF|$|i? ҆bȴz/#QۆR[l7Jpc+\[0\PEr;,!SÇFz;˰#ƒ8S ʫ< wE( Iu+Ӄqэقs k[0& 8(H QJ\Y(pZ'pzؾ+T7Bl 3a!0Pћ5dXy&过 nX;|hIo8wb0WؿW[Mꊝ 0>aY#1A;;;b0AZAA \GvlGw|GxGyGzG{G|G}G~GG HH,Hb ᅆQ}lvn@#Nb*'NXm\b`8o|a&;|hZ>g g~]\m7삎U>=߆@jΫ왌no:R5gP< ۓˊ"Wx( (0F=`#mнBt@1P m@>8SfLB%AMog= O0=zz CP@&Wc5ܡ46 ߅cVlYt,?F IV1t2'.:$ x/ۊ1yAsRE)PWnMQ/xʆw,{+W+|1(YbQvdvm~-pp؁mzՈE)*ȆpMXgFu.BMv>Ӓz`2xFt]4&'uڅ=]uyɌo|ȄtyyO1 zOz_/zzzzzzw @z˟ucB -I8IN|1 {z&{ڴjhg$)Y=΋fcşqh񕝈׬$<0B0jvBيDO|| _u%ۊ`Ќi BUuw+o?qv p_}Z %+\:Moi3kn(8LJ0\ŒZXes „ .LE.]6ʕ'."B.B1&\vȔ*njRRleʜ:w0Р>-j(ҤJ2m)ԨR}aSBql&FƤ VnoJ۔q/aމK;.0l\mK3V-^3zv᰺vM n5ء/keMm.Ҋ3ۢ;э]nnƱ'di"][>UT;ֱs4YkSWM'w;JTCI)ytJGLTLhJĘA!z!!8bPVR Wt E1:4 R",L7 9N%>xc:'H"XT6hK#9ew\r&>}F  qF8imٖ. a')=t,؂/ uN8yiBhʤٰKz95O:r490D"^{P7z(>c%D`t| >Dj;Z*+>Ų*AMtgJNi}UD^i2#8T#o9#˻ +B&Eκ02& 'h"1qBİrS)K1(I'P*i(l͘3=3T8]Q06>Čq%99ds aNz2 A.^Q<4͖MBċd%Acy&/w-4*xgy-zܝw n'$*@zCg j/ z8w {d60}ڜө,ޭ#̱MgJŇ~6^*D޷ צJ$1ʲms.R9p8"]~HSW#M¾2"a V1@l!Z&$ Sb=XI:BV%C|P沖&dY'Vr'1  c(P;tJ6f%DYaMN贇E%0LzL̉qgeJ S#C,q@rѝi#ߘ drэv j83* :q-bl'(@)ͱCvN@G9ftc+P'!ϘBbcbǺ&P;plwЂd%ԪA Ò+ŇZل't幤Buy K3 S0/b8]N!B |YK46!T< 1I6! =bć [ΔhH!,> JɅ2ġP~>0a\!yTB N[c"6tik\z>#|1tPL0zb# {JAU.=pULrLA*|1buH;)v;us hEZZ}ȣT&KyGKjW:X e#D [N Y =/zrۥC$p\Dᣣ LC*R+t0W8CEG[C_^e DN5XF' {#3pzAD8'&*Ob *QLUr8Y QR :%2ԕ&1-4L$9I@&+•A_=[+'ұy.=IkY-7+ xV-Y#vB$|YDېm["N)26"0uq#xs!`5ctҍPuD/BMU5XFv'+O#(bȢJX$'Q~tŬ)8=ҰIdCbL,|F$=Em7Wsp(iUt#;hOr$QcaD hU:aWb,ɝTϱρ'@}%hB'$<LFu9j9@Z\W܄'3Zlz~gZڳ kkm"DtTqk^]pK޹2xBH&U>5 ă%KI'4]!oBZn{ wJKzen(Z*K_F*$>=*4Z! H\+P5K̊Q;Q+xtQuW%T i٩y-!6TlUT(ͻC}%D~Dl}:;30^B8Ta DOta$;C~ʩ@ +9!l|:89ܞNL"B!YRQ|b'!(N"9a8IC:8I@$f_+BY-!^`܀ K ce=J>CdO7dċ&89B3YH tPBx=d#N$EVE^$FfFZYB߃-OS\O0 `k$PJF$LƤL$M֤M5\q$!HJlIbakDSBSt8LQN@fdb$w"ľ!8AJuʙ9F~&T0hC }J0D|nGzN@23ibfBhBRTk>+1ʍ(BzD,lQg意&C-B|…ڦRT8)LofxD5D,Mc,sz5hFq6ܡ,(qrHviFf FK' Su^$ }FdgTJgFI,FpDz9 -(sd1 1HIJ>EwĬhRN,ZĈDbz&&TJb ^*Xj](C$+p):DDnX*q@z؂WFSDkh,YiHv8(训b!DhрeCw jx6Ť5$B^봥1@C !B(# YB|CDdb 6ʬeNCf*C:ʧ6ǨV+Gl^1l6 A7:8QDD#b0t,PQkCH"B,h#83|()>@^~N Kb}Ñ)X-1~-rղٔB$DiNHhh"FDX9 +D0 4nۮկE..+nٮפJ8 DJJ:Th2JD,f+9|}L9:FЖm5B®ҨbD#Cv"JC૘B AȌp!i |0,lxb"_Td`,GA$C@C6Ž-́ "\#p-98"TM:)MTf͚a,Aǣ`::"Tmz,-_4 \-v F큃 dK`YZpzg6찓@ CIc D~2*6} ,8E^%"O!ZD 4t u]y206v̊9 ^p6SB ]/FuwM›:Ws4d$;S@D^h\szO,ST 1u +> 6C(fsӸvJƹ0tG($3,S N:wTD.W6:&.>F~|zP6vdoF4EBTDFNQ6B$BCNs4#ZBW4]ps 8H,u BJuɺЉڂKV-pus $ #ªZdݞE8Hˆ+m;-F쌑ۈ_s252f2i6bgC34cyL9Eң?ЉMٮU82ey1U4ǬЉaҏ:L+1lz+1(Gqo#^谨򺥘zz,Q!BTt(r Ze[ B1;tT{BTæ– tE& Nz 8^(m/QvHUTGIzx׹T3,"eY~7ƃ9B ?Eѻ'Ŀ{{n;>nQ'|Mr,DW[o>u f9Y7">kPbˆUu@`ÆKmcJaCigA3Q+SJ(+lx$2 M"43OnQU5̶Es^dxun\*W]q"\[{} k޹ 64O8Mqڄˎi '.LlHo>oPT/c}Xlb-Ì/5m;eh/%t&SQIaQ3]7&O2q~˄1gCЫ|I|> ~ً;5"zȿs (;|/Ԉ;'|iB<|I>hCDo'jPEson(GȋqcW. Em!)rf/Q !F\Lp,5/ćL1y$3Wf[(ètqdfl8J(j|*m i:KOYu[VUp mccs)OH֦rm3@KGs5\u=-7vG]k8|:)ܓUN|:)zѵXiO&W'z=w}&lpAlrO?Ά#oa2/"&Q|nŒPqOưPt9q􊤍 YYh N4OSO)vnf'7N Y G|T[WO_&j/7/3>M|So_p4_}DQYx}ZHp0F|[C7ցtCt.xC9m$'>!#UaqC?- dW!G e F*BD C񎁠^E 0ͦE^*(F8\A2̋q 21,2(c s4ߨ;Df1GU Q4bb@O-Ē ]rM(tB5|Xh;4I|xM?{ .H,QrM0tc„XHF}S$g42A @B E(I.nJ$ (.ӂTӝ; TXQU q} #^yAq,uTCFFG C|ʑчɣPlO%0Ҁ1LiZStZJ[acAu#a$cJ]H5QBJ BYQEZZXZVՋ:J pLCWD\Eb}r!mSsSճZcV-l](r0^5^^mZwZpVhI[E-Fڌ]qK*[bLny[pK`E.d\>ѕt[]^v]~x[^}J`*0ǐOr!FDIX0| \`f9 )"1CNAJ$1q4c B79+ q2Q8ŧI !iaPЂ hv(.R\<$ZDI"p|Ap4PreF/O*h_*e .[ 18|8XZu|AǓ êV&!+\ XzoVJԡ -r@j8<` T[b`4(8xqm֫~*%Y*7 ,6n$정[D(N[e ^x0PF%w"Lu "fv`hEtM+Acpi8"0$צ|)]C'qq!P$8:?y+X1MdďYrf( h#Z-X̓gcNBLh$qEnBxd, 3z~eґBE-0Dv +hI؍$B%%8tbB#=$4Kzg "/hQVzy/< Я<'o<|-OpKv#oyh0' ]SQ/m v QO#@S2WD?~|p#Z؆ᅩ̍#3iGZiOn_.bۗȳmqXyJ2 G,6/ B,.!'vErtt屚gkG(H-!~*,bh&LB_[40gj"@`!da 4 8/k&. FrTL=n((t`&Jޠ喸Y"/`h dPf!",. bRb~K$ "+p@(k*nM AVAALh.N"> "?6!O "FΜP!J\,eP $QͲ1D$WTfA$aWP`%z&~%[F($&\"^K&`BQ.!f 0!e.b[ndGARي*s'o8C %*b"y-|й+4$L! đ 1!LO4j loMaH:N!"(mDx 3?&.R4g$nL S¾=­- i#vą­.7V(IA)E'Z !r"^72_ P6sa-B q%=1qs//0/3N!0S&*(A2ߑA)/c374WEˈ/,o"!VU,7f*f3xB\IEyt#24`,3޳ 78XI8[[8,!N<\V&Q )cqfq&yy0vQ-fB#!8' rq0t֪Ɣ&M:*MT ӰE{WZ%hTX)\|ġ?!"Yx^B,qng'T@t#Z`&cBDfW%cS(ڠ J"ؐbW8hNM21\X<Bf!qs 0aNUP@e. ]yndy*f^+=ƕ;uf4_0SdL43crTЯ\b b #"s+Y1& <\|ġI9 =vXtġ <:\ rw3zUa$IK4WZZ G;c WyND̠&>Yt f0vPիS ັ৥̙h)Ctz aI6b,]l.B٫i/~)f:~#Ndah"F kq3vwVÉ+ZXqtmG sժm0,[| 3̙4kVsfu8|Ĭ&#˜#S| 5ԋ+WN8oլ[7%Uk$l)eZlf\C5eö՚pk2$M;~I'Wn͜;oFiѤlГTkJk۾;ݼ{ <v5$7.p$yk(YCb $߻sL>qMMWxl|vĮ`0vkO {zCL '9>— <# >Xr" WOM4) 8E `Q$(0XUWdV9cV$7;Vn5MN:񥎆5 B, b(aMFeEVf*lilٚl8 hJhh.h> i-Q&5y)]W[~ jJjjjR+niEgzjk lKl.l> mNKm^mnm~ nKn枋n[0l Ko#US˯Vc&k+gE0QE`J KE( 1Y2(ƺB+ 7T1/L 96csrL>%q%HJ6t>Lc$B7洳/>| tYo=73Tp7Y.Jvψ^R=SYn8a Z QCezE`6}#,zEŭ}4~[K_#FIPf4әq1)UVM4qOp~h ;,YUQ([ZEsX<"+OLgl*_*R0q*dKf3crv*+/"$I6QE$A n"Y8H絰' Ns47p6$1qtL"98kd IL(>a*dÉ 3כ/Qt(V#`Yd}aB*x5t񆴳0;\Mw2cr:aykҤ&Mˊ:S=`jz_',B!CrNS/{1yj3?ON~s[R@b|+7c@h$9@q8cgτn@G0b"Lg0VbҬ5a2Q$l{9ûS gFΝ@.$yǙ>G~ *fCR3 *;1<8 ](hHa:iD\#R5ԍ>\dtl ARHY10/n <8J1zr R H ) @R7ܱt|k |Bh@K%b )mO\NS+^{Ĉ1p]ca IGćph"iX[(6+f1q(/&%щR6-#Rd-ZGD'/i[m'fr#pҔq#-66mC [Nn*+w~.8LΙe-smv]Wݖ `o"1k"K2`o.)̠c-'r&5"4 V*WAJ/G^ni^KYv4j /N1j" ;O"#.Ɣ)Ly Kv@vYE@:#]JR09^N̐r/gSgmb#lsU(gYd':p &OC42d1q\36x0u0『 s %2CU^a,CA IWpMdF3P|ǐ#pv,ūQ>([Ίj b8v]fcքG N):m|Ʀ:7N)ӭo=FqQV7Ӵ-봤GϘXgd/UpDc;F [[2^hH>+52e$fX'SPPf`}4|(E*'>!j˨Bd "$ʖ!h"iL ~@BPNvxH\55Y]@Y\.4rQ|9\-/< x~ Gx/`2w?1'4'F}p Pt2 ~ o 08_E$ ! @ wp/}җl2&lX1!34q1D`00_? (l7|EG$lVX_2%csK? AL<CG(E7$u)|F]QgDpuK f3'0 "0 tt pBnjCvx;c1HOy4wGeZL5!x 1pxeUT g'G5QnvuuqXFR ֠zM(NNC F:y!iP{['08|H S 7t> CH B(Zgr;M = sL0I(|'|ٰX$4)۳ H; smJ[' ppE1ϖ :Zރ1#B(#ME2/Ր0}~h1Ñcq )?ـ2 9s  _# ŕXS- 1g A`V5n2zs;70  61wH(FK1@5t!F/ 0 Qf .vhN5fP 1b_y5(N"0w&'/w! xCxBYF _G?EBx*~,yCzs-uC!n` ;{b1&HMNZU_9Zv |?␦I[!uup^] 1jZ ɦlJxda$9l Y@V4r^A] n;B =Y2iX"ʔZ)kĀVQ4iiX-7D`e 'nPʄ;sYdyI[_X*bho%kY29W4WKs Bu53 'L@ @4مЪࠑH(0 Q(HLBFtHukg`SdπbiI4H%҉OxXT$eCz$jhqH_y J*15SzeSdeZڒzzG-NI`' ɔip; v!!i1E||$a9Ff&Vܳ<gJ8 +IZW'B%y~*sE BۓI:'H0ODɁZ P?\2}H2 2D=U\Stl2Auzr"SpJ؄ո^j_J@ Z2C Exo*$7賑El2 @ f<3 dL7t32Pxл8 HKE "Fƻ[:;6&`[a0 +W  Aq@E(!q<ֺx> SK jE܀ dFÞ55|guUπg[2S,a1"ќh-k51 7! ;)B01D w y;f qڡ S$fbفpu&g2u[}E ^VuXal_ K#LlS ln<'50 11Pp1cejXr?<[SInp妫u(뤄c p[ӧJɉ Jϖo)gĈrƦ˳13>?t947Bֱp! !ԀR1VgE@#ʫH#nQK% Ή%Rya!!7!7Iuڹ/ 2"` xkTbyTRUGθU/`RHѮc2QZ" -.%T P!k%Fc"iO!DO? ewY^ $ dSsLp\ Z95ȩt_? s-s| H0 C õygEH;2z1NYn4ɚ]pt Y >I _˓XAܡ 1~&ʿ( $BiH*DgK#"481D"6/K--Y Z--="iv>*5ލfς VˁX (mJP3PV.Z\32lVbq"N5n79;=?A.CNEnG(.-HOQ.7HL<{X^A9U\JH@J* v+bj;Yn qm_AZ9[-}I6Qf(M~ s,P5!En5^ ؀cB PC^C^s nID# zzC[NЋ?J$M~CF4,,^;>2X>$z.H)9+q=5-@ B! vQN| qBTYScYYN o%nCBpzB3;Ыl.@ >POR ]YN[OY9;OPAXtVס?L<*jٛ|%HBOW__Wf܅LNQ_nD_Ÿ0O q,MMĀu>Yqj ;k/jCSFRhY(!n_TdvqwD-AkD-^ĘQF=~RȐR֐KG,c&fra5m޼\9qx"s8qz ɓI1)g*D m*NVӝ0'>_UD]ZXĀ&-gL޵;fhM .ŻM5?~J+Pm*D$=wΌ$Ě9Z̧>mW̯`ެ&ޛ\pōG\ro^"8Wn[O<^<>sܹR߁@KS,/<|;j:;rΚqc<<: 7'$ʨ)4|*@=|Xői2  2I$0 ar# |FlA!|fjx0|H/UaDbd" U24y @"7"&:S2|G#lÚ@ly"T4 R+bӻ&R4R[&j-hیPl3ފd4q1W]wW_8F%@/@<.ravαZ%/@H|dСڙoKhr17X} V: ui0ȱ&MK;jH+y M~ 1ͮL8lcqL=Xf<3t0E0BT[}tI)ze\m; NzVCMkJT ū6W)MjVN;o]CJ"r**o"hp@`*7 " ADWH{˒)P S%MqRL+d(BrH`K^boX(JQjT4bd4ʄͪh@Ug#U妛h1c89NrpeER^` <#<@ >lܭrAġw #6v4F3''׽{`9{`ʹҐXEFH9`b,% [`HD1Jz>%F:Z=b\WҊQI\Rd%>tTg?5Vgԙ%GDU^i$`5 UDL25f:mDAmKȭVL6ֱ,sh8m¨H6uNBL=/|n!8J3|cpGQ6[|^l>p#D;]bGBցtßMPc.E2#<e#V(6&>`AXȅeMQ}}<ل0mH%L2!WR-=;V^ LgDuiZӴI+2Vs *l^DT!< *ʚExSo?rt=hBЇFthF7яt%=iJΕt5i/ot q|939$Hc0Jg8B4&$ q2nuU:NȳC2 j…_ 0lx+@j3ȧօknup.9sg&9ph׸s>$8X4"StgK rVS".+n%='׹#Ouo|&Gwݕ98ZtxL" #XVŶojg/#.ֿ,,' O#_:o(@|[F3 㸩@5xolFछ:DımD;8 q XNOw|: 肈NEx\wDXgZyIE\.6Ys !v(a9NE|sl X<$Ul]˓u0l A.8r -ؼ]@ (H n0-bȀxk0w4"f(ysA`A84ۺ2B=THOS1//!x 5!X98p/5X|Pp xπK}{JX(ʣ|$ɣIZɉCdA9sRhiȸ"CB_0@BQ.Kq\-L &{Q1 1KK$ q 3m0rYC "Kv3:S8&3Uj Shap Ȓq $@0mS p@5 \gx{UETPWQ) !hNNd$@eON3Mа n:q4G,$,oTx4ȌHwP  51@lvR (xwؑI聞.yUx3X|XY=! ۚ%z"C:t$T/1]VS…Bp`4ڮM%E%(Ӆ$9dbCy3lV[|CQ̙$@[|ЙgX1(#թ͝<)x;P8H="8[Y\`ae ڦQ)W xVZ`a$FhVAFx pհXO,]WAm"$rOzG$|P| y-y ؁G$i7`, Q* 艢Uu%EY} M Yى@8݃hh&]2$AZ`2$#l/kBDaH$H%[\StS\r۪B<&xJ'vTÌڿ:I܉)ƭ4aȝq`UD<Q M)ce! 陞mE R f5 fuDمVhn=FnKfB5@]!^vGQfrw{%_OPe_U_!SHӛ*"Ȣpex. -Ɂc,".i!= )=`o.R042$Th2E=SH˅`23E$}h{/!K: c9t0)ڪSZˆ@[W[=bWh1<:"9YTTɑCMT(%$%=7c\݌E i2 e5d%ۭeEVpU)_&XŻH?Rd'Mvn{Yn_z5_m_`'UwƇoRp}M()p~!6ن'Ss(r^?JXIʉjhpqhS{əgʠ2$MNB'=&kl˒;\h f\lp5%zK Ui-Tsxcl|2SpCM+QX劢5願UΓ(++(ߪijb W D~Rq f}^W4eqV\Ԍհ]kR nžk%'^Z-l~P^^\^lƾ4d~pvw7|p4"bQ <ҚP. 4A詭|>Q|qmn-'H"Lp!Æ@,0D/b̨q#ǎ? )r$ɒ&OLr#oU\ smkfnƱsou.sY×XӧQ, [v48ЁwK, P@&Z Jw/_|35ot6ne$[4xpI> cN0u7wZa)Nh{7޾.|HI+xF_ 0@!t 406ݳ]?k Χ9se3>tc;g 9sN~u@O܁`}䐇*Ȝ 7Xa5ib؈]8ecmsP&ȘB:M Ht lzv5|u9R+M[9,`b8홛^LggW`3N6490>|#ОMFc6pMW;.[-dnGMSS~ e 4<5g3,t9I+/SfĠfU[ fcQmݧG T /C~{s/")u}1q -1ݘ.7m6fDjsy$裓5$Д7^Pte@w,3C)dfS@zHw3״xP6.\} 5^yv={N G!˛G@A1Cf1จ~*r2#e"9 `4l$m#989HTEkLf&a T`ʁD"D$AgN m4@&=4Wi9 Bȁ IH}XZ"T _WOz$A +Q7#?Dg~Q!2Fx -c{ mPj$q$$Ru(SŮs {TrohVяvc )0Z*(h7XnT)BL[GU yǜƄB*Qj]W&LdUYdqѥƟַ&^ۺBTNzeRr;ndQ9'<ʼL`#lC" t6 lGM!M&8xnHHCZ)2 I1gڕ, gyԧ@0lvh-n[}CoEzК4k5p &>^L)84jR."}}Jzgj<a&mAB Bqy|q:z/_G H]f7vĈtZ5(i ,zhurӌ w8(p5<|J}rlHKq}0_W!p "A\b"|#ZɲdA L.@!MV2t($2'hZI;\Bd< #7q܄ρ~B;4sH.~E-vI`uD,=͠7/uj_֗sN2[-&$APǑ64Zcȳ lةǶH?AVec';Da{B)r~&U7l<:;غy z>jѕ6k~O/$b~u2`:HRH.0|uxEinFl HlM5U ` `88C `Z6} _ zG$ razz~6 J4aGmpa,aab b!!"b"*"2b#:#Ab%Z%bb&j%~ Y|lY)D)c`p&b! ؁NB~x H"^>(OYQ@KOQ<!7,1z5#x1#uItb:&gbF)X< 8'ـ.0ƒc#f=F(J"if (HW+ ]) p#~I 訒j*ި5NdzH;HH`Ĭ* C`x,uU xHد*# ]#n)yjC@BJŘe8\S*xP|84ѰL*T>&="ġV&vf"kB*jBpƢ\jn棦,hj>"?"mA'>Ψf^,r΁E C3\ldiBɦ!@Xe~ ]gt*egGVڶbfmֱӸ&jB(*vf**).k6ĥ &&lš"Č^ELVlnjln5<%BYbzZD>XH OKb%LmC`.\v6q+U-I+xQ)V+fBf&kfkmVVFvj?b,RƖ  @Zp\8EYlC/7Я\HE\.q}1r,NF@7Y%1m mՆD,f1c>:o +J*R~ڦBDdFŠh1ΜjlzD1HBؑLTnT:x'a:z"Dw`wKe+G DސB <d *'HbV*!042dA*1َg6DFjm>kpgd*1N*GF(oHr--r..`.>lzq)G%/3s3;3C2F(_sRfy1Gs7{7s8̬Bs::s;;s<>s?E?4Q0=*&qLCDtFآ@@( 5N,-M ^Q49D1OB44>tX8c]H]9F@8B0#^(Q1F9AGEb)FN6,BA7L& gY_37'5C_DF@`tB@[3C]"D_'aWF+QGGGIkI8$d 7 WN73TeS@h9\Q?{ ,DfclGŋ봊mdˢDU#\`|doEdUTA6{PO*FLue:ĺ5ItaDi+bb%.XH0=W^5Bv6]]BOU6puHGyOk|@  1NDHP@e 8L-/ I;s[AT} X@ CBuK<A5B0 D_ Xrh֑7FMI9Po Ao8{Jy}MLtT84 ԧXؠ9{#''@K87 ]H Z7Z:cǖ: 9Dx\wf:wͻ L3~K$7 ι8%IL5a{D1sWBx[@ E-đ+x'S S,u {& !݈bVx7DZM46ֻVSųXZhHGV\̞CXbRUBؠuNzp@HD%IXHCS0:rȃ8|•6V)ћ*=G aQ[`pȻ.TwH;G=s?^9L`ru3#`Qonli)Q)>D}yT# X(=³O 6@>aE]`&y}bXk~^|F?/~Z$`sC̶O4+xBPws˸=@1jȥ{Vpsd%VPs +WnrK7k,l S.pW0JBFmrтBrYt٠j BWe' -wKn]wջo_ 1|Mpa1j!pB\|B7n1["1/_SBqڴ #KY=Ƨ޺R5*Fc)%%wX)1첖q0\ӷx !jwIQQq99;>Kglt^&f3pq?uNk.B:`cL:ү399'lɦե~sqISkWi̘I3⅛UI+6 5l *q٦1)(dڛP_e20I$Hn-r|Hxb8I>}MޖoלzFixE!S{E9Ri5_3>@oR"m a– %hn̒@, X`7Lq49љ] @ϋYc~Ϭg`ɳ{^| =#Yko1 <P. uBum(d6ϋnGAR%5IQR-uKaSΔ5MqS_ޠNTUjHT*;$E A`&a 0"@re5+^ CdRRBт i(* Plr +$PG xݫ٪u\Kuf-LőLg>g ̖uN=VQ$ Р (<0GzUp#hIV$Ϋ+G ߉CzJ{[tc)X*Q慮yĦ5 T Al"@7nƍn ]!m#FtZ㾱D .ҍh" }YBaZ8a-\[S]x 2ug[|a7 #UZ.BseL#d$ۘ'vt r|}M0  0[ ]T&[ef2+.gqlCq'A>GJ'f>(p H JJJaUK™Wy1cE-rɺ.ê~q mA'! `%0 ~PX 2EZkMnﲡ~owH M6Ji ޔ@hGޭ⹛# Iݺ~b[$QҒp 5~e`>Z+8YdOpnn%q=5zD;oJKsG,9e 8Tʨm:9q䖐-,FE|F8AX nb0M)aukJXA.X-av6x}](K01ªAX&H34_2Z6ڃ [HH4vfÏ[t h?ڗ!{^w[Kr(wjp"H?bпWf]& lr1s 3TXAt=oht!h8(LϸD0-T3AΦ(:UDp(UTB&XNo0.uN"`.@͔evm"\)"+ڜ"xʾʠ m! 힁 U3!rIIT4dw~q,$ML7신Tu <}.n Cd.j$A Rj{fCȷ)5/Х 7| a{wt U4#˪iTh8%XfiʀՃؠ0X0w CMfN4脃JX0scmq8uxy}8xg y}kX1JщR@%dYS…#ƊM',b m//b/seXZbSjڪb`+/jUa%"ˮ<%y@t$jUy,8XSK/2*Xȁ$WYX iRU;*3mC ·T&< 4@coQ%q3ƌɸ/̸%\.x/1/.8颛&>AJ:. /oVY"L- 9/0LF6UΡ񁞓˔i]BAAB!&R8a6tS@be!{DbBL! 3prdKO01/.0z?a μ,8Ci,^:slc)KQeFZ2c`M*`sK9 7-,zӚ,Isy7RgKGGCa?sI^-`+0g@z,qS>@™ {\Z\h]i $By|mtg ;4-c|B=.f?4: 6û<貫;6B(B23A7&߻ ޸[t` .'yM3C5o;%{"*M+rb !D.掮,t-ĕBijT/!'J;D4 SG[MZ(\[fnΤ{P838Bނ3@ LW&~&@dShʷ\? Ʌu\g mm}&A/3~C\H۱yK#':+G)l5'/,H.+bbp9U8UO*iSkw+ }oeOܫmp]xCzןݴ5\ЯJ&'pg."Lܭ;@tZϝם%]05+.*X #5z`GcǼCUFU@3,q,5=< õ?94XX <;Y l u"h_gō^!%IF0}|(:}"瓧5&ӵS^jpV%$#6BmsQ\VˁŁ/Q{`}7N!Q9"O;&]Pxj* t%Cސ*}^_/&7YM|+=%cf.w¢=L_A5S^&`Y]+r['xfEz>)&`  "w1Y3.[q3wYvR\/۴cyķGlxlp!ф-_VJgAi3ԟ 9RHU^24ݳVn[1gJKo-8M{][plWdۼ}+.Z~$21>?}9gAJ/༃8 Nȓ+_μУKNibhkv+ eAEU YEQ>V]Sm~eTW mVaƅi8mc d*Ȅ|Z9[~4k6dt+Ni@+k*'I^$dY-tEQ{ CM{h5c5瞟/pf/c9^\pC0 `C ?!b Bb(اG%/' +K#Q$K"KBQ@G]\QeCI&FB2AYH^S a%byLb=&BbXjL5qype~5y\-TfӒTe9ij)_8GlhޕWor`G.fZmqiVm9h i&+&ܲ۔Au6M3j0Kw HhB Cgpcq0p 6ߨM f8F"bIHb,hX}‰ F PdĈHqd#gE"/`! /eE,0 U5hrB g 9:⇧!ƅ\-FI7< ||kRJ$Y UW6q18KxGB'Q PEZam!W?&Tq'?CqEy@( I%pK$V)XB%(3l`V7rqNVyQcY &zKbj‡x J\E&_Fm\R 8INq@KH3|hchy3Xp.RDٳ^/q8y">X w!`C!x}CA.|zRiA8y)>![$@Ou*M?Q7ЇZ%Q (+4 HCs,5n#$0B:D2top8䒘%)'8S$z, Kae!XmB&f}f?KpXv6!+k:䕔qHi')|L6lMH7 oeK3RC'euOa:(E@ 2N'ZIƒR&P|bRy"CMP?;+zΤ6,'!"{3$$y6Rըv6kCpɀcB^29!v{y>,.q N;k pjLs>)yBBy9AAxSs+zne "s,lA Vil s/$dB;G!f ҵ>_%@e pfO =& A{u4cc{q6fg$GWmsxJq!|KRY}U }ׅ^+D-b~vkxvS"'09qw` kw |"#7$7* v h&!*RE hy#fsz"2&Љ&3/uXG$ Ɔ5&ck cc0B>@fI2UOq%8baoP@ yg \ gLtq%}8#bV.fX*h8Y @0 &(6A3xHW ؐʖ)V W  "`U8'3&21RJQ3=(37bBtEpc0=gHBxØ^VV“agPpenXXZ.~!/"mROqPb0h+!Hyɗsbȑ?a8'.@) X35";&/9d^0c1_BY5E|XPpgLM0Xۇ\/p~~p^9RxsF 0t0E(% @! zyـ`#ב')㘎)/SHFyEPMC~#Hm1cc6N^D S@%AiGIF6P X* Q*S !*v̂i6z_xoo@"6A6Oqܐ GDOpYCJ @BJِ y?V ?ĀaZR*lIi9B%tB8Cj XC0C.^*ȂSclʡF<Bs qs!po2+(pĥ;r Eqa D k8bC+<~T ro^ , 3J%_d{[\WeK)R6}H>l1_AP3xwq^!`Ne H;'1 n j{lHKO /W (&At"HB/' B9t{5B=Q:q҆!%q59q%E!j (!m??PW>P^rI^BZQ]5A DaM g<#A(2+% (_^bAѭTjdBq=]ĨD1C 7AgQ0$H<$]`AG2c"$r*a2rH[71Q'h&A^"%pgyjGmp(tOƂE!!^5^p+ʀ$P R(õ^B `Tb`Evv<.=:_Rz68Ϋ׬JC9r qك+Ng=/A32D] q R|P0W񏹝ɏ +^ &c }C[.Q^m'rѝ^WjQcm@,08! ~>,,BO>,|nˇXE$1"RJRq>)2Nl.a'_ FE3c*e?tS掾Aj*!1flƚ"j^*!/h,V{E4 m /q@pُ9"P$?jcT/[5l _PX:X*)X@PL4ZYlc"_ ><^ӎ|X1ZBαWA .dC%NXE5nG!E4xr&۸w2;pۈt*Teli\m؞f+4U|r g.\='&ҜĬFz(8A gP 9|;j!YXmfc&emwkw.qtfVU٨q*NV&\P+TMN(2eTt&l#bwՂ eTPCYJw~71>texsu +W>V%)Y_8b,/K,>rRhxn*5{(S Рb =!'^QE÷&22($);glаE[ꜝ6$(9*J,rK.r Ytevq3&)BJ!܄'r50 M6 ,2 B?^isPր,hJyh"K4GOGOOUO-3IJ MySǾ48͇M[ (hc˦9u 1(Yg2V3&!Doۆ?|2 >P*š X!|r۫FX ڰC|4wьyl*Fho.IqG 1sv&{oo|Z2q!|qƱ!7]%_ ;F|9bBfc%B3}JX _v mpAqAP!1(".ˏ}!.dB*SsRxF3N~ F8t8XuMUDdyuA\ll`i58?ndd# &$@HӐ3p6"ȡ",&b 1CO|/P18lWJdc!ð(pJ ڠ.EGTp@1R<$hnIH48dc/l[ȅ1s i+7Q~fԌYL˽o!"8P~+h#H4&hRQM G]8 U*QFAv-p Eh f"s0tiC>mYl;܁ S0"V6)Quh`uYh¢ҸgbbⴌzN<;7 c8R.46C'1>?w#hU,` _H!=WgVAQM H4Av\;)kBjdBV0k4M) *hK֚@٥|,2Umk\ݪ^Dfpm:)vQ Dbc* '-X[`M(Bfڂ.CjA|1>SdM6u'*(IpR m1akLl9-iXcJjVCt .r(erVᇞ%i,Ī! qǜMc>zHBMe6_h v=gCdƟ2~J2rW[}iqz3)PD,G+aJ(M.ipD`H-5ApU"uX*<ˆU0'͔ "eЅFUe&SPd 4,|h8k^{.tdMA`撘# ! q+x$ R!P2ț,XƪA^coud!蓳4Ms8W)h>~H$EZH>@?9[ɼz#\WsJ`Q?G)|@Hw#ҳN (T` ȜD (K"aj7ږRze.j;G)Qhxq"Ym0# iFnoCy[+58 ^4^htbh8+YCу#h(_Ɖ~&ۻ!hGp@h?ىӈј!? )n-?h @T:,p1R@p"聄(Z9rH;?+?y,(jjH؊9 SE53hP ;k:YO Ejf@&[ [l.p $z!0lFEo;F !) XsLjH)L)p/h&1^ 닔4<f- 55ŷRf B XuӅ^O pDH*'46={s`Ѧ2G` 0>t1?,}[†'/9pkIpصׁDpsJK4D8?ю* 89V,2K|Qƫ`n 8㣆Dj0 $ƧF@IK${;tT+\$FrLu 9BK0 0;H5]X%88 mXD hp+ 6m3eH&C;,"I4 =34ñlGYHɬ3STrHi#2v`N`^`n`~`` ` ` ` ` dUp+d[d3 .a > oөf!譪bc06xPN~H6Par cJ]$Kc3H`"v&1[Cc[jbFdhEƈ@dcJ^8?ΜѨdc!eBT2Ne5tV>?6qc­Xж˺X_vV֋W^@-⊻ P\䠪x W6 X, j֐ahN'KdQ>wgqz NqhpMx}V}a~=6g&纔Wy d"0h~F艶eUh]9X|s0=3 Z<;4 S̖s0 _xP7/sosh. h,iN-fcX?Iq 1P źHkS|1i?RDPg+mkRkqm8kRk |@lk~laeN&h2(ij1iao+n>扱LÉU*꾈"YN/ćgA ?qZ'pqqL?1d"gA#or4raehh_o&IxH`Ȅ#s0+w5ڶBoN$ԓ5Fs,G6c029?CoFksRNqmF\w~BFH7LOWF_MOr;]\J6*or|.lI8HoEFQpM!v;'s8g6bf\Ŗ:S7b7)fpn~mHH(H!vňX nL9Jx?{p~wxGrYX|o/ ~Ow?xuwu4BZ2@0 qBo s`PX mGjon!5lH$!sjҙiNy.9#e U8!N 'ل4B3@&yg1tvn{M0A{+zx+ccAG jVq/ma:X>5lypmN TaVm‰1xjGznfE5G$HG.WAtqVXsF WM{4O7+ddxgb1|'*\ۗ˩0^tϚǖ|,h „ 2l!Ĉ'Rh"ƌ7r#Ȑ"G,i$ʔ*Wl%̘2gҬi&Μ:w'РB-j(ҤJ2m)ԨRRj*֬Zr+ذbǒ-k,ڴjײm-ܸrҍ5s/..rn1Ȓ'S-]7v|+s3ТG7 .fҪWn5쩉IC6ܺw]2G}/n8kҧSn}5n%iv;ǓxWG׳o=ïo>!9, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cm݀diN:`s4q*79*Byt38g9vM9N%:J$NJcޚkV-xLMϒ9$"x,l{'xǮ+XfsT3Et'Y7VڸAh*8PKn2.rsJ8˼/yx08[lra J,>X1"*'3>;gr&v9d >C1tsf7ѵs,{2*˄<,6PvƘ -j mOc*+EK4kƥ$xQ68g ٘1)8St58%|B CeCx9Mʏr#\//)/kh6 N8yS1P&fQ׎BPMl(oؿ+y{>ai;6P TgAx0q1{U;>)O76o +{gĒ3Er1ac2 jR_P*0WޘQqd!c($TuzG=vcP[0Lf%3;eF(5} -)6pH:x̣> IB:)$BoFHT[hx[CMpGQ3,()V# 1|tcI>#`4^KEvn8f' Ј6)Y<H.uf _(m]KtXY&)7 ͍2}M9&^ESXmO~9xht1IgrO 4\ļsePq eR"!́?K{ x25^CLxSIی5AT29iAtPuFЛ 5.u*92`A%&@k t&Qpn_D#h@PT!".19]t+VR(bu: 5xF.ŧ k)oXW/{;Ԇ(9ĊYC:j8aCr 3@L7 |xq4w2A)G%3 E+y@B8DXFxHJL؄NPR8TXVxXZ\؅^`b8dXfxhjl؆npr8tXvxxz|؇~8Xx؈8Xx؉8Xx؊8Xx؋8XxȘʸ،[wTJV[DuPKNt' df@8 3D+DNCS xhQ4R;y"QKԐ)252#{!qyӠ@ rb*J$$' ݰf3XV+hӒ5i8.)2x {)ȏZR+i t ]1Х*D?g1xnpr9tYvyxz|ٗ~9Yy٘9Yyٙ%4a7b'/5' wA%2b0ycT y)cg!ɹkm1Xbw  Y cD'xb 2P @)I10۸A4НDO@6BQ 6f ڠ:Zz2"@+w!$Z"*̕\+S"L"j*ޒ+qa&b.+ӢLs0"9ٕ$%z1+LuCz321:L:ע:$:jHě%c#"P-**R*lxFpAj&%oʕ"tچwVJʧ%*$ʏ:hPkh52\#0$XhL@f^ӝ}*. J\+ } B7E'1Җ1#'z- } zؚںڭp(2+9[H]Y, -ʮU8.@jʖڅ+cv#!"#ZȒAypL5 ˑ( HYU2p +Sp*Qs(KJ0a+XDO$ KBh B;D[F{HJL۴NPR;T[V{XZ\۵^`b;d[f{hjl۶npr;t[v{xz|۷~;[{۸;[{۹;[{ۺ;[{۷iлiwI## wv@Yt@mj] ۻbߒL ^I sDm |xpp1kK+{;^ڻ *1a4yB2m# x bᑞ" y" ^:+qP$&5`|4\/ {lEG}urz Մ" |bw2݋ ؀~5dS;L+08S*\bďǑl.ll. C)wp04运ʬʮʰ˲<˴|T% > X F @[2X4`  L0eܹ@, Mp !*3~ɴ@R-@ G+ &X8L .+!3 (1.Ck>0^Q {$?.+egV9VMqg0 _ r,:%LN>̃s 2 } a-Cyg 1 1Gc &&jc57]+/1 H)1. />tMC 9VcFM M ck @Bv&yV+ Zf` '4f" (Œ Y C3M]ս  ] `~;_^FH ?iP-^fAYN"h0=2E:Y18HS qF1}'P7hCw!&"^L@ ;++NhD ! ýL NM D` ۀ  N> iė˛8 ijʕC(VV(N\UO7Be KMjulM9oӹ3#>TA%QI.eSQNZUYn5ѢKf"KGM(1TEg$y"w>he-4ށKCbjlLkK-˼SpV|[s`KW\g&L\fȀ}"WC6Tx= 9jW~.4ǎhglTn5ơM2k4n΁nȰreˮpaZfk"&yfɥ-|dhlhli%!]bzʉ"HJr?,rK.K0L$1a䬱ZmJ.\δzK,Bc ic2L,E@n$f [4F &*bȅNpPO8@r3!PDԄ0[]OV < 70{'(v{l05QHղf =e]ݪ0& <}1plzYpae:|X촤8,'C? Q阒$bKT`(ClLbE| e%$%SII(ci;cCydS'7E8NNK3̱o7;'|1O?6C' ) -3 m*i0PA.4d/sN k鹠 0ըn^0ήUVA[?#ٽ~06v@|틕nq SIXB<B]xhMܵ|=hKqPHșXI&}ʘʍQ(7xW~r^&j3Ny.""(a6zo쒆ldS<hLVpx$pٍ kB%* *Gl&Pv%Gj=E8ƛ:Elǜ 17&Xc_knT~4.V}J b 0еe_Gˈ@ @بK$ƍ("Ӂ!zeecP~Wo}{_Wo_X&p |`'X fp`GXp-|a gXp=aX#&qM|bX+fq]bX3qm|cX;q}<(X÷鸩d|d$'YKfrT~]Ƴqmd,gY[!d$qtE|f4Y N`_ dSYssA[(3ai u6;ZЃ&t RɦB hHGZҏ~- TdZt=i,W|giPZիfUαttm}k\z–~MXJOrIu}ld'[fvlhG[Ӧv}mlg[vmp[&w#kxfwݝ/+)R<1(=ݽ;+\X[ח#B: XIbLpͷcU#DЌ_!s/P#dut*> J]ق"j[|!Qf\,1tc^ׇYd=ZQv=<Ya?cPq74bĬ[*PwI99Fep|{sGp\u΀x"e,]"x5לSK(;:ܤ(Ty9'Y@\tx8>,E p8@վgG&i@GsBN!`FbݜWjbڤ@X_o2#vW ޱȷRp)R@:(ȋC7[ *q㼟P=`P9^t0H3 KMӽ"Q/I<Y@Gȅ YiyX0 В B+ {6:к{H`ȟ8h љ +q`ܯ f1< Cb IɌ'Ȍ4x;RCNp|`M` i܄I‡lim8 fPCϣTE1ķTWp\ @pśچ3U\O\),AQO4;0īBŚӏ5Xa8u9FЩ]#tІߠє?LLpH;@ :̭H?|>Q0-t#UBt@y ӼG`X|(?|v،^h4"lಋT''ɑ:|N13\ = NOMhGnA]"qDX<0OJ0rk 8MM EE E 5DE4`X($` IBIxR"Պ8eek)G, X8WH H @ QH݌SpӤć;\!Q0"@TȾ@ DM &X&hGO(0ē8ţKW\Dӹ]ʓPQPD4հ<"TWTUxJU\j=*\ \SI Ex0jj\@Ak jj|]/p"<ҔXȊiWvw}=ð Tz팶 $׀ף W|MNphIiNA%2UQ =eT؋ ϋg`,hPJ)ُK;@j`JD U9QY|KUPRP[+ʉpGEVqj1R_:EW䤪`Hz⟅3-*9 '8 ˽ 4,̥r=SkJC#C]9l]&8?Y ŌE+FDf;h}].F /$0^3w~ųKV`|c.hފ;;M/ >hh>;Z:hhi.i>iNi^iniS@iyJR#(w:fۄfh<=277Kjg i͈Ipq݃8;ВF.oVѩDkpعBj$Y\t r0s:;sȹXҥHq3Z9(@-NwJV ~j'hh0jD7xdFh "rj .XŘYq &=(p11skm] SnpIn LƇJmh&0N li ~ >!vV Sm^ڮ~Z<f88y8a0Yڜ-ܨ`Zɔ;=@k0t18e :;-3Hb(g*K6h#6ɄE0Ei~iNmbāX]|j:7 )RG1MsxhMЄpYTi(E!qgqLOe-  o>l  Ā3\ӟ&lcmŠQ#"{m1 DXJվJbV$Sޥ RS,@D8ݑsqo"޺V(>/Ԅ-v"sODbpXFmHZnRth!}2򄊕c uVZgM 0s(Kg OSvCQm@,zF0wʛYdgp+FD:T^`c+t'Qɋ_ 8rĮ3dH 2D_=PS=93n1$V'YQbt\8uLyOM"&B2TDx_6 RcRWZ!VΙPY ~&lL\s%-"18#5RB8B,ceAB8}"th 55|Î8TC3 9y6&>݌7Xhj䌍q&/] 1($ > U5gZC 6()'e8(jC"mJ.Q!D $,F8"؊[8RPOҭ`k A T6i%bhI)n8WZ{-j-HC%Dqkn!+fYCN;Vf; A}N C13D9f^C" {홚~2O&Re#F"RD U,>SUT2t8Q)̖h,3u}7y7}7wT&1ؠԁ+8;8K>9fSJF"{9衋>:饛~:㘧:뭻:>;~;;; ?<<+<;>髿>>?????(< 2| #( R 3 r C(&!&c"i= ()bV<đ *r^DM4f<#&i|#>+(=3 +<$#D0|$$q19e$&3Iih&C)Q<%*SU|%,c)YҲ%.s]򲗾%0R!"D<&2Y"|&4HɹU ּ8ėUf)q <'Q T|'!C ^]&JtOpֵ"b8ts֖x+dk+^̴ِ1 ƌ.i >ZU%n SQ\ MAղ}-lc+Ҷ-ns򶷾-pU(ka) RujȜh,j`i@Obž{[ߞj@aYf:׻H"KҤJ/yx[JP>` F¾t&!R0Zju~O,Ӹ61s>1,!F>2%3N~2,)SV2-s^2,1f>3Ӭ5n~3,9ӹv3=~3-AІ>4E3ю~4#-ISҖ43MsӞ4C-QԦ>5SUծ~5c-YӺֶ5s]׾5-a>6e3~6-iS־6ms6-q>7ӭu~7-yӻ7}7.?838#.S83s8C.򑓼&?9S򕳼.9c.Ӽ69s>9Ѓ.F?:W4gP;ָS`f_ ;V=κ?]uJ6홆B!ugz騥;~;/{ܧti+O~uPǰ?II_]Ł cVڗ-$;TiBd@<CUqu&8AZXQ"8o {ُ1k=n?m@V,:|?FOU`#7Ѣ{w"b3|?`h~&"_E4XHt|9 lC`@ָ<}H5ԋv~  Ơ ֠   !!&.!6>!FN!V^!fn!v~!)7<8CxxrdĽ$4T8t9 8jGdI7Cxx:x F@ 7@u6`C`8Ganl tC:tqFLFA"qQe"F8tbCxh(ƼGX,,jT;8 Cv1w|"749laC%E9J*t<|"5"XA*A>pBBFELD9!h`@bADbC7E}B&D/X6hkq $c6d,&%b"C.$63.!rF+|^6⃢ Jʼb/ EqCJva  D_7fƔN6S>%TFTN%UVU#7^s60bA0W#<ʌey#$ZjZFB[:ZZep%eCY%p%jB_%p]o-4 &bR@!,3 H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0c2`:xɳϟ@ JѣH*]ʴӗǍΧXjʵׯ`ÊK]i6ٷpʝKݻxi8sesÈ+^̸ڥ\g3k̹ϠC#|Hn^ͺװc˞-Z;է٩ͻ ~oܻ+_μ 7ѳkν)#"ӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihl _ݘ#978u8 AD#5$1SDA8'30e0ޜ w9fnf >u,֔3>ߴs,@ZNSd(KP*9AT <{ɇ'M_U[p$<ş$W6Z\  :+\Mz('Spn9^w9BիtUH5\qTcWSQ`:L9fuǺ}p`ApW >Aj\X3È&kgҫ6M[n;YutC9 uqSvϨPؑv |g8E؃:׉# 4r:n@F1AxLқ3;ʞHL:'H Zj67]l fD! UxB%| S8C87!>rhBć u(PGd!/T-|,M|bYpÄU"S zM0 cHCqfcǨF8#D9:EHяT"9iXƊl!x"  F4JH9td2F'r)L5 ( ע>ڂ{Bzh>WnLfe:lhGjΑׄc6 G@9H-ăƚ-tHF!y$RŚ͓3 ; H ϓ>P,|T%P(U! ZKFHTQ]vcO%>pS&;1L>ӥ<#Lg*ӚVgsjÛ :2T'!C cC6dJ !q11zNBꍲ.OFI #P\Jt)vmcK7ᬋIQ irWQ)6R.elL}jDVVffqzǝ1$Rԏ4<88@UcVLYɐ~gЦ,dsB]瀞-Ս_"!,> k^,MWYȒf׫ޠnOY&AxɎvmmńȖ Ȇ!e zvU'YjF:Wg5THt"A#;3kjH +XlNqy^qY T8j&ַ4@ښ6# " \eQܶ8pּWp gA7ź!lvME=+"64ecKvb 厴I$q *pn!I1wiNHլ)@!mqbĕHh.Ս%Ra{Pw E'ш汵-dI۝MXLuo -5"Kmj|064fYN(%>ZlZrvZ6^T吸lن=ZBnl>[Jd˶<77li%O1LGNctTztRX͙os۳48Hh[r3K`GHAxgl 'yQs*{{l"R3y͕*$H$ BOyOy{@B8DXFx<|%>{I`ez4Q+Kq[+e 䐇 !ݐp(5zv(8@#K'aT `paWxyp%P`R1Qpe5 %uQ܀e%PhC a z  B.p8! 2pzшH)IԸpltvQXlt{X4>j` X( H,( hgOK׈8J 81L!45g܅ vU]i (V$A @&5t1Uxxf$#f[h'frH%X6pb)Jdf8<˜》yؓk! tHeٸT#Ie]ܥg`1O$'.>iׂ)֋IpRi킐B?A9'ÄlOYTa}k!]>)?(A>۹?j6ˆ@j& c'|JH8Zzڨ:Zz2leMȔpjq"Kg?%\#Y TD%Uԁ0 /b,V!m`9qT䩣:#x ra aEPhqSBf[6ٺʮa0PԨ)02\]lPKKWV.I;:9ۊhe Ĵe:,#f}qk% H !,P,i !5kM)A*,m3,WjP |l[XQ {JbPyl*Z! ۊBg0 "mٰW%풟`Pfꩺjۀ GO!Fpf;%6:a9 {*'ڨ`=g*zc<{t V`+;[{țʻۼ;[{؛ڻ۽;[{蛾껾۾;[{ۿ<\| <\| "<$\&|(*,.02<4\6|8:<>@BQ*e4 ! h5_* NZ*Ni-D1 0\#|꺡!48{`0T.;*|ƱNm,q1 u QI0Nd4Ea.l 3~`읨s/!Ŵ>"51Ba"on /^i! @Q 0vvm,};eGOK*S=&u[AQE3!v #Lez{;gDI_oNELIYopr?t_vxz|~?_?_?_?_?_ȟʿ?_؟ڿ?_k{R'ЦvXA- t;*tA .dC%NXE5nG!E$YI)UdK1eli8nڝ;py 7rq \Ν;M,SeWaŎ%[Yiծeۍ>I3)׃ShǯкG']cȑ%O\e̙5o)b|@.["wjK:?AmܹuoGT,0szE;'T|tJUŏ'_y՛\1r;,Gano= 4@TpA[d4J/|/]qlX6:дSTqE[tE-J D848L HDhqI&tI(dҚf1o9gA <=FMrN:N<\+C|yvIJ/9Rs mx+&TRJtSN;SPCuTRK5TTSUuUV[uUXcuVZkV\suW^{W`vXb5XdUvYfuYhMv Ag Z|Yd9r TIiw\r˅H tI)5u\z^d0. Zdw` 6U})Daxb+3an:B-cCVc~CѾyEVye[M.m]\fs?G4jyh6^r"gH?ij>W逺#Zt6lV{mvm{nn{oo|p 7pW|qwq#|r+r3|s;sC}tK7tSW}u[wuc}vkvs}w{w~x7xW~ywy裗~z꫷z~{{|7|W}w}~~P$Q RIJIAA-8BċcN:10Ψ->:B6.@^n@6  E0F$^ _.llPaQ"`oPWQ"!;ЃF2F. azG<ҏg 8bC.A  C_ RHk2qxXbȤ*"QR=E`$BF.)[T"Rkde/}K`S$f1yLd&Sdf3LhFSYs\/@q I191ud$*|Q߀A(:2+SPc Đ&zfbn p[l~n7t<N1J; X 4aQE1gxRIc0 ǙH110yJs包Ay:FgRPҖ".`CqU`̰bNcwsmc T=SҘRJDKrA)SM'dUjmMSܢ < A+>~q[1'I1NG[qWa8e/zMqTKRcH=*Hcs3(sHPYR(fL8>Zq{e$ juIZB< Dɉ*nIjj0Ӛ4L|I۶vYV^Aq",YYe\Ж|SdB G o"/P7kLDɩrL$T҄7K!t U"C9<:l,&fidlH6\zϪ[re0Yc&s|f4Ykf3zZ&ds^JEnY؃!)GՊ\ OSl%(B\g&:щMڂ *,m6WdTG.ZrMI!=ҡA $%i: c%.pA]lE0$RvGkiD`J y|Vm8G6-&XaxVDzfVPF7ъc[jM;ҝ8H.(# 1q^"!pKz;0<:0c@8*YPۘJ:4NqK*s|Zh\\nVDE1rztϰdܹ ;pn&'iQC!iBa͞C㑮V$o<E bM@=q};$ҡQq%]4%ˡm9ԋFi@3. h!CNzCv׫1bODzICl0GJ;B!Ƃ.nW23u<uwH{&k‡Z@ۧ;ۊkng෌jl_ЉM@;7h3#$򠘺&BTm'b=ЃZ @>X>UQ [ps!.d4؊FOd;t,Kor?`*:B2kHB;pؿ}Cpx sȨMh'`;Ep(n+ kl@h O@؊]$ek$q|)TAwt $JBg84wBS0V8 whhw$aCHJlYbex,;';F[L@T!(㸭 Hl`ŻH8DK&cE ƲQ+ pطyFX@06 |(|ȹ0tK(Jp8ʖ(.,xD,Ty䥉D$8PL sn.p`KxT8.Ќn1c`"'S TH8lMP &`]7Qh@V%_ Ռ4|70%дHJ\ҘzÇUh4IZS|0D87AVHS!l#D""5wt9S$q`TNTHӃ)H$ȍ,OKMOL2:4Гp7O=0A> ML WleЕ@>9)Gl e'UxlD؉U kQkKxP0ahTQh7IQ_L<"mFň{ܧ`f7 +-,=Ь׿?d4F598]p5|'GqSH!$eI3gp?<|0TD켲GT2IMM0TKeY|YzOP5 Mk8TK` \6V\ŰUkZŐP_E@@3ֆh>0ۏlX[ň-ŀD7+ճWuh?;|c?bH&` Me0eȻUTxgs4R TX(lF | Q/W|\e )PAbXXpM ćݬA‡3jUR\w;4j>ت2X~ǒ= Py-ĴEeIUٙJ% b57Kk_hq s1O3Km\xaPňPmXRI0BI MJI&2 PߌR !X$(a.aՒƣ!FջEVUWX[:cc(% iwu:d*A|86na7mAȅ'B=^mA(\Kmِ,EdAԖ4`~W=x VXi&SWHν7 ;j}CȠjjkkp%k ]8MEq3F& LWFеxΤKWE 섐^> #n:0K5=l;/HN<F kv‡iЫ 4!m"ߓ)6دt E6|[lJs2vz1e31.8߃f:* `n8fo#o$,M`Ž> +8kօap VTx>Aj^ƶ6آp }s6PȔ@#Q"qP:]3fFd@H1IpmɯLh-7޹s(4K >(rf#P>8m (M/9p8n9r̳l#R Droo9$QdM>kE_t@_ns<0.N; 760*|l/FIEg r|_ڻÏ] H-6?xc *8+oćfM@ws0nn@ 9:k˦j+%&P0 8pp`EF>MX~rjz<=S0Dx[ҏZ/jf`#"@Nbx@}@@}p|stEA2A?fG |@sz6!Vb%wYVvpz_?5Pa߼-Yʐ2S2AD2>¨h 1 S P 17|b1Og{zsnd?&#@angTXlc{N |$d'xGʎV{R]T~+bgy6J~4Aֆ\LV``|ܹ̾l̥g !e%6.,r i̶#PBMLmXuCH,>k᫩as/3Khm[־Ѭih*DvK(,ٰ6V>=+ذbǒ-k,ڴjײm-ܸr-.6Ʒ\ѯ{y nYl^6D %lCx18^x j;rFQhr@#&d`7gV7p˂_US` H5PC͂ (% `WOxQ6U簒WτxS6 '#~X"11>Ob>1D$miΑI42$-01NH#JFND&BUMgSs:fGwX~E'XtS*(:(J*i^m80&t)>zcI,;\ehMNդ/%.Qt4mR0:RNL,[PH qLk"z⃁@n3xʝc)gM&κ ~3!a=Ęk %-~!`*#N4ra9]/T58hJ:8cx3hcQ o&|ΒR2ճf̗NIdN٬%DHD>f,LoL(4~&h`?0ML|tLLcn7dΩ5oVy|7 >y S4ᓍ_mXN5!mShdY⚅NRSư3A茖TmJ~W&d ۍ¢mM{uf].1Y\kMM[~lQl4ʖQfă0eH\1gMQ|QCi9P2ٰC#D>g6!aip#2:4E KIM6 [e#cFl3c26ԊX$[閨ᮊV"8yQ\68z3&Ʋ ]XL~ kTcHm}f&/1 W0!Bd1 !-ޙZx:1f1H dA)$FA3Hɋj4` Q7Gh8QqFq8l C .<4bgć\T5P Y`Ԧ z?<9L A6GA1jV9 du=,WGAtbL1|HPtB2)dl%DF(q-0vƷH.})Lcj8p 5mC$V%GOœ^ߘ 7qHɤCzS*dk!nTcj6j"X*KIHdC S1 HB$AoaYVb nd$Lwi=&zg&AX)bV:+b}`A?? H@P!<8R`&QT^VN/'*< $#Ro ц`R tqcZ zQ2P+kA R$Q| 7d*g dC@pN((ѵX{a&Τ8ƐD+]S84ˋk raÌbG%"LjŻ򈁥c3b#X{ n73DvDXx|3Y {\\mm'XTkqcbOFH΅Gg zLsJ*2V3)p?Xp'4CM6䕨g t?kOMy+/\wL1f03dk\%eن-m""G&sz6bRL8<#G*Qv%sJMi$ޛQb!p@8#.S8pP.' u9.K$?9S򕳼.9ceu}OotsDF?:ғ3HƳlrSV:ֳs^:.f?;Ӯn;.ӽv;~{mhu?<3^pLSk]L/SoKbթ_>Y??ӯ?/ӿ??  &. 6> FN V^ fn v~  Ơ ֠   !!&.!6>!FN!V^a]D`~BMDM!6 G1`8p_ơ`& t9>l%!!"a68!6#C*a=%^)"1 9T"&~"(a("*E+",Ƣ,"-֢-".."//"00#11#2&2.#363>#4F4N#5V5^#6f6n#7v7~#88#99#::#;;#<ƣ<#=֣=#>>#Rf@C B:BF.+PI$F6BF~-"" Hd,F"0zId#*"\Kd(r)DҤNZ"+N$PP%QQ%R&R.%S6S>%TFTDQC3LV EVJ5YC@Y% Qm[ %<]e@_ YQM0_&vOa.f$xeV2dN&eVe^&fffn&gvg~&h]\7PChf!jzj&>&,Z&0A0AyfUUF&Z QD;Jj>a~,(EtDTr5+'MbEdmCV6̕r8DpZFIhBXXs11|ٺ`O:\@t9C'X' izʞV@X96D8a~ŖE&\i[8h\f6 *N`TgY&'y)0(ZivSXK 0y6EͤhWd|(XBoMlfeHoeL`NM|Q<΂0m*`0H 8&NLMĐlʦM0jY6hG5of+vfЌ[B 9YM4jrfLKf+t;C:Hg*š_YL.Ƌƕ~ERHF~o@xN ^VjFfHmì*1AϨM olW*>Ao-&fNoM&$,H ̶,> kf貖C,E=mDGhP*r5nV(jU28,N՜CǤ6D3hۺD&0A-WG)`F9*Z\E$nnB/"L.._4f&h>lIoo.6lp".p*l0>d8sC8,6x>LW NATp4JC_ug8lƠB_dև>+լ$Z1>T2"toMO/8 k5ﲞX> l\MˍV񽚌fT(hWt"'r'0S!;# K8lH8hštr'W[,[j@t&p@=l)>0jw0h0>\xTiL|(@ .{E*THj%qUMo?oDLqMϪ,5j 8#|m6& C yDMs<[L|h As<SwFobEr6ϬG#Bjֲ%-B҇+Gw4(E>E)^BW "@j] ,>0*RNSO3ɦB*HT 3:n4C/~#fC&U_n5X3c|/` ka-ifM4mtmBgV(]^Tq4گ,%Nt/K4$c$_tIyy4>G8|h nnpQC`MI Z}166pNC6ha9>=mS3}-tulw3&,*,1,5Vm6-[XUE7t7+ ڮD|mcsFp"#tDڂC/0FC}gû:f6[ goלE(pM[Z>ه̀0ǕM@p8^&_MZ] rkjH&l$?64-V6\lljogwwkZWT벉3=y+ )C,d58VFc(YCcǭߓu%"B0 Bp["*nn#(mȴS)¯EKQtMfÅ΄U@4xěڟ 84@ 91ER{F/_*e 8(-Ҟhr6ܼ7-?GQ8C;\d>>z?7 zXy;/oK)xkFPI,@\~8QWd%`~E80<L%>| $@ђ4t!$xѡB9rL"&#I|R&'WҥD3iִygΙLvvhPC5ziRK6ujTSVzjT]Ε2`,1u۷vE{N9>[@7v<@`p[߂ (@9x=th>1(7Zp+کo+W AX0ق[%Z9|܆D clf%lg#P&0\]'1Ō0bt:F/W>D#K P&`\|%L+03iwL! 'lDIGCI8@$k.Vl!K R$2CId^Aٖ 7qfH4Cl&Mܢ mKڼE"&zH!DkP-@B SK ;@@STU]V]}$,C8@1X`bvTQ qEWbʌ^I1 @ͤ匲R<ɴ(۶SpK(3i2MlLqg5L 8'2fVrdGe"mH=!*$@#J7OSN=-5TF N}e暧p֯+:E2Z`:C 9Ҫ|NڦxkŚ9 sgm Hƀ(y"F8;W7 fzF* S+.X@fX* YB'2b<:qD -;A eOCNC p2$ 5@$Y-:`B. Q ) ֱ,|pB ;:SƠȆq(&' 452M0qb16WB/ˎ QAES*78YNs49͟``d  Mu.&>O@ ZP UBP>DkxF9QN4{HGlbAj(&ϫ:yQS4dPȚvDqrg>H('R[ldoxSbU]8rl=xt4kƨF H^Vx5#8qT`x}=$Vuqi#> LfTfʪq_HQD#>~B)U$>i>8{gPIM!ap9* 3H*bӌ FTè-Bjט Iph^nWbGAl9z^D;r(AҎ83i0r`l'ZͦElGJގ嵥ix%(ۺĺ9e@ @4Ao@NPQ!'$L:\:0;RvoيM21e1 I˶0`t05* fqQ0 )F;+!mZ8c|8Jj:P[R1 rZ#G6̖((%|H1/L ,4{"3L#ZN3@9-RR,f먎"o#60,TWQ,]4"+R#18C!LM-^PCr..2-0ӎ8@"a 'nGpFC!H(D,hjf0Pi*'"#c5AkRӘTR * ]oJd,&&1#Skz@Ҁŀ,p,P)ŀ3*C1 +H$<+5(#ʲb -qlr;Z Iha !i̭B+(gqE_H#A4BDC:4B(̧A֎"cˬfH jCG$/x>/|HaHJ(ʿxԠ4d}|I_HϘ||`ó-.,)=R+<@r0aq]+Ԩp WJE2Q5-o򶉞(V4Z ."O/sAr0U/_^U(RXWhE!xK!2'jp^*P!6"ʳ*8Z͌S1mbF)րLA&DI _E,OJȋT$aQ2|ಲt("Pk8,Gzk5pB8p5خx̴~Z/sZx`gTZګZǚڬZךڭZ皮ڮZگ[ ۰[۱#['+۲/3[7;۳?C[GK۴OS[W[۵_c[{x,E#zAҢ |6` ja (Hs1Gbq5bk. U4lA`f '71lA `[ ˰Lac [m Ϲכk;Dd1c|0#K2ʙzʧg<˿ 7.@㿥@1 t8` 6 4S,x{By%  aC6M:[loWsV4b;!1Q{1VbM#Zs5b7SY|epFiR1}No+XLk:s}1%jٰOŒ;^emؙVٞ#N*e鋧M;i>W(kvs7157a-s|WN5-G |=Lc4ܩ_zw4ge0Lcl1l@@5p j(pĘicN7CAxUa9p4GB&Z jX^ ^x Ԁ\ &s!3 Z`ԀGjbLJE$ZظV0*KĨ^=|R"8D:2bUۘMʈGװZ٠Zec]T4fԁm *L 1|TYagD K̏y ru,b@RL2f:Ќ4IjZ̦6nz.bAvqs ć8yNsl'>iNu'=ىeܳg@OT%@YЁ  C#EQT ]h:v2*x7G*(}Ԟ> ғ,gJeST eFӆD-:T:%G?k>BU~@H" ( XoA8IĴ^~|8?:d$뭆bW6HKiЗ+-,b;IFs:YHjEYVV K 9T|L*4ʇڮdQ+dqRGjk 8G*t}ѕIpV(E`oKo9X0Ucz g# )y׫Y9 mSE=mJH gQmqAťCM \<#PXC+#.I> dzwa*^#>lz{bʢ/^yޠ׽1R Et#O,| dtY!;Z8U!pS$N! k%Iںc6(n:rbw͋E1;ꝱ 8FjQ,áJȅ$YpTe){[ [@ Bq r9J7y s~g:ε3, ;Ac;7E $Jxʘn{JӲ@MD&bF|k:ֹ~wwMo`8Ͼ7\_bh#H|[þ"J[~9qMsw漞Kso~/!?9 ip~zәVU=xJK~1ePy])9}o۝<=$=jwGj~r F_ j#a^G\#A}6H'wTQﯚ7PMluAq\] k&<9 )Ra$˷۫ܛ#䛲P}dwQN6I! Q찮QHWS:` jd|ȏ>agǘ(AgfZjgX…  yA4 7wpkåė;|^~芾>^~阞难>^~ꨞꪾ>^~븞뺾>^~Ȟʾ>^~؞ھ>^~>^~?_ ?_ "?$_&(*,.02?4_6o(k#5na4|I\C 뇏0PI)CZ<}c$(eI!" B_ Z!cS@}A}Z"Ha q"6st*D7s$$FFq vC"a([qF2 uc('8fÝ9e p,(>v5g+ŪVH81h3)Y>|eA2 8./! P R,)bEAưfH*+:\:օe=R4^;4v `g<EɆ;Jdž*R1*)ba4bMaeVeE*L2dJCJV|(aR8lTh40'g;p4Qo" [<+#>0Z!IBLea}+[MlM~bU>έ)pz(_K."( %oR6Q" 6^! G9Cjm="5ƈ7#>d8ۂ cN!4 |% nluUBǕrE&E@2KeB (FA X}aŊzD{ T M8Ǫ =qE(5H!qziC [F[lr0ǩ*%V!NmEApb2x6@L"#S6Ј;:Qܟc x>QStc5蝸+P K O X'Zw=P:CS\6iZi~Gqi ` s/+ oVⅇzE* 2+ϊ1KV:8{5 =h6Q\` ɟ'%]`oA,KE',=pݰu/~r#6OEx^w }HxGt#y̧Ȱ,lO0@!#GM_zf^g}]z^}m{^}}{_'~|'_g~|G_ӧ~}g_~}_'~_g~__ @@,@<@L@\@l@|@@ @ @ @ @ @@@ AA,A@i\Zbxr.b.qG?):P'hYf`Gv$C'3Êʈ< /;ŃĵZa;`_|CD ֐獈X- $U [2l߬ra{9{9܄.ۈ ].bl[ረ\l܈j02q0H}Mb&vb`]-n݂p-Xip2&V|0SPXc7fS`//.ԍ݂`]W,2}.C~2ndB]W8d;P+xdH-U ^`^|(G O=ނτq?(9"$q QE_9Dy+JPtfef!YFUL`f!YpQMTgsB"nx({81._Wl~6 Ӵ9kM9[+\ƥ75cy%.)ք*6ݎcBݕ\jV@c4~c7F5Ec-~ֵ:|crdFdCD]G䃠idN^Qa ^xq!jj6.nS$Oمܽ]fCd֮quc8qƊ/.@sȅq,*i R q)?Fs'@Jt@نmOeas}Cr/ ^ѭ~Ub"QdWQ"6nn.voZ"7bhqo.b&OȤV8U<ӑ~~R[p.ZVHMbGMp]+W+o7`C|ee+)BUJS)T^|ɓ*W%̘f:V ͜9VlB#ƪ)T12E)ԨNBu91Z_bj(+|WlXG#mdD0岤r+ކԨ9knC;u[E1%ʒ krĉ]3Т='*rFMg`Հ:Vk§ |h.]-851|91K> z ҥc\:nvŧ\+|Ï?x-%^|}nD}9Skx A'Ѕ xg,Ô,wL̈́ 2Ӏgsg(FEN: ' b#t&BL0#99nFFh&M$9Pِ5mOaLfJQl.g63ڄ)<}S48(nd >la:EDŽI*5Di6%)AdEiDؔ#jB48h"jRJ&-TdVLDPA 5MļVLRQճUI5U/r KkYvduՐaXl.cnKK(5^z/>KM3RXbJŵQ* /1kO%KC$k } LP6m0u{lFL~Q*savZGt*LgM } -}E1Gy1ad;i4b"2R+ 22jLݐފt3]*蒐 9dum78fLYe^nDPc˙:M0ryM-¶y1n_up1fjFcX/6BԐ*$+TJ[%Y% Yޒ;.>4tKBy8@jEK)[K-[F1W¬uKcޕ*ZE }_VSЃ ׼Zr0mbhneX"lsÍ 6l,&FDfkTh0C/aH9Iw EhB rX^ɧ!q#/"t@']{ y(A>gY!Z:dCD&cu8,,chBp4Kf1R"QTꛖ2[LӍ"tg1Zʖ6~!#pl2ҋh. sMm4sh:z9sdCptsLpVh1kYZH1atD]Vi`LOdR m''5fԱ9oPzָA-FQXF5|$rRNdճgevTC.Y,IB:OʉO\q UI"A<&61S{Є=>!bNRs٦ G/-SV:ֳsi{ 0:̜:)}2o;ӽv;={\Vգ8 i+/`<3s]Rѓ2+}ճ=c/Ӿ=s=/?Yqr3>/}ڃrc_nMvh3"?-S$U2"XV?%7Zg7d ҲjX78ʰCڔt8 >>Yr`0 zC4gCC8e0V4S13@fý1ZCY5e*aHH 3DhW2en1V ^tUOa]mP]\glYalVL?B! E8RсfQuԗ8CfG(8LVt >xt;U7de\B.̂Ā &CE1D7D_7 f0R'2G}}"aE.nCwxV#:"h`㐘O¡ȡI}O}2">^00Ї}%5C.FAyWaGvh4vAh+Lgpe@@b1jfB&7ID!0ځTK$|Q gW01 -<$!H5C$dmBY !6>+hħ@\Dld$f0Ke8J'4Ja>\X?>_nG9lV|f4g > BB" A$LQ:hLdYU$iZ8gG7 RGXd$# cCl#^B}RLǡq( ND5n4Rh`Ktn1wV R(8F1=R3(jH+Bp0Xg"nl2O\nB' h'X(~%6 UD@R(DȀbB@BFfݠtDnt̙ĀGjuVh h] (3`AfBl^FX@Gv(u.9 !n@AT1Beq5ZxsC&8/G+iD eX h6d6%\BlA$832>B+>qD k4D)gCOC \fj^ _:~* _} P„`b^Ć;y khfW(thLDžFk}}ưkZtgëX2\ 6sgN*!rZ2gxiVDH>֙fIrS) 4LŌ%XLB*BdCy3DŌDa"8]FUnFDHC'T@T*ɖ,f^0P a.A@ėT$2 Gk^kDb V l Nk0 Վ-܂D~+ĕtOCٚS,ʍuϽ+E.D8T%rW3461`^%bj%~aP5@ ,fx c.BEyB",I׈lWeW9#KѺ@Һd^0m>Em/L@@DOv-2yk$LP-$NCH|Q2/ R6-F9܄ RDDC.E.xLfd E $`С1[RRHZu3[Ht`kZh gf2_!ଁ^JD\Ȍ~@h/--@g[t-$W/v,8cL0NF@2ETą'n>'F,Z2? ߐtR1Lj}zo-5QQB)="5TGTO5U{X9| aUwW5XFY5ZZ5[[5\ǵ\5]׵]5^ġn^__W4Ȃ 3 !}ET0e5E_?vPhȰh68KrSD")U0vu>A2GDAYBV Ln#_EfC1EV2 6I X oĶӶ"#>.974`~,4c@%(_% 7$[%&c*dAbv'kVm"8XAW7O/&bԣKpĝb*6w73 ß;_^EDwxLprSi+8ىHjƘ9f ]ćC։ot6Ĩ0Bn}ArL ̮"6:sAAʸ/S Q$cbHSFfWOo:[zH-tBg9~S08dyڵAq:,C;C:H7e6FuIJ6X6'd|cKLv:ā0l4[9) X4*Z6BkIEdeZGɇ +<[93CZt}6JDn0XHT>%D\%M|⹴T.Dx1C7'׷=lTL`JAl:LQMb0\:zC#l,B tAp3{n ;8mW~9L^`gGyP$~n&7oBAD s5 hy/Vn0Cr%s! r؈bG]lfE+t2E V}y*8Bold{8.3r ÇoA|*&bDp˪)OÃ*Ql,Y’(ZhK%GT^ǪaN;>sȐ7yl%ʼn/P?V4PV#BgjU(߰CM 3I?FS{R`9pa朋4ܪx={ԓ s{.l/m*r_͛9wthѣINțmJ IiFMs7v{ݹXpuc8sŻKT<5DU\yS`+Tb bRĭ@ZГ6L| EṯNlzWh=hL@wW9ftx2zqSk,Ɔ~y:-Fa47 嫸|*;sÚةg]I ϙ!9jmWjo7,`XG^T;G d͖KeEwxP*08&˱/μ"[VV&'9YzY2.L *Df\qLMhg3n.+0Kj&<ݶfY$GMQmj#R.f*)e |蹿gXeS?X]0oy_@( Yb Y_&?` [(]?h_.C2 - ZpbD*RgA@)0)xMp9GCDb " 06^x,,I"|$d BK ŝ 3$'h)؀FlhtTءI- ?~9$f #q&mFҁ(EINvRnd_#px(jȓ ecLܑL5ihPOC6;V_ءQ:ᠥīIDx%T'!)Ll#{f?y @r}GNBne=B t+dEҋ~Q2f2AԉcݢNʰf# .K~KL`YË6$GYSm8 4[%Kc%.&F51"&8"dt`ć.~*Í֨qv5r3!5>#b 7^uRCDɆBNIE&IǂR2EH7B^t) a6#|lBPKD ԯ-.cGm*DѤ5MlR)ZqEP%MZygt (InRncux򨑍 m&>:U#jDy'Bgˆ;sW2?V6/-R \-LJNH{lOy"I !:b{w&,%AYi儌iNnܐrVgkFEA7 h!yǒE$K&sPe(` yg7-hXTXc99@5Mm GȳΡ ?s mu({,oYgh#S*1VCJgETLbV`Ef/Ij&7R!ҜfL(٥%zKщMt{4cx& oxI|#JA m+* O|٧?)|2FZE̗nfe*%>*u*FQ_1aeZ 1]jB%&$k8D;*rS|8Z;" 뀇;q](cF}g/als( t5A9lH.pmyz2f2|.]:ˌ9I=8.LkzY;<{'/39ȝ6h|sn f2>cK߻~Vs<^ C0 ^m &vobvkيj 8-w2r/-5&\HBWC|/-"'e)goД!G$/-h,S(&τt$,‚eT(㺥R#pZl^cPgkop@HsrH<vi36et aLw0P  P BuHr^NO3' 3r( l). =P\A P;5zBPe-NbJG m#Q'+/3Q7;?CQGKOSQW[_cQgk ,M'~@t!Z@(4O'3]ɮgA11BMɬԠt2sVJR+d7,$E2fb5'C5tC1 ?YbX5L f/D?q/Zt8!e"$DG# U$ρ 2"2t-2Jk'uU[q"K5aL3'L !O@?rFFvi MI:t[OVKaqB;yh6,mQQQg;{hURcR245ҔbiC վ(CC1`Ϊj@ b@ c7IW_ny"5sYwn$'nYjcZ EC Y'<'A7$]_aLY(]H<^ ^}A_ObMTaT!30W7@ eapDsH L/gbHqeCevca+gvPz/Q'PPy",!U!h˷)R@44 cj/ɮ6dA@DIlӎ 8@6d?`Wה#IKcYbou R^pBp! ,$[qǕ\6sZbrLQA ]ޕX*睂_u9#sⴴϞ3'PI v<xW9Rii#ϠABl+e)9BAU{蘎 5'U!Uh|)=b7Fw36(8vCc=G76$ : 8Vp;Sぁ>nBH>hdzo_$pM+B*Kψ^+wK,Qrx]cs"AM)M~+7#sp vsbLu7w%>bt'X:OkHԖ#'woVkP8g{Qپ ;7aDcyCaٲ8vC*’IdN/*.aKˊ z!mX8~ yC!Bbz71C9$ӄںK8 \Z(Co ٭^!t˖t!y3\s<[^ewv ىIG7&g6{WRx"qSTiMyz b69Q z{xi{g;Z5>B/F.ᔍ, Fl!lȸJd h0d0sf&aj@LȜ ?De:bFv<&|c<v`Ubo;%yжAgЗ@y4b53,I͚MO @p񭫵5מ :$ؖyv"@M%εZ"8T\ ǟ®%\ڊeLx9owg8xgw-0u bN5:ꤎ F?(<{f1 N+88R4VaRA 6V\!#; CcC8Z§xG0'~uT ðܰ-^GKwH[4_c^gkos^w{σ~fjBbC?y6&AE#*dl(=c[^u x6aIؾ&>'b0Pf' oD}nE?cp-"ӑ=c<Hα&:4K240 H Fh!#:b,$z[!½ab+*Gg9w6%?c)<,B ܰl;c8P(^'Da ~/6jA $)?,s1 R.!F?p30eCAhfA~)<0_,"ݴ` #r}1ĉ+Z1ƍ;z1 2D\7s`㆏9|,ڢUwh2n5@=4RZYc..s6-4nbiՍ˖ = bٲG[q7.\y]:3沺8Ō;~ 9dFWl1KĆO2v(ԩ#0gI< n"YCL.ƋJp.94TkD][\dzP@=EYۻ4kӎ'^&59DVNu)`M~L`PLl" ds4Tteqm ^o5>_s45}4#݌}S%G%]E ?Q^ 3d]E :HYne"y& Z^X|P5 FOH&`FJ T R BQ3b.U9YE`fl_>O5X;n6 G7kU<'_teW ^M?&lYeasEq6;qQ-s1LLqQ>s)Ng3C%Zou^oMc]a)8wܱkFTG#J]PT0tTk/_s~Mb 9(StEQh Ea6U:Gڂ +bDMJY{1Ý w/8cf߁үUg8"Z2\if61g}W4)k5W:VF$i>)o ̪J)r\#4 __*o3`zF!WP>T\k:`Ah@5j2&ocd*du<CdQ62"YnDTƑhy<1NSCmWPqDwqGp% *sbz!tJ%T}( @%v/"b;'JhB<Ϲr'^ P 1OC^jAzXo5 EF {|D\BHd;F l+HЦK^#eٸD݄aC%% G5یa94EEL2|HYDb4\$F!,CsiqHS)w\ `jʻc;bPlTE Xa11ʮ:Lȡpc?iǎdsCIWh bImKvy$D`ЉAMxBMN^xI"{JҕJeql ДUlsiՋ14)0FQf$&Wt$g$nN3<ߢrBg)GecH! |Py[P)"EHCFݶCG,Og2Waj4"F709uY1XIKr&W.nHrH`BtH$4wF&0cPE! b0ê^X`j{3+0HU~KkDyJ+Zڈ. ި^F4{r34"yB87faJx7$+yQ7$"X, 6E=X7 V)L4zd C!w*CB3H1vwg褤 )7D{; dUXNs5=H@. j4R6XXzmU;^36AyF3,w-3+Ze xÔb5yl`yE}&4o@ H9)40m#FRD`=bQbǪ;Kkp`f2".ΦpO^4\hC6p"vPDF/ʴ+ F3 x!p82jԙ39>T:tJ}H/]y8OM݌d`8zF/IOҧAVP.pt;"$ .rIHQס \W+w^~T:,*m/a{,ǐ[ M0I'iKŒx2X([r=1J#p^~ՀR6:a5qsz޲ѓet$x0"3"׏+o$#ѯ c2 .?N9kCl/&$az~Hh Ȁ (Hhȁ!(#H%h'x-xH !.h7.!c9^1W?hGe[Qh(0-"WY~[d #caXT$gidZЅLjQuhw:Z[Pgah֡zHe%[(HI XP7豉@=Ph CqɃ%s^p!L2GUgh1ò gTl]Fal0sj)X1h03,a ,cJ ~Ϡ $A'Ѣ˚ P3X׏dua#3q*q;Ibś  .p)w.u:IDkqP3XEwE v!eXɼ= ŵـmQ) q.l|"C2ύ %0naD %$d+[1'|H&ؒRSr~1mٗây[ٟ ڡA-ڧکګڭگ ۱-۳M۵m۾}}Mp ޠҷ-큼]$r/ R:ҕa rMWfpD(|1 p$0+u3Xq@"7*s;I@MMHpQ,1ó_`fqaG8SƬ~[{Ja Gb=|aZ! c`(o!pE, ~amRܱ^uaJݟDvQ݇4pWnt!7[qBl-hP'' PwqT ~n7 * . ޡPw1Eٵ~;w*0-!qSj;4o RӍ}7l`MRLh@L=D"IqR\RL5męSN=}TPEEqђ60k96& ouG)N4ʦm3 oΉ.\sŝ[fȝ#֍]F7Ydjw.W; [_h]pF|ȡ;w1} >˘=iqhÆfnZnJ 9&yp lIdV^{0ܑ$F}qOWټ|tM׻s(Nrh$WGU&b%ae"qX皎R(# R!\^eC*&L,1:($YT%IFzOr WJ+2K-ܩrFҸ Ĺ`ʫā.|I%UvUCfP$gMPIYZ`y5Gsvu8>_oh;c%1 bl6Lf^*PҒ1(4^t 9Cc(6áI|XGWu '4g@:W44_@tQgԕ^i_#.AkKlݾ_o` RS|8D>`LGC"%6 fUM%F2pBH <n5awqE,\y")RP /qeFqp9J Z%׈OX.\T,RKePu 7M=O6s"*Qi}'ceԁ*+Xaoh\I!㣣lu)/vt8 ^ju;D _1Ny9hV)/;+JU'K?ҝ}Se `c/DHFr#XI-~#5:tX ^gxg "#@"! .tНT &kT؎'1R '0'xH/k'(08?Vx$&')ŽT!2.p36 ˹b464&P&`ʏBCz1T҄npuHqЋl8도9PQx A*D D 00hNĶ:EE>LETE^ć^l`$$!Fbb>|4>|pW5fjte,n'pH@>H?vshI?i ȿ,q?y‡ (8]\1]Ț@ r`;<Ű!Ʌ`Ű+Н#upP H8|`gxC&=XMlIP{--kB-<0D >@3 p(6h!h Td˵؆pİd>`Rh"ؿRDX0PpMKS؄t)qJ;񟂐5Ex\0 x7ŝE\|ج4TQ`a,LPSFlj$N{Fn/g`|XE8tN-+Ⱦ h~q ? D@p \p~{2@|h '|pHH9ӨkxIP2!Ru\$IŸR'B*6J~Q!|Q]:5~IJJ`Cbxh !SQbh&NPҹ# KK`@܍"P (<ҠMhL|DHp |0$T&y3?VT Q pS#)M<*cEJsԛE]>٤Q^t/] ؑ2Es030 ۴}MpgЄ9A I+qh Bl`6J>ÝTE/>\ĵ4۴EP 66Fj \΅U99% gXK`Uݢl]? y\֜3 V$}y]P^k\Iz uu#umޠ`UUt^mŘ _)#%PÑJQ)Bճ չQU* ZY!_M&QIlh [qYRD\&e'R{QƨZZoU~}Km9*F[;]R&yL ! h#MaQE=AT\`.bJ%cI4N- 7՚0TV5M 2h \K@=V1:$@ qNHϭ%ie $l] Q6VI^A s] @'ybXnv=e wm(nPbZ20ɈU"T9:YjFp/dizɽ&'_-\ҥ[I+gHqTJm$F$K])hA"0BK%b~(`9mX6$M$Ɇ>'A xb Di&♖]śbi&UP,lN(-G XXxǙ- ?wֽ ,ylt CkױA Xg姠]ST,"uպ \인, XZ/Z;S.h᪉'‹o=p0BalB8ݳ##t;m 4.AY T8Kphܭ.K=D(CA,2/AaF. 1/RJPTԑj@ T`\ūU, δ/Mdo/oބc% pbL'><^Ugw%nv}\@8[!M@ivPerR y0 ֣6w- "ǼYhl Dprx M4,YxGwJQ7Gf+ۄoxg @~ -xoy72N& GWgwyd~ў@v Q ҝX= 6Ƭ u؍58a@F ;iМ Rh8fY7v h637|֕z,X ^) (X )<(*HC)b}S4w.xz:gk^6x; 6AΗ_.`B7H,a96v6(w ByIU s_ Mp(7߉׉U8'p A_ι"([l vko"/b̨q#ǎ? )rEI#qIq9$yox`';S4ظF1عw2\&ҁvI̍_vq!Pp,x0‚t{wfS/Չv0axsL(S_6kȲ\b^,{O@Z*WΡ"gC Ʒ9nR[9ߊY G+ g9wcLE|Esr}1yw1cu+ݗB Q.)u|raahG2Px(NN@ =@@VY阓pQuwEXl c=D]>[VR`T#>'5%|bvqV C,c@b$(U)I tIKB(>t(x[9܉@D&#N6M(_`^&UdcfhffbFq:@-(>ϼ6Tx#K'eŦFswSFzho 8~Z(!!AB(H:Պ:Hr65T):䫰X ,߈A4S-sthZ DìUMR5(ԗ"DUlmX+{NuxR@S,}M,r|!;G0Pq{̂8x`e-@ xvh4о0Jh t ki Hpr(6FμC(ZJqڅy8 q)f9Ļ0G"5 i)͚ FH3c .m{#`FE YLP@РpoQI" ݈CA Yb \zHH *BIݠ ,J *1lj+4L(tJ%J- 궇夃Z Rx>^A.rN6m5 ڂal&Epu8ș-+46Y>Z0<h(L4P6P{F[U\$(> $"(GЉ%AP?Ǜ1F e(q8A80PD!8%HFF',pT8&y1&/ j]kF☑$]kDWDLdJT՜$8l@X aa; $Iv/zQ .u;AsE_-Bn,y7ݪK]|sADzuW,xK+杮ET>K!iR,~GI+*l.^$V{/c@8|/A#R*@4B%}hVaa xq?@↰(K*;K*wXh'Q-,g+Ol2|HB ^n;!h[nJP@D*jDZ" QFk | SEb9J1$faֆ^b,Ao;_ mES"MUN5h|ᗓFݤ9S 01Hn %.ibXMqV=ӣ6u j[K@$:Ⱦ ԟ5)yd/g鑶YLy~\u|n޸Lu1s0>ojkUX҉$7)_,/д4B0Oc\ `iB tUҡU$ 8Oo N\EX879$Xlt Q1/h]l f zHtCXP ~CҠT \0M<@n8Dl.eCe.SN@!Iޑ\<@^N&^mpNE2ނ8Ķc8O1`ùLG݈|K$rI`8%3  8 j_[Spف X&E5CB_0 8/Hs Pll5D6$Fq܇ _F5.8~D 5d*=ak,`N qQ@iPO6mCDK{DK Ua >KN +D@E8:T8]$>8$ 6dT)`M >!ip*ťy'Ne(zWKg}}g~~gh h"h*2h^BhJRhZD>h˹JhǩօRgH@f@@a>C~G`]~:l 8ŵХh W|Z\θ(|CbAƒ; BZjfsBm~4 D6]iGHT>%>$a%4aݏHlzu\8@R^D. .Q2jdC)$#FXBE(r8Π*df`QFjj; jތTN)H@$_яL>vxD*GDA^bekS@1BPibxHK2͗vw)A)dɚƩuxaa`$C*(μRj^&Ġ%I Ģe3X*QB*++D,$jH,T,bNkZy:C,IhGAeC,Ƅf,^ŎA@Ⱥ ܛsrPg\K2ACWO˴`moeA.;C:6NeP$Jl1RJ6k HNp鹊j,Mx۫m6!1le QB1L DDb,e8X9RD.Z۽n&,E@+F5T*% :F0>-@@^ƢZj:fj6t9fCFC&Ƃ( -o$ Dp hlO*Hlh`̦hF$hpZԈ(8&2E">dZ!]mC4LA7ڢ 3O7 8Ύ$Il4 d 30ŽGHdj<(QjOryڤJljinl3qkZ*ZJq 3 * NLsF->`R2D'gE J)*l:&[rJ4@*lr& Q@H0Ghao],w GC4](@4/sf=%@41{rs Ԯ&S ?08p@sC0>mC9G(0 *Xn!>MT6F5+FR)aT !0QH*u:jn4䢱(/Ii&/k4kj5%86'T/.TFTU$ҢΒA_!_ .6 *+Q뺦 *5*Z4Y]2F2m6t)[N,aDboZon.H6.86>L6eCQ#88<@햊Ld=  wB8E݅`@ds;vCAtV1g$gsn6trVgՈsE_n;7 7skYsmwF{@07[haB8TJ6D4cۡ*0GVlICZN݄LkM2+8IZBF7}ڧrW'Zo*Vy.GnN^# ۮF<, 遂0X6“ DCB“(+CjKqOdɪx@ۈk{F8s  C7lv`8 '3%!ix9O7=C7׈t?<[7:Ťw3w0w@z^.ۢzJ{w|B^'AB}GptB6`8};8Ǯp(`+8xl&8ĶrFzW;AB喻w@8rjA8yS*}_1VJ%('& 9H;&; ;􎹌oC`8K fYO'ɗK|Hx]52lH9nGs 54 Fyo64IosG d3g wBo3CLgCJD:>^>:psdxG=l+5B7z9HtDd18;8J$j!=9=uֳbTGlkn4<.XN,m6`088+;ا嵆/[Z+kUB*>J%&Nq+&PL o/.}gÒ'g§[g8f o/ovZ D&7ErC)*:Fi!@ۆt;WDAni`6sӸcGA9dI'QTR%, ϙb9fMAg5)$;p9ٍ8bx3MAeCSUI~ zXRD*H+͛\pni'Yr5MnrVOU6aM4d\,.&L[ lermFcFRۨGgll9fZ3vyyt6|v5J drMnff8M`8VKs^<˄ {9b05WR)U /Eآ9PrY-P 9U"B%EJ#]is^ځx n<| (t&krlF#§!aćI'grr,3AKlS( ʦ11GxZ139ttO@3K- #Q󦣻8DՐ$69)UX5 7.Ĭ |J MF-| WtMU2Ps rMlcQa"2ulom-p3t/GlˏbΒQ#Ō}S>5"076qLkfIWW|5ތcy//> +Ĭ1laYiqYgbbNLuDJK`U%ՕKc#@zVjZ뭹[.쒬n Vfĸɞ6 T/꩛E.O\o!_imB :6%hiJ-o I/QO]Yoa]iq]y߁^/O^o:'x >PL8@B$B&D >h`$-D9*)%, Q0 IZ39 9im\GƳZO1gh!0TQ"M++`K0F"pd Rݩ *Ј8GJ2f'I [XJ +eah.FKq/ >QEN0j$(& 骺ucPGdԣzj d% "?@Q=j"II\/׃jD],ժJJU"*EQʝ橬W#U!+:Ac=+BX@!DJr^:( aEd#1r2$ՊDFiͥ  Pt|w:ە84_lPT1H )2.80;nD(>1lc)3\j>1/51{- ª" H CjխP7c  @ lR QV,uk|C%M$ig`p8,FBl%اT⋬0-$K\EC,\1eaـl3;b1g:@GD#d >ТXqMa+rb$RW&(K]IsSZiBoY Gm}e.ҔnUA&xp|9ӻLUrխoI#E ܑHu8#n0oD]a{a qW]!`Bx]޳;CWH)`oˋ{뀏Lo8ܕtK|.jFk@I&RsFtx&[s}GKy]6f=  J7gLPލ-+jCB*ݪ-ސ`܌pP ёu@~LH#vQ%1 A"!")0Š$K!2PNBB!@(0,j.bmxhCof$!$MdTIa/JJN /gx΋/`6V)P>"ɧ  "bLN8L²-!tI$dL-H ,q*RbObr~,2 , `r1)BRq3[GDԧTRRCڤ|l%P~&&GvKP6-"Gāz.$jkGrdi&+Xbv:Sb'fʄ@R `;VU֚RR͇Ij+.LS%-2@QJ K> Qzs@kʑ; *A1\"ƤE#(3.W34HtH$Fg#F#sIS>WMtL#,tKKKHFpԚIMLD|!(XN7" MOO5PiH3g#δIS" SQ?DR-R15S5uS9S=SA5TEuTITMTjPuUYU]xXS$L# W`kmު2DUUIX_5YHd bBYBZۄZ7JP9#GEށ/Rb\6ABP8z( x9nʕM~Agg&)4S]g֏aD^T)HGWg5$@WMdIo nu#tuW7cE6;‡ $nNXSBf)#Ym$5h0(#a>hKi :xBiڧ돖 "萜$$B M84Ҏ\-PkB(Lvf@#PP&MgN%W7⎸b9qD,8v$R6ds$HV#NV#2we? &W"%fzVhaLD$0 .KG8P)+#yU6xkI P*f )vT` oio|mXjNbYO X#.W]!?ZW D^@)U 2eC#  7thL" j~Dp6ت0)3_Վ48A qrjz |<5 CLE4OcwUhj#H'ˤH04$~ Exe+%0%yRkHz,` {ek<+a{ s& К8U r 4Y$ a)@T#HW!2#2Y52B[#d ,(؊!a6-BL9(ܢɄLc-´^kxX#XqɌq[YxM1\<֣"'6zP4"Mb"|싋]p#@3͒nϰϲ/@ I0P;Y(ĀWD#ZoIWC 4؄dsU)Wm5 Nrx>TtÂ5Cn9ɭf ݢ-XRZRR4PCuu8+t@B|:%c<;8JL^Oc_ONGzn9k $ hzy ,IlQpF i z.C␐`<z*EJ8BQz]s 8)W#JDVw:*{"?=Xa1BnB?Xc058𢚨wX+Rx4Qgt`qqGK?T`M ,4/;Ȣ$$)o̸b,iB{gdzffȏ!ڊ}+C:W#l`%;r3Sǀ[`#X 6LQ {1H lY9tS";Gx{+S)5!t RxE›v%@Bw.> E@ #veÇO sJHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8srUY`O̝۴29&GJJիXjʵׯ`ÊJTaހњM߲Kݻx˷߿9xM+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞MV1f#f*A*ORK,cgBYܶDP\3r<@@ t3/asw_]ށ@9gET`Ce.ߨ>ktA6Ȑ߬;DM;#BvWq!Qz܈&!\80tI9G9tPs5hRAэ8RJ$( +lU>$>CcdGIS:%W"W_Bg.TIhI^`@1T0F1D,8 ФD p: j(u)EPPœ:]tyf0T]INEpD6T¹/M1oA`p&<Mta Ydi0>T-Wp$6oǢxMa!9*.R$w9AGw񒘣:@(_:vݸN:㴣a7x'@ k^B @ ҨQĠEpͼp`竢>qP6s#)N4@)!@bdN@ś)]hkrzeo0,IH4 gyGA*|L0o>b :oJh(`7ctpbAaQ[ċL ntˢSRy vACS;D)H~طFEbňW#bωh-L(I:'9pt R)o-Q2$%kLd!?1O%]ײ ^$l Ø&EK`c]M"]2rQ+b0Utę˙jHVB)E"u4  _uY/oh4N"pX0bc}fH-g=9hP OQ&@|h)I +4R6`d&E>&:UR)$h=9R;i* J _6U-p\`ъ$p)ޤ"I7agP[h&f".q3FUfÚf FDz;x\-yG0#ia4_rd"1ฒ,bЃѲ}$Eb@&¬юEE ڑ5ȗy$#f> 8lrv$_w^کSRlb(8@t)PU&"=!77, :`mPWU" BkԊUӹSJFI&U{ -U `9(/T)/A5:艙Q+RمeVQfY$US2z )EMg,T$#lg8^4@7/MTfL~n,񱆇B)&\ ۺD`F3=*yuT\WμX6 `7Cf[t;.UYBB k5c]y8YnC? 8/ Em #s# !SQ?à1cC$!8 *$zg!x듢%i:way(@Cz<[>b"cnhEɚZ;I\2&ը W9O-% (k0Մb9dċ5Jx6I-$8ɺM#jFIfOg ZRDr=}KǾmOO/˜Ͽ+Xc@e0eX2@$qnR1.'C%!Cc66ci;|V'"σ#s` =B#r5a $TW0fQ|G]6#W\Ѕ\ 8hxX'|w${s%1H)4&i+V&l . [ 2P_.Vؔ)sb$A(dT.uE! s,E7*k1hx =q,ȅ^a84ghePmlhnptXg^Ss(xaވx  ՈՈ%фa=`[1tD2ِ0~MObQ!=%}UP n5v`~nW V@^44^ ee(X\A JwnJeB]Q%=#7.S]R|x^]Eˤj A8sjyjox{ihy8~,AXlM'٠ XV'PR٠jрj#bPɒ0]4\B YmLy׈BKP=eAXyɕ1I|yh|D_YiI`yɟ*藃}ɈiAW 1j!d*q irF1 )nD 9VEt0g7 cI!%AP']D tJ \,)\ VCJ-S D99UPyoJ>07[Y19%TyYiW(r9Ȩ)tIਨ驚Y c_ɇSy5(#$R`yVP:遫B+gOR҅Om i|NĪ(t1Z FZ'+ʕ /qpi?#S@ ]Ι)ubPI]!qJqP{S[ڰxKQ2fҩq)˩˪nizzy蠮}!h58ѫ?[R@YW"(cXf3SXX@tbQYk Z1՛ f--W5 #+0W G1e)sNyp*~ ݉9Q{}x{U ${ ;&;#۱";`ꟕZmj{4Kyz9&@3J1PՁЫAujQo0 ԐQ`aB:Va“-S\[|N _SPS nQp␤\` M/U m ^ .F@m'cJnQwd+TH˔ >PS+uU[4k lkzk ۹z 0I뺵덂_5{Ķ}2 QS a90*` LU*2D䑴AitiCG&Vihiii'qXMPܐ ZK|ylH̖;`Q; p@EzЛF;e-vㆱ-rXH]}J)&ܕb;̘K <|^)<, Ĭ[(*^̖K|2 5EV!FŰYX Mvb&\+7zd), T-7! sbuP\Fw" %ìFZ5_gSSuھ2Ȧ + v2eGV{;e ++JIe󂧀+ԑK'ܩ6 [l̀T 0ƟFլzb={aȣQ{ q{yQ퇺d}x-~ɸ EbZ# l~6׊秒}~b}ٜ٘ٚٞ٠ڢ=aڤڪ}i>=tm:2ַaRa<1SRP"Ty!5q!Ѵs=g%֭A0QU`g 0lWP0n2d@,-XӱqBrLy{%1}B#rӗ1%h2lm"Nr{M+׊-=+h,*rV#r.*+P4KZƷiϲpP+:*ő&A[~F Cd a Q7KmjqB ^6i.H?"$AᐍA+#A!⌞1P\/^F~Ԑ c舩uuw.[ V5S1+7&-F[gt@410r .(+bPepS:`p95B 'P("y;B:J=cD5I%A@ N]jQE rW'W@5L,YL5ܹ)̡+'񛛹2,*gM4rփ=u&,X.>}#?sԋD|po‘=(b.d UAD`p zeoCA=Bכ@\'`A ^Vn6]c'Y'L eP]"u" Yú} _;,8Ԫ?F>XYӽx񍘊l%T[HDV;[q1c Q/A1C YH *e`>#!KEr- +o 1L4DE$ZyJI= e Xʕć0W,@bPcl6lH#6 ܆D*|AL)H)bl/Č8KASŇO I.eT)PJէVJՆ֯\.QlQiծe[qΥ[]y_jLɂ p,F܁n5C.]Ž3w.U]]qL nNjhs`ڝnV Y2'^v䨑Uus|e.0ꢹ\]:|1^޼ܹVbf˺:Jlz! 5c %&hgA,&ÂnzF0ʼn&r &L&:qJB#JIJk&BR-L,,rK.K0Ôk,|Bzˮi-,L8/7߶s9;O9=QΡ8QH#G-.*=-k:HS=Rɦ:3?|V1E֚ b4I'di"|:[q&bX0#|fہXQGGlG-Iȗ" ʲJ%jɂਦ|rɁ5,U+b3)Z'R^1fZzVέZϗAJ>Yfэ6zjR;8Ҋc澔.ѸF2iP5Y{-X]ZbmԪHPS˞5g-!m]*ִ(\ ;de$bhʆ%Hfl  L0z bi &~-2xRBv$4J7x5A- xfpMo*5m1ӵlt.8> <Elgt9PյajANA/TK vcA3V!+XmmG*Q[VG6Pg8э"=}+4 +ZcPLQd!M8rqJ^R|+rz=-{a%Hd6Z$`'%wCqaHcxGa EaT`Tq8Lc r]J+pP-8e(D*0vHxO3M('QxDp/[(uF.t=i[[Ѝu#B}=21YH - {=()Ĉk\wIqK#mDEɄr@HƲ1aS#甆FݱJn F99l#%iIMzRT+eHN.s M[}J;iO}SUC-5I/i3u`B-1,PjUzUfU[=iaJc%kYzV8bk[VUsk]zWU{k_WVZ5AelcXF Z([Y @iy פE fQylv/5bHb1*Ѥ[h!Hlop hΈͲLf:QHVW-,\cF5pKOȻh;׽|kA"[Sݢe-KZl;!ZψvVxobF4^72ҽlVwv0ҳh.r v5-5jIZ`ۼ⠘!Ml B׆wqq!Gx-H7!nEK%1m-܎7!d"v />(@>6 ȡf)rg S1>\y4dJ0P岵jUݖ u! $|>&r7ũf TR6B<:;bsSw e{L4e#nԘE50n+oi@k(- Vqx%Xӝ .*܎`HFF:-U!()Ϙ,sr!ӟ=f.C8`A⻑5p7Ql@ ~M3?-t V8ZL$ڑ8PPlEF:'!vG& ml @Gkx!B@#%堺s+fcY%nY Z[d嵑iIU3Sw7S w{|_#;>22';\-4ɱ·ߨ{) klC$n48wn1@޽Bej%j^Qi[- 8B̫\ONg9\ ?N!=ϣ1+aοy[lBeX>j?q v!C+ uI1Q7@"68 >9%*+ ҞـP9gDg 7AbsH pD1 xC BYP'K@0l F7 8(,FC0bԠ,+1 >[q x@ӑ ݸDBL8`ӎ+rclp?|p5-M$؆UXEUX:a a:xX:#* 2mj1|@:HR:Fб5|q$ơj4{n k,GaK ֨KA$[G696s>j%<&ćsl( Y C,iWɠf~2(н6 S/CRRCâ`>p8>|4_rDpD=iɢp' yyDEx1=JtO‡+pE|tJϲlk Fpyфe\FsaG)0_lt F L} 69l ( xČǷ [q2H=|&m0+>{V!hVx(I% WVp[!N[-)Q#>`N`^`- n^` `%z khҲ5ɾ)p"0Aʴ)@a-`..@EPH ^ըM cr' $N&nb`:\0p.w̺߰=8hO.ۼƂ==t ~&1V$`P7 _Hi* (1F ʼn{Fn^NaN6H'H۫ +3|xZƴMp3Ǩ|%nb&.ʀ3H q -_]}R[m >+d,54 SeH]M(pc%1drfW8 ?F' D 鴋0Rdq05d6 U} 32s聽aȶnCLXFPZ^!e(* Ԩb^6Hmf=‡FQ hZrsҐc1i! mC\ >ix]9;#D*C9 !H[9 9)Pka-\p(s(;,h Ph<Օl/aPWh$t &iٔ v3T(q=%_-ʃZ? in %CC !~5$fl]n[ak>jgԪ꫖>x@ #a X" XŇ;#@B*؜X#~N 1&CF`ndQ^h<…hB*^XN0|l| ^c> n֮I}8DqZA=j},.C ~k͔ɻ `qq&NrXg(DEW| ~L1o ġLh-J @JFS{JNCm( Pgŏg>K>ׁXWo%.QfP (z2 ɾ X@I0q8fhit c}QaX`PsF(w3m o #Gr( j` r &j58+$.Ok8@ 군3ϯJ a1R@nA@Sra@?;0Ϣ8texqtOTIWLm qPNt'RA &bDsː p`i^Ymg q؋`$g C!  qy P`,pͲj"8wHw_ @Eo9#l }#{ba(vioKvVx=~xx x! 㙬ڋfqdbO(ZyT0лh髱G ihiZ-Yu}VD` ZQwhyPp᫗W,;R;s sT6,EnNBi~x;bx /"Pԁ|V1ʉ+".*$h"ƌ7r#Ȑ"G,i$ʔ*Wl%A4, imo%h\m؀f9o΁!glNwKjTfsdb\Hy*k.^vk++ct[֨8n](P~ F?j6ʬ %9]\zuөfm\=vuXڹQf;z'+ҧK[?' 9Ph|̋; mw zb̛Ƿ{ɇ7'@:w^gA WƁAv!j!z!Kh\$M䴃;i9H?; 9eM;. T3[DVXe֘OYOށx%"Ph)u:/cKi^(^ F-F`g Y"8B#$<lbm=ܖF12Xqw漓ug頨I qFAirDT0 ̓cJ|ZN6A,_Ok9$yEi`2E+Ϊ-z-;.{.tZԮ&u!SF'90.f2|0 +0 ;0KfXKy68㕿+8BA1-21<35یU ep9旫DqyHN.@"p .@HƐamoᆱ!lF<|A=Iu]R}F{x*qıo>pѾF~S??z?M  W(7#CEmD  I.&.Ae % EN`$@F3d![hv'ayFDh=Oz@:d{>!%x(21S]_.9 p*9o-5%q`T28X` 2k2IJ2M!(9 q9bD(R{cIEzvÇ-@e{a.<&2_ŗ%FE/| #>ɾ!$7G8ʑu1 t)O60H*GS cn*q ɼNtB G8 F4# Qk!\FɳQV&ŇI_nd:AHRc)SI@,i&1 JÌ$3'?ٺ·a:R-wQe\ʱBeFliKMot3e&"8fޒ9Lo|&4/.a5IilO7Q tLQ HCwoR'jSkOb'> c=hHj,(pM"EH:m* >Wjit]ku %^ؐiH ;|䰇8N4=\n@j(i01hEu=,A[¦DŦ>To#,041| rcxъV=q#u,3v1"mC}D Mnk[T:E[F! UNR]D#%v|YiAx+7ɓ#sT;U陇XFƢ$ë >ߌg%> =Źѭݸ`2A׻ԋ0u1֗H3|Æ9amq$J5m\q!3G4n'iulV#q(&=f )Td)yF>KPFE7n;qXhs+*;LG5T6E3M,s$J`!|sU]?wA "qٯJ)[-m%"Ӫ~\ljQD?M%12X$ec/>ȣ/+ d ?;csƒ<ǯ-[cn tWv{-R(d& pݏ Edsf4/"7< /0iM? Γ# ^gσBEy[Uq:]`F gZ lHry]z׺~gW,ʜխȆP/κuM<#) BCn$'dHru bS;f;qJmm۹q[paEGJtI1"-Q L% RzT `^YYn Oy_ǩRFޣ^ D!^9e!_\\K D}9V71d}Oա߯=_ј@_jVj_y]$AbہD4!^!ٖ^FGj`EWuL ,`+ -xA<¥^V}^1h1 HHM{ Z0Vu*-QYDFT!A!\% 񕚩c9hD!Aҵ!daR!܏B_Zgm;IA!bdTL)ٽV$ A]%z܁[uךLbbuePNs ,`"e %բR.%S~5ˈEE E L5Y^m T~%XeH@t;KŴ%BLV:fY֥]e0^6 Z"i%lM%aa&b&b.&c6c>&dFd2|8T͸TevX&f>.xd&iio9Kj&GH9m_D"fmަ0uЦjfi'r&'=4JHgf*t~t:̃jGwzm"fy'z6"gpo-lO'=@'J|9&Iw*(qf=|T9\JgoH@(O<@{JlFtw]h("9<<؃60g6È>gu=C5x:9֦@= ==wExm@֦^uwh鏞/ns×^i6iL(xz)s'oZ=ܧfiMtC<94BF)4lhpi#,f#BΨ#@)6jhfk*mާ h*fjRh8x簦4Ĩ;,j*p&9(=,jT:gzgFih(pj2+m:kZn=8-C{ڃ:LZ++=$knsk&j9>GV+nzVNj:,=@,0Zo&ZD}BiFBilBmN(̦nsB55pC"=DvŌ6q6>l&hz+ %dDkB"`3kMɤl&,`ڪw3$B55XiM,mmFJtm"\B~6m#0lĄf@nB56m>VrD>'^ćfCkBj~m6Fn"@'.f<+=fjjsN-ƭ.8|h.F|(-..+}NiEHg^hr@.~/~'D|^~,mZ췾9nGB~&#xj2/.f9Ê~^0gcf:ώh>o˭k~h+'Zo&m~,0nm0F|oժ8FnD/æd2q :I{ w cD#1?h 8Gq.j1D˞J2?m vmjm/L,- WtI:#.Ch:X2F&wr%`22>x~bpF.F|q:0bn&p6r**pܞ22qŶiW5_3_nFoØFDw:<8?'vkF'ZD૫229{'=_;,9s>&=h7s֮+&=x3t?C}<,?糴ʰEsBO`[zj<D17Is3>sDO4H[Ib-64O>-U*E'o:wF) *>EjBiB('iTuګ;0FxU'w9HM6 9tKCa zU,jd':^(JG;s&܆5%wgc_e¡WY(0TmR,X1Y]1½ςyc"tC:܆F e@d9ɩgʋT40WFÏH0uɷΈ; :•CWÑieM˿B˵e4;e Rģ;HhC7Lx/mAŶ7 _=8 }ú#L}л.{s Y m{U0]1wCWD:3m#97jP-$>7`'/3jCNUX{ G!޴8|wC냃,Hچ|61 >!cߘ??ˈmY;0K@b݆>!o-{V۟ŭǿM7c];pt;'@| 2d(!;t*UpcDF4JQc 1Vt.boѢ LsOAy ŧ۹pF]Tt%]8Y{uOįeŠmijlم F,n8{p` 6|qbŋ7vrdɓ)W|sf͛9wth^u݉[s[t`>lوzí75>q>>E !P:ӁөCwjql"Y_eYRFY^)(9-騤+9gqAA1䫮+C򺱈C9F'muܑ} :Z5%jFxFm7pFć86".@k&C=:rF0 <&,sz|a"gr"B/&O 䣯$Fd?{D@jI$@:l&BIdQU C7#D;-YD/.#Z2Ni Uk-Ch<-(wp$$sPy$}+K𑛶e)}XG;yԣ=6i "9d% ff$)YIK^~؛u q,14N$H@",e#IP)Zf!K.yK_22d0Ӎu c rd.є4YMk^6Mo~8YNsT:Nw1Ax) ZxC~>ڡgL F.nI9V`;"A{P!HFIURohE`̝FgIUUoS*$=!4$imY9S "5 1-~_!g`X߷ IjABvo+<78FYh 1-8Fo`X˳2W ӅtZ]وqLaH"N^'?Q@CEcHK0-ob | [G|0p`R H` >)L !وA|a1 `# 1C# Gw! ^F5*-"eSl0,f$b/@2&!bnbʌ`4wWRZT>L8 PLP&d\w5; RF<܍nA1Пl3i tpx "54(So۞G˛%|p:480c b'6 =tّ]@}meO5tk|PiC㷪;љN\v$64 #ҙts6˂ى.@cdE3͋xGܬY`mO)Z y"|HAӾИ3(@=EV 0꼮;1̈P :I9yWBpݐbˍ=V|d}L;;xNke=ta=qp>|}dp"yJ\ +۫F3lSߧQ%$(yq!]~ Na r;@ 0L$NL2hχD Y˄r 2 Aʵx(./ ADP$zf܊xo,ʟ" ۂ̯ޭzL(ΠN键 0J204 kfp !2 DP3PQ%Iа#Q'+/3Q7;?=O.0KO: BB(_c"dsQ'wQ QjQ eQjLaQqQבNQ1!<,X H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗03F;p1sɳϟ@ JѣH*]q& rnF`JիXjʵׯ`-]7vঊ]˶۷pʝKݎ4́;߿ L\#W-ǐ#KLXϠCMnR>gװc˞M"jFͻ ;s&>+_μ%سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXflXcN 9#MS c >1x38إ7$3 u<Λݩ<>> 6t/G"PB^ }@npMAeM9pM;l6JkZ뭹>^jQt NiY|}z$NRN9Ϥ1S06@ٜpB &ؕ!ћ϶!*[=PѪ"xP7bޔCP*NA>4mfkBYk!*1֠ťP^h +!^C #Ih]CBR*+Wh-Vk.Ɨ CX8emeޖ Ab8`PͮǢ{sɷ P9 &]bKL+\8mu؋5hיזW8r9Ĭ+Nӊ ӎ3*m~>jݖZ'_"A"UHLA P 'k. S T(q#.2  Yj (upMYц0H$mMP@XOet/aj5( 0ԢDHX̢.z` H2hL6V(pHG!:5ȁDL 8odO,;71t:ufBN s *R%9)"_‰(aؗ:wcLDts_Ґ$ w$8s k>z (`+t&$7q̔Snz "쀆Ͳb%. sdջLƖaD6 h: _Ь!/:̂p %.TͲ< s@##fڑ` D>,`+VA xG>EQp? Y0LbI [WǯTjASVzfBAqO8 HKE^y׾HA.31 *Eƒ64F3`fr; Rkղ:8(W/cAԼ#m2d9` MḛEhg'1U%9֕Mk'8&""z^b1$0fұ8Zh‡Q6B6!шVP1L1c!ojzЃg$H Э#;G0 ;xnL `jJcchN3l6?P%Lg,uγ>πl@=qb Cj4MXӐ ]Y@!Ob(RlCD|tsqGVk#IV24ԋH- ЇFtb HmW hMcߑd/#MSR"F`t+5xlfy-\.Bhk[Q&>"=GWE5fdAsP~A/Dqp05l [B  O2fmFh2,7}. 3xn86@&M_/C8q&9& A*X(@z!+SoMAwܐ,e:.e/*ql|L6۔;. ъyIPo]\D\h9u3ǟq2ƪ}*#h~ w>@N.wr;Sݾ g%ڶhVBz>7Ff ^OoA=GYC"2G>d70f5(P>&j\e}rLM'$sqSzlC7i DWIܦƷ|Uwؒ u<usa]} vs[#HB^'Vti}TR'vXPae^E6"@V"G#ۀ  #Vb7zlQ27B4c(pEKUeU`OVmz$|sCO&SQV+ ejtLhk[PkNH&D&pEt(|h~J~X!hʸ،8X : 0$;g({VITE2h6hJ k6Vsz1BtBxd q`P+%A݄qAz&,+&V`kP(@#YӒB3BNLd [S2A5(5+E5,  Pe-F1XNgUYXXi1+h3 G=`s5a$v--u? CI"WI`&:y@EUP患#_9I՘#w%{dh+R*m?SBriJ9', هsh!89V-)isW`z'~2*`q *ey0 0 ">-CfPI1Ry6w_wZE9o~R T s2 eX* 9ٜf' h!}f; AXxB90C&D6eD5yy90 0zfS E>p l3yi;?#UC C頚!&)Lΰg$SQ'c)bAyXBZrYPiDbQE q={(!fUiDԊb(14^id6)940s@x:Zzڪ:Zzګ:ZzȚʺڬ:Zzؚںڭ:Zz蚮꺮ڮ:Zzگ;[{ ۰;[{۱ ";$[&{(*,۲.02;4[6{8:<۳>@B;D[F{HJL۴NPR;T[V{XZ".е^g؎h1pp* n C`*[k_pf .P\o Xv[m{[_Ke _D `;2 mK[*07+}۵%giOúnm m D]˴2 [KҀ~@{+ B% RKK^ |zز ˷^-[hQ$";8;<&`"0Z5*pb{۽ <"0+, x]*r6}(Ҥwbˍ˴F+ w6<])<VJtvgLԕQ=d]f}hjlnX &1d+\oJ k+(ck[oͯa \lT)10#(s9ÒM8깹 a5`˗;Bt!8a$avbnj'c!0^;`}c7ؠ%Z,o{P K-]ے=pCd; ]9ؒ=1(|q̀- ͠2m_bԱ;oJ|1B+3҉tB9L"A#<6~8:<>@BN4IOq`}C0a l Da,0 'GxN엎oKAfnθVpGN~ΔL:nXrl){{0r.=?q%~`DȂD a6?\՗ @ѧ(CT..02?4_68:<>@B?D_FHJLNPR?T_VXZ\^`b?d_fhjlnpr?t_vxz|~?_?_?_t @3u&jOT qqNv^E^&*j2< +̰l!nc Vӏm-o-zqv@PmQ4 .dC%NXE5nG!E$YI)UdK1eΤ鲛qޝ˦pO&҅/3|CfSD.sP͝eюni6kP9X9|je[qΥ[]y;[tnpQE f4M]So5M-9pSUsVv/]6:3xp_رeϦ]mܹusu{I>wkh"Ɖ(PūsȶYկg{ϧq DŽ4霒p*Ʈ‡‡B 3pC;Ckd8 RĚjFL9ioY $lũ;ԎJ ArH"4H$TƜ_$0|XnIDpQ^F+nzjq;N+vLsSl @/ \h̉-8H3=SPCuTRK5TTSUuUV[uUXcuVZkV\suW^{W`vXb5XdUvYfuYhvZjZlvۺ[^4\n'z!r%-4r9G[|w_~ qlY*-9bLd,qr,|_Cyd(*O4b<.s>&yg{UEX^*ses$)gj%땷0Ơ2zFSMFl2̦k{1RJ|4^UjX:cH5 kZ5) b*e W# ͤΖƜ?M:HDƉEO,},+ 20lhV‡mI7s`S%l`Jj-KXDlE'Z + \(27!ډږ,l8UD&m]G.MTQREyav؄hހUؔה^^b읊3W(l̴ȹt9_ȹyTN P% fqЩ[acie6@O[鱑X+6OHP9pF`frk !`n&ؐxi8YrgA  G{g~gghVVoXN;v|Sj`وV,YVWXXk\ʥW`-,)Vhx&aӆHa<3j&v KcNh )&k$ 7~eNV(A0`p2jʫ_Na܉P=6ΩPjc cPDҏ%Դ-\=g(Ȭ, `kR$%ivv<:S腟-M`Yi|GoՔI(I9.lm. T`Ԝ !m|Xm.I:^ɲ) 1Ff3p^0U/)'3Y`x 8\n 9A9-Me8! aT6;*`;p m` کCMдZ+t)pL, c&Uʥ|WX7Zmq`Wn\kP8kpg,(tת3P'V@ ehMr ]p &Vn A'5B.l @fh`KHhԅj:EPܔS$uO9  }ƇӊxO:98(ەΪ|f[xc#N1@_13sjZNx4!T@oڣ|jZ:h۴P2{m uC&Dp( )MA<:sO:8A D}-ZTs/]6| 2lКs! BhBƐ"G,i$ʔ*Ib1awKVȘ;NIŸAk*cld2mTdV?Q-)T#Վ6q&bא;ǪϮ\MIϷBYuktk հrqU _9 KЛ`qm /`ʉc 2PQ9zj4ԪWn5زgF-QaS"y Ά^֖) _8MܲE Ĉai)"='ƅH=|>*"\Ք?@0CFQt,/B?C97HoYSUT_~ e)W5VYgq8jmb +D3. Bt+R3 Wa)vY95=)L4I eqǤ` G!a9&ey&1TA C/u # $gO>Q:. 7bF7pC]sh:rM*^zZ*֌7ӄ f"JXMsl3>i+)kMD`:t18 67t4 1tM6n9!XMeVW8M7dJ+PVN{3ż+,070)=2t)Ζ\>J]>2g-)2-leH Qq!svCMJTX{8_X< !D)9h}&leQVCQ=-(]!59@c5+=[=k={ʅĘ>髿>>?J\/Vӿ??(pe_2| #( R 3 r C(&*Rx.|! # +{HtǨJ݀3 ం %'hdDN"H/I(]2R# FDPAJ$PBr57$,1P!2#T%ጷ|PxGIOx%\ldp,QqhSb9љqXgArv2Ic?Qu9G*yOE1 oSVfCIRjJDy҄H Xb)bIYҖq,ˉL11)h31iH"5#CZYY(%t*tPRʆB]Aj0`XXH *.EDBEҧC5DQ`$P-n H"xft+"bt( r;H2˕ M$2ZB axϊ "HF00o[@F!D'DTtEuC ˄! x ZFe14 c+DfSnN{L| )=mF3|Z ~pK`;AuS.0>. b\4&ىS|&gUtFn#] "`\Et'U5s.f5t1b%7yZ+#zV,`"I|q@y,g!,|hV尅EbvX x,tnV!ϰԳ8iq!F`I!ˆ3"%O|f+U"] ƪB V|W6)Z]ﺽ8F+{kE5޷oI`eC! HO̰9ƅ3Tlb|;-qgqE*ZQ$w.Yt~qiOhJ|Kk#Qu14Qz *bqLCJb !>,l,!CJ-H̡ΊG-J#7Ig:!j!gUp36L(MZԭMUwխL ѮD^; U2[$;-JKNl_ُ7Hi~-bi mowgܲ3jݻ>1U\r1n |vgu䋤#.78;t x p$3\VC7옒-De*NVcBVO'#dX뛆`cB0Cý4HąHyVRcaK0BCTl1koh 6dVQpPUQhLcƈ]s]'ĝݩAPEݫ坮WyW)AuA19!ф->Oނa^^t[F~޹ߊH41߷tD@_Zt29eDZBDSX@4dK쓔D]bfĘaPd7,_E4ԘE4xS6\BGH]Jȓ$rbt%Z8p"BCD,8tzϕ\*ĸ<JXB@5FC-Е9@\9̕ƜZ^$f2Z 3Չ WP 9D*x>dB-mH5T&IB ZTBx׋(Dz#]W>^Wx !զjP9D*dBA$qvᬥ Ir3BSxaGm纩JFxVȢx60Cx䠡 7 JA"2ˣPݮ 7T0˒"I(nʌ$h9í<~>HDgM|']|Iu)5e2|FC">YC\{hD#BR `&o$Z1B&N4 .JDQCOu-dNu tuW.D|mB+k)x-ĭm&j)A"o&[S65[strP!v^Xq'I2~S"HjDBlCNdx@ g9&'Y*htK5B؋Y4A$.V "E]BB-I @cs%gFZ B)@F-6"p*,qZHHI1-Bk U` >^y1İ)wjaHA&i11t!q!Hp**l*ujGj$Ƭdm',lENO0+P1͙TL-nil^-옾%mʗBsqZW8-҆rf-ƭBm -<6-Aڦ->..&..6>.FN.zmgfn.2<.DTDE|钮%LiTR4rn$mG*D)FFѰ ⫞10@I#C#qĭNR :Q4>prҀ y%yj6`ѐ_uэEحH&ZCbCB#7&IcaDsBfCmHBnjcC&JDdd/F.A.q cD#>(S$ܰ8LB`{y9LCZ :iD 7V6],lap*;-(g!H/C-@B6x[ ̒rP2LDICE*DY^D;pM17+3Fl0m.v$B0K -W50uQu0dX"XWt N%@H"<{.OBr_D/C>@Gl)6p$įn3B0C*55eQ;C:C; Bj}&Bhoxk#gzWP  }#g14Ҍ.nC.8BCī6r-knra8"G 8bJX sp4>h$tuF$ }f4```b6GGD udlIsMDsLpDJAw M+]9#Pl_"nC!nSD")BWB/I@8F+D,YG~PYD؂1n/c/c> OHr 녀/r=^)\]D Ch3e/C*VP4]99Z 0Ȱ<ˌ F 97m?eg3X OdPtQ@E{ >駡48E 48m6LC*ldZ{s+vtHwspqZpsFuZxVUĎR4Bwo~G~t?0txStw@uثoY C_7[[iM2xBF{>J9b7/g6f b-B,@OР1áMDŰT]|VjEc'アrʾmX& gr:,*] +:~:.X*.,$K#0-5]q)D{zi:CO4TyM_+@kY:p$R;'q$ݲ'FXzCX5:` G{IuH7g⃵",_'K,8Syk\C;]B\レ L8H,ZQ >b7v/lׄcW O$ġBW͚PyMBh9y9+Cжkip:N'X#r[#I}.&̧{xzu֌5形9WK{ڣtwi}c΀Ct"H >kq8>r8C۷7W%_~/#g)Zt$>̶#'Oz$wAO$ zrymryJ 8T&MfVӥ͜MiS٘k"SRLȂF8Fq(66YOsć4pn3%Y̙qQxxӶ.S*336vcV  Ϲ%+&v6Z̊ZW-l}~^].۶E}&Tl1cʧ]hZevmaK܌əwe~|׷a0FpD EYH"kEr6 Fjo&@`>ϑ L 9'<FuqURcĀ \dHHMP8("| :Ttj(=jAPRII Γw9v+(Iͤ Db+$ôq.톫l&sJhآHcX&좭SgzF+RoˍO$r53ڌ\v ZEUrͬ#\$N6Զ"6j7qīV6Yn-nZnmܙ;-m:צ|3qf_z7ƙ!AXqQ8ᨑͽhhc=8Jب_~&>`.'Kig"9>;I\|1`r0Tsp0`61@ n~)Ta^!| g,  Wp9Qc &RnpQjOIҶ7#S|' Gr!d#(D\rݱ*`!֘LG*p)5&#UD2j2LWHq dZXAY_|>Y) Q_[P)ϔnQHt<9IbMфzpqmMf<}:YMk^6MokH*rQP;JTg&~gLWc<,~@ ZP*"v6 -O@gyfYdBF gq 8jQq0)UJYR0](5)Q>ii~rR3*}IwZTIURT>QTZU^YVU~aXɚLiUZVZV#F+&A_b(IBhb%Sy ̯P(( UofT7v//F@01B:$2M!j^ t1`Xc"<5]! ʢ 8l!,+^u<=v cXF%XF1d%( o_# ^OെVIN*incYmjMHߣc A$[Ba\k <,ЀDHU((bb-.apЂDfx+W_` zCE16J>gH|XaRBHYD' θΙt8>YT8 TX+<^rV9G=a@ 1`h#&jK 0#i,CCXA 0-$+יAVQ^9. 8+SAzV1{V-b#ۮi–lgo$7i3E5S!V& 2Jfnc5<ֽ %#eG2  <4>7WV;ogmxdθ 8ewoٌ'g~=~ W\8ər?mh.5l.1q;BtpRBE}"CIb]Z!.e T YJn$M""mL&$m#6X!>s4L"BlLAކ m#@o#ǿHqf4HO. pOn"N,N, ,P^2b2mE opG0> ROl,&)|/V$p䎊s$cLEҁhXON0J(l(Qr0 -rhpt0 |P!zp0.FL`Eq1!2t/p. 'n"*pC QlҐ:$ )h"A8 / 4r! hͅtB`d$C #AX>``!RV 'B2Lwb60Vq]Ѯjj"Q0 z1*AgYLf")=o#?±Q kia.A"^ 4qqlu 0)B lDlL"2%/ڠ =x)nd"=x=tnk#A 5g2g$O6o03Jxa!>b@nR5r"B 6s &hTP*P$S/6j:I*=ĬMX sHv/cOB,]d X>7ؒ*֒En#.Ob3XɱZO"Z/07AN s> P"P2'fFS&29J vaf""lI5;"fJg^na$BALfr #oG4x69.S¨R188`(.V"ͿFZBA=4~g"X/saf"@?l'*45k\@AQA ~pU[ 8ǁ#s5aB=U"? _2Q AnD9n1ǰ oF!Lj.r#Hk"2J歷㴊jnVQa"Fmw[oH*:I^۔C:K5Ncלt"` q6K6Q!-RE1hmT>eG(/6d? 脶 bCV#XKQ,.u +8tX;/s L>PTo MW{UJr"U[ nVnV8DnGmpWpv_ Qmߖpr#Wrp'שm-Ws7s;s?tCWtGtKtOuSWuji4WvcWvgw"vG/]%R%b(aC=CQAW' o58t ix#4a4^7>ܶc7owZiD!lk&]4!F=rd0haڐ7r}`H"b% V`C$ָv>NAv@"ͧh849"sL;'b>W]=t3z/w=89ʼP{uD*?2=l09>T#=X)}w"\Ɨ"ȷ|V JK/9pL!z$D$#ALj@dhn?6erL%wNŘtшj"Vadɸ+:  6doGJ=l5p>fesXQTÇsX?c 9Ne;sc QaP 2C89ٌӷX"A|q$4 mF#\@FpA^S"x?aF@@nxAf"d{ D^&aAS lD{J̓l7 $I bͬ@ۄZm="#z!č )*+ #>r#d^9Ͳ M B |: *-V-a21#'8b4y%:|jS%u>),؎"9`5]Y4L*!:ct"NiX>tcyZ["99n흮 =:m6"-f2$G Dz#`"{#["aYp be!Q|E 0obbT/gKn7A+21VPnapY1?Ms\=̫tĺ E$3a0)Y ؖ|"ЈI5D|cAxRw,gqbg*.5xڢZ#C-BaS~G*YFƸm=8y>X'ⷃ{#='Fo"qZ>`Kl!DPMeABRd $Fݾ'"w! fzV=no$@#~PR\#b1""#>M=#5o$lDK ^!47ϒQ2"heC2h#,.\`ɛ<MX#7BA^B!#)uTxnݙ2)?ΌYy`Xҷ!)|mO>L,LL*2Z= @Bm j=7{zp{]ؓmô}+~Zs3ۑHN&^eAYAz"s" % H4%BN:%+M Ѝ> )ɳ* +84z+$>53P珉!QNQ/d#,06cl#4+|UpP< p >TQ W$E ,2ʕ+OK0kڼ3Ν<{ysXr=nf2ȥˆO҇تuK&sՆ ۊ/ZVvp" ޽|Vj[&9x lV࿔+uvڷRM#wڱѣ'\Y[ӢB[1e7S'nzuh6}Ͷia>h: dBPqmt8 v|LhHKCeϽxS˙I58a#3˼7M} >B >WAቧ]9Nm)e؝w7"Sb67@>APbJ(m^*b(ʌ SAD%U 05B5q9IΌّFLH"&KnfJ8&݉gGBIp7%MwE% t5mU6fZl]XȅcrzIj5+* 7~d zj@}6x2jWovvA[TS*1qL_s8&`79t#6+L4X!  尧8Gۡ@ +\3. iA0dH!!&G,''cP6~816kx"2XHbHڈ(J@U^WC qݐ@`L͌IFI3Hp͒qwݺ7Zjx8]0pCS(XncKqՍ8ܐ6Y83j\rzs9,w#+&Kd5ESs]/_gWu<>|#xv-oTF`-;9Aڔ~SMM|X}԰2xcbb9MP׍ְy!GԷl;ڄ &_=;׊A@X|&!pdЂ1|cFxmeE!>@dPuԉ$u"F6v %XT{-ES"HR6yKi؆8CNyf;MN0 $~Rq1UPhrh#!դcG1.iSuQPr*AN@e67QT(IRX5DYjA3$A?b&I&wIKZDz-&z+2׼u|_ױLXAXLu&4&U,$'9~&:Ɨ2;ygq⑾ܭ2ziOԪvm1]ڣ.&5ltOx¯lf-Y:ԢE2Zʔԭujw?b۾yBM,KYHHEJt w}Xկ x.+x n Kx0Გa >Ā{yE+^ӿSC6T.Sc'ngřQє%DLPzҋo@;";шY:C!Fch^n[-> E䔈Hscͨ8ix;IkE01!LD7NnG &?D A*? j2>vA=ĵӈ踁>PdTҁ-P<2:Y.(8.DnMQ"rn G4Tr)/ȡ'Qp 8xww,bu Xo]DT}R  q~mb v-n:9vOBmz kh'䖶w('L5A xwI  jD p Ud,~2?:#\]uK,uF&M.I) Kx's|b@?!} XrQIG`MD!9NlґX5q|jrI/M v0|8G v;P %*xjxDdXf@Gg k:|)9`{?H{&9CH@q,N ńd7xʓLKq_AuHp.DJj'a>׀I`@> gJԁI}- 1yqv ^U j@=qIт .(0 d58OX eG v#Y@ umͨ @`=\Yc`Ϡ, 8wd d7Yf@Vt p aEy;hSw>p\[beW C;&; Wu)wx`y>' \x59yy旦6( Pv!860Qۀx~>zXd5f(J p!䗩) s;Q!@Wa 5A}h}~}5 xяp n;U`b)/pR)9mau H6J I iv3F`Hp!bA1 w50 L;yB M֣.{ї dWtMQ/鱠QWѧa8AP8>m:>fn1 svTBxvcI,ɕxچaAπ6it)gJcFhzxdɪj9noO(p5`.@)yN0ᝰ8?Mq:ڀ>z߷`p:@!ri8Qa hG) k>jyQq SO^*{ڎ ~ ~%'P0:12 ,Pb=c? Ck@Ma!7:Mp vvT* V*X`*k Pd,K6wf!(4ȢjM1mx:mpw5/y;з<Ѷz^fcixfsh y#Dfe8cʃKq~?iYdG'n7'ڇQҦAA*+C溜J ʆjًY0  P5!( ՠIÝ7!f<+[hfzImpnK{s杍wywyI9= [x騱+} {J%[Egm ,": H;aPM@VH-|<[IM#ٰjM. '\Zu`0 @őU-L}[Q`,u*;ϣC~ ;o"+"nxTHmvӫp ЁPR- Yd㦩w c l ,K+ 1d 9`d,iث![@ R I!l: cA(mao)iMl ȁ!9\8(} )  m{P[} ~`'ZKp"Z**R c i_ƕPƣICJݴCL{[gHEȁ cA 0cAkǓbj dhzm4^c qȩI q=)/ qQ kmZ Ha-z9sz\n +KtI l91v{V-nTxjt(9ƭ ʹ{?騸zN#2LU|=|XJRB +d,ۥ9^eP۹Jz4qaI裭(P!  XܐyaY|rQgIew   ;hVVQ0݉ .+-Pecui:B DB[ëzVǑ? <<ɍy) CbG쒢0aw($Ԏ%pP!8LJ0(Vb<}x:wۃ|J\ e WY:ɝɂB^a[lmx4.DE y5Knȍ!~ )jbߺ՟,Ҹ)ǁRARK~qwivچdrL*g ̢4T vWf <|RL5Ajm"WĂH޴ B $׉s|s{R8X; w T6|#R0j;j3LB M]4jj6DgN,]>D20 R <6"w9{(4.mnH@*aOviXǩzY0ρ_]tM{wʉws덏+O_[?%spWP{~5?j!O`?ďɯ/Oo׏ٯ /<|V'K.?1P1Y{vGlß41Q @ fܳ 6f;p-^ĘQF=:U\$YRJ- v#N&sv YХ E01𒷁Y>q)fu8gpn8.̞u[;xK-F7s-̷u܉kš"~Y۶m܇RtFY#.Ika'T-\WMG~zeᛲ;pbBnRFd݃4$(vZW Qbp%h (LхZ&!H_M8 |EYfArncU+qRE$-:#g*Ppb0c=hS ,=hRB -qxt-%{ `` <=e7zUEtߨoל")JZrY".pnY'!J, JB?ƔY.1Ӭlxؒ0WR]&ŧ\rO'byVL_=QMߓ˖>z""pK"wDib2` X/x hwUA >th0#:' c~?CLC`Cm9AOjxJG)Zr %і a($IIEX4$!HpBB#X2 TF3ՆEgq|HA 4d >ZA2T-hYqLN-qA :ly9"ИM [pr}[1DmЃ8Egĸˆ Q,yy,@k|d6*`ÄfC( s1AsP1#$\.9ǡ-'458LpdO{PYLE؆/RvGO 1ωthMZ|YgЇ"{EYGsNd7 k]'1aİ6‘TF#FaQXFRfnǫ$&Gxe8#82Pqhؘʕ"C*xlVrl#^ \p wfQV+\-;hD&ÂV.*ch K1 afeAh -[!beIˎ#mYHתKMv oZb^ ikkjCe?HN;NUZ b&8*ZYƘg*e_tLcY= B !^)D;1LGLg:FNeo*a6M$0dH-OMUC$hb6~h1X/UZ]0u=wǡh!~xXgb4#8H(n1Ԡ">(Wl;πB ep'gk_;o -Gq{,rɷ1Akz,f;1`v0e.ɮEfL8㹣yDGZӘe\zq99`I!X95e Ƅ$GC" ,C2~)T8o,{&C^3bCsC= |9Z*4]2_ 5*\RnDǁoD6Pcb3xm(00U>Ze@tC5kpl6jzs_,L %[fiU6+BDYfG-z\L'鍝Efy5$na&n͊ӦVqAG;Nd}F"T_ [\4T*Y}|ޏ\)4bG\?C x _OqW ‡?h'0n8w*# #֩)Ps8X%/<2l1@tiNP脵TlAM(:9RX2*c\jA4;Hkl;$g l=4øc4 8;B*;9A=T,;" =3=E,=B=<3٬H`&Xc55Z=^=Z3Ꮹi xS,ID8|@@a0x>hZl>]T8𚼀q8kF[hɆj V s ;rк1"Y+?hYȅ~+ ˆSiұk@x@)[x$SP%@uxv[Зj`&G|91wٱ+Ԙ2# y" /|2$$%4ٖ0(1lP'Bp87hIx!2 Cd csH<0,j`oL$J|Aj`AJiK3K ,"B2D@5*2RSTKpʋf$hjOقscɅ&A GCh p080 m:@p,9\{|ly6"r{9LVx0\] W;4AV ʦ\rj ;B˲|QV)!W3{4Ap)%Bњ𠸀WTFD0C1]ǑK?SA@˘ 9XsÁӔ:I;sHRB<Y̤l,zLJ܎ɜ=ZS ū@E?(H IqhP"; M|p ҠMJ7O[I b<` 1#$pŒ-^(۸_<~YUɌ.iux?Cc~|ȁ8s 0e;i l닜lPx[X9yq}1!ٸQX*2PQG0`(4ڢp2 # r@GبBS;JU #  Z@=} TۡW3m9"ⴥ)+2)­ JL3qO}j!] SI<uGhٵt BꑓmkyyR mi -w`rƕ^]\xW1^%5EVя0ϙ__%6FVfv ĞЏQݓ5r` [†HR %SHPaaM!9>h -<BX' t`R4 gdaX$0|H@W_1c,QX& x@6͂8hCdD~0,TPqyd(^YrH{)D(NaXfQrցX '~a)5q^@>@bYߴaɘT8N|`cofcN2Z9Oc>6?V kyXD&Fqi&v'J1~~Kdtɝ\ RY >Wph`34eAMāxx 0`~M fCPu Cz!YBV挖5+EŬf3!df &xgH'ބF>MxLpN"RN3h3E賞-na62ٻ뼾هVM%{bm(+ɅNMвRaSl&S)aN$llVbea>SqXm;Ԯ%+V /[&4P.i|`5=G9Τګ0$m1w,yoF>,|8Hݎa,f~ΖF=T놸l%ۄVq`hž2Ba8??ThNnW@qn K@m9#n2Yf~袈$^@;+ Bsax6W&.hҰmmc\ŁAN#$tpxmx0X|@ptH'mj0,ۊUuHLJF5ȴFQ&h QO0uT]kqlePfqBFR!3Rl!hvw!GS8Wp%_s Yj`I@"ӗe Pd2woKn:\S>rt ^^ߓM߶w| "i^ë|В%!3>{ xo.&oǑW}p:ߎ7,blpyM}q by7 tuYMn.w|ukzaq~a/l.dqhR6忶khi{U(w8ũKp!ÆB(q"Ŋ/b̨q#ǎ^9pOLqXrT$ P |̝{fgC ?!'\GTXz r鲩dx£`8ԕSXŚu-۶nFh*KXY w[\bjrR_1Z>{OX41< \n$ֲ> f -ojI%ڂMG2b0 &ڲ'|7׆.8MP%|޷c%~6[^ ђ8D_=ZbHKNAҧFhɲi&ZBJLtD!nJb)q&ؘB6 W]vuGC敘{]^}mP~`#B8bʞu ~m}n_}1!>Jx!#v+VWz" [d 9 S#/D0 mQ7;&!@ PljE߬;d/$V;5w U<>#tA$8?#OC.V=#>]y28bDmk]>b\de'O5ۈaj9 ' ٴ*>re6Pb؃o_h,wzO<$J^{מnB "'~k*/սl bV]CS_c7uJaR۟hE>߾/cYw$~1|݂ g"0 \ B-N{"h b0 ;A-~ Kh0*\! [02! kh0:!{Cuo/ v2hVK~@)EC€D!-?G($x IEZXd eQU6qn9@$q4"td;P<;Y6t2|,@@֘Ɓ D> xpa%䛊0%>(` =0dY0ݬJ90A5tc2X7HɮM!?C6IBJL eiAQCwD5䚅$bC']QDaYoSB3&XaC`L!`fDރ$d1Q'ENtC -<@)*3ы "х$(*-J8$I "9]Hq Әq!ӐlIwI\$ 8IaHl^GFtan|dtYU0r HvCIX7cQ+]U!FTH7d#E-j+12U%=XZY'!T~b,q8{tQ ]x"v(9s"8CQ)wrb?T"՘Bbܵ]Q B[F9ZF2$ I)Jґ"+)}?W$٩BzU!DaĈ4ɟ kH-b$fO6$XqL Ks!BE[إص(F-HReg PAptPU!]&{*8DxBBJ&$-DpDz57;mcB*ȂfobPbT`clmf (S 4>HrDteЄ2hBZe8n3ΈD%7aϞ7g MzłM+iVO|04X1f>\ɴȩÇ;֑q %β )#&IEy\Y,<& Cph( Q@u!sV [EqCv )IC_>!#1|${∬* lb2OG<fȥ`1;>HKk=,Τam F 'F$_$\EGrњ ,Ba?$d j&a T&-^ωMil׆G<8;>ߑ$b}F0,Ĩz_Is*"؟1tlccWQ7 =!Ֆ`k>/7 giCC*6_P_6[8LBhBU)du^,^WzyUZEUn Ea ><IQt, =*B~!H!`e7VE= >U*!r>-CA͙n'|qqXeQDXi^pRHC ]B8WYeIÂa0SB"R]8IAZ=DQRDܽ)RC`@,T,d@Z(],F@$(/@H@+Dœ}rTs%8et$8W$ шaKF$6<VlcPZIZ<{hZeqoVCD0+LhGGQ1#8c#ʼn3Z<I6TO_Dd|ILPh\uԑTGC9&t&D݋M@JQ'`(t ?vd(GuQPF'H1*VbVr%v`1TUC!܎)UBZ>e9Bǩ\XK&idRC\E0!&D/`CWi#q;Uel؃)4 9m`ـgP7C`&`@qDr6-1#P(8Dpb)KsQcPTZ;F(Fz7ȫ)[}Q&BZN'^Kߊ.TY]|Af  C68mh->E6I)e#&,ȓBB58m:-Xz-8xf*tQ сÚ̡T&e~I׼ݭӺVf+9Hj*aRjԦ6j\!dbVDLd.ΪX6^9Ā#S C$INDi*2XbuEB5(R4j FDP(+MpAkшQk$=Q 5QE 2p"1u)@cxr"+k1+,M.),4!í,pnCR 7]BFml&PC?P5WSAB<)q,\˶,Iid|G-JmJ%JK_fáeمT]fZZ`BB^^&rR)8tP.ÚM55h'Z~L!Bfd.$ęd:D57E@PPO3lj>x3<_Ë%,4֨Ep2C+1@!8Dh$0NK__ -^t.F.}OPp2&]F6+B5&0K롰BCΊi!I,t=Z`hHO"7_OBUV_l-r5.1B_5BWbOa-q(ur BdtlyqܦESPzQJ} QI|.84@ W=aqv)}%&o!g3Zrn($.a;6sWDPw9 :{59R(?/7N͘=7ӈkCL;UD'=w6CG[6 ]I5zc&\R!4NUBa g0 Z05x6_' EgXǃO`yCTAQ]ڌ w!q$TZE' kQ58W^c1u|DqVHMۂr:08CĂ\Ɉ PJ5)X(ZnJNܘ9+%V*r0B8BWTWov?FB(8FŮDp-bG{J$;J`ѭiWd{zk5 /pd;F;B荣;;k}Dx`8HCWWTI%|BPPOЦ8p;' |ȋȓ|ɛɣ|ʫʳ|˻|˼L]7|P!>2f<=艼b9*_^Hz𼶏^R{`88SQ&EE));=D$QIM+-I$ti.٧cwRD*%abTDX"Yy wOK.>%?thsAIC=GZ([=[vlڰݖӨO|-xq᪐'Wyrϡ#gC!g~B6k=ቘ":&1j[ b9^DX{E2E~$ȿn'fRJ*'z'|$,sL)Lq.5!Jq!+7ȿo/%E=JJ LtO"$NUYE" W!{Ҭ[5\(x|lw{P _XXgY*> bV"ޏ:pTs M!Z I؅6 mB|=7>C0(9KBm%|X05ml"ś>1GeL߲Gr| K1:È@&9n$&۝B9whn :bBfB1Vdj)Ot21&DmO*6tUE7*j _|mkc-ja˒l281ć\B M/dU RI$Ȍ-dDITRv*B aP!CLa Q*HUT &,WSV%!YDBWD (f^]ႜ\*Pg )E;wRk}̹g-qFZ?/hޙ+7M"+&DȽUA>GIUq 821NBN?t:@6C0@bo&bNX Hq7[nBLL lD!tR~TbFE2k uq[6t(saQb!]d&$!_ WsX60uB_~LҟmV0VkcRg4AcZ6MD󢇐VoeU1 f5,4$TSٸ-J!ۄb{+V>K<)^{B}j_>-&t[IM D`˞\/`Ti(>R萢r0ѓf0`8ja,((a $&H&W-R%Mh:SW`OirՅHQ9NH7z|E 2>^h1xȢ֫ċfNm~R!2V&IH"H-=r ~XeiVO.%+B+I2 4!m;q4 I5_o))U06Z& |EHs]QV)5]`+x&ʝ5/gwg[W|ͰƎgSWbhEjb<+K !dc2>̐^TiFSp"x6QIg V ETtYm#1ߩ\K+Q[\BH9DZ X,kJd99HYy)G@爝b!!$V;&qKev+!A 6*d& PzVy-V=Yb'綗[T;vm*֮{oE,G.绤 Ju|7FJ>EdBפsТhhö9B8@ICPnU !7~\ָ]!~#'+㄂'$l^B}&fBsPk*b-'!Jgq'Go?Y0BLN0+t:tgO:)Hgf"X.]xg vcjֲaQ2!U"!!wL'P E; ->Y`qs܊E6kٖEv01 4ޘ#BTТFaR";byDdnB/dAKO&-hOI D)LHBNiNDd'PK PP$#ߢ(Hրq {$eAH6^0DKP'y) a(Nlq,NN! ¶$cB P EEe  CK ]c0V (Q'c 1*#ii*! 1!+>8(YD.2/r//M.apJh0k b,/%s2)2-21335s30!8g! C@$uTzKn 2G3es6i6m6q37u3-BώqF9iBKJn!R.)y*O"=)4d*BƸ)C{Ot֡X =)N4(Z _"jn4ɜL4DL>4sO )y#A?g9^0,>J'NJ"e>+ *D"E z0BMA$4!b>aKd&P`0LAk/T@)k"K#$A))aA!%T++4SJb2{WLGf,Sj&D$$ `=Lb@& +a#4VMh.B/ V4XUW3fhsaB+"Mebh`K. Oku/\+WX"I!tLG$/*nO( 5"@_qu0,ԉ"*HkS55b#5!( !bD &@VdCdd G*,Pe G\am#@=PE"zs?li J.[s6@LG͎KDIb-/NJ@0K. T2, (/ n0b6pc!*E WJ/J+n@}u]L)H1q*GL! RydY&Ȑ ըaH%#UAy|R|SK2<)bwkEbm;,u!e"BLrݵi@%pHtI״ogԔs<爺%h|` b'T+VU'UV 8"xXR7 Yy7exͣ{-aJ o!x!H,BZp8 x\XrYA Dt/ bBrX$J "0~tL8dÎ(A!AETabQ~X6.#y\;< dZ 78|'Ruz2z8y!<|z<@ ϡƪ%Z}d㯗iBFeCd a&6b #zafYiʬ!"#1(؁869$xl0_n$IyFВXp5PG$t6aLZb)Z;g $߂>,r"K%IP1ctX2!ku/FZ\I6㵒RW&S!: i)l2&Khr{7MSġ:7!7WT1dϕR|5k z?( ᭹(jvO,pGljjwSr0:Qgṡ^K`E,a[6,7>NHUo~2p0$ LPuue]p> r#A }}x#|~?R)V'92F,.U4"8}9BN=">$k  KG|*\\;|e;( "fa:p"2W%Ysa6!JDxFɳϟ@ E:xEh0ȇK.9ʵ(6DwF1Tb!kȝc%.XcJ7sSq*8]/L$tc $Z.@v$ꍌyף4m] #>JLXhmD2e&(G67г9/ NU#ߕxS"¾/\9oi~~WM9hR0=>'}_~( `ҟ8/YTՉ(,0(4h8<G-TXBD PHcwC PI.Sw")HIj`)dihl5 [tI%*iN[I3cOzBZĖ% 褔Vj饘f馜vOuեPk>H8Sݢj뭸뮼.2ΰ'&6F+Vkfv+k.M2(Ƽbx,WcXri_η Aa qHy not:AL2Pe@@ NPaáFUmCP t΍Eن9VW;T's@7E5KW}YQSmEM#uՖVHt+gY>L&)M(JBb7B|_e3e*0Oŕ4P s[/!!chKUʢߛ_/01FTb03ʑVJHΕ=і:ÉEP;t@QB* x#A? 9F@p#\ \`7#w37H+Y>R6Ip47ȁbl#9&k߀ Gv(:r4%Im$Jim aHv72-l߂2 ES 7+tqrAߺF\>R "7BbLQ|&/9dapu[މ/X Ah !ÇT=̃DH `V4;F`F!d>r 5 IE8m ^ $ʃU .a'' ,fD>c5|0S.Tm$Ap60hro}ÇTX?X!8b P>_ξs^#yy.H7bhNt`LJ-*.sNLJ` GHUR. ݒ#HAaIIâ|<Bt"p݀h)s0d7 On5qcb46Jj\ u*aGRf68+yRj4($d=DdhmdB <,P62U@'9eǞQF!#GGGMW`֠,O0Q|1}בR7of#]Ѓ6 q<BQpolF - Pq+f4#|&{^!?fm yB\"" kl69:rE)$fKM,)d %g2á/! IbftPUX:0W$l`D0Y9e Qꦴ:]%mp#181aRa5&P0jl|]ԏu9$Jyϛ )ؿrPŗ]ܪm,Ll>Q溜MnJcp̗?Q+J'|aXpȅiΑ+1Ξ4e.-i5#\bT8 De`lYptjO^gA*A as~MT %2c8TA.qE#B6BQ]"JT4 *w~)'IűBGeC !|*9=,~u)TE x2@M0g)ρiҩRxQEV+O$F||Go}VRXdy$eAQYVIto3J"@dj8,PBTJ8jAuxg'9ysq:?kpFC EDZs'jDy<ȒMTQ?2r tE=eA&J s*Qo f>0OU PQwc9FU^:A\WmJ cl#Q+JH&1 #+JVQ2YIYĐ4/eJ+Ay 51!Hm`1Ȕ!UP\ xVʤk|sN!NSOT0 L٘%bj!ǨAP(` (cQ"'e'Jb.UI8j"Jˀ&B Q#C&ȴ[E 빫d6o;q+I'QvQ 'KTѱUA {k[,>>7"3 4B?p^a[-{v.21;,2@ |;#{"k;-B Z? R(ǽ; ,NBYfr2˾CQH1<[{ۿ<\| #1i" ANr$&#Ap!@ ch!|wUE3JWa3Zq9U",<e4J7AT#Za>Fe{S>.3 6AlzH12K<c03N{33Dz[1,;L*MA/0r :a !ZjS{|!\LnT eP^Bȱ`:`+h% ZPO*?F TIT?ȇ(p7>"@D@fF d>dԢf$Rg CS$@Ԭ58 RV>0׆[R^">p> md ⠔HmmДl\[@Q=%BvF@EViwqM3r;g +xTN ۼ.éǪҒ4!I:#S=d(# e[&vӐPv"l !n8gֳ bmҖϐ cVqm'Mm z\A$O !Vp·\d$)!Af8:_篭000D_2_!@l#M#K"0זIܛ jHEؐ|K! ÍNE0q+@d`_xNBf/: Ѧ@a#+@!v?vZ yȢr[@'0^>8J˞#9t{n \׮j/,aV߱sѥ7ΐp g@N hpهO'_p+VzJ}h|cFlM I8L#i^[c ̺ SBp ̦j*CIM- kgFqm,>F"k.)aq0a {JR`G$*2")rXgKXȢ3M&z%6a*#Knq"VK0=C?P57 F˨GwOqLj$H)D!+%ZuUXc} 3$\jrߊH~{&٪ ՞90,δj7|u\r}t.13m5w^G .=ޛJ>bn 5Տnw 4БQriF # PT@ $!`')5[Q*hGfhgJR:hEh+%pdKa\ə"a!"t;(Ĭv*8b8̹i#r'O_",N*YÕ0L"iC7IG*ټs &t$ b,=wvk40|,Ҭ5pyko^sr]TlPAym8pt&NoBۆ"J0mV}y$ś7q& x;&ìc {W8}H0 .T<5@H11d N0F+CCYL&ĈAeZ1: 5[K6nHRL `tqc*6""'n#R 'FeYJFm1c&CmNN< bDSq-AJ XH!R5%Ph:$+| ED- YJtdAXrvӝcx'.xx2fIV3n7(Y i`NEy>e `v&7<@&Kt1(f6cs٦.yNYRVF^erKg!@xslR6z`5= Nvv&tٕ5F- 8Ym5;uBp 5 @L˸>Ǫ|Jb%)k^9& 9q=,|LDwM9cyGc g`p@shw&k1"f7 >̱W,Gmsyр_}@w|FcƷL$ O*Og771=}Zs;uqMk#Mfi~S \#3ȋ1dn7_^2 Audv^VDIq*{ c b{&kol${hDžXra(8(F.2-“f9VfwK=m7ܱt? &S%|?"j߳/ ZCŘ~9jDԞE_OzE(AO-Y^Ҽ={gwanoJ0=sWX q ЙE͑r{s]1(@qڅ?׌O:K  M Iw`I:@wb(B# @7?5 ;Xһ4Em2h<>#®nw㆔ v`~pl9Z(8!kh8x ~q 9 0b -|7p})D((B0-,É l2̆WjPBGC"DC|8 ]ۆ% StЈK[ž)DJħ`,@GEcKqEŠhile3@ah E#˼,jXKK;,|)MYK/#̑HMI4l̨ˆl(| M͆$ЏnMވHqlÀa@RjЭ 98,} OR @*̆Rrl5S5MPphS0Ljh%Fuԯc\ሆ Pap)o xg]  7ցAQQ AQZp=]8pbGpXw5^K+4 RA  Y|cKA|ڬtH$0(HŠD 0ӹ'I$; <7iЖSveI߬NXi ć~ ב J 7]9E=Yi^QY 6bkAq3nk 89!,` b jL7wnx&AP9Zm+Z2|ZEĤ LpXM]tkA|1^ $q5W(T )ܼu(gHwM+ Lď{Ć;s0踧1e SH9DED<-ً D͆fЁIԥCT+Dp\H}}Յ C% DEY蝗) Α%a ql )hȀ }r,vZ)#ǎZgn&m 8K&b&k@g|S<&]gw1A'zg,[>?ߐ[ A s3]sU`=}(@(ۥX~B<3u!߬(]Xhнk^œFLNQ[͍H"#Nb Cb9cIb{<^dIdJc\ "AVǰCvgp!e/kXIeHl erdKeZe[2?/dBPn`3fedNfe^ffnfg~fhfifjfkflfmfn+nd睨 Pc<汬l$!J?*mcg"۫(`J3K:uDæ;.;f-+2g :]62.hغ{{.ט璘Nyȁ9 >]034/P.3nC/p ^. ?@{?XI ( b{~阼H>|4_8;ۉ)a^ iôM^-36rfnדe|HkB[xK(E`[Yr1< <8ljē1YI7o@;iv7xE"6;Mx:r3nks t˽򃏋 Frg<( -.sc XPjnj~F8Җj5ڔ[Ƕ Z6,S8qĴ< 8Cv뼑khdb;D ۣ`8I?Ş(n BKWCbc-̆xW<9^2@Q? Cm k^m{ԝۺs_@{UZm}(p7:Cn3 FzT.s{qZ.8osZ5P8&8s8Ќ+ > YH11i)(*Nl1)vzը,`Z3XgzzP Q N_ boycK*ˆbf)l)lvXX_x7hdu2FLNw:潁jt8s8B? ,pqu:蕃cRqXq[U:;P! " b^h@aiD  @@N݆B@ޣ\ 7uN &L3lsаsMeۥɂxjD?&PHt11F.~D{4k{I2l8XkN`zo]5]z)z z2|7$ID4p&#)s/ -X@蛌l@MqwxȀ{|'|~ ~F VME7^L lP=&E_Yۆ^~GR d؁k8nڝӁ၈Z30]7rQ83ɝ %fȥ{C(tè9VBz*>Q$g REfF`„T0ǒ-k,Y?jC} -ڥ\:hhU<'wUWTJ1Ȓ'Nk_jLD>j gIIG3>5{ht`/N\ B 7JmdvAAdoyx۽,je?Vܶ2]Ȯ7 & Ps_6ns_5SG|ܷ=҃ :h_9LZTPq1߈ K5IFeyAS6QY!j&4c.e+#YJV8ޝdE&G]z%I5EYSl_9gV)1E$DS*8u#Ä4Gu ʹ%8 79J 6";XdY2xSA yHtĔpMQX=ASUT&>̕8Tq66׃sQ瘝a'wĽAnzଗțAw_4:}5#5`693>sH&v԰N9SKP /14X4jo#FD39>Be vMp]5IDK(P8w*w4E 1 yI9nx>z$zbF!2>7tjLJr1C]e +lt+>WK,AmG_ˬ8kqJp(R3 Jb%{!aFV*0T.=^]H`S#"`DmQs0PFGϱXv.6`cG4 R-n08h&!cl ~V#e8j %2h@TG|0lduαc?c|/vQ4fCcȄ&A[71αl,Xd7bx)dd(A\& TrIF"aPJ8 9U6rHDs*0xnvp;n~eK6NU|ZJS\5=XjV簊񪝽@%4 ӗfّ,p(V .~,@x2MXP@4!5~Ԉ, 憂XoD'b<|1}Cnb;Pc  =#COHNEe,+F|MF3h &&"!W!ppudLTdQ\FB0A^I]#ӰGic,Eh})FRi5hPҭ ,h7ҟCqFL],QCv$u >@:7FQx5s (Vұ lȏ`ao\ۉ&^3üP xM*"$ܥ4p~Q bUz6 &8 B @B!F/o#RmKƣF7aݍH/pԛ&]rTc q`+(ABAH64|S8].szl̔6f;[> xl GP:UMM۠:3IFTҊ͘,?|UfYRlWpɁ-[aᛍȍ d+[."nq#ºA( \<(|wDŽхǭ)7=XЅo_Ȇ׍Ӄ, LO>k/&ӿ>XAloK=&?SXI]p]X8q_`)! FN V dY vLjy > Ơ ֠   ! Ǩ` .!O<7L6.|tX|^\)vhDFqt ) ᯤPv\jA8`ِCڨIѭ֛ 넢Q!֕oI|;FC Y@a3Qa6- /JY:p"ͅFA!Za)r5!Y@hYKŜ!GhJF!hc:T>a3B9~$$ Lp@Xa@x6$ÓԄl1D&RBp球:@I("EZdP58=aՄ4P`a>߯>l8P 0"B_lCY8$C/Td2cG6T\J]6FlMH_x9 A3eC(ZDm9tdΡHZOؑ([m[eETVN>R'yDp[`zE\6̤qMOvC f `C`qh,s2 t" BHB#@le]jLlFxFTA&Q65(^lChH!A9>DĥӉJ͇;´CmY=#QZOFxe> &%GYNG&aex >,:enDa8mN@ma9e"lLNh,Za\kFΝG]YmD[k>86B9W@W`Ojo '>q.gr>BJ P'"lB,@OڥltqDQHwKd'̔T8XnQ3 GRC淚`7ǣs%Z!nC4X6DP)TS\kÛ@_9@ jaoDC6C@'s~nR _Ll'[B=(Y?CBlCI4I6%LH܇84+6>X>`HF7JbFk3G7dϐ`DELnPL\VȵRpxL[RZ Gkjn@sիekL+%nҨA4 mþβƞp)8l N54EN&O<Ȣׯ\_ Ε0̢` K9DHm6 ->Cg pCp.F|?0>N'A vJKR%P$K׆'饂yr5b.C8^JFCLbDtMִJ,Qx ߤ F\Mm4۠㩨Y\E°p nnnʱ۱qdd%h%:/qUӓ*b"mn)NDR #/z1,>\<2)φTC3,.LkoJH T#2/#*01\T.OuaC`Fp y8lB 0 FFB mCHjFex mXPO25mdKlS*pK +mZ7 UVMpn nEA >R.65[ Z!w@$U]^FFc5꒴@J4@:4wwMY f$IBS]hp "N@cM(peC(oPzQNP8gNvW6¯w6 83i`G+SiE+fH*/rp'_'r81Gj Xu0 bW"|ewQ/j oG>F5ڞQ3ᆟ|`PXDIsB3FcZq7רز;:P"`HywtJhxtK.zzGC (F0I:W#30Y NG01#3xeR'Nnb[k >d@־&f xf&]@u_k_Cj0 [v ʝ[:Xzqg:H7yvfGGg  }"x&>;sX쥆$K|;5gDpSݵ!?;FK_sK1o (R?DIth~#w۱xzғ:G=(_󯨥u .և؟؟}#y 6_ 4׽1=#P :>>'/>7?>GO>sWo>wuia/5>y̋pAFO{>c"a<#X')rjbߨ.B(J^9`l`]jk'C:/#<X$C0ؾ 3G@{#aW77929TtqGA 6,E3]i8bBX[lAHr4dɂA0xdȑ0uԬ  ;shPC5ziRK6ujT %SXˠ(fg( C[sڊwn{ 09CGt7MnsŒ@p(J8FI6ܸ`Kk:i4}.`QCKX*`pa H&V\z],>)TYT&N7aT'n׷~D 5I  j!BP# $H!:bp&TЬPlB 4[x1]`?8FYit;xDJ1+r1έM9NklCm!$šK' Nć{Q59'w٤zɆRL_,Qjb3" %/1?VB iQ $H"?AB%<"xG"H+R{#`HXB?H$8( 1bPZs  ծ.)Ѻs4JB+2F4E8 t ݦxE:G#EczB3JF&\+Kbt1O$i 8}*KST  RJ -fg Ђ %5QA*խ#2(n3RX#,0YLc&1Q0f$B#b襂SL`@F87ԮD*-0ǔI^DehBXbnͳEgL#Nؘ<8BIGbNq<r{C#A!1sӛasRdAH+&BgwzJH SHX* !F(R1`ALWTz,JP2rCq+A=C/: 2aP 9 h$E:g J4{.R9*Vuq4A9jā $(C>0X(pV;mr)ilـ N.щ6d2%w*()ϑ⣁^[2LRqBuOx[H! 9`!|P(1d# 7˹dc'pjO2 tb_54mmwrLhRAP>V Ìd7m5MfgD5Ĉ9oq\HĻ ]hCsv!_aC&/;"YZ#t{]'x*|zQj<4 1=MB5D G^J͏dv 9Rd.-48>CȲZ|tiL`Cb>ǥDjSǩm*cDWHlUz!`HAҁ+L˛_uVeZ{8hAV9qoTv"B1ψ4:0̃T9yى\!c A8"8⣷Sw}^u_YGνx BsiWGn^wyw _xWx?)_y_9yI_zӟWYz׿i_{y{_|W|?ї_}_}_~W~_P P#P'+/3P7;?CPGKOSPW[_cP&Go_OFaFrdlP dIO! P 01ŨP PFP PP   ."  Q Q#Q'+Q23 21)23* b\BM)"#'Z]4N '-- ~qm!hpv>d[΁r!;2Nq"'nl{Q, b+81sn5)~b bgH"jA#[ iA-ބ"S$N@l!) #X"jʎ:j` B9B^ lϜ~V$|"ڦ 6&uZZZ ;ad5G1JĉFN3]c,[(a55T."24iV^?""Q@cwUE4[9~@`YvBg. 0 J"b*vuc d b0[3'Aߞa~ c6Cݘ#8[v@EGA17$N4&@Ah9 e@>7edoc8T!S)>ݴcХFMI7p9!8i'hq#.u38mKa8h*0hl)>D iB-G5M;l*S)i`,9f^+l$̆"AS, '4->a1mo68T+C (5PpMnkʥ ZPYBΑjFZ"M:Tzb?~8%9#2yq O9ِ 8oV^a l|Ey#AO*U/Yk:zBͼq-Al#w2=No%8BA&9} SkIL& ># >F7dŜ> L.ˆ1p VCI1<3bV$hجfj޹wgG|bTh0S(% TcK 1bp* ݘc|lU`V$E ?+Haba CTLaPCˠlv8rff@%*x‹j87XUYE`Z^PD؋ӹu# EGڕ d/+JU 8Ç@cSB9ϙ ґl^JZ4]J;6y$h{a>Ilc+MTyPG%l鷗mn90Ev: L“  H3}*ͨF7юz HGJҒ(MJWҖ>%sAtәt 4-LqzS79ݩOujSԨC*P* MmD#BթW@HU]*Vź e%Z͊K\'AKL­uM8饀OZTbT6T:RV N}Xٱv*[3U͞jE@ָεv@ܺE*Y‏=6^;#t{KYJUM91SH )pLng>(|* zN3WBXDz7/dK IJjiY⃴ Φu k%H"Qۺvu-^c BK\q̢d [-N! Â8t3Eʒui zKY=r}džv^~UM-X<`6sozյrElaC!%r9V1}sjܓ6ćTf PhAGHp>#h~!+پL^7^MwPW\.Ԩ&Ŝ`V @u/~-v -{CX o .ARڦr™ly^olwq66 #OgӜfʆ55\U/Yv5_4]mx![jX׸ Fc$oVg$] qR{ s[ޠ}zFGҏ.Rlqa2.dz20g:';vǣ=)0ۡ c -! ߹YFң@?9 BYFyEJ $HٔNɓDR9VXhZHU/el%xP(Bl Qٖp)ViؕوaYjP\[ȕz %ҐǕ\lqJkO9hـ>\%6)kwt5{]9p{A19b8Hp+̕'r$r 0 vɕww ȗ_1 y[b Jnњ$V;@)(6~qP9P3. g;ə>%@(FbHäM)P..G( 9 y)[y͉u}o*i[yg 5ZGK^r)IFviizƇs9Oـe=(bya!d8QR35z>ڤScPS #xZѹ<Ǣ~u[Qq SqVq9a%# 'eᥡIGR>Z7Rj|VmU!vFzxl(=i!ᛧ{!)Aՠjy -4a`Oa'qhGz$M`њȥ?鉲Z2sC/t'RU`ڙ*vb-p:Q0P':@A:˱ڬzj3ȗ&Z m`O`Z:0 vypv\/ 6NɳEYZpJP@m7o':(osHZSIEkR ![8)`^q ;W2A>Kl*'om{Q0QF *۠VhЗnѓA` ȩA ʪp{xtۏe5` V.˷pÄ6ƛ `Hҳh;*M ԮɓUlb'C0Sսj H:UHq;KA)ԶSq&[`~\ф i eQXы + &GYǓۥ%tMхF{ :- Jh:TçZ¬A wZ+ Loʢۏ6&S$ zKxˆd O鿱0<5rtQPYN<ȠŪ Hb{lLPT\ Y<{A|[Ufe K;Jʳ`ź }~ Ne8mҼ,ȼͲ|܈NՍcXTI< 1,\L|}t̐,|S =]m#o'&qNـqFp"'j)"j4 59'~g46ԦGҾmY}  W3o'`'~cwr=c}MBm/0 #f>h,"U4`P|j[i e$ [h[59q>PJD5 \v ag䀵&Dr϶k6{#9TJx&smh)o͐]ϰ =U 4G=@^ʊ$voPܪ2Fb1p:+rw8 QcxAMc~W$^:h==(B#Bo&}XU`]d+|P|uئ$™+6Ɵb4>}>*.>NeQS srA$p@`{^z(!JCJI)ˀ<^6@ Q0F, O= ֆ$ mͥ,MN A81 O}链 (ey" XL=}Ĕ*~芾>^~阞难>^~ꨞꪾ>^~븞뺾>^~Ȟʾ>^~؞ھ>^~>^~?_ ?_ "O4a y@]MREsO=2A%]vEֲ U/o3_vQc%N03{GDoVG#1e̙5oȵh*fkرeϦ]mܹuo'^qɕ/gsѥO^uٵowŏ'_yկg{̵{Ѫ!bFA>#5դ!'k4> qB 3lKq1Ќ0QDC ҅FA 5|oqfqH"diDꯛtGE %}Jʆ4ng u O}>6ԇ@D UnUU"pā CEE~5SA^ԇA鹢J mx"SǞ#/tҊTؑ tmE+芏Ԛèt 7H>Q'm74V#+HǑdӥ.> bq၊gӞ+;HZW) qYu Af Y_Ă$zѕ#F v\B~ex,A1v,L0_8QF 2Yc06&]4%&Xc;1[[68 i9uM@,U=%ALxE',r$ ak 3ʞr 8K Oņ=*ñJ¬U1@`+Y|Pć ‰a,P\ec.#>vm Y :!{Qrs|[Ђk=+*NmT:QdT _#LoCé-9!m X{E&H_\=c]M9EW^qdq+6 Q0ŢAz_- tu5A\>?wiDthcּ/&[8w\N]=0zR&mnCUXbn6`8yMt7}ǒxcIE&X,ޒB`E%Iை4#Iu_1 ]\R5|lARZpXg! B"mr eۋ_)y+k&.@~ dT#‡$ *g%[:Ys8oEYsha viC*mcHCXx1 >LAf>{GbiC2_|AFlX)zovC4:&;|Mճ !o1sC:t hA?p;!1$ha*bk>-"2!dzA )(hwHŃ+@Э-p>jn:4ۋcߊ. ?0@'#s+nxSRuAR+k:c|`B%|[M^3A0'`*|¸EdAFԢ(0@bFġZZI4J9%<bDW%aQ M,&HJlK|E^ŗ؅qFa c k$Ee\FflFg|FhFiFjFkFlFmFnFoFp GqGr,Gsnp&%Є`,SYMX׳ۉ͗s-ܸ7| ФQXW\|y[m5=ܓ]]]] ^^-^=^M^]^m^}^^^^^^^^^ __-_=2D-]x{8y{sr_[{=S8PYZ"L;T88>J_ ν=U- _j0mn&C͖oyC nnӈH:PE b >Et`s},MS-0,bYYcHybb`+`%q !֭a)>-!act)_b,bsck(Ç`ЉʆPI )5DF(8 #s=N{P=Ƈ:X$hpRsMe Ԕa6U6dd%_N=%B|Pӱ5evaHg~dHjk^E" mnJ\`^=RLIe(gn] a<|ADX$5go&fD&cghhhhii^n tHitk:^>ViF(wMduBϜ!(8/TSR$) FfnX`Tƭ`v.>M:p>n/s+qij2ńЉ 0(V๫Ѩ 2؄\阶.g@GE;-6 kؤAQc6R')iPҨŅEF/UZlsjp q>\[8#bЊd>g$ofan;0PlDL~H=s澈.<^ii@β0AVYhq v2պV`  НjSDp0a6韖u S"룑`|Q#QN \DeVr#p`*&qxlyl_X-?[a% rym>iLRd@6l0jh)>pA?0Kʴq.[ s%:yYXsHlsdp`uscd*z)aD t807^i5oq=xtH낀mF_(Jp0rO9+no1*O5n.u[-o@G"v&@7`lP0;}WRBN#'%$2) q*WBSt+'u_wxyy/y?yOymtY^)x^kDIP *q &XU|PL0zhzCfʑWRMcVF'W5i %l( v'tUdN.hzz7.h%| 'f@.dG\hy|s ۄ^Hѷ^PutY6[wfz77Ï6c!$m?pq|PsimPm mhKח2B 7u?;LJgg30?O~gtp8 l!Ĉ'Rh9g "1val#ʔ*Wl%̘/oucD(:kӉ 9x=cJ۸vlK-9pSkA ̴jײm-ܸrҭk.޼zTT\Gl!ʉƋondߍi7d AE O|}+RiҥΪ6sN)vo|bۥ×Zʗ3o9ҧSK6Uj6fl<=|ӗi3iۯmu4-ӕea%HPp=J|J8!Zx!^/'/VN5ePmR4x֞{'8cC"iAiP*`:#ځ-ܓ%S+Tx%Yj%]_a73 Dip'NɘH7pCGq%OyxT7p}c6X3SCLJBJzԢJ~K5(> NyJj4T'**]a/e*$0ݕut<#]141^CPI<CN;sN6;$)G2nފ ԤG T/GT / <0|0 +0 ;0K<1[|1k1{1!<2%|2)2-21<35|393=_8U3,O8&@EƵ2,Q'I[@VwRrݘS5^3bۀh@4P#esDw7C݇ DG/s>u,C|NƆ.8~YsyLR~ >#)OQmQFN@bkR<@ )FPؒеB%ٺK^s߃ \P'%8 S9>G x3">@vCCJMZq lMP5A"WKZRao#LApe~a\Hr+ҦBm pD.q\$ 1c>¾o7 sY:8BEkqP!(8X#YӀ(#= ZG,ɜ#j`U7qwIH#w#^`!AQJDlz6჈`C/!ot+LG4/@O!b6xRWL3_K*p- tD p㘥0 ƃM #2#\!6A#IL"iHÈrݏxՈ%I{N38ܒta@4_e^ Gn5C`~ gFQ{-| iƮpq4LJ` p'!787DhZj?zmM۝CmEfe,s,{Y@l1)G3:'~ i b:",18FgcL?c\/`  8Y6 -i 1 ݕ+D_)Y&MjM&zGÖ1 40YM, W:@dݟފ͝PefWᑐ` j9M 5؊!Ua\Iw9T ĈTlK|" A, }T\z8zi\:@ÀY<-1JlX%HG7]›W@pP̩\ȭ4Tb#JFM MϿIDƩM3}L͟8,UՁ_+,x, + ` 53TC6 #XM@1Z9BR5OYҘ| IM 02] 1ȔF|ł`-Re<ORV.[ 5LD2 5MuM7M )F@ѨH=! 4th9aX y!KO . 35%OHC#f"4Ȝ D%nI9ܪ(WNia1t"AEbNa)(PţOs8`@5 SY+R._МyH/>4Մ1]22+$]qEY O<O65^"8Z)P"Y) DYiV'PD*T5\S|dFȝ#m4]e^?r DX+fjDkJp`cD1sE=$u[9=D9HeC /L%E0$A=aȟ6²[zdAQDƧŖɶp4h>6$rUAC-2GD%W G=@D_B&1 >8J(>D0J"C4ÄOAC^bTA͈1,)1]_ՠB*TI]I&m>@ݙe3Dcy 6ᡱY6ڵ )}Y8LD5 pOk}|)iRo&8:Śc~%ڌBKs>ĿYgu^LGxjT4$BW|40Q:H|bY$Wzqdg悼`KNc$N'Eq@DfX@+8LA\(,ȉMV" }-(dÍ| >,IDu"@tq$A Ab9(UGbUYRϓ$A&hUz 0), f=:ݕIKx`dl&Yk6) l>DBlʮBBlg Ktذ,6~n- ΎsApq)dB䨶۾џCyD-5+DVmAZq 4Ʌ:T..6nt-AdUWޮ9fpR*Xúgq.-㦮.qtd\վ소gN.//&./65x*T^/fʌ BB6a]tT[XM(VUE*LlVƯ~1^ 54./ AbL/Ex8+DclC,!r9 >G`t8<1i|gdKaM k/0\UEGѺ z`A'=&œCJ1ʯ"+o/$ tDI5DGOIwADD0>}Q1`/`T<[ChҊv@SIp TpEM 0$8hA`:,8:s\&I&<1 3OC8s9|Q ۪Ĩ% 3$s+"9õS' gqgf񄭅0m[oA`gZL$.^5`>C@$ıϿ3D0EH,W蓂a/ {X{@Hj N40''Oplc-t`@EFI(Z;C:υWHY>ڧMoJ ]E8؄)B* W{OJC1^2[lkaJlbUy 8͔]BԽē >!u*C(j#"w"KxxwW/+B3d>d||w|;+K|$GK5 8{89'|d:mWwJSD: o ї}ωg,9WQD 0IESׁh|ANa-Dh}Qhݸ-LTY gź݅W'b>JKmP*C_&O `%؆SPQ50C ic'}639' 0HWX OJC<'Cuu[V#Ã0E#;HPH DNbŽX,Z9|Ԇ+c/D(%>[880AţO`g^O'nM\.> zFل?y11zXc] me ]0z6d3,5H5laPA+B',[.Đ 8UUl./.t3n*.uDvv/x﷣w7zk@B+z{xk;+8}w3H*t*D{8DxC34C3;$7?>;G$ c64x[9qt"AlyG\D|%F1FH>E.]nu\"NėN9oUEw蒚9vE^&bXx9I%i"B~4.Tz l2j).d8, 0X/ "b051>@ 6>`6TrAQ`>%l*9Xdّ|@Ky]x'De<6!4px")"yʓ .(f3䐇t˛#h@#*H5☍-#," 56 A#CoۄX$N8r\7! Hӈ$"c'-QR.J;%*N > h^iH *.[XLc11"҆D)3 "YP!,4}s81<&щ4 /)!I ҍq$*0 91K,6B9Q] tgT `<Y 2)]|cz9m|1q.hD?zh"Cq$5K:Ɇ <#I]RV(37đ l<ͽ"PeCL3ӚDuO3K5&FsIzXbqdËcOJck3$E3"#1iF2ң$CЊF?hO!6jM!\cd*gڀ b$$i2" myI)2Yr+ẒMj:2g:=O/w `RԭH]OBsHn m8qhSiL)CRNs|4tEχċ 8GHx8/Rؖ] ˂'xXL[b)N18|a0& U"bXXDb*Sд8kS08] &Rw s#:(\PK]%F^#~G,A<8 k*q'XF A_?#ϰ}173X9@-GFxYezc5MLf-_Tqkf mÒ$&q!-鶘-pI4.+\fNvt1]<`'ck_moܛbŸy,2,:=ᨢ46j8k]o ^p?pܬ9tmqw "o S&`=p'rI^r)Os)M]כI2xjsAЉ^tIWҙt?Qԩ^u_Yֹuaح޼ݝl qGĪ7XidqHyӷrid'`b0ϼh,^W/gᾈL"B#Fw8D2-9?E\TǨF{tL̡{/5z}Pp#_ыrY'9Z 1ͷ";CTt HxOBhڛ}SoA"f_B ("2 =$/"Є,;le h=У[^m ~hexl( F~1 -,ɱH D*(O?>S] "܋VL NBLP !#)%%*!a,'4DX`/:'"N 3@p !I)o8t# }pZ dhH~DS.8.S O00E"EblP ۂ# =g$ip>4 aX!ghc(]', A)QA'I6xT9!,"y Kp0 ^X$#B!$a2Bd14R.x}AB.XҘbJ]J$l10ĶXZ0XPW"R!^%!&JBfDD#E.b+2$Юe+ekA,a FC2 J$R""6A: ,6)6.Dp1BL_ZOK8'z %DKCJ숴C5wQ#j{7baĈn#M87Q%,303%0PiP\fG1Ratwnn۸%6fK@f) rDMU&Zw%5Ye[v_PdStq7 Y($0(()Yɓ{t" d1HZ#^P"<95Q;yXRۚ f-\ xl> "+<%" ƔADbƛ a)' Xbb!KSR BW1B'? >6չ"H7:\ 4Ȃa91h0 `Fb4K"E!q$@^ Ozz!vDL ζ A k."s-n# ˑz%CiP7Bq5F0r %̹q^zs6/l5;vr=9^xϡחW;wv,g BZ)ZOWvbø\  .%} "šiZ@   "ח¾Q'"ŝ' K$A%1A-(23BO],|8 C8Zt2~) b$t7 8jz& Ak!i&#! TjIo\RB?&ޘʣ > E6D x c7H6UMap1`B>t)"U؛S ݢ3`an~8z%E1/9ݓjm &BWa"}=cβ>W.-mSڠFDP%"{8@y}a1hb|Jbnb2ԡ蛛^&1M r]:r1a[;|Y/"wX#ݹl;llJ4ɚcOF`tpӦ"7uS'؁YХC/t 63*ӭ\25R *6WTRģ*^C_Y۵ӈ XpUuz][WR}W-6F&|ʁ-zZނb3 ;ٴk۾;ݼ{ <ċ?}C>K]s?`Hs[ t4uVYw\y-s p!SLT"J7Pe#b.c285 R'`IHc>.U[?b J.dN> eRNIeV^eZne^~ fbIfffjI8 grIgrY۝z's&IJWxyt4YGil"z>u"n:iR{L.'ꖀ!GoUhbCX؊O9*7R1T/Aő`@W6Nᣑ49\,-Nba7lLg0߬;kPLF۞juR )>>@A.PTW#Ƒ/>z.m]Z2W ɯR6MVveP:jl6Tn'sWiO*n,ʰJԔ;kұnX+YuW^=Kz^BFԨ1,[x=%C]3bQ,v48(t4p椃fG1> 9IkN;6L7c0vYS8[A"8F ;.>"پQտ~ 6sCenTe,C*^s<@sKQqܴyhbmJ"]6մ?3lhZ1w4\ӆ"mk/pӉv=M)X۠pE٪֗ٸdq}|+! &6m%.1\$nw`$I94z6\ R$\0E&At|[1]Jw:$etp,GPi0ږY8E#YF01[ G0|?.IЃ וB&zDIGQ(2t>"ޜdSl8r_ADrQRg- `Ph?&r"z Ԁƌn LфϕL(B\H7Df >R",Ӛ1Y 8  (<`R4 ke >:XS#<ݘP) E;%π  (,WFb0Il j%kBT9YC9r(#s{\ԓC)k8H8/r@hTCe@D񅮕 l.3P ZԐc ˩7zU* W縥pCI|1LMMEIkE|h;MLFso+tI _#`">b 5jl`<}$m H ,H((TQYT+l6lT0CW(XnΐNP(9ēTzQ6eF1l aa6C_jр,Y.{c& /\^rDԼ[WdwM< LhE‰M+lHA4!O6Bvm)}GC5Gyp["\Ѐ4ư/7>65*F1 8mji_JHc- g0s"GPݱWid縷Ұ%Cn<-SƐT6S\ Ţ$~ .~3 5m|a9lSѬjV%[ϒƦ)EpW WK&NJ#X^&J#v؏ Tl5;Ͳ+0mQګRV`bv+H vxdݻ+3;F6*8JUN75J۲G'|@հQ4 9Ίa$fAM4jUf_#$h&&H.ŹsBÔ#+9p0Q|=M`;l(H[B!$Eƶ'c u}BE+DSn(Ave67+^)-P> Q 6F:LZ"Jxsun j8Pu mp4>vcW7SՔ}$5 Bsd.9z׼z+9W­, bŵLa ^!)N K8 m<>ea6EڡX"dRkCm3;!:IJ&=-oQ?}WԱJ5fڥ(V@gTѲ/B1sW WQIqqFx ӄ?PFA us f4T@@5a=H@60t}Qt}cF 5&XJQ BtXh;ZAi!Y\&XEDAQ+oBvKqRBvwQw"T0ƕg'G1xTEUu!@_ jzLqgD0x@u0 &E&EiaEVn V%gIznLkm|g;}Wlv}Ȗlg7wc7lH~d s $zH~iraX\AIq[93S]E\5,ѤJ]t @et @/plA-!$&qô#A4 &7CeĐ)ْ6ML6CJ`7a[Tc) m OQ8Ux I!c3uY@QnATcXc"}цbnGbse'CwXvWwAiِw*"nb sƇP ۰ rX牐@ ^ 0w6xyKx@x="I0{&EXƈxklkљ ؘ ōXh|D~dT( n ([m S; ^AInaoCTU1o D3n o ` ? 6ML W ""7qA0qq3pL-QaqLDcr!liS]"*lP4)7QM M@ PNttIG0F RǕ^ 3` #au_u!*k\EJd!uwfwiw]/vWGaCuzץ kb꘾e\vxhɟq[ao\6ӱYsz©87 @˗gJ@}pQ{8za9p c %V/0x/SYw Ԙ ǝڝCp:~mZ~Ksb$Yڟoi>үKQ &_:L C\  9:Lm3TJ5yh $n`붥' Bg8F7*Ё)’'FL & wҪS3FI-uQ90Q ^g ˊ25hښCK~~PL  {s#QIлYLJQ3r0s2!ѿoK11;'taZK>e\VA0U$ $YQlࢤ$// 3rS2 " DCF aKTT`.> Yە M&Li f;_G{ KPv؄KKPey wΐ5]xNS]gTy[}i~,^3\5p; LQbAA エ]ə #ޫɟ<%:G@ja K^d"{a ʻ|q,Pq:ġʍ$F,Ll׌٬ ,Ll'9Kb?T1jqL\Ͻp w,|g^! cI"% j!-[1U Sѽ{\֊DO .G{+S(FYi9LQX&S.P,Za1:>pR s0P0}#4CNi# YI)<+:%XbN.K!Tj0C #`]] tY  ;חvM֑rז\L رAw'^!琫|V&>7_B=HW0,F6` [(\ڰ=۾ E!T* fṚcsCѥMs< 3D]o:.{wP$!^!DBkPkEPjűD#jiS,B<\/qk=R!P]PS7UJ'e) j֎`#>(.Iq<J ;q3FMMaKQϵ4KK1q%qDè1  / ABa4B@AaHCL>N3J> ŽORk8OݐΑJU&4[#", 0*U! Q+*X! ' $3h  1^QlXO /6|$; |' MrCM/Ȭ l2 k+TjlcZKBAd6fvjΰj2Jf9Xš.FVpؓttFDibsq6Qa$>L. I6i593C3;(2/WLlOznxdT&ҿFEo{KDTjBS>n^Z> h x"Qf~6b$QpB:0Qb¤ D)r qd)w+q΀ӕS)(AL#t̺ +y%_'>2jI fYY=74OT_5d|u>lìAFHWt\|ql8,3Mv" Y9|l,ج !mf0r!wmJ]D: Um[~Rn9@yů0D B2tHCKI@ֆpxf&HtiǴ{+X]Sq[{Fr6 (Bps% M}S xvDPúUH7͢NOIA> ȠW"RF1c@,Nl*zC1E xϐE7oq(وrTnCAV2=NN \96 N^ )gqé a5z=',lyd C!˝m h[ ZhYT fmD[Or,Gi;.QG#`]WT"L"X 7 ֳ ׃=( # f XopqĴ$sDtQ:*QE/)*K,J(Y(űX=u4ȃDȄT2DžtȇpZ"yH{||ˑ_܊(ȈtɗɘtȆɚIuL쵈TOț I;ʓTɢDʤTʥdʦtʧʨʩʪʫʬʭʮʯ˰˱$˲4˳D˴T˵TD?[] $! ?wC8XᨪxAA:p|PaN/ý00 LlPbLy̘1Q|h(x/KL̑+J! 28 Q`ь)Ҍ+LMՌ3pMR䓈d{Iш7u|7nH+ΗTlnPb #c;T:Q>ek(q@TYX:n F4KHئZCSg%ϴg)(<C= Jw$%&Qcl'&hLYQaɄCQфzΤWMlRT8Vxf~$62cR}i(EI{*mI(W$qCԴq L1źꂜ8N5O9Heh.YQ.|x.! 5S8zcZaZڥڨO3.4ڮڤ)[,)M +<U : i M[88"APćË́?;bh5bMnON ' P'Bݜmp95hC pڸ0bb Lf  h H)23aćj}/ҰbY(yt^`SR|0M ;zz_$_ RWsqҳ@I+.~,`؈9pDp a>q "qvi;pa4,&|ЂVPyU09 [a銿iؒ ?;BlZZ2>ո`ZZ5F1g((̔V=**ﴴt[ |-/<ωHfp6_b1oW8Lp `A ҖIBmyҲ䚕9Cyt.cݥX 01L}lXvyv4Z͔~M8gh݄RWYg@^Ip3V`oV*[RrEE V w*nWoD ``hΣWg7!HػJ\Pn q#q,16s(aэ2:pp;%Yɉapv7pЂ5Xƨ5g0'y ei75A0vvwWghW~uwy_o#p|ptOq׀w)]p@ g|/% ~3q/=x!D Je;p&Z3wnE< t escg.(fMpHऱdqL 39Ug[(͌< XsE,6^3I1c=V1ۃl)|-\q $h/߾A,x0a6X؊֒A_.g W cάy3c> O 9|Ē* $SKit|z9S`r 3xhc\&\]2[9q?kb=ڦ_LJ>A`Y0 DsRyR6iiJ*x+X%&tςӉk6XsV! i8 I| ]I,Vi >&!' .؉&?O)$>F2 `@QN`BY*%\X奕WI&`Am mIgl*4'p扊*(41_뽢(ڙr.FA>S*9 uj`27j`װtPjI`cNIv#Q* tHBJ笔.qS6B Qöy듦tD6 0[7pC;+Vo:{1,1hY$3]e?̗cpE۴GD+mfJR"ߛK/,i7d.>vjZ%!ҼftƕTSMLQsU "T]yE# U6fu 5݌GIT7>/3)I Nx?YEm ܤM;`'l6H ֶG{WwJ(hRJ)3$id ŸIhiAi2O&Ay)]xʉBvfq~&it2J+ߨV ]z/8(*8!*Lsd՝*$9 FPz8GՎw0AcaeDYOAx [r!JH0bponX#. '&&eXV@ >ZiЙI& C71L(L /eN<9z-M1r` [8?p f_Eǵ;k9ʻM 86`~Ho i0ʚ5 h*$7 q5?՘8&"EیE',8o&# 漣5k,Y7fuA2nc, S*h 9LHr^J (8eP/$6~aq=0'kdJŊY|/6$Lg\ 58iБTQ$Cϴ'$A CCӍ!.M"<0>Y䉥 {`l< _7UK <3Ł=fCQJ`9C GA1+p1NG{j ؐ`|d LPpؽ( 2%vge3ulҩY!-i9BӠ8CmϘaJ)EaIġD'6t+M])bwM)GF+Ml̝$ƛ5dH &8pb'~@b)*B "V=/rKFp^``y^ aa1rhYK;\DC@ %#`h#MTLEUD"T3 tIEx:X7ȘF#+!>#@E=C@*AMYB.$apGBDML6 HaN8PfuBHjfnF/tCINC76 ̊U!E)M[2aRQf}. čD@lH%g^_BFVC. xBpLdW:Z[Zrbϸ1@A\^ʧ2}hlkGea_ x0x0P>\&$$gJ.CaUq,h (v(DV+eC(aD0(IB|Llǀ6ĆpEٔ%Wxz^:#mRL;r/hP]SoѩelMfjN&&*R[at|D.@,`ZbljmqdD,>TICnlʪʲl\,R͕άByl"dm"m*2m:BmJRmZW-maYrmv=غV*SmFClhLffi- vȎeO`m6׺$_ *D:O Q+>rn9̪Blk%RB#BxeFUB'.>P>Pڑr)MtMAXj`LAXGka._luȭP+Sڮ`4$gmEv,}f,YwԖM n-ߒU vvJ)' Snrnrr@(Dp7֫3.K_rR^`7Zi)=oap!檁P@9ګQ&0';K7l&ńKHAqClo첄~,ƥf,/fnTcs+$` C5D0ipNd&`8_f 9ONHD @QH">8D AA = J)BFPq Eh3 t3q<! %8;C:C;ahH]q8f*ǜejS]ȱ*`$DBHÖ6ȔDthERwhpdtwlt+mI*&mرL/tN׈C)A֬ȏxMC' wG)ԈbM]vlBOS,f>-**Fn*I+&)%ĦR(mBeBp(fBH>\!2V[uHIuB03]Pަlb'c?^+Er)`M+[B\4j~5'1E85pr՜B\D!E@3OcAFahsptaLJDpC+VKiAF{ǽ 7؇ʟUA_N8BAqܪ-mN R3TE4cM6e288 -׈4lACw*h8pA0N?MYNttGP9Eb*zd*Ǣ&8-88 BLH($b39ejGWCFN30 v,65[5ad909D,*CxՌys@L޵r9D r-kcgpje.Whf~ #qwý1f -odjm_DĶ9a SsB7-ΠP9M8n6gs@Ed= >D|l@D~~-0Vm-1h0Y6j Hбg@G. 48P+M һ!~6lH?CaH*#Bl"6a=AV&0* P۵vO(5PvvtAԿBϳwނT/*|쀲'fan⃕C.)2[hpAHB=t ׫*H}AP.PsL+sDCCя}(yB$WAbw8G6SvfK6c{  CDcT ^>89"D2zm:6& v0,: ss6S F27M4@_o@DB`ޥcgĶ_Xf9:~E_PWLnw\$B]DM5̍&@z߫aesBBB| ŕC{ƤHŁD8 -] 9̄ZXȓ⢕S^Ҵ MRx "C:JSW4ĄfZ\B0jcu-Z1bd0a|a?̆DlCD5t_[eט#DWhX+UQe *]ʚ`m۷qֽwo߿>xq<`tq4ǜwtywc9涵O?`m;ᙣ]-mfXn[3wA)й!B(,D; 9-P L@0(H1;l[`tٯGxl$(<$Hre?&I$GoaK7l4 ,rr)[B21D,dR2q<f!W:s6M sMB"$ rҕH)T ,Osˆ"F!: MuMT!pHj"|:!bO<K&B֎z+ ̢հ /HLU(Yβ賉BÈ40jPWZ{-_XI{:m-8nPsǍuG=qBͻ3{f?6oc0ǖF i?,GR`E :`y@nVn- @ k9>&< 5$fʆ*Kqh,!(L|,S3\M4wCNx&B*T aY]Hԅѩ~=*HIK &jkSHtx upL,*XZP`u'X;"spB?\BYQ$ͫ=ˢeXKZqT,k/Tr0U&_` 5>ՙݏ3P 1ҹ Vٺ cA j`TEHaKr#,p6m0G:\6 | q6x1' (6wp@87HP b:H"Xc7؛\b~D!#/(CbэppCEY46jkAx/qu(Y >?KjғȩfMb|CLq$̖TVIj Α/H0u33,0 qa;ᛷK4"/'MDń2i%CEA5g,e)t BjykjpY\G&|h Aju/8jGAUbfSh.m&DqEh"M XIԃe9AB]^)!vZ q蟺5u: G;qg0 X`n7HA!N&p3LXf9$4mΉBm`jj' z{ND,4߹;QFT1_W-K&NS1YqOᎳ:U% E3c]H_d5`e,P^i]U6B,XIU򕱜e-o]ֲk-q?a͘)&R jo`҄U?XhV .LBihE/эv!/كS5Qi Ì:4.@|i  (/7Y;ەla6_杢 r(j+ڃ3kH2YF*l'Bn@6ѝnuvoyϛo}p p/ w!Ak`Fp1q+Gbhn$\Sq`ѩ 8 P᤼6T|ЅWgĜ[Kkڴ*݀ Y*G@ >{VoZ~Mr'<v2ͿՠƉkWx)iڈθi"ZM@ʃsGN9m4# {;Α Hg7Y@ #7Vqc;0t(` @w,>ZFtc Qyo' 77w#_ayFϟ@ďj@oZA8#raj(cc gܪ6b qMF@BPnFJ iRkc4 ~ hl7bfb&GfC`.mph I!OB蹐bD>"+K4pyp`D  dj pp hRPn8ZH@`N殍j?D/8XƦ* X6jvjfޔNf;dy*G@ q#dAlhɎ 0zC6{ʐ` gN bQ E,S\F#d A#7!t; !K @M'qo2ppJ N6P!.:A0Y)p.O7RN FlO8c~P>^hL7XSN,kC!K,;0,H"#"}#<.# +E# >Cj6z)ڡ1A%%} r'Nz) 6s6v@"4A.f+ /L˴A$0cc;R.<đ}s.R/+RS0aA"7eb8Knx27zAܳW6 IJoDqH$KyPa) A3B1'p7}hr+;7xH4<.m8ڱ*h77.#;Mr9fB13"rcZ#< HԊCop7@Eyp 0,nJHD~!>khey-}2$ صAA6I ̠p=Di~"GVsZH&e X膸AKBz9=ThPG6As4?/mXX dҘb0HaF?H#u961Aɉ$ٌóvO;N$ tZ[ jĆh[з66b TcbA~Þ~عcwc!7qڼr#y;@X!^ ]Vl \K֬r;xI =r6F&A9p6G |J@HsU r yTPʕa?GÕA?=<ęJ"ť#8  ,=Bʉ633GBD[2o&ށ?0k^^= ^Рn48pFygk ( 9Ѥ=\г֬=hOr׵%-7@CIL~O;8e0 S,%r|"crf.O;bA@OTEH8ᐃY1a"# L"? \m-7Omxwtd{~S9N2:Uh WyUFZA7X>&> gM٠jz8N&a&F-{cpeGsnx8GG^/Mno-ܟBIax,d.i3mdzu(c86(bO# ?{HDT Eя]^t$I-8XhAk!;g9bA[:\62eup2pn H2hLx6NBB8Q+֎\4XʑDC$oL"F:|$CHZCbDZ4N3@[;5đʣ %)#L̥.wKU00i12c&sЌ4IjZfA8 j 8IrL:v3. *ΊV?J; qzZy1XbQVSTptIYĹpT+A>i"[$-VFyJpԣ5J7ӣT(lAX?Dp1$΂'tr.# ss<#1M! 6gy1EZ ()UM΀:Xߡ!u?BfX/eq jUF>"Ѓp Fٔ-AP,4oIRjQP^9**KjrW(7JOj7qQM M[亪O&UO{"6PVR:7:nG.wEU~3}Mo"Nf8nBaTT9ZQp)7G&dÃOtqL4"aGtcU EB@s<x9! PmL % >1bx¡3e3ZFೡr"RS eik[DԶ 3U VY K>DIA|_愻-MrTfdw/Mtw9+V)t B^wnos|ǵtܪ(;ġ(2&:4\xwu1MtuA[!@ $J8 +Y2ǁm5o7) bxZt, .bC3  ǡg;`g7SR#+EHS3p61! 3(12B jcȉ \y/1㸊~׊IC1h2߸ x&#9.ķ}0㈐8A%2}q/VmV1 W-D]77,1cQf <&fvM4yړ 1ЌSUFYYYip gA.'q٠q` q P 0 WtQe`vK Po/`[° @ I[rhgAQ`?}#u}SfJxE("FS}:rUC>A@(0t!E %ϰt'4!S0]\R%[B)Rh.8Wx+E3C8~]y"*(Pnqߩi/Ŝ !CI ٟi2S ,Y"D}jWYS2!m&isyE%qƑo)J!q zXb0ӣ+!UĠ<іTV+ia 9ch;+3 Ƃ1> m\I9,)x.SIoMZ!xSXRcDg?砤'q/JsNsoG fEA4)[Y6{#U!i>.B瀑q+j”MY:Ahzlה1e!IEeCp+bA`Q q/r"IZQِr@'(Qr'b?纪L|I/QuP% + >%Zuh&%%Ċ4u=Y1Κ n2쩰ԪEٺ,5]భٱEʽ*UxgZʽaiǭ[`/Uq ib(ڱe!Kuם30lu  3vpjar6&,sU6.6 ;=ϰBu9:|Ãt(b2kkanhGInd1v+vknUդePpikBم &mh\ rQ&Bȋ l  vX[Kʱ)L|';嚥D;!/yX0UYuXtk$2Q,$:|U|u(*2LiWX{) i W1] Şqc++2w2!DC Pb zͭ>EdϮC+ucG,! 1SBNW+Bc ~(boTU,gY$ o-K9K@q%Ho41s 3 P2Bɇe4cСE/3fL]}(uLkY'tZem 2j$A]7%6$re{(hf7qEHcwկ'ɒϧ_߾TWJIf|ʉnb4#gJPߊ8X2. :|p.pt"iBRI: cQbqF^\Jl,G0Ǚ[ rrg1 $1tJC !LgڶNa25yN31 GȻv$I(ۑr º 2 ,T1j%HU#T!.L1MV[}U 2!5M"Bco؈|=ϼ]HZ( bgw\r'6SD)M(:`ćA2Hb$eI*@`z߾RE\+NLbyQ"`,P+5!k:I)fJM0k)"ML eLTH3(qD$ͅ MS! '奞`h^fT*7"9)(rn41d 1TQTT ӡprUʰiqγ!9/@oM6e;OۜDu=7!TF( 1魷 }/xsXy4%88|LB  K_~OB"NQph6A B'8*!ʈHᖨ+VzI:Tʎɘ4ĢjvB72q#Gu-iEN@jK&⏺'b !}הC]"j&Wr-DP@K%(0%j!WVժXiWs)jX{0Zz;SQd.ꗐc,X# 9sfTD'qc`1o5+!*u9j)P)=-'@MRM,(Bi/p$U Љ4BKFT=M]q=+={]1JפhK;]׫4#Mէ5lf(R Kd7MXo~PɊ2^TCjJ`4Xñ1"XVJ4<2Q84LV/_s%y#dî A`  5 a%D勜B~?x*@, iHx3TS[A5iۢ D,m6θ"wkysȭs\?{H=^*bHOaWe%7 %D=[ NӞbm1 &\(J˩İQOESvMD{BcM@ٍ̋Qj65^wiVbWAg%*lX4]iTȐqc. qbnqcC5r \ji'J fJEnG6~S`/^ \څA޲tUgƐ^κ9msr{>.$@QB$&qHFbDPUWB~3|cp8QI 9*>dTRK$|T0R] ]yt$>5> =91;ao#yPH͝*)cM*UP̜N mu׈o8?ᒧ:^.J B[%nQ)9~p:XU/[?"8">7'M`</ FQb/gz犁 @ C1+X i.@:@@@ A0@|  _;h= 2@ $AAAA B1qa@U@wAJ/!B)B*B+B,B-B.B/B0 C1C2,C3 !Xp Z?ˢFK `DM > FPCR9:9c#+sPa@=kc P3; ><Sq ʛbLa|غ[ B 1q  ؙ0$ɻ@;)zG|ć)؅]y{K <C1=)A+L x &Hȗ𓅈|E D˜iD ЄD6ą3ĔI) MD Ed ,EL,J8ЋY ` SK b@qxIz`mO:TO p0JKv`K.q`8ʄ{ QˆFGzGˤGٝ$B=;&+eOrH'E$JQl ?:NxI(|KM,Kk͡N< 挝NHʋ|MuTZ3( &@C*0+(P€0puBA1)0*hL[K 0С||L,...4pEY ڥ[q<@Լ&y 1p | k̟Ք=Nq%P p|[4( $ &cN4 7R|˭„.K ؆77;*e3*S8r̆DS:e,5ɈS4eN=ӢS!37pSLT~NRs bIUޡ5O|<5`L;C{ HƟBЄh `t!t)Ȕ0'Ɇ^`ŨLJuUWP.@mIˋc7i1pa,&.W!!U !؄' P؊X X !pHeΡye2X|M&1͆2Sɑ-H%HTTA"?ES|(ڑ$2El`ڨI!S Z@hRA|PZDZ|˗{+qhٗ]RǨ9YɊ+}Յ0J2\5!GB!vyCĭ'yW󗭸ed!)𻦻alw%T+!iLJ2T)`ׄXu+peQpWȥ0J+X2@ 2 /VH3XXXo؜›Ȅ=,ehԥلٜE( EPI`m(" &9"ap|aQՁ " z a  ` >afN+:Ʉ9eT%/[)^ 巿8ӄܞXa2OI*GBa:cVybONZKf50yADR EB\ˬqT }N(tp a[UuM^.9sh] ͆]\_V^Q q h]5ZV טXM M--On'FM܄juI)PNMPSH{cN΄hfըytNL+jYXz=HwvUOARHa&FkޜbSrwE\|0h:RBhF3*\" Aa+V\D~jMFn隘䅰vMF]RWz׹ 1^X^岮 ,.`%c6Ϛ[fႺR,$Nxh#-lVFP gzr6}~gnwVC]poچf~͞ [l셮;QŽ\Mh߶ j78CARvTg8`U Pc;6x;ʬ| d%snJ*l$P ð ǫE K$K^@}TdL*@16/1H_p]d>_S(fQ@G)2>n55 XmVla@plΆmѮE Fv5al{gfXU)66Ex brX%m|P,m;TLĦU^ȶVsq~S υ5VsO|)Xbnq?LJ>_+̄poF_dzp T_SصuN |ۆ-odKK/̵L *"98XVF1HSlp&^ ٚeq`u$hvsH UXqصPWZNԐ:u[Ċ7A54TsӑL,o0x Z1Ƿhml,Z|mtN2Ixfbb N6hӕg$hYCM;8S)(ug/X .ljOrUł. v/. |rMQi=ؐsep"g0B)qz B!|'곕kzH>Ө .T|(,N4T>u&RڤIg|xD<)P~%GCmfD *$ÇraR(n"a:t Ǝ"G,i$ʔ*Wl%̘2gҬi&Μ:w'РB-jNkč!iJIj\*bVEr*=jÆ&Ϟ6rҭk.޼z/ZHPY8$Jvq'١lGv0`a.m4ԪWn5l\f#8*[cܖk /n8ʗ3o9ҧSn:s;Ǔ/o<׳o~<r8@pH wT 87Q\UNV`S"->c|He94Y]PTh.W1ᓇXOđA"I%HRg*xi9 3MM7QS S73%]tx.|tJeӍL,[ =o#%.bm%Bv-}ҍ9&)NuĖ5c $KEe'8D!<'Ό :q?J$d9LKgn Iv$NBSp3(uN636̍CCN7qaėAZ"aM9?4mӣv$iDH׈|L_%I4>tsS8|-57#H%5n"ֵϺ">Ύu枋s;,z{*>7o"xnU;MӲJC7>όI gE15D9@RK^sN)OuOUDgq.q챻 nnJ/'& ^]2%9IT ~䃺̪;"p`'_#4CfAp4$7ꃏ@R;RxK*Uq)6$ba s3Y[(QC#W&>G^XÍC w#*)dAU@x1tcJ&9kU"W| a :l86*M5,IȲ,B=`R,ai<@ VRuz#?*=C[, ݤ*5 AJ5)'abV:K.mp3Mu#|aF͊JRC)<]&a+1 roy$T:H HtTd!BD6g&les]Yt5EMbS~ 1$ f?,|GKq$)GE'y@LT1e f\`:*s`mVP%a09L>vFSp.H4)O9Zq45 n0BR^e@ܸJ+Б,"_G[cUVpc+znB - r_ X}mDD]>HE%O`m;LFC*W <-D3VVKon'23;otV>0I+ĚJ0dtdsߛC~ęҖL`k3Khu$~R 9B>Q.;cICLHA|c))$ex\z0qXY)Yც]=UV E8;ߍJA)i-8:(_E&*!9x:SLu!72PϱHj%OiXCY&&Ϋ&UفffP0A=f1w$GⰷxԠV!7Nw:*SyJ57v lpm%*Bg7w.>BB,Ů%M} Jbq#b f:D{ fuKY!x ۪#=My4J7b ƣ%S..snc;$^fQT&֔fYŲq[_N|DO9u aϐg­{>[hphX ^ÞCjz9sl9ZqZƠMe]')q\%K U~${L}fv)Β!B玬n#h|@:k9Lh k a*s~ʵSk%V_PqպTzʵn ^cJ V݆h\*YɴS!D!"li;$ X7+gF齩;` !O"#xWE8xT 7aJߍ9`Q~a QD/|]I, Cl +uS܇l E qBA<8 8u jXCܓxN~Uh4Q]FhRh8$RPߙ04C}E;iYPOOCP8 ˶9^6G=C~`lH陞7k[Hā;"T3,Ch{CS5J ɓPPՐJ 7dC'CπãxQQ|llSGT U -Rd@i Y a _q8͗`_( 7|8. мy@|sCrbN74T tRgf]*gq'8w!fCx^udIr9D7peXW-(W ermT9 \g+H-(wmU` 1LE@i kbz,rMUdC3eCfS :DuT6i6tT٩]vv fDJYxūuKHJ& ,ug8Ԙ>AiP]DJ1P)%(-fj$ >0Q 0tj)v8pK @ 8SI^!Bf$u ɞ*D S^ S B]Ae]115X]X T'E&1m\HT7 DT'JM H#1'w_8r6'bMc2rCXrE"x1eD.DQrX.D&en)'2. 12G`@dVb,l/{E%KH383993:.;3;#s:dz<3=׳=3>>3??3@tyP*0Y@q@C;)1&6D*uNBot'O%8PhHߙD*f8 (1+DnGjfhVJXHovʉP -JH g + x J/K IfopLD4\HJ<TGDDEΎK\48RG/saୠ5\GE5J7b\|C qC>M;Di64$l@N˪D90MYvJldu*eH|,pmx5[G4\Sq^?^D_wTv ``rFgawBTQ5ʢ-FAl]9>DDg8yA%w+CTU]dC&4߀~D`#my`]@!ikeN :<&7':|7vE4@F!|~3zd#>nI4debB=6PIٸH<.\~T¥٠ސqofjqKVAlZ%+XMyZuώS;I:IāmѬh;wB\0XXu8 uẅ́ĻFDAFげ$8ATHW0>2mm#֍WK g|hM [azG|.TEB<8e6ܷZrWб84:!_<vLIr+:wDApY3_nUL rZATO t>+ eJ+YtfL 7*tӚsTsHpIyiRKSVhpy*N)VA}V PɊK5T|VF4jiіMՕ,F/h\KeÆOܦ>"n!J;T76}ffͲGٲΞ]6nۻw 1om8S˙7wztөW~r eo)I4>?y9B[ c;p((Ҍa"#!Ϡ *0fA3sP!)O%]tcLtsR rNbO,H#=z(tCTJ!D)e%EcH!<9i*;V` +K2F2VPMZK.2MDç 8 Ç[!3|({ &0A3 *VB4,ȵzhMDߌ.UyMUcb\uݕ^}Xx3W=Ja避t"T$L2Z-1`ph{"@B }AWwhAOE"J|FٛB2mǍV!]D=?1]ٓő'i\'cp2Ȑ}-#1h*1*]4,a(9)i:˙Kh|p^暱71̇.L֜ "p Lf+ PӜkW{Ku8Wk8-5ߜs%D9%^ƠmC`sFo=NVrG[ɚqlK\nfwB*tn&PP0wz3 DG(`/ Da&yݡtaȆ3L@9>4mG 99,5rmBe3HH5a"bLa C+S3B1Ue6Eb L¨Q "lgsß (E-3iK8E >$F3!iT٨qsI*PNyG=cF|D#Y,_Ea=n$F; ?g:.v+%`'PR-A78qB]d$Nsk8DQLÇjy˖+I%)Al-PDf`;$]XC1T1:(-1J"RI .i"G!y`I|pQbb0/EY2eIAmeF2l`p>ښ/tdj wFլjҘ7FcoTE;IURT>[H*U^%cEnXkRZ5ViUZڜ9c"k\7J [$Cױѯ` [XZ2X>d)[Y^f9Y~hI[ZӞUjYZ׾li[[kDIDA$"MR{K")sܘ,̆.6 |op CmG#MrRP.';g(1nk76D=9q" ugk.iT3xK9(Hy(IlF̔W#]lt`+RƖ9 M\AJa]#>]`O6܇'" ɛ\É/sPP NS!qE.2QXX#FɁvnINRR֡$nɌ rT7S@5E-RVL3[+bw",z]xjI#'1=>X_aXj0liu*`,.D 2m\/6%S|$OBXBP}C*•7A6გLHNqhȲN t"[(F7 V\6&>A_QR$t|3D)Wyʻucȉ)\Z99h< و] N4a.EA@qR^_%Fί>ŀi? -VY3D%LUuK1RdQ6znds /y:f`O]mjcھ;oڴ !ؐ!j6BDhIH e𱩤`h56X'{O X%q#Uz{oArCrN촋."X‘@Lu ).#F*‘&"0-)똮.<>b0#@]Mb2q/iS0ײ0109heZF-ϡl0Q D4ծm@9"j!'^ d@%.B!JPA9cf)4"."$͚AP* &qsX:4-( <-5"BR!r(9AIGlʊF"R)-4A#Gb#jA'"=St"tF$s$SP&C'cfF?@QnF_.2Bu"$a,:YbC!jTC94J`G!JG2%4Q5ks?_-|j6i5? i)8)A*`^B}D@~9WIH bP=$P "|κ CPOA!b%@ F=ᔏ0op-2 #JQ?QVtZ@3+DVLWBA 4Yۏ,3NNADBUG!UAn$0q#v95\45Af=$\u\ 5:KuI3t ^"fqJU"qHW6Q}aO|>ʌ|@>pP90xrZb# a&w kaPvXO%H&Ochh LbBR?!p/dgOX@06lՄL Hm hTYsf,T[o]WvkGtp^]#HP%qo7Boo[&p(DQ(B%QuC0ax]/N%`vl;*!%-&t`4d* ZW 'L! n9t!A {)z˕V}+(~R`S!WU ?NCº)A#ll^A/oX?Va1 7x v ǻ(D8n"8$2ʚ b OSYWK7" ~GyȔYٖosYw{ٗY٘YٙYٚYٛYǙٜYיٝY癞ٞYٟZ ڠZڡ#Z'+ڢ/3Z7;ڣ?CZGKڤOSZW[ڥ_cZgkڦosZw{ڧZڨZکZڪZګaa:dWIcǪJ뺢NT؜D!||xT'?B!bAA@!`KZ%ں![BWR~!,1s?W;w<}R oLb%Zc(f~{_['fZVv::cI.B ̸dGi!{d I~$*w%HYB]ǵa{|G`'{#MDbRd{;%\P'.ں(tFgh@02I:!FDBئLhDi#n!24 a'Jӡ~< ]". < @t{ʇba%V' R[b((/ۜ; ·ID_O"\6FvMH bĵ\5JN3(!Bˇ[['%a ^bDbtcMDI&D<}C"Aȯ4M zn"Go!f(o(\7?I%I|!_% E yb<o$c!B'>b'${zǾO[!=}fgW'G8pܾ;j5s TC.n ^ȑ$K<2ʕ,[| 3̙4kڼ3Ν<{ 4СD=4Ҕ1b4Ӂڽ;'ɦOf[Ել QD2JxWewꈏA]D88]F/;q⹌'Hw“"D aOwuNmәz2E%\4#.=<̛;=ԫ[Ԝ'.8OD[Eۻ?ۿ&Xi.waO䕷T݈Ok|#qMHa^ana#"7#|a*b.c2Hc6ވc:c>dBIdFdJ.dN> eRNTGlזG(ad[& E&>(s+faZn/`CyWRFAaDۤ]i.Z\S'qjVuJ}Τ4 GV]S3P7Fk6uZӨk:[bEWն́mЦeGcjFUA&>WeHeno_|Aašca}UvzaD{Ƃ G !ҼXdAząfII\̅#crVXqv :/J3Ao$aIp:)̜G0չfJ/g3V@ YS5Jtv{r"Y㶦rϭa[qt,K,voԷI֔3NCR8퓭p8$Aӈ5PM6hy:tyKNA-;IYjOz6i 9w nIjhy6c(5Gm:8oz6y(|nSDI( @?7 >pCU:~ą.ާd|30Fl+I΀ލ.&J=NpJ&=.MN@90LGH@f\:∆5A&p_屏O0' ըTjyϡE}rrSkGXE%Ij [ +lwC0 4@a#8y^ HS/p:WHsҚvcED=yb+p|8HA6$h)8Z~"kZ݂"Ű=%86V #Ń/  GF7qt3 2۶탂W+)F8fgZ@(w<%0QB,=!S ;U~;GD8?ߕ3N4q*DRr- =5?Zk'9mxuFsju+̆r/46'X&9lC'.'wFQXWEЅAhxuhyW*Tp 7je$@[z|DkGeZ-b :qQl[9nԦxƕۗ\gB׷פJZ}"~d LP >C_Qt2ބpS_\ 8@quCOU+)Axqa p! >s,*"O|WQ#tJ, 5 O{%-HH(ɦl]b,WF օ4rJT.r4*qM}}wB n}۷Y0_NXgTq^GS`kшqZZŁN!P0@>AqPo Fs PKVpx>$fbtc+<=Jk cDl⮩21?v4p(q5&UD:(FdfsB)J(۹Pu.xw,*[R[UiU)/D#*;q'.<"zx$%*uI2C1_JAT+ѓ,&q7)R"l*4? YCLītI)R0$͉SK؛Uf5X8 19Lel!$Bj7E\f BerqynLȊzLȅlȇȉȋȍȏ ɑ,ɓLɕlɗə\U1t*0ɣLʥlʧ<!$A8z ˱,˳ K˹˻6*+p  lnj%p3ã,L9   l,@̜Ual:9jܰ Mm#R/\| -7;glances-2.11.1/docs/_static/screenshot-web.png000066400000000000000000010065371315472316100212430ustar00rootroot00000000000000PNG  IHDR pHYs  tIME g IDATxw|U5ǓuGnY-=ZFY28آ AT7" C@URM)ݻRF}{IrI6l@fx4Yxݍl:€kǜÆyy (YLCvJ  L*dѹʘE BP( By0P F;ˉ>cu$9wwv#-q&EH '`EQ "!ՂBP( BPy݃Cde(@ U@yݮNRu rqIJ$e,)zs`/&d\Q rD$@ՂBP( By~PbOH &0Bfg_XUbJ-1c.!P0\u<>ZBWeu9f&c!W,@H Vu BP( @~f’"j[Vky:XUm6^Eaꂊ|o$qOxC|hɲ =*8Qeaxf+&V.[W "Z%,w/k5-t%2 kTD{*s̨lGGO?I&/_6L T>c0t۪]uk r#===ܜxlVd&#&{遭[W$o>{S2#hN?}zӦM#""ѫWQFڵSN$U鯽3 38 _~;wnժU-Zjձcc˽BPPPog{iӦ(h6mɓ$JYcһ^ `^mWmZ]\SʅlWoժo0 ]Zr=q[=[w keХaURNj[|m->k@ѦWZ&{\B@cY٬qBU-U @ ޢQ˧*cy jO:xK/6= p|bDfwρQɱOo4/jrǥQU;O=0ѵ1).=jI;;ӻ^(8zeJcxkN6JrlզǴw޽#6[Bp{/BEk#S( [wRC#\8}Fҹkʦn=óϟpmfvxwc'*kctdt>>ɢ_da.L.F(cU ݶU)lan킽`}{NdK~jf=p|%kJ|ia.tRau[NF*D@vn+wvޛ_}{Ӻ5BK.hƩ?ؠE&K8Za(?ѫ*ѫ{xۖ@B&xї WJOMVBL?V  ۻ_`&TI !Z fyرy> aXZ،+g]׸GWܪ]7 rϟ)SJUV$''gffJqg5ZnjcbbC" clZϟȑ[ny{{,˲^/(((ͭ0D!qT!RJl=|1{}7_)_AaAV K{G_b2[ul8gS:o_|CtFN $M[/ꩿxsq:e3]o3z9r% Si2buҡ3VǫtԸ[ӳңًCH1l#G7G[u})GX{<Pk~yi^DkC\b <iŠJh[c}cr\5<__`#^Kaaӝm;ٽм즾o[nk;82ע/Jc5]\\MfVek"klEust&ܜx3D"",٩Z#+^7]بeNhV̹_ vl -]Kn:hX `e'[ml",ۆٷ~Wa#kx}P(Ok|Xlcѵoqk%޾pp^S'Wp$P_[+n>m V:ˍ[ԩN1}2Xp!GPf$f{;6tׂ^c]_ {^p: 3mY=\JAߨgM:eCFw9!U2/scW}۴׮)pЪ"4ױKMUiP(h,JnN^ZU(ڕ?;X8lKjND@omnÇ;wnҤIseBxر̜9s߾}`jZ,T݃ڴ-:52x0b~Nj5vĠB{pkJ9Z!/_Rʹsz5rHOOςcǎmܸ144… 9SU ôj*111::k׮$8p‡3oW8ݥ-9}tp0ͧ&4 ם0^^;dK>wlgv{}$cI9Pf&EV!E>}bz=x0׼̄; N~ yi)1^rk&jsV B^vL>}.hS_Q"ɧm˖iSU'T"&Xmg 5ˣ2B@d}kQLhte|x-ƻ,I1qW&Zʊj(v֖6o̐Ģ/Yd8?RzlC6;8Q1dKQW&Zxa2ӧo~kPW]qh8bX2C>7io!o o}Ni 7ӓs=ڼ 6Ug̵o10x˵OsЌ"ۻ}sј[r%@w]ڰB$IXQUBgΜ٭[9s`ZEQ4i~g͘U_W[.5c>v{o|qI'0?5Qh~Zj*foy0`eO>?5l6={6;;{ׯtRiBk֬RU/kX=Z:ewѣGEovl2OUU91iZMTKU5_l+&~>absN`+ Z q !RbΪVKs2JBE@ & עv[. fy Zym}], #/wYa8$j, W4zg_l=47 zu$G:AHY+Z#@ 6V< X 6D;uBH sEК]h:a/{†EM ԗ YtzW*2y39\[{'.V9+`)H?%0@/`AQX=|`L1Yh.KuInRFxUA 7r߷DG NV`1h'#VV(`Ih6AֱEDޤBvQvL -}G%6ZVUͪo&L1>bΖmn&Ѥ(fafF_b+yb͗YC$~^NP }AN8}qrՐ @,(C}>ZoƁ`\()jq j4 C4MƦ 1>xv,9۫>6`Rp@B`٬چ&TpvxT MAbb<;/dI빚*a'f,j󹜆\XiEdZRmؗ?zwnrF 2PJ}4wjƁXrד5|0{)=]39mzEz"ٓ{uǗmm)KF6sʏ<|:W mE>زaڲ_V`_qAы' `:~;]} @ԙ>3H>mur{;z Xn͕j~0]! ln Gq b)/aՎշ{C~yZ֣[Nnhz w;vq9S2◭?e39)3w1{)ڄ1/ FUՃQ694UWjFEUU \XuP#(JT6[y!믿0`K!K,y>nԽ_w/X%W6OOx5amֶmO>dѳg>| A1:NN8!Bxx88""VZ!!!v꓁ ,Y5[+"d]dtTT2;coNoRGHef-HOI-.nߜq>13--τ 0qٙ,ZMwySv={s4ԴSs潻2]_q<=l1;mzwީgP鋙YbYHK!T i)@ɘn)SAъa zk왗^kQ oVkآiﻷ#Ŧ o?Ō%LR@X!~%FV!?b~MF yws卷sa%hݚraFת.u!B,( kH O`"QyJP:J!"FAPE* m&ZUdߒ+%7c8ڛGtIQmmQ?nF~gYŧX* @giYrr[C,kU8)lOEP(?K\uAVUDI˷7h\Ya|Դ ,C+ZB"ˀaXw:}!'w}֬Ynnn-HVN??gWŠBe|&/>eub}ZŁ1^o6v˗/WdWRW5Ν;G)%F122l6?5\yS♟oL C$ BM~K4 VkP(0f]:mVl2'pHRP!,٬BBk5eaƌݺu;y{!#3zoSUiӦ{VEl@~@}_,PXn )*۽5x=%->)Uł BP( BP(g,PK~E111f=OBEy_Ֆ>5=l6 BP( A!tR$Ih4o6*Bʕ+M4B \]]7YBz…F-Bڍk̓6BP( oc|'NM:R VN[*8AEĻ(J%Fx() ??R( BPBTUL&*P)J ԧ+g.[A TQ) BP(@UEBOѭL@٧J!U5B1!(İ Ô|NB՝BP( T`XGʲq\Ν5PTi4seW38Ny$REK״q'pO+AUe0J| K32FS`̀B6QyD@0 ]<{;$Ydѭk,Kg^.֍Wo#T,^#dYN}{֭7nׯ=<<* x Y@0?'P!СW>mٶ=fn/v;y`0^vww_bk֬`B$h4,lI VV6&j&pgXm2 EY,"ӈeİ ,4`BP(,FFF>RB7o4*0*\~~(!N*'إmh|`s˖<}+DQJuo:rC밖c|ncI*{fA!EOݳ'Njaf!tA,Dѹ㳳.\ȲP:n(V;aiMv.pY1cELi,t_[Νyfۉ~> e9;_2B8{ӹՓ>G9 ѥs)$iQQQ˨r!WvI qq:3 77r5dX%ppp@ I=K!buB!tl􍄄mT\»vwб'ڵi1`eg=ڍ 899]v=?!qf*U4ͽL޵,3*;4{E?8o7o8xmʐEVa3Rϟ}y䆁q4az:NEB \N) .A߉9{wLE!HڷLM&oԶS]/=Pǎ%䊐wl.Kr=' :whX?BP(BVz#M#jEw77L&Mp/͔|l65 Eb\g8-ϱb\bNv={zϿj5..5:ZfYj88载BȚ^6ѱ"#IҴw&+7痋mټ~E5f֬Y3Lqq>^a^..yBC\ `TU533%9YV!,˪BS_0i+Yv-scFVPX8cK^Ɗ89qʻq,EkK9ggn/k >+jԨ޿Kmn2wZӋ=&9IJJMMU!sƍ&" ,j?N?NZu6[Æ}PsH,;7A1c ^ 1@ ф&_2eG:־A ݻIz[5_u=0dF6n8zA&Wn ZRVo]iTŀF~].vvU BPBH1.}Ch2]Ԡ^=??_f,͝EIIKmN}`PUn^Se#LV탏k\z iѬY\!BBH`cl6ۉC*Fs|16̝;v mڴs^=nYm[.I9nYW]g8YgnΝTEQEՖ6PlJ?{?t!&7}SV[ӊ/C(џ,lVuO+Z78yr'Zu|6ko]Jo"~&WnBrss_С Ukɲ\v>CGYo/N5 =z w%˲l< @yOUӧO{xxkN{>ܹsرYfe TA/^lZ7mڴxbԪUyUZ|} MVkil*!Q#ϚoeY/1ݲ߅&iNޞpB\]]2 SEBB(-==?Z$tZф $ >M j&Ϙ 1D}s٠G Cں-Pۋ/2C+fo-#[ň*&X uz7UҰWq[ < 6tUzwGFe -2Pb\8Kα6ޮp#6;~>WLP( AVo7 JS~>FR| Sxz4mbW$I^^^XU!<ە-x="j)Ȋޛ13)9XH+Ҫes>~PITmGı' N(:mE%===w޻)) ׯݳGc/ɲ,KZCH>dpy騳..cz(- Ų,!d…)))֭kӦ̈́ .\R !SL`ܦL&k&|7˗.1}uo՚nnnÇ .!*pȠ~Z_B ݺTL7_[UUw'M,rODV+@wr 7oBn3Tg$I lٲb A333˽(?ѣ...W޴ig}֡CrM7V...gxާ BD[2 rU#]a-[ &=QϿC *Y@e% -Wl԰All(n $, 9:,c!cg9D[nrrrfͶm3vB~?>)4L&s~AA^~ުV\1n;Qgh41F Znf<_NpNۿ-bG6i\u\rZ&M5q/_h74ٟm[^c1;ޜ1[Lʛ0S*UBBBܹ#_```\\\E\} lذaʕoG:u84dݺu wqqw12[C.KW]0wJ'пߖm۷+/izCL& $M&$$.q59ȐѲ 8e0<8eA qUjb "4dd8\b,VZg4f%mu(GĪ`hԩ.LVY`7BZ&2Pڼ%^UX45tƄLj.ғDvڪW+OTR( B陛PZ۷oBJT6`(lbT !!.6I)/% -7Bb(,˂ uS;J^^74mxq_|cf!oتe}"Ir¢[!òz=)W/8p𐗗g̀?6o>zu$%ԫiSːv:֭[SN7n\z,YrqE~ƍ-[joݷs-[/^ON4烙:9:ʲբoOFFrjjW8Z^+YjM7:~d]_ܹ{OQ8'owi֐TZk, 99 LmӦ͡CԩӳgOV[PPo+5kjԨf͚}nڴSNu-W ,sO'*2||e T8~ִ~e?ct*!A<`7ʊX53+k!VP{T(LM˗C4;w^cY\rL;Y=}UE{ lZ{,|h3__gضşȕNYTڵ*޽[xhN^߾)-j\W;o~=ֆ }_x6{hOksrFC1$IUYdXe͟/Ba=[_U{v̹xִV#48tgX`J ́#WQ( BUYܹhB4֍ke٤qcOD>SdlvU--9 Ѷ2ڳBعSa-+W/4_4Cm֡M\zkZ "TU%ev)iEΝT|/ 7 uvro !trLN^c;Ǐͱ&;::;q7xyz^~/p…\8yZ@)Wگ9yxF3h}^ڸnMC]]]櫊ƿVrJct:?JU՞Ǿ1VU!ddk-V"Wx`'?,I|}kvN_s ..^3UK3,,ĉ7o޵kc^^o߾q|ᇮK,2dȻᄏe˖ڵkk׮"Equ%(*/!dQ͵aؐ2ϙ~Bb)$$$ڛeϜ=:5E E)-=ϷF6F0P9u(.\;kX,FЧ2r]/@ByDRlֶ]OXN9|#7hۭ ջo+ c}'u՛h[{-突;"XM 5>@6hV0&*ڸ:"H4޸ɹxD2L3 N޵.DP( Œ`aWW@^tw7DeW77~7F1+;瑧3 ͲlfdY=pNPPUN s/}&UUB])BiWgYOko|Nh4]:u|ܝ*!+W^˯ h5׬vqv.[&:uj˖-ifZ o+<TVn^_}jq2a~ǟWr, PeqoUG_r:*1Fquvt޽܇„{18)YSKh߾}-[Z,ggZjV&h4̿k7o4hѣ[l1j+.u$۷ԩSZ{e ji!PA}u !Owf BP(ʳxsA@TU5LY DžaQ*qa*߁ _|bcnRYq\*<!< DŸއPU (LRPp ݝPe * W8B(J\$&&UzGW&F=pE쥊],+Pqi6zʺ0ߘL&I}o'ZbYBz\ܮ޼QaHmU F-6k=ܕ90@(f,J$ Db.e[X e:'#л^/Nj ^OL]Bڼ0uzf6Bg$x@ IDATF<ɒ\vl6g_}(w7 2'D l2Px1Õ$BIg->K[CA[@9kz-ƃKub`/Soe5+q;k$h|k5%NXCzQj@ ww&68?d`j)j:8jF ;*[nSU0̙3g[%@&;;nfOM!uUhSm9 Jm[G`7j8lD#X!++KEY޻ɓڵ ڕjT )P9tZwlf|BIwt1kCXsr2>e =}d9O=oמV|հNW@W B`1 <\,dKԲOXlQ71@( c !rc9;ZTO``#WAvI$0۝C8'-[A/q)j)Ϫ=y`s׬q@Z(ؖS y:V\ݟcWG\]!!9*zďXZlS1C}RƓwFSXX8r0l7IDGB89_Z |,,,%4а&pN{w# CHr<<\Q.?R !W* MpQ/D`! Œ'*@;y9!@$S~Qf!`ŖE\YA`NvwVczYBT-ٲc^{{rjr{/@ ҫ * HQD * "E@EDAz{9Ir{f' %~xANʞfZkf)2[,7e%%?(={u떷 tl_֢<et?L4 (ȷqA7NӤ8W\>crJvo[-fgx`UVQn.3,zxhkz;$ҰBX%lh,INB[ :~Νd噧B#RZ\R9QE Ng!@@\RSFOǓSHQ@ Vj}j)c_8 +T|*@o=c ҆qif'q p/1*).KTyys@%[y9c)\3 r1@WaQL¼入1К=u G%%%l6P~~޽{Be/,)u `1!d\BrE҂>'CXK mQH(K~~>k zr@0ǏKzrI1.}rz k| "48Gm ^|ykז,Y2f̘o\j qWp^z.j AFU>z؉PXTԪE BbT?AEA`2@*+,UA~&wM[ bC 󵾾"oP@m Z#V"&9;S3Fls_3x(Wo>w|ۭ_V@.[0edfڻ͢io,ucFW'rߙNJ|׾~ŕ+ .ɅU;\8q쟓'L?\sڴRxy'G>R6'8ye O?U̱SN^/-;'뷵l) 5o*rDmldau-Z8p`AIAU3?95/֮;CkxK__$OBxB[%&tLj=k3&һ9;ݻSΧ]?Ѥ?Q,%/ZuЈ^AM"ӗ@t$#jR{XlJuԐ +++B?>GXemCWۢϿ؊f1f,o|)Eq,wlfQlN~9ew'P+ d&tjЁBxs˥*U+̲U.h-L8_PX_䢍e_XBAI=/09s'4iޖSW=KRp[~WO;t`]:~9ql?/ecpևY\yOWCw,{}Bu#+?\Pw֭[7nĈ/Y|y i} c[R1@Lz1S>*#{,B;!g];vo^}/} Y42ӖI͹q7V}C3s>/ťfGCJ0'\ٿFs_웟N?.v(*Mj)mBg}33Џ=gT~]ԥ'od&Z. !g7=y3-ҙCiNŚ9G{ sʩU^OO8y#~h`iΧm[kU"L! 's^p270 P|++wO˼'/Nٿ~ [ ~6_l5U\;}2;׽}rIIQ~Ar-ƶlْdɒШ Tze5'’ u"Q1A3$+$oO;30E ~!H 6>rqi09kܿ1PQYYPXgs?Q_!٧{ՙ mEq돛KJݎbk#GMwcׯ_q{yyՔ ytc}gz,ɴ?#h-?z=7=i~Tt0VTVxq2=`pM:ZҝG=ƷVN.7i섅z$RyuFuzn꺲}+ [?qG؉gΞB55[TT5{j='V;.gNr^8;;.r(KJ+&6B(KMϕ.".cΌ EB9Lj f ~ +F\-tܮ4Q`486GbmO :ͫVѷ>OLX}գy%ڄHqV822""3J.whBOQṈb{RU~qMzCƒa\VVo:DOAYEu`ʇ6أ_+cQ?0߇UdP@xLIĊ3Ssʜ dS߄`mAڭJ7,.Wr)jօ rglS1=y= FxwԊ\EiمT6bFkjZ0"|dX-o-*,. m8ۭ+; z@ޝt0gxmYIVZnC!f+(rӛ"vՊo~ rdPrRoXUVZo+(W&q>.8&ڃWofYޡ>ǟF}QųY$gPJkFR^\DkW b9٥V$Dݼ|K1aNO+u(SfZȹ 6JʊKޯI\hΊ3J%;SClٹV0=vJ={|AA^OOO+1OUh%qAB隱=se7eM/dlMKrP!,6OG2ndVrYqVjn9)v00Xӳv@o_\HPPFMh߶ܑ>[=yf`PYQ0a1sNzņ5^M^mT}E(L͵Hޡ1:wJS._E(+͚y./1"dLuFCl Z 2?{'?*[ q;k}#"1F]0嘋ei'<005|^5E\UNYV{4'V? wؑ{q_G1 w/B{t">[.iBضt dJ]"}vgN~a4i(˗/:? !CD˞[8]YRT7&q^)2q(; 3PɖU)Q&Q>4F\Lg)+5|â¼ٹ.J x@n$j˔ti|ZU۽FwRLȕ~V"cb=5Te9K9BV|,zF@\y{ Ϋs›&8955/267̥oVĘvE׀/ub鳝K u~a^rIZhW,EPo/m۷x)A7o]{ ~N#$[t|O' S>>>iI+cGB\; H܌JG@bl׹[soy_GQErJqL8S2-MQ [Gv[ܸy34$db ow87{O'J<}(KCȿ]B.It]Y߇_L?=?pO 12 ʑ+!6?*7^I:AOj[,(*.# %.VTq9pMLLqӁzA3`㚺>zovk4wDkEA+ ҔI׹<ˏ}/p_/_aՉ.yD!x9ߤxgsTZpRz$w픖jׁ0p=*[e# EGF`YWv,e;+@s~ /N#Wu9sZ-ڰr?\`w/ya0s>ff-&Kb߃|wű`]>r$vג??Bh}ڜTؾ`s:VrVċY |ƞokVF%=04&_rsЕMuS)O }lSo~jxKRbJɬw?)՚[NҢmɔ5ނ7?EXyk~v5OtUZKmO0״Z=q=9Gߺbx_mk+9N1$ +q Ҳ'y_7q/{UnS< j=2J'6ԷvĜKË~Ek8:;+ܷπА;n߱-230AC6~l_Qܡ)ۖLZ}RuZ PٵW6gn5c@Oo|%w>Ɓ3b$vgưr*YA)Vw>=emTs8i铯UWq Am?$}RāE~}6<ͦe¼>qS|~a9mJϦܼJD^oۿ$! \+3__2բ@VKt)ݽZ+m!隙=pb}$0 uaXo Z,]#a|tԘ_/W7-3i;vx'GM)% 0pĉ p85eg ylO\?ٮ,|H@H0X,Z4˥qYO~߳Mh`M|Q^_uHjKw_/;oƸu6,O?? ?_S?0d5ӅWҜtG˂)R@T./\2H߿qJ̔{ݹm۷;@nהRƘ90NX47K m֠`V/؉3g,7';$3^w$c67Fsur)?/uξTKec<]O=3ax'>Oh֤5L)3C3s2[';⒨ڝ>uc_3zyeNYsxz3Mapj7ߥQo ؕog/-G_ɜ =vf0*lSݚ&$0؉#n*+/{/SuzyҌ (\_qf1%a$I`WNK^\[p#Gu L[]6 '?w剠!=[xxz/9F_r0p'2?2Q@`R xZu^HFd:No׎g(L-[+\Q>\1yIM[GwddH? r -h5B_,Mx]aa!اF?`t//vm.6O C+ 6;ڃЍ^]s!ʯ8%; Ȩ0@1(}uN|xui.[i[^wO[Wt`|xg'w6θ㞜&$ņ|QK$ܖgKj7ͻ~۽s9}QU}演=|싻~veo6  Tgid b*yXe1AWr#쵉#b"=QɃ: LLhծ=-݁9a c]>v֗)_fw5f] B8nјB崳ώl, O^g @oѽ"畘B#22CD&PCG㓂1tt0~C qQTes]Rw'h)EH}v) N?uӶUbpUx0|ऑ )c0wW߯]܁)vӯSp\4yd,H4'{J}=~:#q@er{D)uW?y|Ƹu~V"eSƾ:KiuL۷>#̨͟c_ȒOѼK?C˜Aѭ^h[6BBҀݺu k_*(#'h8 YQܔػ][Y }79gخ}zDl(gYLŗ/PeZ"_ex(6Xov-nl4Hv sOČ׼1GoO>Zdw8vo߶黵;lE $]i4YoExyzC%4 >x܂|鮈)o/H982#*k+?rj1Baz`_TdV|WiƴBqG=q-[댱記ΝBF>`P'*..I6i{v۱&_aʋQ<,Y#4.!.Ыf%ajI'Tf.G&T&=_^%1(Â\BC"AXU.h[nݬoI/Ae֫rv=M%' 0yxxd.t0Ŵ^v5_r烱%c\0 3!DQRcF7sS)]>yŽOke]惟sP!$@dw>Uc%2XF|f&-e\/AQJc_"0F0Y$MC1%%%b]6FM]?{rZwDiXތo"Dkٱ߇;/,1s`:!2hA4'pDAUBgUjΡ={ZdGĀBqեNjA#0qLQJ %8FryE/^c;V/wI}s(&x=QuA0BX* _e+f,2:dbKt;61~?^9TX7sH L raka"Z3T(@2@uDﴖB8jo߄wߍG2C_2eJ߾}EB|+5oҪuf c]&HGL\ZKͩBsL\1`**9` v!"D5Mjկ& ߞ~ڱ7cfY+ 3;?0Pw@\!/b|@7_zOi.`VרjbZi0tWxeCD /WdLjFQ{t I!,ſ<3e TOhu!ѱ&5KІ>hݿCchėILvƽ0"9BȨ,+*K[WqZ] "BbmekԵ]3sqXu*ҿ!s˗;usN_׮]pǁ=:<X`w̮*cfKi,SšA pTqIy~OQh(J-ڶiӶM;5#ΰ^cZZ롔}y'Gti6'>xO1f+el'6 I**v犞.} M}"LXQa"No>?gޔgxl%=Zuzeikzһh>߸Tz:|\HH;V4hI7&Rs"|9wBsұT/m^BOzmuIr|ߟu!a% {j"Hvri׳ 2DB' µ/Mٹ }3{4"(2dSYO-Bg>k[ΝnaI}#ťgߙQ;Z[8F߫_?tC6l6|nR87^:1F^2K&0"8}}!o5] ~ra3/6nс?,\Cwk-ϾYYP-wiJ ),m4\祭$~2F,w[֥_EO<s+]:=7}2h>pnOo:r+2~_z{Ttky>܋1ErI@v:ۯ.NprQ@z4u_=ZOhޠ$K3my̬cQ"^f~dži­Gr<3Fҳ}3!c߁6Q"|dH\kzQM%f+89l. 2bXV" A9K2n٬Q?B% n!R74VYt@z}֛6q+N&N]-*N21h#ʒlUKe@ D ǧf-+|sNnʳKT0pNI6o|m) &{) l+?]wΝcIl?mhOv esϏg*2ygz+ /W> ȒD1%i;o&˾\gfe_}O!۷衇o߾={:t())i5ȹqQA }K/6F׿X%dP(q11`pF=7Ch3K;fVrdw~/[NNl~1P&Q}hpw>\աQK^~3Ehb ?'vϮã4DJ h4~-Sn\}-MԼ0MEnQ2{6uxKO{%.G;1 I6>;Ǟ{{zCd +4a|ٌ##uƑJBlv-ʬ#;9d{B,,%ҳ[?/mAt)cxB$1JtPHlգw-^˵yfP=zݷo_NqZ>^ڷnPC\ŕ\ $ s9] "gmł%\  뗭7J6Ӱ@ ܹt/>!lL׋5 =6#@5rSr7j?2nfk*~ mF./'3AUִ|4fj v>nm=7^ش/M:њ#l{w|k\~òqw\Fj4QO\{*YyAzrQ-eCµrxa}>)+jϡ+Lz}|||nB/6mZhh,z`1128%ӷ0z ^Z)p,}{V>C*|N]1x#e8w,p{W9zJ Bga!`iD$4M(a =jGay|dpb qû>9sed <.ϭqhy`#*dI#mM<>`,:JkpGmECw[Af0L#BF*//S}`{zqN9D!Tʜ%X8 .J}#ؘOӐ=O`6% _i2JKG( x}R(B0(w(% qmF'X܅gh0>B1ݱGc9Zq0sN3{%c1bS0W\|= ^ !T\U8!TϹ%XD`K٣^61qgf|z%QAK̾^\h].U Bs{0a!Ban'3t/6|.zeBC1cjcD!#OLf5ZCzP jt=ʪ`AØɥ2(5 f0 vmxMN +--uc!%СYRH̓0[N۝zrӼQHf\EbcD94be}O˅H'pޞT 6-Ȟ%|ITՈ j nOV6(VKUHV AQàzcQJc]65V~NX-C?>VyaDAG-'a|( kkwƨBh.U11v(5&@U2ny8dYs!("oU <.FhHW75U1)̉bc;smlΖnD;P0\.kckdPc5- HV ;!: c^hD1̀\λ;'v)N?ඡlܷ?氤hZp؈BξگF"oXbL޲5V7PW"n!jP um>Ӧt\7P\m|?jxkm5M}1jfwF>C8Rxe7_}xCxjˡvKuƴ[ZR\@|,wܩx6/慻sFղE\ݖ=;[{kW}[Jκ@nݦO~ʲw4鞃_GoS{/G=wP]-ꨮx7gc{)\XX֜hDݹ]ﶁw)R85ތLJw!}4j@Q- c?}OUK뎩&më('Ntzg$cJ)}ߡWYgܥ~xgڧ[7}^DP rBMDh'3Nrsw:zTgZCCV`Ԡnn]wv}[] pN-[iFFx(װ;}dT]0UT !Xo pp9hQ+pv\14x:8RpάFL|7n#D};4F?aچ0J!1sbo^5z***** *`^0rNЈ<J\8DQaD%TTTTG 9]j\򟞠ԃZ򏀧, U)4_NEEEEEEEEE=A aJ=Ȳz? XiiiWR^Etw*.K5i4U*********( * z@i4B^qp'*yQšr?-c !zJp BEEEEEEEEEEEE埀:AUQQQQQQQQQQQQGЈl6og0[E9Bg΀,ӑ#|~3 1 ~>Lh|-'Os߱CTEEEEEEEEEEEwTd;(>"B)S'Jy '1@ HԶ\^^x !U!) Xqy**R auo*6[̧CŒ%\Rjj3-oBE>G\q _ÊC+W^7K.V_8;u>< (yվcG???lXV#s?p$赖/7j"NgiiiIIIYYY͂EuzhxuI Nk1gjTTTTTTTTT'kW'8p@Zt,d͜ɵhz1齤T0OÜrv V d.\ʸq#GN>tٲF(..޺u+.SV=1a8|\=ˌ* 7c;p8B$8}yȨWbB,˥Kfs^}ҋ#{~xk3޴/&딛7$'c,K4k?&"*********]4.AAm{x04ih(`f A9䝤 IDATl/QH"H3//E˖ \.SJw9i$~ sEys<ScSd yq<PܙLP̈́0?,0AՏ!9C e8c`DV( y\"^BE y7y^"% d8l#ST   Y*F[cXh4:?},kF(%f3ƘRtJJ̒$! ~޽KZ O9Ӿyz@C24]yu#T'?9Ay>/'j'KtZ3)i$h-m}xFtoF*<{&8(Q=ykn8Wӟl]"Q L)S>Fe %v]b`yrA:-)C+o;bLQJ])#!P#;~ɚq3Kپg"1jJ ~;4(̹=7=u5w6˩!l=1.w5|ez9¾1B#;vF;*737ɥQLE, PRQET@9z>>ʝ3s==5R$[UPS><0˖VL\.WL*)Kٽ)oZ/=0G58qr-_,3lylZwqp[0%A$>3=mO?pJCDrT*IIV4-]F9qECՏ#@ Jh`i) )?$ްa^ҬX[;LE$Q[:%j䏽m--0tذ (ʘ'GGֽGBR)hM$Ȫ-w`QQ$IE f$F(t:NgR1$SH(,+1Pž jԪeC-QJOIbV&DƘhHXI*QhTIq^Zv@N" !ҢҼϟ@r p '$APܢMCǀT "Bpt`9AAsJif_Z TZJ:f0 HCJTLETtLBbb~6b$5hl% uuu?R/x![/9/EA~rA:@RhjL*P,:!U$'C# J))Qq]qgt)lVΦ}0[.)"MT %Ħ0 $IT*U*JE i@  T"Ȩ!I 01bacJBuN1J\Hg42$6:pqݼY"X[[slgϙ#,aTbaraDfYDta!}Tv)Rs-p=մ{s}TDRRPQAqMK7%(l<.a4aX! a$OOs`ld)z Tݻ! 54klnT*~ϚJhmHpfW$vo\r eRwg)I/;+Oy `AnϷ Ajqgq9E O4zޡךEQ銿S643k԰ayܱ PwT*ΚA۪`@ d >I(HRSSÇJ2']]^(,Nk %\"W6HODR aF4dȿ-9dȐ@SAkiiq8׮Z_~DNE^RLrP,slSs-eT\岵gj3iR"!ښZz<Nb)T~gSyՁh @ @ JF0 $M@  T h hP@  Bq)ÀtW J`T* 3!@ AٳgH%SYP=|xQZZO Tzkqfay{s*]q 37obO҉=}ZK;z?u&n86MVh4upunzi"ڷpj㩯ϝ [M)5G^ ؗg]_,|vfzzӈ0zj[|||}^9-'_{ߓ'7Z2X_RO{^޾ly_nWo:i @ i²ZO[>ח1sV5ͺxY臇-vF is3J'5y17v6]A>^^OÃ]3jv牟>M5b%W/?_ FӍn?}I](dY.Ov-Yr$I*D Oֺ:lUQ`)Wθ}ROǪucmy޷NhT'=Yrksf ZQi:]_9g\9~hq2\ֽ>).R#{rѸni=:զ։lI>.y6Ok4+zݍkYm&k+.;{kcMG]CRF`tc[G5I~$,h2$̛ #on`u4wωM5tոWW ^:5su-ykKo^xL:쐇FT1R{>)S*"<>y)N3)Q"=E2Hk(֣^z-{ KRGnArX(>c;*M@ 5}77s)4AX**aQN^_  JUk-X%e|T 6߫ cו=zmf$~&m쉶=x7kiv㍻wu0^mm0hkyO]r2:VgE{ܸf8il6_EvײZ=֮].^fφڳP>@ wi6)̓vG/\rab ڭK[ZzE;:En>x{wsW]_OЍv ׎2b K\V͞5stD1[G\<ղw?MMo5gleUzFSdN79qɃ{5[Z0=?7EI4q~˼8_=7Zbm6ۚr/jLo )?ھg(45*MZ*AڊSR󄤢7UZ,K(VqH@EI@Tį:SM߾ڼoJ* E,Jө`8lB^1ixYA796||Z"@H*$AT*H *j2xgWK?WDFZjioa߫po,vw>z?:wǂE+7y0O qǫZcײuf&~'mVLQlrH|($ԦͥC&O8k~L /͐mFQ\LTJLNhA9*B&VnH*hY!y0ECv|)q{ނՇw jK.tl֯۱Om,5i;>f&'[kL=*@dsT| mE֖6񩟟}{S:l:7c$1 bJ bbcccc}Yn|,\a ,6$0KۿOxdsS=5&G<~FzlZs_X\'̐j 4c(Ԕ/~59U^ M/A\ʢEBmS>,0B@  Y+ʇ 0JI$IXjjؘ kmE1_x WHwjc95\)P:ʔ=fЧ2m^U%+߳;IӒc[ 2 ;#굗cp) dغ9] Zte5y!P6\oX4ųGgH%лomb9! $Ť#7ƾgufDžBwt" IDAT5DqiѨR2WPO]_@sp6RHj!׆G2]VEJN$-5qIr9 U_ٰv%~HzPyn*J,H 5~Z)a@J͛Q?tͬ5߬9-9¢#U5 HP IPhf=YR뷑~KaݾV1FSBR1Q{CXѪĵ+ 3fΘ:S h@P FfN1sy6g+@"meN0d)r=H!=~LUxWV U 0S}k䯲PixZ:\hkUΓO)rF'ȉ L=YzoӏgWHlo UϠ<2SmR)idī$}ntaMQa!2n;]N~Z6rLG>/,އ  qM+:4A0 0X"SR8QEd>?i09cDDDDDxT|f8JO Uѱ9Q%ʟӢJ @Ffg B+Fn\ӟѫ3 =F._b9ED뫂%7Oo=nv:M%~;@dtwbI[ժ߽l7yH^&6b}Sl.hǢ>cV EI!6?v6yOlr$H <Uq=.KK&]1R3K~#4Ls4 _ Ъ>Sc^EFIAqJΊ5Dר5Y=Ww&Ҭf_F K^a. <_iXqum$V8l'5_P}bNO̒jʝ?4R&˫x &c%n-ʘjJ$?{pvMj@ٵG<\^| i6;1e!Y VC0Q/W]:]9u?r'IdMuRlS|ߗL3=0(_AįZOH0M=t%@ Dc椮333Wn~?$Ƹ,wAo4O4$1#/;4"跷047N;r"Rȯ|.( qo Y̻n+0k3dqGG&ֺh☾MiQ&ͧʐ}h999~ȴ*qOeg3Aj6Ok""hĥZO;ϫ#`~[ɸeڇ;(xFGRYu u7{IOr wY|`i ݴFvҝ6j;kɅ=>5{i޽NjNi=Zm8ս!-GI3svsϻVnu,A!o_xpzw<5CӞyW6("Sb8?S qzT_X/t=s4@  "%I$%@JʊRcʔ,z6CebRe?HpR^?}[VSY#5~˷EiqQvFni\'+ق(>cJfa^|r7=ҫE%gefƧV G&Ovhxq9Қ oҶ[]VLhhhkS@|dix̘q UdFo-BZ\J%RT1VqKKyRPjF+P*)g:U8R^ j1VvǏ b\Rzχ0X) })_]x;롬Lou]݌@F~€ﳹۮeko T q^^Ng\#|_%48 A^QgiU_~S%y!O=~OccS9\UI3BT$y);uԵHUc}#c$r(:ӏ̕z IR}̯,ԇ ׯbJXZj5 p-.M|cEp),\äK qfTKM^Z!%󅂜L8T1MeF>qVP蔥Yce)j#}EJ8-.QX\mIJ[v}^AJr4x&0竌\ ,'R |wL1 F견Wo R099Ԍ7O|3Kݕ)1IҨe"\XqJRB|lDiJ@";%P$bTT] oٻ$ž-[۷oWH$ 5$M2 |RN2Ԕ?㐱]Mi VWgѨTN7o`Jԗuꨇ>n0=*@ (M>=(8tͣj'`8{]]kV|կRN.[QKP>DWY (l|SwX/Aᛆ@  Ugl}eBECcE[W3G@ Q7LšJr@J :E @ D}"@ @ @ @ @ @ $P@ @@ @ H"@ *@ @ @E @  T@ @ @ @ @ @@ @ $P@ *@ @ H"@  T@ @ @E @ #]XȘ4_T ?l0)* YO Hw-_ k0y+ *oF`i"@Դ7M\=/p\u|޶l)tހS=my">27l]6n[zukq?Vص֖\ݵ _}ԮEob&_2ldt\cr}[pv&1270G޼xɣ۴0s_7ჼצ}췝N ۹jk$eY<DžF?? ҩ78ڏ~Rx;0&ta/9 R[TGE͸㊕i He~G>A}{ֵ1Q|{n)Qt^oe:S!$(zmr([k7]v?@6>yI;.(}:o\|ֻϗ6l~\?.ܽl.y^=qJ'ݴ͇ƴɌ|gjMt,&EF(/%]B:{.3~wnWdQqA0X,Zک$NP*SU@CZ,8߳t Uf;<:jqO4hf}іKt;k60|ݩC{uTnw dpGO:DaeP %Ph4h4(ؐS$&;߹M+O_?n3>βi6tv=Gw8X: Gn(0d_n1-;{m ߵ=xh1Gέ߱¨cf7Btw|Loy[p. e+4skwJykqWM'PW,\d@Yw/^۠ޝBV{Wb,c[]{p* +iPIhW^},bAK Vw1>Ň J Ĵ.5`H&"B/\yEs6WĽZ<ú3t:橋퇎=ttVmڶppzEo:8P'= oC 0;K=^JDk@p%2e=ZY/J,2>kUfTqoK# _}4nQ_|voشbh&z5'dys^x,}aXz=?0vEfL/gbSs&1k*m%'{鹻[*sMwbŖ k̶=,i Ͽl[4sԩSN9"žs7?DFz]Hmܜ4SqhzFg/5{]fUO=~ۃfv42}ql~kPNg?uf9Γm>񸾰1Ir?<3SI߃ʹ(o|~Z$,w)]V697:áb#;>})2ᘋ~; zb(.*ʏ.%ݖS[$sͰ힄E~ u^o V@Q66ןm+ `ؤkjIv9~4) O`#ؼ^V3Y|b#/GA fSIQ.{NgnyqSy]Fvw5ݔ~-7mj Q%9W5J4Ws0CtuR'P11n/ǷǶQiviP{ZWS;cj߀Gp0=z}\Abz6͏ʿ@kvYLGDzrIcSp-MdqMi2 G۷g;u1s)ZIЎ÷V*14J dAokl7qi*nIDQl%փ%rNDd`̾}{ϦxE菵^6gE)Tz2r]7ugbҋKOtN&ȋfNvKP)5?xѽ]f w Zu} 떿k# zM9yk; \5 "F;SWJgm̜m瑱woi3Q^ IJHh8aɦmGl\V ?ު 'CRo H)Zuj{2J!U+*@ Jdqs.0X+'6աQJ9YH dycI%:mbs:ܽwnws،% tѸG h : Jv9Nv@F@n+,f=)Rרc_be˴5 ))eT vvcFO'[Jl?c$͏+fO=da]*Ŧ*ť_VJ<}lcFA*τA߼scRKsuԥT4&wWE>F߸{06?.2X\qƦ.\| ^P_ e $BMm XkБəYIT$e@*"@(*_"/%]jޫۍm-Lʑ4jJPÞkfZV}VHBK5nEg| ^}%xRO.SreQR,KM:uե'ƳL:5R)AؙPq{ *k÷%$Ѐ{?"PZ!$9F̞Ԕ.QP9jJKO%Y) yqtL :l@&qNjb݌e3փo{Ӿ*iAGIi1zktWFn>o̬pۢhJcĦ=^  =}~W_E˺oUnnʠ1')H1nD: Ȁݫd9GUt$r-u **f3QwbfZnzd^+{,@BE$ID/Q#?u*(Ea\)tJNO|..saX[w-Vj7n2m_SHX- eq"KG?/}8,39~I\-(u=vxK 1ym}bbܰ1Q~/>Ͱ4XrLŵQv'C}}K~6fvB 8 Glwi*lP2o+1vpqE ZT!۸_:=n+&'<}rT+Fa%zן444HH1pC*,*N<5c%0xPސɫ} Ηq,5pP#M&ݶ^xSqAiO_#;uQ Nh>3svSb?{ZjPLф␙ߐto{Aa{5e4iSG~\@b+15_3\ϾkGN: KQJV_$H3mR"*tvOS r6މ^M8>Q([ m2;_Z|~ Jw gw6Ke2TF*mZs? il|T*%]r5"£KC6*? A}Otzuv.D2 o!@Ȅ9Rf&̧a~RIHYFdLQ|I['@()]ùZ/)orm/ 1)2Y^XXE6HĀ3AkȁGc1 (阛ż%_4eߊ+ KeTL5YSxBnbݤLXddfvm}Bߓ}A0:l$Wm w. J{},7Kj^m=+ sZ#H'+1K1dןħՀJ2'<) e1#g%湍@皘*%Иݭ,}PhL-A"?b}=pa`8IݮY\$S*q- O-s%9.%.CUٕMj}S?_^TV~BCح@UF8\u樭` ;>ՠc<Ѻ5zlau[SH^j~+9z:YlɡtOwOK[=afm?z鹋ݙY37|LМп,~vfzlC] gqevv1 J|$*i66*f @w9'7n˾CcqY~H%er->$ @sű]·y gFxlvvRhӗ\V#&ӂk7' m@io1tHfiʠoQnj vkr"Xl-:Hh#J7#q zK.RObm\> `ѮN}lF44G Wditk=@wd~-lkF-8J;GϘ}F LɬNf{gݤ]{x3؞ Ǭ2H~*] xֶYyΚ-t# rSc/#N;ct2Dž}#|x`i6=i:(Nf>PQ|h;M*=heyɉhKθn˷۳9ulY}βV?Ia%9՛h5];ɮ_z Qi!ӺF1ێ)]`Ln3ͤ};ݡۖyM3g>Ng)*虷k*Ƒݻ+M¤ E"56^$iz-l.cʘhՊH+EҼ,ZpMߔ׏rP2q5 ; oV Od$AYUdm9oec)kvxg7:$&>+/zB.|:6e⊗$&* T a:XzpиI.wKW٬\`q7Ns.U%)ba\`$9ATio|ܲiqxyK?1qXL=Ke͒y\v.cf!;dRݤIWG)=HQ~X @ܮԭr1KW^@wʔ+sS AxQbTK`"^TTdQ+ϕDOs0doszrR@-͋A.O+Y9cR{jZ'3fc8^~ )00ko2?E𻰰Nٞ-uo/K ʔKg6}kCP5#up=̐wÄ"@.B 4:M&a@ ]p@]6o;JgHMwQmMsv) ݝ؅VnlAn@n@Q;o|,>{.=s朙9Jrc';FאTΛ}[_ի$Qa @q3>b)a=GȜ{fi~hcMa````````````ݻbrrRR<.A-7#YK , ~}*e=100000000*C@_"&@e```````a% v L_7͠8 E,i$1}M$Vؿ3JK(i[{0 Mdə8M$]1Z1_e5hZC%JF,!#hBCk0!'r4ZzpGOKP4bej"cw_`:ܯ$ˬ20 !h(v1!i$)ݖwf"׾[N 0 o23X8NEpSD}a8EnahMń o(Q$_7,LPJL3 [O p C@G%1cZJ_ ʱp >0CoP9F9OzN3_h=jј5FqR CG1iǝ&6fAIS@Sj0 j-FdbsIvXV޿Sj\ġr-v-j8] gﻞ(6|@OO=ǶA%t}Q՞ܕ@<ߪy_.,نNpn[Rf:_^O!ϽZdzc:5)1O jpr(=,%'5j9`lmÂa t߉;\0m{7?(Fy~}[4Y:ͲeYm/j'P@\n;g}#IJOZ:*zZZѶc46LL+aqGm-JOɣ8|6:~W{9o7uw_,{{{>|]إ}w/iȸH0Nn8k /In4M Tuŝ["|yf֨xKfj(hN'X暍3$Ie7\"52wV;8_қ [>eRj!馤M#zm0%h?u՟;>πQhȲri]CYbnoLn>j d [fPi}F9Q@1_CK1fڈw~2kt +vȬhiî-a GGgc3d.JÏ^_8aG!͝4t]NqDiP2@\iTm" BPk*L( 9'dcRV$*ݒ IQS>\eHWE.}NhW5C.BL2ԱAպQ'MjrC.CbaYrݵXđ(hRVTDP \Z!G\doġ6{&iLuTխ=-Omm6s_]%䱌-l-I#$'R0W(!Tʊd9b6 JŀV(42"jZ1=JO ݹbZ_:lɮtY {OQp%H:KDʸoOpRhxM eJ|idzH\"hD"262 04D\L~#U0DIX<1$ ,T+_Mɏv鰯萾<vkUNAE!Nj}KD=7DwK(`ZYjE=PJ*@8W$a@)dEj.G \ ѥbR.WH %/mY^I,<Oip`Ȃcv xxUޡ遧J]{ ̥c`cq4otlG?1+ID4ITeE\"n^}PB')A%/Rj*4TѶW*k ~6=4ێKt5.{=zn,+f\mn_7;Ј#!#Ԩr~_3MN,!2#7P p?uGM5SR L*"U)WYr8lugqٯ}-x[\C>n>(Nߍ\>c_E|%݅nE[ ВSG$}H)YZj3|')褪Ԃ* ]r9FwsLB4o9Iewꜻ}>Sȹvvч ru0v{z{lJ<NCS'&gƾ-MPeܢOY&6Φ3}Vs.:Xmdl1J˚ҔKr<&mӺ|qXѮw22:g@7e&կχ]~ `13d}+Lu{-ew{cjA<6qcf%1ݵ#+@Y+ި].,K(odx*i۴cNUJ9n˅_z״CGiGm#e4y4I/i#A_bX]Weϒc:7tsQg\(;&@x;ﺟVkic:Wq\8kmJ`9Ƕ{QV@&j2Xd.Xwj]ޣxReܸӀI?3ƎsL&m.b[O^^q!CG;ΫcVk~&?޲\Vi+-O^bɾIqtW20B9=6zrmM^]VlS[lVpҺ֋n|Ļ{ݬ7]k:(369am.`dˆڡ>TȗHo==ř⪎F1[^{] 7l۱io P+ݓ6/@(MOр pǡ,1 ltwq-A"&8 Ubzii:;XhUxv8x}^rd΋"T*AZ\Y~\bv0}W<&0Ũ( es;>φYUɦ1hDvN:ڽݖӿ<ڔۏ|Qdy0q WqRf7XTÞۚ۶lfs~s?;D] ;BeFRaC%K3"ss'tܶDth4weQU{U٤mX퇖\:m3 F+h2PNT.)3'~W!i-l''YWZ&޵K-$񾕻_K.^(߆MrzI:k)EM } a@\tspZN;h|xb-z@qhյj켚 z=ĥr<@\%CNܬժrooz^]t/NW%2T$=]Yy: ۶ 7X3SiYϺN^#v:tʗbHzٷwTϦ!mݽ<2QE0QԸM VMs+uLذ, rvUmi ⯠5jҹԢ U%%/odvӨﻷh=棖H5mWzD5$z?6[&xl"~yrkVXo1iG-U@障kbV,+9L1 \umJ~>-nX{ZNTV-H=/ǹɟ>3޺٠\O?=kζo]9wBu̐hP@4&fz%5 ac⏬  }/˘>x @cǚRtsϽx@Y.uOR7K;ty`_׭ |5F٭T<®LtU! _D : ~z0?8F104],!.r=Vwp+_.{U8CU^Ezq5@AR迋y΋z!@yri$ N{zwSH r~GӝK5Q4 uq *S.7JFP(<&VaWcy䥤Oxdh 4{ ?v\@Y>Iɚ#_Mvmvê!W˼qV; G@dYWVm 3 +2{q8@U{_εml̎m3!= 8_oQ) 㰁" m4@hkɵiG~JIٿdO !TlJ"cLk-ִxGB„O6mMOƄ}>$}!Ŝ Z4c YO3R+zj8)ija aW?}ٮZԛ}0b␌k?.? B?v7u~o '1=gКNM}\CVoh,0ˣǣ(T?һ, MeJSmmىiv1kw%g.\6.c`x]VP!,}emLlrSm?I+A+=mdsTY޿ӟ4B[^*D SR*MTt9)S IDATԾcG\ujK.QrŬCogFy*l1vץ;lo^'IJl衟.>Arу >SRsl{'=K^HSw/EItRJ瘲&i(*MR9o"m6瘋=u^WkYvfFFFFFF,-II2KxUV$oD c(ev Q1m@J4>1>2pwF\;/^<2ȅ;5hZڽk괴 E#nuLx6;/]>qèn j)8Zdػ6n)ߔ%Ʈ[Gq*Q==Դ Y7pZ իov>{81 4 L7lY$!)̞8/CjRm!A,^.մW{x+!IRT1yMoTvm)/]O'=e_%3H4i&ֶ~xNعĈ_@F8Ojwq=Si[e4 4smeVcլiRݗ 9X}'#N4=ԷcwPӘF7#?&bѓ1d$6:d(5I%:WFA!iԚ?f@jk^Nk|vՍǝ\inHt΀M|t=]5#m[C/g_3~\n4%8p9yglb})o-iU53+sc]#`̻Vzxy5!U0}$襼XߕӔ>M YWN T'e<MRƲ+>s+Fn>L'\:B@\Wis z|dket]Ҽnn\ w}s^#+e>uir* @ytu36<}ga,fy6;\p 7vp#{w`}z Q D^YBnvW?]ͬ_=~+p+:kvi7.Ho\6Vy\VXz8AI(ߟ>DnjHyN& |uF^xHy WeЉNO˼yaG=uEG[ccdu WV=09f Ǯ[yיlO')Hٲ.V ˵NdCߒ@BX#"9O KԄ(YAWTؿS8Я7PCIN% P+JKn/fIE1e!Pead eT.X*~\!WIE\yA!Q'rYZA@Qc RPJ,DA4Z'J)+TH,(v`R9 D"6*Y!AsB>єR.St8W M% 1tCBZYpR.)BPlzbJ!S8"! J&-j6Â1(nJ.xB>J+պWlk >fL1xlP)S)Jr6O K"NiBY>[\0X—HKr_(0Rɋϲ`qB[k" H@@(dԨ%[u Q@%/Rjl-H"RJ/aiT[ȦTX,.5=5=Pkjm7K 0W$ +.TXEB\/RJU%X\!(?zleߒݻbrrRRq ͛,c`` M3t^nÊT_S; ;83F ߢ%/ϙީ;Hre_z0`4̟EzǭF0 -:cq4mBK' e\BQg`̑D4:PiFzT(F f`S1U4M4EMrw3b \k>h~@"čtYbzqω#rh%I#_'0vXQ@|f?_,6!3^|f&زz:guEz+~ISU66;{Pm4My$JgCpkow_N^^xϞLg`cv//]k=yTonӻV4r& XTGڸ rh_ihMD%hr٤'O[a?eLF~Ӽ̭&CSys[.=!G&Dq=_rRTEa8ϱkx:Xj2*L1D֋ŏmլ)f j%E iX j?B؍7L>T7X:I1J7nܼqK5/Tw+!#W~ ;!["+[dzr'ϝ?oK*6W 񜖅,sL${T`b g\DŽWc nY0fQnM2׹3FEԪY{=LҵnݗZ,l,XuӴ͹dD>w*_' 1dp>NMlҥlŮn ޲_= q~6n֦a/ͫǵ0jBd\Uoи 9v_z,;Sk慁~q;V7PJgs\j;¶m hj]-ZmۦA-*@vMmm P{u[m8[yOykpH+[_!v/lW:ͱunphH)]ouZy|wp7v8MѕXC,/YFqeA׍Q68cKȎSKk4`sPȤ^MN?OsUuoiMV1]Zjbg4곮ʀu}Ha4, 6lXԎ ZЍ аڑ`?||̢mAk Y.h;m^o Z;m1K'{v\@6m\ٯ{6s[{Nqxy IGfO99{J⸊qatvv>Frzzp)K"{P|馭[6L۰d)6A)Cv9Ȩ)7k֐Y-ߗU$o{b{y('qDd'o.{lf_5mҼ~vmBCE;CmfR"(7eR.g޹}}zVЏȗhC'l$l D-DTm[LcP4@wfzl˦5oȱ1%$Cw>WKq$65SKdyVFN.|紝#O-kx?ҡzzb?ؽܥ;F{ZJL@\{O#zv2B6N,h <鉰}Ds6ۆwWҶe[MD][w5dwnN5 tn=A#x5#^q7cڶVv=v}pHVS=Aip7nyK_u 1h ̌j{+Q{4+GVˈ:>ͽᛗl9dPjb,}Ch|m.%#]!^ET YQMxFcp}-7"t:z{ Yrip΋-_Wo Z=lxWIK)4Y& |3+2V' 4(6+OGtiGj8{pr]mZ@֋מ@݋7Բb;dUJVvrR_1x_ m5dy^۸δy?Nl> @}>Yd^&wD2s~,m̝w˾tAQʌ,e*aV݋7p@QH }6O&v7MքgnJ;s&~EnP"HL/ɢMkӣF7ost˪J;[qCӺMpidF(2n@p0gMꄋ9l[AaƇlee9/\WEpz熓7n5bWV0&ʒrJKJJnM2R yس_KkSgZFJsq?sǷdu':af\N01`iuGP@ E,G \ 9{ d ,Kn&sȼG3Έfx:fF=t\Knٮ61u+zOM:])-tЧPSFu[EtYc։}K7.-(7SJ'? ]9uI V7o MyvԵȣGr \1m8v -:b(XUm9w颙NInlv{ZÚ6͌ i;dF7^v&0'&hW*EvbQ#HXo7%I;TkޣuNRe0djJF+wk5(koJlmi=pƣǷzFs-nk"@ .w4IPRSrNOL u}x˰F= 1]@3Nb*9†K+Ux.#5DB:G)٪UnN :y;Aǧ'L<{Ԥ-%Tr+c7, 1uyi" ׼>xyF?4K,Tz~&"s3oٱ# qEhVO) $K-=1r& }u#S^ME|)ZHz\{kܲl h TISRKWiqTW*xX֛ ]`TYJJ{ GbJԔg_:KY"&in]K)Q .>mngK$\2U=)?0y$?i\GѝlJ`%(rSMϣ_kM^~=ܻh!.i{MSNe֭m)剕 ɥ#:=2|=0@@mоԝx(hiI F6*#I.|ZŞ;,Ϣw/z-eû6ݵw? E$H$B0={ 0ZAady aη;9P݁ݿ1Z9Rp2 ?h8\UC ǢQɺv}C-ݒ7f`t0J4. .Zm՝e]!kK<8lÊS$]Jdbh@;^ԨU'XqјIYeaw!A]Q*D/k/y v^~q|i.)Thj|OG)GVfIn*m9wUlP IDATs8ʽ-Zo@ցm0xQC>#9b'=<`;rOF8&];~:INDQHksX~sݽ\I:,x=udi"s0B r;aLU6G p, *v8D_:^G# ibZY _NMFJ} VX\ɠҮ$H ׽#"ϟ ë)VN*sХ8[Y7nASARJ66bZGhĕ}767`T }AwN@Z1(H̴wt55ԗ#gF׭dfn^ms6.mM |$ݶy Јtf[pzty~cuv>Dq0b0+p8|6" CY^ nfiүs'O/ο%r7(-L\viِ.iڷHu]$zz"n@`l*uR ]w 6f=IJZ 8KAx,]iHf7r4P{aNmjIG%ShxK s{Wp@s}׶C,uci<;Vx/ݸ\cn![Blħ{z/iL1B'N}iVAZ[{ *zJiҰM6U[7%^%q+c#E}(H[uX4IP+bMn-+i;tׂ_{41.3i @c֠˻.^l^cX_>ueRMEϮ^qx}ƽͶ1gX?~\J<Wo`ENJ=E۴Uh?1^=>"yyL}Pnv0WQlOz>l3Zɠ4h񛗆常i-rQcZ};zYXQŃUCgܶ7Ʊ* v1kg[!~͈X(kݨͯ~.]`B#rhe<0`mr9y8 GB8@h1|`x=r:aXqCNqkG^ӋjaO*^z$ Jw|)r*L/97>E1_nͽ݇Α?ťfQg\I7JW;qFE*@9,֐j?4BEP>߻I2MXw=M 5PT4Td]G*M=i;&dʏ @eBiB uŏ kj36RT6XE(@p98_.1 |zTsYe/BC/Y0xQ0~c(\~ , *$|/a PKb@?-dQ;4 u={M(~~I@}2Q,bV.84&X .P.0CZC0/d*B+n} C3200000000000$P߭?v%s6C:y&|NO2qWh֐-hkgU AUݺ=tຮߧB% ݾݚ.kбk!!{ `nĩ2nD0L2!UJOBCHTAHTNREHD ~xO20T7 Ce:Y@=sn @kUӑg a!9xz[{rपo={냪U]L` bO?BV:H;7uEM~-\8ϵ{,Qddj)MjV妝=xrhW} {EFD>ޣ-y:{5rv?[=jɈVM c[Θlк%[3Kcˁ}ծg"#o޽?Grڹ-gN>>\zޱ؀6RAۺݶ8qjO fo vjO8F\pvO?;!* JQ:&^ݟMi tv'b1tL1e.$z LˋYK?ZׯҏHfD ` @] {$&œ$)PL=% Uu?3sթv)F/8(mF-yfrI&)&XW-KTvd_0Pꯟ5qAg8}o>h*ϻ裘&P-зy_PDz|ܽF[|J֐[G:f J62`aQ|h@f{f{.ƀhū: :jl"l{c=#20^Lٱ'`aj0*`Duk"5F&Mpo¼L6߹ Qw 8rM&,Yc^]_%]]}KgwQMz^WTYz!JA@svlRe5r^`JB#VXXAnd)ijg/pkA??daж2}ۢ}g\c)6R8ϤN=V4D<fZe$<+1ǦZC|J$)J ۔^O/| 2 Թqy qBvo#p3l ORPe"P#I;43iC]DѼ6QQ01; QNP@ ;owKݹyffVD(5ƭ:%Cؽ#)v]+2Xna-G+ST%E(T ( IL}R,AtwMZ]$Q@DXmg2⸸痾EаCw$zZCVM:l_\""c/יGแ78V_KcWķ۔RA[q50;2H{[T&V,^z&g$Ε)dİ%>\ M+Z(U[,W1 nٮg2:1SLYcUfVaQR2W`Vܐ /jh GMnܻv۴]:݋f]S11f{@uZDgsC*-gaˠ4<]"}#I~sMm=TG@YW~Æ7LvGj7v"MoؚzCWZh4M:XIgřr`ϐǞ>y2*GUuNWٵ4uZhINH1wtDUsM;li~1Q[ ?,1c}nqVZpq->oԢiǍzV'n]Ƿ6en41=Mj]<5u܅ ' uzx==>00NDvbpZ:::uیpd#NhJ)`68i2*iôI{gTEW"t}{ogo]{:jYSM}`ّ3ҥbR H U! c'GfYtypVR߻H͠"ah65l$wWkе9.AشRP=u>C2'uq$NbH.$Wv`exAkWɋ)KJJa CSV_k%~ǍPJlWW+(;;356e210HQ>x:?YC30Tt6t;`T)D_Dv8g% hjTlȸV8]mɃF7^ >aT|aƶ(%?ꅊgR5}427~󷘅ssޚm -9஧e =*A{6~~%wR40U1B Һqb@pYuڶ0[EQp9ŢMIВ؃} (`_[|C:P i$kl98^&S@u',~1*ϊ;vӛ;{=Ѕy2)E*q)|{(dP.G&)[,(6ԣ1}Żͼ'@ j``F|aȡKӡÂz)83 c\M(@E5b#(E űR˗ P1VP)Je<UNІ5AQ[?#5ҫ:Y{ĩ>V=j EQWuiRD%FGg1 yI$*OiLVHhʥ 3UA@k6!އ.mߣ>;aœ #xqvtl Cy8=() n낌R;wObJ__ϝ`-g[K6]"&|/xpy:geTŏ.mHָ=,XoBwxeu!Yc2@!ԣa[Ce&F$H 6~caJ:a'ZZUU; eA}~69@$EɷZpOW=կ p_|M(5 Q^a*ϓ(q v NTx0-*:&0s (ή=z^/( -tǤ/ZŹ5s4[&7cms_BN\%5NH3 _ǀRUT[>=WWn O_:->R(hdD#[eBcdLiC<i˥vw6ЮmtLN-EM3Tt~Ls0 _Nɡaaaaaa!! ;tjِ@ Ҭ"heEЋ2x@刷*0jzb `r&T犋1J e:0u%fw9FzuݮOjVVD~^/{: e|x]uul7hX{Jg1pRIhnyeܿ<՗ ciߢa`(NWOBVj~"K3IqXxPYVXtT'FUیӼ[OkcW(QUbuҶqE(nt xr DչiQ8/. IIS_3_D`t$W\BZ%6 /0Cګo92]:nc?HspP&c9 h4*}TNԅ$U0^ %0TWM;E.z%ӷuLg%Fg47  N>\zz wjWU` L-,rՏ !qvm4 *z XX4:P\y/sSLmOzWGf-ڱAH{ߨt[m1ƌIKAsaXpHVO7:(i4za^]M!kpF]%zc=hZIiyFg/8_|?$98,SkLg.7,LO(޺n ]ȡVǢΛD@.#-gv~xQD=LŤW(%0y]7vQ;?pry6߾n#]3}$ogtre; {[!$!.}aƖϣiv4m}4Ut^=fhh xǯ0쨳 ]Vx:"8R'\}8.|xw}r IDATCKLf&Z;qGe<5*0i2npIs3<]ݳU@r;"gv!7w9tqypwn h?kǖN!u ?pr=gIޖ!^q=KcGƩ-O{o}5 pͦz&O}vVGa"q;9?!2 Q&D Zdcc 3qEx30v-d[cȔ Ig$ž?V5p`Vx'Ƥ[z=h55"-9MDV|dkf.m7-={h}@R NbtckuXT*Ҵђw\Kp>~ya݇4%XcSEz4A zl#N꓅zz$]Q?<e];v!"095O Nz&U19"01Y`_[[QvQZzA#GD&Ҩ|C2ZR 3͔(.D5ovJK^'Ŵs=D{MҫcG'&*T4'qM=BQNxJ8YP,WWO抛oZjF|A~oٺ>J!ΊPE-vf8_WҐ%.$Ą?py>L"0 !I)eRÀa\ܣ#) 0Jw ʈK{:™N" R_`kk۫WEAAA7#e!ë]~۶m5zAAA=   ؿmJof   %?[_   I soGϠ"   (@EAAA"   (@EAAA"   (@EAAA"   (@EAAA"   (@EAAA"   (@EAAA"   (@EAAA"   (@EAAA_bsP ; c{I%'K8/ahk 8f{~j__ѳH~}m8joQsD[u詟'^7:ݽNm}A}ˎO{xsrS}MRM߼jA # F$~q,`H6軏"i K?h~ÇHs=)6о42Nb|w"^lHgj9}XW?'i!rdYJl@/1@Š aqav݉+7'--Ozf_\ C4 ޼cw+Qboob`ÍI 7fĄ▸8Ëwm.z'`$gnDa bA[n CmSzWT^. LXX kh1+ u?vi/| R{# R߹J_ǀ5A#yokn/Xc~'$\={ӠݞlKMYz_:xD2KeׯѡEqYVu@q7 ks썫L^+k\,x$01ƾ1Hwt>N6YU?zK;3LX'=}}ެـm ?g߈Ck4(Ր }>s9@f+0IF6al۽Cad tMK~v2 sr헇0㙬CUS_&cXNfmJw#LdFͻ@b-)&4pxzmP{q^_}Ѹ̈́^~O>Y h^}k-9όMux){|?}t9G\{=3жuc-[LzeWn u~5^c.?|}H+1nIcvGOhnh9ޯ{-Y%]xp_̆yoD땞Wk"  }W|gwIMدS56Oa:SgϞ;l@EB ԃIoA+; nݺ,(GPfFՉ [ mEL:i1Ew%Z` 'X|î{ſ3 @[rҒ7ͨI(xڡOp/[wjp5[opCe54ȓGbz|" w0 nˌa0'봚0iҤ mjܬs(v*40TOR?e HQ4J^h+E^\ J\Vyz8ȫ4בT J?|[XkGtZf"0&J9d:>FuwA0y_^S [)&MпUbSOcs>33tF{}?9Ι+FܰD"V$N+1J),xF`2+y#TJ oxګߧ᜔ۧ"JKUoC6gzŐTJnx^{Z|5'I񱋱Y~⍺b*Vnmmfcۑ )RG.=~~IOs3p5ԬWh uqrYn絸̂ҿ.ۃt--9b."P  (@..M ud妪8GK#zL:SV7~ \.ѰDR2g,.JȹbpҊgJFjTU_8gH)+mu4(_Y P- Cf}:{!#{ {_v%abKVnDRQUdfqO_7-:V\W5 >+NsЬ J ǔn[<ҀHgx#%'/n@9tW? H?jeX^zG90҂W|T*)evƆm:w7Vc?8ܲiߚh \^dV:l첳.83\O5t؈Çnv/Ib $2mGD 59b]?ndR@%̔!@)TϐR2PJn%۵62oxC R*-f@K+)U?J-M@LjJ)ʨWy ǯ#]>y‚Zx{t<XыAߛ\*lVi\. +;*N!u.+yIeR h`dܲ0g[Ί!Oo @1¢@MN#.jF+*(E2YQFk6 ^3ì !+f 繼K3z}w皥goo˴F1v;}U~deeզ*ߟٷeHրykm]@KE5y|Mck a> H!'q gIV[+1jD3,mCc]&HrH  *Fj)dr\A1˘UwNpjݡtRO rq0n/ƭxѥ./1ȎS'ΒZN:;[({r{||!|)͎  2Z|˗]kcemݨ<[ˮ|y$|:fˁqo4@AQѡqIOzJ #ؑO*Ƭ9Lu. =՜{O74ׯ߀n6hl;eU:2°s* PtQK{wmsX;g-W\G˹l5][=9@w;fu4qOoRrF]ٯ="KNFtg'H_>I|hu׶/}8J*޷w]mگ?R,6("sevM_[Sa}ZumzI|KGVQR_}eo`ѿ(I5{ ԿF%O72!?&G "S`縊Z\хAO3 U>75@}J@)n#Z/.A̺1?G)1Ӊ|YDo|@̽pX7[/ktO@K㟆[Z`E j/_AgƈT5(~QP 9oN]-8gf|sЭE K/Htq?und;)FCԫ3/Cs4}x $[DK ,qiqaN\@@@dFaqIހI +,).****,QG~)h(\x޳Y?f9OCS +}M;Sn9~ر#;|gr_qf.x;c@ӦB pݲv@y[/UI 2daq.hԬR>fOnG=GG6x4?uSO.7 'h㵊3^dc&Ģ݆8d_r.3ulk?R|4;y6} ‚\)/nR %1Uvqgo%^]X5d3I~d5М4  +i]4 9,oG|] ̲V{A놣r@Ao Z5 4Ǯi{Pq  _ PmVtA~eZ`T,Ee  TA!F)-)E)  HkAAA"   te0 ^ğ/V Y(A g34EghZT K_ ƬϜKd je-]BMS4${=]'du߻]:04o.t5zc@c/l;8 9jfKPʮg;uG!8Ǯ]{L3ixۮ^Dfʜ4}־Ҧ/D -u.Nn}O>q=3lx9===۔4ޝ YYyͮ>5e89ww(̕!q2ٴI?r$A]V11k\xsrC˲uM>k تPߎ6[%r?T*b-h\%*)H6eK2P4Q2c2pXIC~WVm5Ϻ5e}6`KR_`K[ ]1)s_yt >cJ!K8Q:m_iֱ^+l@I]rGmwr8LK-,Xųb*;N'!^쭈N E`4%ԏC0bʕ o-k;.Um);Z~Fr.R.~Eˋ[\\p'Nv>kAN'S&l]WGH'7v1e1GK!8%b\٘JT&e,&؄T,jUTIcNS XJ1~,[.\Iq0KT.B9Xj`T`E[n@^-5IZw;S^:^lc:Lh2n^6RƇ݉o2sE闻5oH LH F?өk7؏>&kp='3m#j\Waٕn@]i@GeBK#)sᏟKZ7e6+=4:g93tQQMLvxwl7múaB3LڴUOL-Ҕh\W9y:c}GA; }痵s%`|"teBԤ"ȯ Pgl\3~%ZgϘxo68}q kuG+n\ ޜ~ xF?pwƔkN0(׷Uqv✬wG^:gj ˒^8C~wm @;?`iv+(AZ7"^M8`a]" ޭ|o~EJ9-.~+llgRgi\3鶎çm컣 Ѿ[{AOO!9Fqz L/]3qm@s]jHR(Se* ~GO/3l` |^H)&hٮuU('$Ctxxm/l1ˤ%oQ`/Au6ʩX_`("'Ϲ4p!05%t(u弥eԦy N/L] huqM5ϽZ, AC&YX#;[noeټLvhej6UG긊3̓N)\EVuƣwf7wB_/{:"(;cA]52Gߡsʃ^/v.'3 <-O~zVʿx^V!+ppiqiU#;Oݡ=Z1gGGn3|cZ|dX;w& J&_:Xэ\ ;lFߌz|@M*V?'9 ¬(Zg3肷z{3ˎ+.7r0*Ѱy`j16x-0 6 `h:4Iè0g,Q T?ArN)+xoJd3Hg$;`04%st|KUl<}:|~v/DsY?ϾI4KbRd R%U"6Ⱶz, |FKt{7s[xOc^I}Bm>j::(Ϋ<椆8oӢuIԺš27*88F'SrC7d_;ꟉNce@C*B/ ά]%JBVSZ0T7ФmFFkv]tނ69ȹXf/2UIqvn:uwc&hJf'[oɦv.^9]1z狰 P1M`ճ ;> gdfs#r*:džWϿ|ׯHg;%2ޝʾĕRl,8JDXz~ϝ_jа"Qs>] WQ2@^"ᄀRpe*F\ S< 9kͮ ui Y7b E2:& d \>R+-g 7gIx?JNʳ#oظiœWpDRV=Gxu3{> i`HsPm!BOu=*NU?(N*-SVqq2{~¤KObu]<8M^Sw2; ^jƍ7]6rȜ:ߖ4':ym1ݻVB8{]kl{'Ȫw~Y)Lĭ]gAN^{dà&?b&Qn\rv@xbfVQXӺ|#p`aa^\l XeJ.dbX\m)6_i%2'HI] GE4qjUM<3*^[OXw> ,v\r_V$I.b44us0 hR$^Ae1^}gOB*ޞX8xHgólG7Nߟ`p`3 o,v߶2e˟UkMtf3;sj6d}3t4еըdio.rd0aߵ&wnݴvL[1 T"V}p2mЀ$l4 7V($ bf7nS>+Ydgon:9[:@]V=rsssssn&qe2i@E*IK͆7l1 Ӹq ?P?&E)rZж,]ٯ81F,T2,,,+'_`ڶˊJV/ť5:i㕯`2ȋ5AgG޿|pmx&ǟ]~1bTiPefLgDGI#~'>9'@*bPd?ª(`B~h@D~H@uI;k7ս}窖8žw=wQfZ?R ]ϓM[Z5EfJAwź-Pӊz:Z?(3v^L*SB9s9dN򭷒^f5Ԋ`2hE'w@P,ekϽk&ʭN5lJub6z$׍Q]5L_^S(xei% T~0)C̵mwfqOD,+$8oTv^/g@yD0cobCwN b6oR~r`g98U2uX{W>]twX`wwwbwwwbآumQQzvǃɃW{sg̙3g5NLybɰ{f]*ߦi*0xa/dN0qGwD5\GNٳ^.A,6@@llD92\aՊHղ [D9'pfMж՛EY[AɸT j' _$: Mro tJRO'`\C@$A:BC#% XPzJhľV!}UlH@u4Y ^Pe!Zid $E_`|.5 #5ZK33'V@%bVP(9@Tj= R^$eRKX:f ٴ\F0#W?Bx|EbLkU SG|"N)U>9BVQl|Fwd <^9ۉҪ*M"9B$^Tu@$\.tC޼L Er">[g,b 38b|LFpB +J_L|K~V,"%bBc@RCaP;P:BIa X\T bLvyCvxusa#jn"$!Dk25$'p+ =$Fa_̡r-`sfy\^Ru0 J&<%bB):tyǁoo ?Kp|iJ-<ɔ NKV׊4<$(Fi4  |XG!SpbRFplJg HBMJDR&È% H*-)e Lp$"\*8|js(V|B`1`ܹ֭s+Ae 0].o-S\ x7)BF|#=\<'l&cIP',F; 0`M i^DDwȘ? {d@0*` 0`Lʀ 0` 0 * 0` 0KPIDaY1G(s^HD"CcJ$l狢!H,`9?qDbB@bMŬ. MLLLܿоf~8 a5O Xbq\?r@,)ѹby,˜2y1{bS)1+111?ܧ@ҿ"d"˪zh2sѬ{c<1(:LЧkJ^ϵ ;g*^/24 QV{Z=SޭWg̙}wUZ{Ӫpvt<- ӽI2ٯ? =k1}Z➓?iIwvj8s卺pyacըbp{GgYi.L{ߕTcHprxXUt`scu'[+H*V "hJL\Gtê,*K eJl؈tBDAM<_|̑2t:!t>eRӟFU$AϿuR}zZN L'55ܲSS)z@VO_H*(kUg¤ &@"w\?pѿM*]BgSz8sij>MBo> ޥ4x%W~ȿˈwcrQqn7Oqqt'HZF&ُ|ͨ4BݪlQĻK)-lUy媕JroS;p[ul[ӗ0) ]qѕTB&HXWACF\n^z\}5ZVW"o7bz#֭gT.(VOa;~'8;׋VS8}e;Ͼg"߃c 3*4$~O gJ'4A%mF$-H<zf ILڏ>4c ~QW(ο?rzAޭtGw&*n1G~^Q@^n># o[o}@k)S:9=ܓXl0kA43%*&vD0ڶ||sJ@ZަCD,Sp?={y?rmzUuJԕM៾ˇRI3K,}ՊN;~ѕ8약{04 J Z8+"}Q|+e͇֕npgu{ͶzqW:I2Ai[ګTWͼ ~FR}0o/_|JE3.6§(IβL ? IDATuCeGXaBۖp(׺íӞaGr)|cly<-~[p^s.!A>2c!+Z E LiC޼ĮU:]E=XmX>_FËز9W@W̍,&5?;GcA?=JS{WRsi ޜr!}y(E ߆D-*5(A__Dq:@ܛ&7"Pi7o9<;tJ3'yrdEa[gZlkVki4Q& 'vսI:;m~Ҥ~VR/Z9Co LO!!#Ϯ :-7 }Ʈ_ݰbի,ް[1 ө_ί;u/u‡I_6}zŐg)+<~ϺknR{ޖnRЭy[{Suv.'0PsU 2ﯘ>mjKq>#dh6ހ2cBe~ı.\pFI5׃f?wZ>D  r;s}. MtC~|iU`L6 JmkS ٿeӃD5n=gRy͸+(A>5Y?eFf=mjoe[p5}ң1 Qvi4RwNʝr[U?9#4;lנT^ڱȣz|Gfz(?Y!xkWų >h;ey_-{-Z ӑqSK~39vr uX1Ѱׂ.K }rF6G3nLSZm^p@MDĸ,X_o'/^95G^hXOXTZiH ҧy9j7O).n +]>̑];x zTZ H[_q>wf{t2uF]?S{x:"~LӒRmz~)ۡ/Ns9yĖ#l ^W|fuGq<':9“o {("ي6mkz]-+JKr/%6w5Zn\w8`~%J57qo]}9iג.ր8bIP9t.-RRoy=tM\iw;Y:hҀV ٷЭWl蕲pknX1sS>3Zn~wޠg0x)kߴKm:yA!NsyaDžW:x}?7uٱs?Yحl&_Q"143>g `5JNxW:Yr9ߵ+v%!3b 3~{{ԯe>ۚjx+;֛YA!1`tyQELz7ѡDzvSVml Rh|H`|*M~x7E5/,"aϢ3QX[YWvi3m`GzbʤJbJ%}u٤.Fr:lyyK\zJ7<5gVWZaM:uv vQ!ͽ[Uki!1J [M4x{9u{?:8s5ijxgxqFzjL+! :;\IӕzYI_Z78p5/׭W0o(bL۫ߍH9^kB \¸hEFJ*.GLKO˒#7"[/o% ,-64sE1dƃKyT/I+ulO! et~\}&{r[)ǁ,/7T&d7mq54U#^ -~O'mˢ8()ȃ̄L~ڲc43Tx_'ݠQi]Zܞ'*QY 8ۣt"ElmȲ}P$T2քAtrls\&Kv,RYEmG-l>B1ʉ"䢊۶l\Ž#A5j$Y2;Ήe/ u4a;VγYG7]L??uokS~%>2"O3 Q\+ɻTvj>C@ų t  {Gjg>(o'؞T R/2lVFoSy[l2c3ͣyʉkNL RfPX7z U9S;4Z4sD=vZ݌/ +xx!Azgw6L;֕1sԹBN1>Ot@lfi)h|>!ǔd]RILL(J7jdlۺkoPUoz4s_k#*ƍc_`s_BպTQ'5$iuj.IPn}q։۞z<|+C =zX[[8jt/n|w}H Ҳ)&ήjZ4[fe30-N_z'x \#S!Iv;w^GVT%Ȉyl<ˆxLJY1tyu 77vU{7$s"?B1 Dk2ns:6 ,Kއ#ɇРO}6. ަ:8l4R;5(B$Y_1~L_[v.y+|6Wj-D?_OHq:&2F+.a 0 @6/Uh FR< l Pe,WN !1-NTҧp*5P, {ϴ,(/g`]O]~ҏ.ZZ„:i[Z= "#9 '-* -+KL٬v8M NqY 8H !k\u$\GCnaak^L5K^%aEl/ Q{̡S{d?p9o_#ewoO!9$[Ӽe{+nm}Y .a]O]LXws)#sei͋ٵݵC3w)2 ^堪7*]Utee!R lGY4TzsbN۷EFF?!IJMu]J>npɇsޤmZJ𩂳^ȿ7NզMD\Djn?0ɟ.&;2ÎFZRbAo|bP~o; {qcܗ5HL:#Tзfc.QGST*3nдyM o3.d|[PkBTlDWssH i X"' 2hӣ^ßjE\1%I5MdN;fєug':/Z&M$덪Wܲebc&hm WA/Nnc\K_`@f"&zmx )@ƀZZ E2UH}?GpK';krN> |'WI^I"8=M%kSDZ침>[0ʈ4؈ ȕ6 WL+'F> )Dϵy+Ti ^) qD@KB1,: $|70 ȼKgGЄH%Rȧ߼Wq۹t~? pq1pl,~9dj@cSs> x&"V\A MkU;WP\҂yUG,@Wn8ƚTp½\Yֳ@$Rx7nsLHH' rNޞ"4m8c|rNa,kO6nȽK ,_kOxZ޸k"X< 4#ce ?_ *6V\>ЁVͥy =x€d)WJnAd[%6Nu)_oYJ=N02"@*)㆖Wpڰ>mԳ uh`F:'y03|9&O$\Cg ͹\=Η<,q16*UJگ;T޾ވF2WZ BU{zwk`kRDpidxӎT+VmPZFOXƮn1(J*i1uXVp@E\E\B$fк[wʾt#䛹 XxI;dl͂ :Zy챬* Yh.\~ΞFU=V͖Wڤ Za5cק7'¢`_W77F2;~v:w;~J}[!Mm|+wKiJ|.ǂ:J>>#r b1EҎMNR jZZY Xmryٝ >k@]LHjԼ#:;7kI~`:ШmTU/1ZFvV65 *kђb @a|m+Afߎd6hUMxw lI5žnEZA- 7?XH:DOdp1<!f?aW!cU'G³u&l\+ܑw]ºҔ{kяp)|Dy5KyTn9"kN٠cٯ$7d j0`΍L?/#r..Nf<]TZOʹjԽkg}y>}B)Mߦ:4J:RgvnЩsvkQob3Q>ǕTL+D]ŸIm]q꾵_J^67yr?oױmo]ϴĵ)%y7_~H`׮VFRnźTÚBh vNfĐ қ49D,@E0}a;Yӹs)ZklkV^rGt % [9qmuŽt-] &/7|K$k1uj{YKg-x^bƎN.?jwȾC@SOmcNU(@$vkRǷw| Mkޘ=v:U/5hWm;. (Wl@AK&ΗRld`A@d<ݾ:k,-F{M{6Y[?9,rbh={1H 4ӆෛg !)#u/lߌ>հZ 27,1lpu;g~9~厐5pS)1Moπ/Yش9'HE D_!@xw/G~ΧvlDFVsIYzkmO`LR@|~G[b;tH;9uO}!-9oѬyȷ"PǦTUoGmݣ39<6<*FɌHZPko-t/0J! SRW/MxNW@jfDz A*G\tR`z@ ה @&5H`!hIj@ ȣOs:.OПސ- rr闉i˙5qUȧi; ) ,@o _X[=C "oM)\7]zmcS<ҸF[QBƀKAbO3+[Pq+oxaՅp%x ~Ö0lktʑU |¤s N?51L)bIOax֭bf-NJ^J˗zV9^f-ẉ)i.Y&(f 3ރ_BNI%.^1?:0G g_~J,]6Py6֑iXRo  3@:u,̸k7" A5f`7_g;y{$:d$AsLQ2`?ȺZͪ6bQ7ьFw.~+Tk7>unݺ͝;IP0` 0`T 0` 0$ 0`M50` j aۀ~ IDAT۶ԑEZ&uײdg՛ \]ގӗT}=nti+6m%a-޼k֍*<a5Oغsv}w R+vkp|'j{ǯN-ĀߒڹzIx =rƴ3͋Ξ=w5\>ט>(>͆>uЀy?q;NZ ->ͷORN9b+I HN{}]|ףb{O9rgƨ a #,x Ǯjx**υ4x9Ѥdel?߸z̙Z>CZ}{7.W$)ɯމs/=9_Lb%Nt‰U`3` 󐔠[&'pLFbדq ?}c;Tp\eQfΎc.^طfBjC!rQOH=Ʉ,~yى8uPн2cJ x -' q Q+?uFyZV;mhv}6|my&,Jb#_m[3_gU yޥ4AՑ!Di0?T53trmܷKWʳCzd}अvק}[= xQʃw7L-c֋FrdƸr){.z2`P(JM o~6egeJe F#)L1ؕѸ~O^Ò!5޻Hs'R,`G<5jL9TD2֠ N5޼ ~jyk5pڛ|q@a^v KBaԾSҮS *֥{46l=||%pm;~ޓakg Q89Tn*#uyÇڳmUOqƐ]6>rȒ {uvl[,{xgzjys^HhL:Wx[x|E۝fuWo7/-] kbb{K h8bGǮwpiCnߨ3"7Aڵظ`ءcGżU7kwȁC~2i_7c3Wo>g.Xb5j]s0)MRi_}?k:=N)K6GVǪҕn8)xbVc ʮ?2h>YgV,!>DE,O ,Flo PMVZ#Y5Y "VV .MTjp6V4:nW>"\(WdG?;??5Goܦa˭ܲSƷҐ{S'B;V/|\k7_8ϳZ:wqI+v ٿ}37zrRu2ϰMHn?>e!&n;avu̯o\ݢ4m  pJfUۥ{3hQ3wM??yWZMz61wf5@rOC/8bgޥws%rɒaju+'`Y/6͎m8j݊޵2|;ݪ; ]RϊF*IcTvUce'k˚`o Zw2QY?Ǡ}o`Inځ0\ܽgϳJ&T-n&|GN=޹gW|H B3^ܹGY]>ݺ6a!uX꠹ N:Z۫G՞ 4\$*4`P޽C>nz/Пw%0- ɸc \47G:oȁ#nOZ egZ%hz9xƝZd3xzژXm,yޡ @kdԣ+.Oշ"Ţ1ݡ2Q *;A`nпw ?6&֌o[[h-སS,ZG/G_O_4ĝɚYJótA90!i{X/![G];_6V*'Ы-T<#uX€SSMI_N.}}rJ`цGooM87$XY;۱Z[$"$6ITl=“r1rj9 ۯǼMv3gųMq6zB,MCj>z]ž8!]o;&.y<+Ub[fo)cQ}Dqݡ=;s.WcN'Oa*=4g~FLTN-W:!)0Tyj͐AR6+-ڧwcצ姼 3zܸwO. V;I伏 l2Y #pխ·޲'4d㬮 u0)[\?kfhiVIa!s),"YJ|v'O9ѥG' yl"7l[eǪo/,`d40G35:о -o\#NK:L Nkǘ7/–u"#niu{WbH4َuVOg73W!TB X.yzj0;u+%;tڹ 'CU)=9G&M4*- ,e>;, dn4MQKwd-o~ t̹ճRUI{kE<{+P֏tE_Fe B۶ԴTFJL@@4` gTRzs+9Iync `Y}#76uԦPl&{G9:9XvhA鴢ֱ42`9~%/sFOΰ.\fF~[ /S@-`VY~v:We.6)sdޒ~PD1PZ ՂI5B` c!{7qDB*e-6 #6A/WA1:6AhMJcΧTjBs**" xwD(2T[S:b¦y5׶ٯB:i(a],MTƣ|j2 6sceRkO.O/?L> 3fiG uDq @llg%W5\X>6ǀti YN=D.wڦ%S,1E kV0-L>Fz,)]ڹSvm#Du>O^y̾)r^c riɜl2.G9ThTcopph]fĵ\gڮ(S۷t 7fաgШm.?bڐhݹ7rK[Oy{`f&\p{U>ܗVΝY/Vln֦-Sq]y.A'skt7};qa[7M?չcD̚}vZeBM/ ܲ!ӇP\w`kiz9h=wiϘ4;= }PٳC3)\cfIku.ö8>כsxf#/T[(_zetfᩮH7ҁ>9`bBs$L23޼H|*^ݸ,(^qu4%:tk/?XimPx?Z_>8sN%4S%F[u ȈypyĔ{m(ST3BnUYLp⽋OTv@kdϯ /w[N'Sgv ߔtޓO(Di3?<9r:sw?ɣK;r=.}t\tu2k :*onyY:mjM|rYo_~RY ef,KgnE\Zu4sSľ}y"J=Ϧ$\EnVFllU|M2]Xu˰U}|rcӔKu@i&ҍ"vbggwww}vljb'X'b-ǂq{_03;y&n%׏sI!ߍ(Jw,:%1WMڔvY}cP8w㽭c wh$]*DyYv^|Ջ4-:=**uXd؜51[?t d67NS^.q/t)QHxˢn0rv{.%uo|Seb^,{ KB[uOtLX$E2UK Ez2Xj"SElfnA,%1E,tiPHd󞥄 .%2 !,1,6%Gw" Y]U#%%! ~ w޶j2}O&K,Q=ܽ"?ꅩ?}*HY1W]v3:9=%%&88B +;'7>qD+<|KzaBJ.kww2uBl諗Mt#w$ž8x亃!#OX倫Uk)0]6 k/,L6}*ESBtVkVɑ/=*"B QʔĐQK5 1a?ӏQUbWFXq?A @I 1oB 䋛[Æ M&Nl&BmNi5wJj]ayWvuV |޾UNJQӅt;tmΜ9?K|Mmzwo$r[Wgx:IDWy.]'m5N-P\G1\iP.L gӎoz"pttQG@B!BSDfš[ybcmBN _W1<p4`ѕE6wԹ) ׯ~^,~{x}t+ospBVt6O^xtf;<JFO$2I 3-nZ"4@1+{L*\yiZiۭo1q.mdQrFSS_B!O Pk{wg=Gx*a2r=5ur*T$C|z^%]~Z(L Hs.) 8ܧDH8Zd&ԩiu4WU8J ܛĵU L!ӻ t" YIYFI!B~Wu\m]|>pYh!f3ӄ~(= UyJ0&6g#iQiWu޾ϚgqOuPqEQdejTYq;ue'~XRH@l&MUi}g,~(PXATZM%Z]SB!BjaO56L"Cy}+trJ2 {K!揄KVR^Ե,4!j=k Bu]o<46,0:1UhWT8h>ʴ,!U.'ɨOj‡½ yjOjf#AT[}ɓ7dwNjWm!< S80wTN(6mްTdHB!B3R%nwz5^9#Μ0{͡IR"(^yxo._v=\$$'h7\>oEx݇*T$`N: [;}zpfFYQ# ,]pǡHtN,aWQGcE-7KfbsM >ԍB!d}͜hB!BHu6g}FN !B!|Wn_y,ODT=ni!B!|5%!B!|SH!B!B!B!B!_jޱCe Q#Ե^  nUO}RN6!~o `/w%c);|d_6lcZU2?jaÆXݛD\ }Y8 >FQ9K !cy+oҿIſeMŔdf=/9s&ԱY-޶O+ԤQI{Su8ѣIb?ua+vG9ugq=,vr L91_&i4ݬ0[RE <[RUO]bYxe;Y>Vlܸq~`.e7z7^9m 5ru%Q<`Iy;ӵ1*8HfWc9dݑh?L!Ԝ2~ϟ1rӫLtcΎUͩHAVϝ2ar؅-]@`nzw#$ Y,-k>{✍,Tc|'Z;}"ۃ@(8o5j3ÑAC>], do[ɯT7ۺfgrhՏ6> />qCo~\%t8kffy'Gi+p%וqܴ@;h 5 xx/~8zᤙ]ԟm3zW OUb5f _6z2!]#kNGnl# uH\Li}j9闍8V9}tce'.zqÀC'l[4+F@>)}8y΃ xV }2F*5߸9C75/?O{:j全oL3`@Sb ێY|ܙ#Zk#cp)q}CEw);}Kp_`lurXX=f׿f24i1̶1K|^N$;wZ~1vjvoRm)SǬ[Yĺ s/c;Wk OcLptaW@Z1pMFmIW_xɢo8&f]КCd8κ?0bthjv,qi;\>2c) r~t)gj^hXZimzűۊxL%`J2O1 `֙1g NfBW;Ar7C}H̪g Ϊ׌MJZx4֞S;+KbB! PS_%9WwMDCșX98f`7t{BJEn-m < )a: V,Q?lDm/Y1Nm2krw/Շ5jbL Z?yj \2؝xeOcj^ѳW)HNIKnR KK"9!.][` FtqUǝ[NZ>iak>aV X}9l<CGu/ ZS=-oϸ,.yN]](`:=ב3Dqc:py!FL}7g>!+~l@]aѬL:u-v խǰ9e=wEz <6iւ\  X :`ڶsmn {sxE/]SYV>x\A ʀCV ŽC2Hvq5yAZ,xcHB$Ug)iQS=^0mf /XN B!?.}Yђ[5Eӽf 46{m-,--o vo p~߳iRAvիLo:PJrԺ^}Gt9W9ZzfBm/o\ru~:~揪.>}э{8ܼp3W"mΞ9PF m;EUH 8Eȳ[y ùj{?E+c02c^v>gj1_}27YS͋rCoXAug oͷc)D|DfdXn#)>%fr{q*Ƽ dV6&Bnݺ=3"j?h/~C&O3OMsYmqzo߲MJ?H`LJK"ٱo_1}ٙqZ1F͋7uwvrJIV2?yb%,0~ʋV,qOQ"&Q(}|uꐤ0흂 Ҹll;: 7UIfr*5<)ϒJbJI29Qj+VlOeJZa%d:>CޱE!Br Ma ~x§E 1Ec7+ b}kf"/ZJO j+AfT*WztzG qiI jxdZ t^0$C.sW|1 "nNe%@ݯғ#.-~3VX5 !H~5ojV~WFm?aZUf:^`Νc5cOGXV1ѥaް429~ 9>Aj:Ʋ/2^ ΙeM >2q:u7 Q 9`go-;W{UJhWy>+uw[U4nNy獩 \S`Z`2M"^&+XVh\؋9׉2T`["2Z17}, ;ն8^hckxZ0][tPGk Mly6nZm0s2\&9+N^~5ħVӏ:ۤXMӒNOTiHB=8ɂt6>x)\U={rXw}pa9gSg$s:rT }9d^bT,qbT,6t!%A2>50ސ@@ b9)3RSrR]_:oJ!*fUw>|f{7 \BYW[@*(D?Uu̴V&u|cC=0#a #sfԦMыuipmܨq1{}RRM~isG"hybzL]>àVhܨq)'VYŁg.u25cj؁j7ѧ柛ҿNG!ɀaTS)@R[ճj+/pvKk&s!/k'6Zs9wڭaUȅ7zǞz*.{pͧ`ߢmY=;11ël;vbSɨw֎8JVTya{q"!{fVE>*޸~s.kզ:sȅK,z v7\\4wСOoܸU?{Yg*0nۓwn?x0tVi,٫ TTnTȋY7ΊC7]ek7=83,iA/z+ iCn]ݻFe;L$g,9sAj:5zmG?/߾ydv&5RFĖ+&B~qJh/yɝ&M 3u%Ϸ_qMgHgD)}&yPhעndAIZ\Wij]ߊK/~NָK]uPȆKBX.]tܵWomSs+|^9×kݽW2/ԤsV9HQ 5׻Eɧ];j͔UkW߾xET.?{{ܾv߀ M|n *6[Hx~@ E|xT5y{ vV .@2/y@eY[ϭd|ܐ K2ABZ.=WHBHcjBl4erx!פG"u&w{L|.0pX轣X` k@4PoR<ع=ˏ^kIKY=0H (ԭ%j~_| H/9dm#|R`Iߖ*:l=z}|ՃnJw5ëcu|Ё1 O &#o}tko^ۯUzN!.;}x Do,J.jmNV ۸3#T5]VTrO& X5Hs4,"2 ?hi"/;m':oqYr8S x ,p`P~Id#<V@WHys//1 m~pta6Jz-ĝo _w B!C%K2q:yelM)3׶u`^g@\=Y1y1YD* [ub1jQUM.|=sq}BR ymlm\,ta['[QlsC-@qw) xȼ/Swn\=\Tnaaa&f f2B&8`\`?  l67 ct&08DJ&^ P N@qXĺIq)گ;&⹶S1Mw |H-|݁D!?,%%|1TD-$|uM,W I @">~W[jժ }ru+^]Q`7KխlZ\rNE u9æ+丆SlUj\{z13Dŧ[,ۖfղS+ۊ,TtȸII6WIa?ꨓ5at)0k[[V=ۦyF%;0cxN}۵J6}hä_ؚ!k]yvn hn{n>RfԐ Ub,_:[tr#8Ioj|SEc\/ 9lr$k5{^L6%Y?i[EµK+Y+^00`p1I (,gbPk=Ko+ H<`fwV["S+lܼcemvQ5kތNj%LNǍ6s{z#{M+ub|Y'&_xg_uJ܋T]`3)Wz?X6׹/{-]aۤK+ <Ź |֍ _pvry>n 5F\>``\ LǁQ%J 6u* %(vzd0W|A[>#J22ǐAA{B5Щ^ 4K,\JުuIWn ST+g<@B<fUD7$x f[klJ47iJQdFZƠ3-K%u"WD*U pBmzFǠSs$9sߔyHL4-?W={iz-8iu K@G0(K++$ Lv@- `d3w20 ȁj3cfP88 84xQӒsTv]+3LR8"Fm!BhR`v1{cxS%;Fh|F/\+8yNe+_;|N1Im)ˤ%33d:R-2_|HBLZc4G'{]afERB4V/ M&nZՍBWM3Εe^'+}T( o&O9.ru;J *٦/^V3 /w/`źUa[כ7H3i|_iBt>l:u~Qj+'J$"}%KDBP{oc?Y9daH.nb;/jfC6eEjw]iF- g9TU /_ԏ|α5 fn=kOt+yŢe7zZNK!B(@.tI7}N%ksP**TZ/$¾ČJ9 ~`v>WnY^e^%iSvg:B2ԹM۽V.N ӖV(WX{We|R3*K~/9) ܺ?ɮ=u*!B! ?/yzRNSԂ3=9diMO j݉(ھ a箟Mm]>N )QJ\lϼj]̎#DvW5~0bUKo"b% y^ݥyztrNQx̓;W !B3+s|2-Wt PG.]IVβc~u)/{}cW#gmIU V B&K-'SGp|7Lb]jG_z=bzj2ՅvjϱC7wkP=:,*`&_x[R IڛdE:w~uM0U>t{2SUB!BnʴxS˨:ZA"VR\:fBR -\ ,eN^l;_< Ȟ8UjުY i5{TPMS sH|/֩}Ky%Њ}qߴZ}{UvȈUWU{z5EiH<|`>ϱj2yl5 u,!B!+@5+tӡ{ߢ(Zy]zebh)`;=m wdC }M,{Xy<sӺWȈ~;og@lx۟l;xYZКpiq1D.OuO: [ـ3&HJ!B53_7}_{S~bb)B!Br:B!Bg:gUB!B~B!BB!BB!B[*tbKjJB~,\Gy)_'>J7E +~բfKݪИ2N8p-{r_~geK^֯.,%l7nml^PʅCƿɶסw\0ڞȢt;cu˞#W?֚|CFڡ~v:8wbF:_LhvMk /c 0} 8OʁF`򮌱# 1ƪg. f-bMJ6Zi'mZV_8v2 5[gDV%:~݁Gx/4P`%?S_ZcH ʛ8p*%:v5w,o5u,S =¹f9];g)???ߡS/ߝe1pOz}}e:|S.RGȺA|&wy:(]R} e;-?XV`UF3u(S~[7s9We.WYx(B Dv?_ا]]&<ĥGmk+YU}o_il̪?u]uGW~OQ={}bz k04eEN25wpӢ5KthԲɳꊥm{`}bZkJͫ~9c[%>O.f>yZS.V{EE~-~v`d]$ϵEZW~.}+/btC,@+ؕQf:Vin5: kgvQ?96j!y[op4lBa7͋4,vaUh3jB2̥{5w-+A˕5)gAJt7Jqgg3Wx-*?X x3nu6jvvđ{ ^dOnhآ?t~Sa :>!||͎^\$K<ӵ){ϵN.x+|N.GM3sflrWp7.C_OoRŘ]1үÈg$ elPZ[='Vm0Ɣiqї-Ø&-1I;Y$^yM9 x/{o83^ N_k#kagg}\~'A5sH$,?6#2 p/sxVNVϋ,\v.σ@xb-`Yn5CtV %RSIQo,l.:/;[s;]o+f &w\n ض{x7ux)fPbH _;$xY{FjA]K^~}]Dvo)aeS@f" 9={89콇H>?{.,R3[3@n =Q-RNl=_;]/kX:5I-F;4Q̋Db'y 4`07R:Gϔj#|t1 f WN{pnC.,o/jaqM#qt຃˻:ۜsK9:aTfczxw V @,_qp"nBH^A=o;VL .QAT==~0I tmvlU/]ۺXRӓ qtR3] xh"M{Z-'|ӇhW W]rmWr\C[ܐêT7^ʙzO|8u֭']M@!K],?:: Yߍ V-N[qB$@q'J<2?@ -|NOO};lޝy3\㙾VE5 "C-۶R3QdD)s !irk؈1W6ZY-JUwZUo eK񚤨g"+ezююmT3}7CSE^%3dcf2/TdԵwݧ_V"[+|#{i R=52=U `fmŕp#ǹ5e)Ţn*Ӫܗ91ĥҵ ޾rb/\ Ujiuwo423L[O,ѢТcM>e}}N)]2Ntx/ޭ! ,ZMH7L7u5z!'xͦN Jn>(,W9 uTUyӲ#'Κ\G鋕6cYkz* y7ި6sQih}NlbiŞX6RD|QP,X~Lh!粓M%z]Ty{يgxym-W)=a  u!T3fTJ4r;zǼYfv͎RIW}NH,خlQg2Bk;E-Wݿ#fgpV$~Ou >3#C!~U0*u]`LoNֆ\ͱw@onGxWua3wȀ{<繱] N-3{,6yQQr(Ӛ yrnMmo(!e^^5FF PѿuΔȌYaaa!/͝s_DQͫ:&Nn-צM;H1MS@Fvo"^h#jD& v-ߘDyQcEAW.،|(J/[qxG 8V&XJ nẓyWޭ!盙Eȿ"@̵OA|_΃m *r/&~ZLWUjRSP4eT>~(ҴMU /Sj-vrnw?)%\h˻g2`v^Ujg.:)ڿƩU MK UMBغGM=nū|NB ~F*$C3y_^۴0 ~Dt^"&Ͷ7ɇ_}u--d1;LB7?zyKmZ\^kUz+f\kFhVhsUP.m]R+o)WO*WShE1zQuYj'OI-~mhY֒@XJ} ]C}T)b4I2i=yx eTzPX-ʼTu/o)1*z<qUW>& $-eSѦa]>"&Ӣ\Sݤu˰csOs<{j/bN k+o Ih(71+NZy00t+kaP=ze4`~m@x#ҷߖ^Cɧ\PІnc9{vaE^,Hiڭۑ{53p@(<˲(Ӽ}e=o5$Tdt̘1@1ǮzѤÿaYdʫONk wGQ ytsC=ul?nBwo*U\u7I{[Yiێ{PdfCtL,ۋ\1|Όc*%uܬ]'_jT|{X^6gF 7k{} uTٔ9Iz, &/"Cc peS{Y:#sf>-ڼQW6>vaIe>-/~vgfߢ݋3uuT)Wyq-8"6n0\j猸6I5(%gm% MiA˶l߽yR26.nvm`R]zÒ ~e2[̸kd_!ez߷mW;|᧨52sZMx UV6lޫo5S6FdxlH=WKj[ 3|}kHGHݜl6oVnP}xSw ˱6+[5h#~tW0(b+mP[v{n'!7 MBO ٽv[@ÀLr`wbrlO]eY9Zß>NPLh:*!Dy/N~/assIDٵ~o^Y&ɷo\{1,>=4)wo]pj/vg_e^n~t!49)&-aK"Cs4zFrR#_ WiJNhd;C_[|)$Tߡ#8lsy5o*R0ьWK-- Yg{gk@bm1ɹfNufX"ιs#"2)’bBҲcὍ!D*77->*69+';%6.+D)911n椈zpGi҃nX*1|-sk+N#JrCS&J]Ĩɝ\?Ȼ&mRgPXub5T ڳloz m ULz^P}O}ΊU|xnי7\H' wS!oS_C(]{=Rs~fDD&d wpKl}3Qu\`@Pq W6#TKώML-bS=JKK C>PQj֬ٺukЗFzWµҡ YXe+Z6EGK,޻*AJV8]_)UwvOUߊcS}_B}!>;!9ŗWq7ƽ0lۨ/`L9qc'm˒[( _H#qq|Q}o>2yOU b-*Y[iX\HS! fB!Bf-2 B!B/!B!0@E!B! |$ɜ;_lQ~*-]BY z9Jʥn &ڨUʵ;DY@a_L<,,]Γ$@Ym^\=B!' P oTE|(k̕][W䣁/@Psʔg4|Jm\ԩAmٍXVW6HNjFRJo2)5N_B!;wպ~rȶN䍳utsZ()Gigz8e};}[0FgL!ĈZS^ʡJyڌc?rOZ(bd _%lB!B),/lO_f agCd PTQ 璟_RbJ&:ŎX\#0Q &TǏr1Hyi=ӈ1EGCa + ^ݢ !Bw^ q^?FeZ` ;?=ۮ]IR h 67\f7*It1=73nrN:8^Twв3⑿fIܕH{f?B! P6VҜXW^jĶ cSmTYp H IѰ؈?5^@$ YqTrM2P\KqvHTglIlצ ol;L ,yj@$ d zzq𕽝B!*xƢS(X*ԯ{ N Ҥ?{$߭[[]r:9BD؎ۏU8y(YG1{:*Xq1WmϷi}þ z6ȘU15 O$2c7hxD B!Byaaa=G!BȜ,ZG98sB!>!B!!B!!B}S Ka> *B!B2ƪ0TVҩyeJu]T̆Ϩx!(]2S uDWoھ !@ZT8IQ2Y˗.n;)*aZ8{vo-fYks>G5( u-g2U[?^s'b} >[>|.ҽ'Qd\hb'a葉iK6vwD*&9܆}l#9A [3Ǎiپ:/lk @}}fYk Ͱ 4MW?&侘1k9Fo $c?ߒ5uS Zł@*=MN!UHָmrWTxNATf#{_~yWZy>8e[/^xdDR9}O9j9JNQb4<ֻu+|Qgݰm?O z^Q >U7f=;7SHlƱ b>l42bPHF.ȴ-Ӟim4"ȶ-?XVe[c+ԢTlI4Ei8WQ@Qا~!tKg-`ژ{!~B 8uXppTRBB9sɈ}N휃><4#b@R wo=_@ˢI>o\|-v vx撟Ђf `UϞ!ybOne~~,90@-=6=tS_Ou_tgGL'?|]VS~[jsaj MlZn'mms)'>l?{hl]Iey`Pn!ʓO %nTes܇ Ypq 1WyAyz7*TEFsPe -V R;7Inm هKUcP4 uk\k/M wmGT9Rr~;u$dws?HfBd14?;!]ƾ R.nsbI:ak~t_nR'&e6"1]NFb%*4vxQjrG5, taRLk#N PYVmT sR Z-jUiyz M,>Jæ{wt_i‚ɓ?G|l )*E$+lAe>1=MT6(䔳38ץHyq^*S4A|r6iF  @M3O֞oj.?73=ݪJFo%#D,e)Ɋׯ{{@ a{ԐZsQT*]vF{3QM(AL9Yaq"hnϘ鈟qtQV@+&LI@XܻwתV,ywP!5$S3&8c,d#zj6->r^*Tڧ8H(@) ?Q,>2  #oXd@r @(D8#GtX*ʄ'@EZOb,a={·c+RhДZj+&'Fu7|(D}+EUR{kȽdS3aQ JW$2z *z6s+7YG FG%%23N~(*#f6/$$<[pEGu `L8M;א@uWs}޲hDqЄ3˹VL2Wi_M]8Dcdqs c}Ҟ̹EHz.q`UIyJCN6P k $L& @9RQihAVH@I) zBPVTSC^%y>-&.SMPJ3}֭de5#j4 yp2 @L!TAmӮ]m"i۱؏u(zYQN+@ w1چjlR9t_7¹7tSgD嵧uˆoSO6vʪjL'\Zr.8%6f΢+r1Q ?Yz5o- gNx.\>1s,OAUȬ!ݟWg" HLDXsdAS7_ˉ=]zQ -V/ 2}!OFe<6fÆ/ס$!TrD | .w=`s!2욏5wv:"1s܉IL'PF(O~5ШҨ{v5]Y3ns IDAT4u~}؝XM`G_t9ͩw=RQGgk&Vq ٻϛ8 Cr̞>;uCW۴.U]Z7|>  &~'?B9S#I~*2 aWK9R=y~JJFP>!3~Si$ȝ)q'M /+|8|6)I:AjWҵO4j.OyzGv^t~qo650AjS>v rek!迭f͚[6z0wB_'LoG;MY!>-m蝽W>)61`EA}(hP2eB9k)w'S0:EaJe_nNF!  uj B"PqF0#!>E\@om!B!0@E!B!0@EgQ@1U'GQ@zy?3~tS4[3fق?aY iBfY&h(BH7ò,0>.|AaMKdkx7kꯓ,7u%2,0)ys,kz?$  >f I&|B41Q@ z 㜏WӸ}?w -s&', If9>C:os{}v,t}MIǮDL*f$k'׊̍K7Mqi;aոW KaY Uj7qi/_\njݩG*K _5geoԛsSAgƫB+9rwײ=w?`vӶSz=Fv£ 9'E~,)}Ak/Ѳ;tho@"Pbӳ3l;}dyvz]zt/uH0/?WC^FՃ! @(3BX, Hv2@--?0gXܱys4Z.G!YP : |b8hAv-iH!tiI s7BA$"pI`WNt)9hkB xz{-:r"/fvwLo̙i8~n2;ڗՆ?6V4_N BbWLKygn,79kE9r|<P(#q]ˢ[1%r7ʧZR>zR髗BS~Gti6N6*i%2yOԚN?s3^d6YT`ocJ̵uo!Y)+g[ }}'=G%<#h2i00zF\:\Yȼ˛@1y@Q9|f:! Pڍbl$QDǃJ2+(l^ Lp+pBоV;elb66eyْ rh:T5|h{([zL-@ޝJxTݚ˺o4)0jLP,m \(7u LH[AO_m۳~Ӟ`!j$eyÊ~AX 7l)@/l=3=q'uiZkn|#EsB=<bHȎy"i1]7k!Y}-c[V>w`ߥ40 y8ēqZ浃 Z;9 Dϯ=9[l3Vd PBs}庌z~z󻛬4{ &%$>ܬD1t٫²곉-4o Lݦm)hKSȲtT#cު#OP3uER(>7jzZVƢHӳX'kSs״"{*2')-@,w&!+-)|3O%iZ)Cdzg/CLrte)t9FbԼEG?x P"oY,'pMf7YI<W3rd*oyjC ܂1N̻)H .''o)''MKDQDݧNVk&ol}cW徻ܨScCC%"o+Zu;WUJ3>V/f(|!5*$עB?̘+; \`\@DŽ`. "B!!B!+B@Y/bKKKKKK1B!zղ휓j yӦbXszڎsAeyuh}_-hs-_c&Mi?kg/]ؼeZԓ?l )m:uкmZT7gw#Bɶ܊"TcKtk4}eGUUOz3柼S0pΊFd2rPҜu/5fRtuwG~ԵM nK$5B!B+@mءKT4lTQd'Ӥ` etE2;uL~Y&ȋ؍^~l&ħ u)ȵF7o4<8cwmS|dk5Rlݨq ,մqUY o\*4ֻj׮&ʔ^ԋ 3bμ3 ,:@UEnUj?iB!P wv&NM5跕&|?& 5k4{˾ֹ=('91[:o,eݸ7 }-7nC]qfuw/p=>yA_&} '<Tpx˫ 6e[<}[o8l:=FOA!cX  z#F U&;yH14Eai"B!TDX\LJԮ]N]gkzN1Q6 ȩV:k׮jm>j0JVA#7Mi˟mk,IX~Yi6*X4];mM1В[/箜w 28͠}FBSFviN;w):m\3 ٥U[pт\89p]Om7Ű!BOaiRWB/z r}TB_}Y ڄ[IqB2"gs[X %!dXܹv`_%%ta+snq|V[w/MN]@͉+}]6tcb&V 8RQLPkd~:S- bfl89k.B! 0 ş[a,Me}i0EvQ$iE͕zĒMqB1 Ud} /!>Zy }J籝'oDh}^ |tT JtLZ&!JVʼw/X8HPPg4n>^rlEB!_)Kz+x!3+) Зqza ccIhw6\>di4[(*yyw)录pbs[D ݎ_ɷq&ڄ1[y QR.)9@X!%Wz(lDӛ71Ab.O*T6B!G;jvMk4w 6<:jѦqf<<0e\c$c1fԪ08*d57/*&'Uwu6Tռcfj% -d<ӛ@ˠ}7D6eTNxp=x=;v@yc +W.{o5W+7(JKN+lְl\&Gc49Yr.&ƃ'ޥ陓!B9B#j9Z&>WҴ,؍Zfz|B Ʌ_Mlj~ svŤi !I.r_,pʹwZ~0omǕkWw.@5[˗=OnVY:ĕ/]qlטate%#mmA>lX [kgZ^#^ugE+v m=[,jS_)}U=1ֹ 6S7]J勾fim?DX{Tw[Tk*՜,fU!i.]:Dz9=>ʘX7F[OqJeMzuqdo@,41~ߺ0l6$)>v:w t`O/_7ʯЌ/]0DsµѲ}.:]{z>+~&p򺟷ϭ}|.n& -^{R@P^/^8]+2}t󢷏u*۰0j1oKo_>5/{z޶Vh[K56@,B/uܩ Z޾W |Nf 5}=ҼG*CVȽ\@h[n@̛.]}oُZ'+/3uo_ gO5D|@M}ҵw<۩b|}o޽rcr 9w"@Z'_;콛WZem%C_t|\U>{tܾy/C["'%i"i]gߪt^JWs6ywgUZ} F`\s Nu0nedu?e_w:igU;XKrm~f )ZYegK Sj(V3ϯj'+,-y^M.YVhm- !p`/[>Y3 cQၚ]ѣKĎ6YWY @:~*gŰA)~~>@9#8ur\c'BP(21 %4b}.ݱk@ϗ.3+37?gT$*b+W;T 5tk®CksFPBem\r\\6o'ԧ++ \P`tjR\Pn-2u_9T*Ei bm>R +drf|O4)zom*w$ҭF'hIr\aYP?z@7\.W(r@4=kKer^:ZZ3@ϙN m*WhTboک #_X2L&SXXUZ[H*WϾtrH H0ONcgoH1E8~\-qhװ[hP&CXe"`3[ :/=AbK/hWL5TfQa:V2XLꖶ;T;}ՓμjC\uճpk{|GǗR)g+m˖K^ˉAmk IDAT \H٪ӫ'i>ԅYi׻;`F%8D ;{Z60fg٣vmpƸ]aP~n9›Yj̢V#F0ߚæl:=- Ӧ? xD2 Wo*eYk=W`xx?ox]Y`g3w~MDx<+-׾R"YyNOMgWNf*37:)(}PtU',3@.A oϼ?{x~8 oRefpe~-6Jf"mAP}GPGf0j[s a?bo#`eeMRǹs16N k^EB޾G-Uŵ@[؛R K )խr6+^^S E~r wVr5xB:b'svDX5.540&BjV4Π6 T- \R ZQjAPt&FMJ)Edh@տIhL߈IKQD<*ިSUʀ ~9;wybU2l3J zHQ9uZyp-AZ&0b^[j5iuϯh:pJȆ+YEdZenE&5*=ZoSLC[/tǪ[9MZ3ks#|v OekIutͶ :=KB^_Z^9i3֮mmÏyTVŰϐX=3c2bC2Vl=>BA!%>#`=+bǜ96R|n:/FizņUcwO;Z#䍠c$ (@&ɿs}~i۬us&ĨKvf\V+ReԀɷ$={tNm>F{v]9ŧ.AвLV&v5(UOܢ2a_d3S'eҢ}/[vPXA3MV (=cp$mΧZй5ߴжFaSG_s]2sZcוk[X;.R&\s#fŦ7xA=n? y%6.Eauj-iԢ_q۷/5Rx_SKVόx>ûnƾMGվZz(tLUq"?]_$`d(sZPtF^&&#(,ͼ(r3MwUk4T/xezOUDFUƸ+i:@\zjxF^55J!*""#""""BWΜPEjWQэC h#g>{5GK: ZvbdnajDDdFGYw-tCŽYz00KZ~'pʼQ2^i$MOJMLLLL(Ђ &8TqH}vN/ro>d-OծZYرΣ A˼>}alF-rFge$&&&&d4$]zȡN=ϿxA%EzoS'L6g3lx;]:5RߖU]R̍#;b‰ +gYM9Lѥ6 u~튅{t}:OfݾKo2/#&뀂"hs_;˧E$W R QgNU-p~*_}RVtܼ!+* U+9ҩ>cL]D+8VpXY\rdsmwlkk׸=g[ST3hC sT%V9".af4M$o0 -l6kQz|X"A Ӗ@ЪJP)9 OVm:sBWw zx][^8##Hf~yho^jӣAGV@Yɝ{0MZP%r+; vm!ftѦs=x*RHmv܄$p23Zv1@\'p8!O@$ʘ"֥Nˑ;^tzZhA _T|t‰٪ր%M9f:ENQRNBP?B|NwXХr_tl ΍~_ @^. \ a&*ʱNɸFҐ>|S8_J+QwH1Vq1"B :Fo374U7֋wW%iѼ`@=(%R芊\U` RwrLд ,|PahU,K|K@-LrC`0C:=Ƭ{e||\2̈́WZub/!1-2oOh5[7ݐ[hJ___1ypˇ@i-̀־5 ɰniM` U) U$JZ b{ZUw\<ʅkU;eXgEu::Z1j4iF%T/.Ҍ +qlk2S]j5ޏ82YafWkyS55{Ob.Vh3tگAk[xqj] G=4߅F ;wn;91A碕wn߿Շ.4). U,z]waovoX>$CON<5ʈ|Q>1^ >Xr㫽C^G4QQ |Vq{?ʪv-M:%̂XݱUe5Ï_g^k|[Qyt]&iضk\.IP1Ycӛ\Ƿէi2Tdi15qn?j\f{82lͪZrׅO2n=z4qէ t}܍3enWi#.IuTl] yǍz} (E{=Gn΁x70ػoGhz;]i{:\8zUm^4j_=ܚ hbe&0?vTjc7S/y<%_O< +Y3u'L%{LiwS6qkQE=z>#Ul>wҩ ^/uxvh'^蕇V54t7֍Yc|i.JWQcI~;mתW,?lճ|K ͽ;'2`tY)irR. ualx\a~nbDxV @aҳ~jd"'m^NVLL ćDŅF$fU̹ONW*թyh \Izgt R[:oP@zAZLYT(+OJMW)I.痴PR(^~]rxF/>}Ti3dL_e '}AYARؤ|@h]<`ܫ+,zqR$u1oyV-zv7(WRfD%gE7/"uf;b ЇOrTyq)C;̞Y=fӁwm H"$|y:oZܰq̈́)k{%yU{=+iAZ3kĉ7!ƄЀ`ji ׭aOfe濩j ܪ 00uvuloNk@dQa%P]&$Ԯ`ã :W2,@[{'[SYfy¬rͺy̜ RcOaayGLUy'%(Y7OG["g'nVzBԫ*Wmh!f ־98z`\p0US>P=רgO3A+uk,:y5|hܿߴCyc'UF/uYOr~gNy ҬiQ~hOc4rjFZ&k4:;KݥHCIyuVR OQs6OJ1ljפ5Z7=8 Gv ~_9Ė9m"\RôKDiJΙx*>GN@o IDAT>Cj2o\!ll+I@4֢#_Nu˱IZ"ͪNDKF|iG2n9vf#iBDdU'f6ΟK N .:}l@Z;w=_kxa7bJliiQDeom6;ܡ R-=8ڽt'v>q.$gFؿthhg~i>`),U93%I?;*rZBYI*rmڕ\a24!i]PxiI+uhݼ)_Xү\5w1OҼmM*Q^js7υe$v&{!0mު _( 4] VnNvNBI=WXH $ >7{e oghj4dʎylV8Q cըUGLySؐG/u(q-%P~s;ժbgFjB~ڏnNƒVyYOQ5!gQ# ,H$1e.!5'>td^ t l@nBZL˳w>zZ4D ח՚g'~ų3oL WW}zˈʰ +``; &]=x&`"05~b=K;ѫ^-27WA0hкi%)7à?"i[E@U;hkc=|y&IwjR)22QΫwhΒ/}p9&ͧ7>iƧy( wEs=㷩/ :1K4 8R_~gF{8uO?~C-8}qb~ٱ{ ox$˯r0pG6՛6)Ÿ>3uQΪjruT9*Uox$mX +TSսaAbHrSc@Re3;c<'g,,?uHӵVޱYLzf@:o>й xl z a^`ӒS3i0ɉIʷMˡk %NZ͈0tpt;+LLN!YRbR\r.XkM:T*nzZC^-’ٚ}WhkYel@Z}mGj6ՅrϽ+ <':O\稆m% u[|1:sao hi ;:%Ԯ?u.=?]Vagl;iA ~.;ܹk5 pv׮z_~0_ľC:bUЗ˘.a 䨐rgAeK~5G"$ج%Ǎ۵e9ڿ.C#w/]//WRڟc TD3^?bu#[ֆ&yvY"둒X:CX|%ɑY/rcnZY8p~~2.c*V|'@#`$`0ޛ}.@&K|vtt:<8P[s>ox *x@ !HB}8h%s~:`(1MmXѥpB}K=Erc=;fh%R. h Uiบ֑{v}UgJ˾i>Un5_Ύ]~{tfaSyOd(>aËTgpE :im j @isw.t ]sHm7c _lW;XRTb2=wk+Q9:`6n] gv\Du9;O:Vµ6%M8vNvzL Δԍ'yn4Nb#Q?/4zaRzR'! k[extІ@#|zybL[77ecy3 ̥fWy8prBHXXBO0 ԹY}֜*_\ M99g[OP@HY77EϳM;+_>}ֺcJ(~x5p5sn6pn#M/{j^c'\|J_tucX~V>9hEϜec9H]VIΕ rh /4veaÍ}^e"Z/yV*ǗvW\ lML~yP?"A?%>xh {QvsPj4Chii$:Y>Ev.f"S k)]?j|.kM$dc8v1A}7|}}}{Y Ab-CTCӆ>aL[R֟*FD]"]3``u(g>{O&;^pxlR\%: >8Fw;Q@p'?dεMʟ.EӄY;T x%w^8m職;81$ve5j~콃tZՄO7v>#+uqs[`| GIgN-oK?QblZpKMW܃|<5;=,'SGP 5g.zJ[T` )8l%h.#s ʒ/ ^_9mo4At2O3+z(]z% W@ }4B$0J @wf aG)O snJNuZ/:||m 5/'$WBPwƑVwG \YD>iI|J0=C) Z .OLJPjěNGEwR@H ޠe0w}BCP3֎c~_8 ufX~>>5Ҡ'݉NvܐHm=|óպ~X}0ia)6C܍fz+Ghb PU[s;tfJ!VMJFAE H"ɏxw\M&o=xF}}| ~2Xhub .C]ZYAjLW7?I.0 nzQg} ,rR³ *%D|$Hpʠ~3Ej\T!d͚ǥΜ0Abͪ7rIyŒOKDRH H$E"ZLn_\ܹмA}K'88$9SPKtj"(ZxV^z)#mIa@d~drݽ^"![ 6MAQF1LL# ̾]΃=۹. D&7,4hҶ'[)7n1{󦎎o).q xo[Z$x|S,bjf_ׯP?jIJ[2J~]YP$mWfg?r8#.ǼMU !ر4FЏm( ]qG zfFnfbԍ+ti XoW$޳*Ghƈ,75214o>77FP-FP^DS,־*jCl@s믍K=a=[Zr~'G&jsg}QA%:p+/]{Ӄ/i}{ol!x'#_hZZ?u^gwuXs/^:U%%.ZY~-ZcRk`WG [>ݎ\urKϮZns8-~4d e]ist۲s?sȖN hkW[ؼL&nG/,Pc9Բ78r+'ȦW/Xzzr=e8;6STm,,O^@zO 8 6͆Uʵ\7v4Qёbv_ `CB&(Geb!={fN1cƌSgmHMHT $7n&RdI.}'-1: {([yNWynY^k-:k٦Vr솲&ka$9ma̘uvxߥfoNYyq/: IDAT=g1:m㼉3c︦r:,8v w&KWtYϞG&AA"ia3Zz,rѝnόaQ dLZ0N(o0;b/'Oyd> Pon2w[YUdhlZߤ$uBY{GO8*Olv߶5ۺWkϪ{3sΦ?/c:s;+ǵ)ص&!:,,,ԆɏHy|4S|91[?);u׹kTx^3yZA16N-NyGZ\H:QO?~u30~(-;.q/Kgㅽzrn?,6s:-?:J40ec[sC}?JNS:2ư%|wNl |;{XlnCf(NZ0IF:IH9W"{?} Mz|Md5koL8ǥl>xOdž?*Twf'FV:k=qgA`h F \RÁP[Y/3VcbnN=+74q|bױʩu?:o_ʍr#:A-c\h X*㪴ZFd,#Pmmly:9C,8+CO#cUm+.¢.u|haBcv2`DN-7>#kyGV񝍿t4|Ro+<{,-1`aaT F"(P,(HE ],VF!ϗIέw1GT IRRGJNKr'H}ǡfcSiKgmӢ$Luy ~(DžٽIyj%)'p2ڼR2WH4okD;UOv9;\th3bbx;iֽ[͗7ݎw\1ݍNi1 $ py/6%#6Ɵ-@zF[J}7BnhlP8ode%P{^?Iu q[$#ԡfV=: t*W6tv 3r׹4@/:u,eaժ]>R`X܋2a;hХ[ZWTC>ЫZ5o^%ª>Gj5aq`BRx:Ԝ|VK!%WHU"!GݛѥKkJDBhR\A -x-)|!qΉZ% :"/*O2fLnP\!TZɳSkQQ"oo`4YYs˱ƌrBqN'63\-%)|2IZ!gdU7]$ n!RQXRZ($ÇZryyf\r`e:U0pp ֵcǎ}V.7JqǜK79kE00*/8(@@( g`ФhRG E^"i䰢"59CjYB#18&P@-b[Il"$\8z;꣫G8|ƔJ~B4q_mi}fƇ$c֍,0ZI>NfOP-k1Mj剥$h !PѐzN3'+_*6cƸGx{+f&}svS '|.E) l @{vl;v#7/Uԗ?%3TC0x?.W&k£6?3QNKB GKE#UȈA GYk߲YslP"T<};΍ 2)I(J ?o\9ݿcӅvDHM sc_t̎2`H7a#~W}{ [rIoh e&y'ڹs]=|n꬘xprk;``aAe`̏I4ܜfM,T.i0#S Ȅ,K} 0eÿ,5)] 槾zU򅠁mb2*JVAE?R} 52cX#~fyxU3 53}uEaeY*-"ۃܰK N[ဆhnHxr ӂ {R۟v_r*$66>}K-1F{~rp@5[e˕~)։G֏M$O4?]`yL*qG>G~ ZXr)3!!2QH3U;_!s4ܩ[iݼlķy[&? 3f~{}4ʚ.61p{jS^Ο7f]//uQ:٢y{YߖOMv ɟ69hNnuԋY*Sg <Fom#4x7+w6t}۾δ9wJAq] GvY<`ܶ]>Ӏɧ')@H l-w䪬+{_=>aУ.#O$Vyԭ寻;jJ,s篽4ۖK'fH5gGϼʊ̨ٳCO:M?>͍O>.-ƛ|N{?Рƕa%*``*z%a_mVQz3Ʃo7llS]a{kSٲHW]jVC}jgDYݖ80@lɼ *ij6ͳ"K+k5jR]^^5 $I sRRK>yY@} (ҪV֍}toϏG]1\ N+a9N/ ;nݢ\4^>]:.>&s_dlʂDEܶEm]o&ܼd{N~Bw4pN|#[$Y͇҉~uڣxs`VGq7~~x\q߻thZ# icwzY𕯯lȌ֙"kNS?Dpu^̋l};ߞ@%f5?ɥ-t7?djzYޮN*$IRljhbn?.57w7ݾ`&6txq%G^zM?Z51Q?wyݾQ lDHUyf<#<7-b }ҤʹAsRVN{wiM_c;7{'.W6ѱPyйlgr)R`~oOx3dyAcP _+f/O_v@RdSO.dSY'?65 Ǩm &@e``````IДR.cf P~Eo0bX,/r`Y,,6P, D,6b**ɭzTf4g e``l?C0Op*~З%)˂/ H8!8^AK >c?J l(ߋ0 wӊ-.}dO>PLOJ=7W="p[n/5MެKaЏ;Kn{SQ@eUٿZeԍ>*.xJ>c/ۃjͽ<-@zXSñيe)4w`xpIm>]TZ',l=-< `ƍfny#菖)$}✔'zez|5IL,^H{肎k1Zd`V:slj"¨f.lh_;Tϑl";Iw/SoF<,p7[MMa \]ڍJ'?s٠g+Ɗúo[ˊ7bKkUg^7|XymNfOg~o*dzLKRx}]*뢍+ S ,qAϟ47PY{83$_Si6ټ 3fC/ѐeי5H)<mmN/L-ѻ{-a OvNKVRnY~US;\qH o3R<4L~>{߇gl׏tJ7+|y*?eMimpɰYCi.)O=__&w8ezΓ:2j:?Щ=;;gS̛]q) ٵ{p <_7}f]x eTgQ0ljy|kt.Mgwg4 _rx?cx=.Ykp"%[6"Hb X%C̢X"N( 6"x8B$,H,şDcbQ< BD"sXQc+x@yڭNվy B4h605q{rpo.îYgF`\-Ưln *>{99}]/K$!l!e!b[bUX\sBD"['S^nş3Ӳ ./0 h)q1| P=-M&T|aWGV>:Az[9n 6^M^rVGٙ|R(20T2J 4NU:a,JQarmbĶ$da;0E %MS ʣۦ.**Qu\G3-#51?\b]]۬l/w|*!T6:XW9@^Ҿ{w)}Ԏ1ֆc3Q Sb_ǁkخI7rmP"8z+"n5~ᯥ^^5CG>.~U[TsĘC*@u:E^ٸȯʁ&A+iG'q`;^{Vݍ8 ^ċ6Z.!޼zb! 6P4?iuKEAݍNT0,6߻Y-v 7nAzk@vhdKؙQnxj1oZ<07y7aġGwv|n΄FYj‘y4;#Cf|Fϩs=_&ٹWrԞOsVw_Z:p'K8E7=;pԬ(&d>jˋK2j:aL]D ӄB*2nGUS(eܾ6۾![y_P⒚ҷ9F#S; 4p]x+4J1A!Y%~Om<ٻb(p@8rDp`5j6`j(_hY̱WXu:d^#YcdF2ĭ:̟hVdwmaZX@CNT4[O]0zN S^y|awѳϢ߯c7ecֹU\߀@}3:@!*od-`ѭO%$x>m>!8B6{y_a"#[2v뎐M m9O$7ێqcTa#YZInmԼf{#}ƵekV\ӒE Z 9 fd V!&U2Pc ,pV,b8:DvjڇRaUseG椼-#c[锣 a/gx/+|ա)HnRZ5 2KWZ_*0 U.f=CE~Z(J<Ӯ1 Ħ:f- y2d⨈rZI0Y7SϝЉXZal* ~ x|y3Q`֥EF}ŀ~e=}m6űmo(P>~Gf0Ilks-s|]zXo i~$\\ȫpAq)Z_zS$*h/OI(ىqR>Ȩ!`<KIp4n0^j"v]ҺAJ>P}ꉹ!ӧ:wV#/̢IFPoNo_=4Uڮ9Tӎ%8Oeu]\:)ҨfFenoߥq t7˲@+@5_W=I#L4npv½ /]} VlǍЉoh%2qsɝwQ&XRԴ9WKJ5=~|+GhI@-n,4㜟)snΥf٢6^j{U^tm3f<ʢCeEZEzkNZV,mڢC)"殺l?B Kz~8x;xïȗA3쌙"8pjȱŮDc'\8s9lD+ ߍ_^fvHz{ֲP` Px9_qۙ= U_GKAR.JM~|1:i]@lnUA@ʔYR~'iZe.n&^뜒/p![lg2a51bǽIM/o@ZyOT+=d"'gϧozM9[p!>ȶ8:ڂ3gv \/N-*;̫ڱ3"@Hs˲绍VڸD͉UW`G zjɱ1g2i0RӶܺ6vEozMЉ]%˼/k|y+KL%K" 9ZV>)Y`Z>[uAnYH/Z7=h9]"s؀w_m߽hC¹ 1^vI![fxʹ. &wjN16/_0dqqzB\o5$ fOޝϿkG O^q64m붹D^>PKCyG iNyu=cOҋb/df uyKOq7 9݆`ìRS\>}Nm?# >Q_^fq s[G< -}qѾت{W=jqMDm~CZڻY}M3'WV5} ,RCR͍q9l :Jï=@e``````eZFqqMv%{ZVĬb```` P v~r;^V{cLt? 200000d(Uݘz```````na`````````````TR% <SɯJH(@B1HK]A8КݼS[״bw~ȪuC~(${@^=Z^K@ f-V,yTd;qZ]ݟ2 qE%޼Ŀm"H&=Ʒ{J͗La7ϼUuoR݋\rnxRߜgYR8ev#cTм甡vjݪU~TFTb؆NԱ{y~[|; {}rLQ0&{O6]#礧a_yîm7 3L>V+οu4np}{籥Ӹ:7&w'XޝZ7ύ|oL0天~ Ѽz۲"_i*̭j GO Ҽfvijluw:ޫD @3JzMg`(& VNy7 }`1K{nS-.0(?u]H_otMESӟ'톛:Y{c UGU [;7"0YԶm=K@,F6.B+O]~g-o:ڎ-7o0{J)i?ԮӮ_bLh^ݽޏ"}sWcþ< %>vЦf/I\L܃{;}}{6m T6'rݎP/޽f5S۽ySjҊ)mo-+ 2oYtsڈ1C %έsz8W D`.myc6GwarnqXh9NôЗֻ/hx!ݱT[k#+k Ϳv8#92Dy?NnSs{%ܹ~aw`Lo<-uG'0k{ټew[~yOz~F;k`_ԋ@V%1}mT񖣁Utk7.pONOYrgvS130|!_ėcʼ^ɼ[I{n3o,RYvO7ptl؞G=j8u) oO$pWMқ6yqo*Zvƛc4ьi|^B'vztN}l~QQO)e5>,ϩV:_;<(]ӡxnief^5o^FGR=ߓM8gZC45ʙ05r.Ou [\=22r;#(H:Yn m?k4z]zgߤՇlzӠોxw6X{(]}SiAW*Ws(8̾ 6.SogXӲA[{}{[Û$.>7cj_rFrե,^pCO.0oiw_q*|Țsϓ65s6uW znBeEm[.lBs J-p}8E8~ߑytvwI.̍aq>6gm sSMQ~G:61q/ln zuD JvN}-\?zz9t=ߍ- BZF{dHWGkQ5Y'(d{of܈^TSމ e9UI Z MwwBwlHwǒ-;˩8pmc+slkPd[{9z9B)M*H_gD# Xo$Bl@SVդ\a!Y%UQQ6mٵ[f2[C7Ƒ?FflxX7s7~aX; MVZ:#F,Ʉ@AFV`:u ,}V̦u"hp^kPVmG6T9jæg/߹2ɀըmƵt3oŪ,]npS퍗̜6dv#CT Aӧ+fm~ y =gߥ6]@>pU:9ւ[NmN޳ut۠C,K \w\;śŰ`P?mid7W. av1rF9kճH ٸXI7u~^횜IN|MtQ@`NfQɢy%r}O}dJ ;u8ЫK~B#4ɭjװ%?{G XYuoJ lj%}v9S$rk֝3_.=kխ]͟JI(.66ke:{{ڥںu>g-[wXd~Me,%e59%N5ce<;ً8wtsb_{F<~/ZP}c/cjrП]51i!EUJDq2NR*J d_˜'P717ͼR~[Gb Jp2_lN1Dj>d O or+$fVv@#vzldՌ<.|L~.2oVhmWvsOD@EbZ9brp3}Mo`ciAqmD\8<N Y>eBBxod$/@1G~|Á~ΒN( hMvNV\g[e6uu:T 5-ޏQOr0&-)7#E \:}ձR$,owr돓Gں"-9 a.WIɡ]Âwu\諃[8A+*?I7拏xпc-da<.i],a6nMzZЫ +j.tߧ^ݯݫFͬRP&e.3w>YaV &VomEE8@9=f,{}~ awߔY<2Rr>Hr QI'I.b2>09ϟ2 ïʗ524rZR:0H=:ZJ00MzcS  0+ +}^L:@fB5m'ş x}fKw~dvjie~)OJN~(=#wE;Y4M~6d{9"چ8ypӒSjLfզW {n:2eK\<530Rx_(jU.^}GVAd|hyHLǷ6(,H!Lb,r><8}>> gF:^^ote>ڄJa|@(!ZFJj dg.2Vձ:|"ACG{@YtAsaOk~Ъyid2`l{K{Fɢ-`wzjacK: 5]LfJp3Zp _pBAR7ϫ'/璜\7U;JW RLXF\A rz#Q# J__#sIM^xk԰M'ztL)cA{N&2ïǗ*޴^ Sw-l_m,-\\fscY{S IUNDw2 \Ϯ> ,&Hڸucd/*N_&>T j6x΍el!mdmkg_]hr˳/JCz*[~ݷT#?gyr#=zլ1(~\ډ+wΗWUv,ڡrrrv6T?{1bĀ3q#&v.{5u;Rvc{T7.{Vl`h0uv5AС]z >bqrUQg-}T"~{w)[7{ԃK9*UUij\e7'™=|)d^WRom25.()ʐ׫*KDyʲA}Y[X8yC|67׬es{sG˴+3Yul;垗jo=8Qp cq جNJ9*y0 p?X޼م3G3TF(?n gL(|{{Μ?qZ 0I:& ZB2FTɨK ?۔U@dP (ДMƞQh$PKhV5l G9مQJ2)>=G[rte2Pz4oy*sA2_ӣqڎ.3bk74YNW|f 0 Oe{(4xr] ԇL>wc&E/ ?0max>Y$ƁMFIVVzu"`\i`k8V|T,dgO%/\_8fݕToπq6,JqȊ9B'Nݲzf3]ښ#WT4=°zݷXCaN4[F{pݘe3ndX3o,l7wþTΛ5#F|vӱSRvw,`Ù˯H*}$zi]/oyIc4"uy˃}~r}_z$FA[%ʄCF,j[<5 [}w,ec<-A5?OʔAj=>9`MZ5sOl]l9z Iዶ˿ҧ粬Өy 3KXۛk2t֜jb#7^ѕʪ[lWl4FvUo.".Wփ߀ -3+z]}f(h-Q0ÚyG^0d&7Ε:0dFo3/ДcQ3{\.d_13T}!!UяBu^2gD9|%30-GO- jy_C' \h&/wLtʴd%00cG %)Fާus̉=ZtN;B\lM?FCC;xK|BBo]w'4کU4q7"{;(Ύyz/]̋ ȷw{6x V/wiRo},y*84]Kq66\  r']NZFeQn靐{!js|B}nnkBʭ9cyD1z{# ,<, U,s'4 8`|M6 ͩ[ܵ?<9woqP)Cn07ZKfibwj!Th bF/8Tl;F,ܦUkp[] XiD1Z!|c'i&!ov^B찎p+˟_<7ԺaXM:u >gh!z{+}BP'ilfPrA{ JZ wpiXc|e]~*|~‘#˘<88L֎,uJm7"f'|Ί! dʩy],,V[@0Cw'U u. SQWUyz]V]Bcckr4v;y{oWwSU\E͵%5Mu:C6lw28xjn!x&cL;VJi1x㤩@ɢGP_go{V ;xoBos7|nO/4^C35jTB#|-xeǴ4sg8>2T9 /9ue`x+I:Ac uxS(3!3,Y0<6㪷$2ҍDļd{Q% `:v))j} v++lEP*)WvAML S:ƿwMF`O)ݎ_J27Qx /8,% ald?᝙"kxiQ1stGMrߤ@yRo*%q9%vt4s6 9I\a,TZػd&M"nݦ"Ls_-Ā(ƫB@X% lWq:؆~icD`4r<%Vr3E2>Wը͹.~Suֽ8Uԋύ2Eρa.-kfPI\GWG[XB8Syv"m+6s>6**>DH0o5aJ (7k~q],į#=n$F=7k1yrN6,%ȪkV ׾@aDJ(/Zo;Vb*+ʚR򚒼ř5bӆ9tmIOC:;b^dK(@fݔj^@ڤAa88Z)'Іrk}Y& q>)8E1BR%݁#T/1L:cfſH$0eVz8s=Si6&¸Sۗ?LegK+`9)T#ގz| 3\b!'^.:_PnzmFlD5z̬"-:7]l ]07i|MMgś SxL$@f]ۜGx,9j$+5#p+qӎuTW3 /͛5uΪ+V450?SD_VHܼ~XA.Ւs\P*?P zk\ B96h;ޟPi28}e)j σwIw=(!Ҋ &TZJ?8r(SކLۖ삌J @I$[|s 1VWf"z:Bട; ==nK q osHoڕQt%nޞ+`5H%];ó\FJo%8qd&*zUw~{WZML,_[gsknRdGvKΑ~lppxy҈'9ݒW?~(򗳯dn3nau9ޕ(BX9Pi KZYy)@:;zjر#ټu PκUw 3bȉg6f~KkSh?EAP@AQE+SIUÇւ܊G"+*Kd\Q⢘\v>g°^Uӭ@)/N̫N YIh:LRűf3EQIs( 2qC@3yU%oDq|]m5!Af}{6us{οڹP&*g灊+X\ [|kW^?t=f;@0Yw }!)CyN3U+&EHWž+iiN[?1Ԁd3 /Hol`$j,ؽpGRpdȬ޲sl|.}'ϸہ!Kɯ.ܚ!L9K^_ Y?o>$#7Ϟ6oٵT_6:s~XjjZ` @P$IuV4'ì{]E(Bi ,AÆ ko˱e6WPx*STN^*û:1;6i+j`\()9)))))>f ( H %aNS OwBT6':QR@WmRTT%v=Y.LFBD6Lj0i6uɾʢO;a%/5O~3{3{"s*sD L%M6 XpG+JKdTDNUʼnHY))JOsSC}&@E{ݾq[o Y qe<LQPiVQUe)^\tﯛTqj G!z%Rzӱ[L0k0 R.k(pXL9{Z UDN!7J!TK 0I*rߊ"LUV ڷ_2V]tڹiA_ٌm'lJ%eEɾ7fv5cmGH"JV TUOSK%)Yʖ&uX{.ܻxܯ.Tl4UT!a*?w02KZ^DM"-UӇ" eemۛDH)/[f,@L]KCI_Wd(~.M3] P;nՁ:[P2>}hsDTtb̈Xy&b `L*(*/>FGɎ.*o2A 3ee%@G*8d cf8 IDAT| f yGYj(fɲu۪sg#a?lL͋Q(`ǹ/7ϊ̬uCN؍6[uP^)u i'͆ZUk5R,HQҰj[aMQ@Qd0X2_'YIhTgJT+j7) 5*Jjj3?ǚ<ڀ,YYQ>k/ 2yg7kFӦMK|8n O͛W2^֤mW~y"?iGHQwRO݅d6ט;# Cq2E!ŗ@["QEv@,$5BD5ouBH(m%ZGv9 (Hg7I.TAF*zF}?<揷4 A%kH i3d,7je7o{vI5Iit?ÝW&N($G!6:~P Zm;MmF_ַRqsflot͸f':uhrq4_OؒN?~?o>x;U";xݞϪ&ZV[,M+vw/Y |./zmW mME *aNRlAeh_FGE\upגbmGZ?ؖQwUz}usW@n*">duc+T~֖2BHD>!(Ciˉ5wF~пxm 4/m 41%VH?%~;zì|Qd%qsd1ԣ~IG]cȕ ?o9ZVX Egצ*-*!U׮8q]j{ȕ$-]Y^Րة]B*%hgkٮRuQgo*?ɢCM_}A-E lr@);J 053STD)K * T~ K!jz ;(k!5QBfP"& Pd ̡@c6+KH ZՆ( jЦ&!^G}%#N#^[NRcbJYn.B";>UZ}m77>2T۲ 'Jl\{ƖVܩ&fԡFu~ʽ'2 tZJM.TN]/u,[T0$%Go2zƄ-"AȡVauLrD zNJa::3gI@ĩ Uޓeaشj\_v@%=}9)z^PD{OGwK{]6 pxb ];+3r➽HatqȊy$FV5pji̕Uz[dˇC K# -/HzSoWݠ(u%~x-WW'M!=$JڸRPQrJN)'2Qu#6[ֹ{eEĽܚ{ lu 0+ZCXSe(G$K WIP`Ì$Nr^UԽGL k ۙIc-\ T℘Bs fK|4= %K@ée:FZnuPÃEt+46[2\T"ccomv2fA!BCCCCtP IqPն( %G׮S,?A6OM2 g ű끆vPihhhhhhhhhhhhhh@߽@CCCCCjujmgdlld$Eey:D^)|-svq7&}Af2K8cXd7fHvY*N]U+%$C5-۴4'+ k_Jl,ҒROmAU7b 1PH% 1[R y} ( \5\LmDE@C J_P4vy z@" b7PzMIQ@DM*?j }+'G; mvIH5ގ,)5yUď T ]4PXTlB)E @t[8 ¹FVzB'zԔW~/OǶ4@ Ϲ ?iTBvpœw0EسoK3dۺz&yo|MQRG8jGPP¥ZTXV֭\m gd **.hlqT ,͌5BI{+9v0Ϳ{"f-ZRc ?+GOWK67s5ju, h+w;KF:,7[<**}PɃIu JS-xt3"Ӥ~oTRc2,~rEv*{i~.O`=`;jm+Ok[RLe^LT3kl䤤+Ɍ0]s4] U\jebZ&aN#FQO ak&"OǭۣZ-P=g)%k:`mcZ-Q-T5#+k~x]ug.W!7j;|tHrBQ|sibcvV{Hd >ܾ_lf;_RnlJFn'Oo▔I|6gm=KnU|<{"!?H86sd୲ׁ=v%\L3 ֓C/ܲc@S8O<00L@*J20:+kP ): r -v 8w7x0?N;݂si%-𖜿Օ'Rm=rp5Wt ܸմC,Xh*x^ղ3UΊxMgҮ zDzU4Cs~CUXړfk99::K=t֜N&\)|FHPӬn<6ީzE˖rb2K~ ~^Fxߩ3{9JC;_Dy1_] @QJȢVPN݄V(;CeZ_Y^Q2y~yx5yM'/>*_Dhԥ}Ke"ͳ7"@-4Qy囇$PЕk;(QRc߽eif:+N9у C_8@e'_>Kڅ@+zSސ+*Q x<fQVȶ*IRip1(jWq1}yjV ,9RB*8/!j E4pܑa (HQ:r2fpѲUݿۙ8t+_) }!Zqi='}_U]VCqiu?~pNky؜ʜFSc'H^Q`jq9fKY$Cw#[]-&q>d e9iV EQQUJ!U1&CV\5CMXY#=}T.B zGIr"M7~eTq&D(TTrTQX%U((\Z2v1<4uuۥ.C,jz]$Zĕ߉ep1{ UQi=iML ((:ghn'l1mt< Iryn^"o@ߋS+52y8o_oDvzV4mŚ32;7˚ @KtFwaυ-jLn:fʍT vI]$ak3kTj/b|sx2MW[]i4ԡy lmgMUx\>?;ҘUs7%&Vߜ  mQn\@)en'UHJԽ(09ZO6<~^Wˈ|ɨecE12RBgs۵,zPN@ehrkEJ'"34Wgⶎc܊LMG_8b'\Vuv5EQN·ry^Nvj-yC<wRPjvkj>M Q=7c*m +%&KnZl#& U1Kok3\&_ ўExo] J|3~Qn]>o؉k E <ޝbCE_)mE~a5>j3=vs[g0fMqcAJ.*Up.Ҍ)?4ߡOk+]\_5!9jA{ "Ҁ/]\vs{|AȦí)~7wBh2 &/_N8tA$"s&6IkyNޭ5eё?#fNܷ}2fgS# Iޛ|CN{2)T$TjUs?1Xɩ0(1QB\ZPP0VU -M/  S44eUQ-zɳ׉5ٍO6ߞReF~Vl>aGI)U }9u}G3~VUFVHv3b9Y*B#ѯ,t0U!kwPeu| )BL k~HAS@( =΃sg+>qv Py5X-u~H5U0>PQH\ DIV|mia)9ٴKU [5e2DkGX(ǑMZ ғe*mTmʷEb2ЂP1vz;vuZ{qr ̔ظnC >w}ޜ1(~ 3FShuڙav+<V32;'Q R2uCA>LtsqԳTFᬪRڊ封`+Պ`0yտ7b*O~_#6fW0вo]iDy ӭeɅL%(#^< QZ*m镆B2/D% 'bhtʯWlaTS(*Bdfn%[ K* mXŒ50GǢ2H6Ycԅu*b "m7-QnHBB~k@P:PTYwEso9C}Iky\wBIơ*_+ `(a("mT%(RUE>$W]UkL%]-qQQ0@1@0@qNalglb5 ZY]Ļ=jpq&'PUr,8+k멹tj* yMl5k'N&YdRNSA h YV;rKv<|xxtdp "󇝨SQ6P}?d IDAT*cCc:XuKۺdmQn冪QD6E"_.us,g圝 @>z#帹r,~/gHdFO7%wni=tuJuO"uj#xYCչU 4x|egX,U|[}}n_ZS/|%s>>oU|^YYlc5z*l3ҕ>7q Bfഒq e qP<̨4%n٤Ldb(22*jd>ٍkU/mar^ 9hyaF Gc\;> _]=.Jl~߾G7[l:_|5o+a)VxҾr|vN}k/=iBxqCl홡c}iZZ{\+{c>b2U]'(>I ku0L*{Ѽ,%3Qϙg=oFY;۫I~@%]{-[7-OM}IV]20 kL> Muqvc1fUuJv.mG3[I VP\ Yi7YUu;lZ^85 8gϚ}Ɏ^o#N#{zKEl9| ^Wyodl%Ve,ɼ^¤A ;eәᩳ$3wUٷ]~j~Zb!klՕvAvt|x#^L\iO:ջDuv -QP}?OYKn FּE xL Ü<21`2RQ .Pyq7 Q1`#> ^WAT*P G5A8ђ;aͭ (`;gH~ KqC]7fҢG ذ{6 <`sy{d[2@|l[v,k? ZuXp\]r㖝>gHp>(\ۺץj6̈xZM>Mn5)qj4 Ikc˗ ]R/ hƽ;s>z+k'Bpqt`}WSG缮rkB W,-_q{B!Oٶlin^({mBAݬ&bّCYז,yi˱Ua ާUۢ}nyM$A!diW69Y7k\@wrv1Y f9#b[P=SAaUryµ'oGV MsW6Կ'~_K Zgu^lUO7m/aPEQ =5=64Zۦ^MW, Wۢ"܋Bm&k$=lՉgޜp/A i:FnݺBڡi* |T=sٝnf ҨUGC#B:O{4_G‚oNj,5b|лw.4Wc\n&W[^mµ~ ]fX^okP5*Ep|].kp=)=ڍKtZw;zjMZo?L_<",444444$8$|trȮ,Z\ rַe%Ns Gvf5wNEs\~~mI^V@PHhhhh&^>S UPd6 ׂ:(~nm.'tOeC"Žp;x^ٟ44?AUZpMys_z)r:Ni ߨY;504_.:'=p ~ׅjlwre (CYhURiF, tg<8h",DDoFW {L!o[c#F P (TPTqU-mJc [V&A QOtoҵ^JpX̐ P(` lZV0)csՙeR@ ȕ Xy2gk7Np(1w",hqU1qezTÝf"I}Yx6'ħ޻y;WW#L{>;*4 Ԅ(@!Aɟ{ seW"\蠋w>8nC&u$L~w#v@@& "x:0<kDi+ !Qyq{. Yj`1(i賁B E/?gS(vq 2( }t-7 ݽ"N]>uK Ѷpܐq vWm-Y8q#qKN3?xzSf7g @QFEJ^M<`؄*rqveiUfP:x sJ7L;*?gfnpA$A;׎X;Pvͼ\@.r瞙y<99Š1NbS[.DAusMCu28o2Vaܬ.>%<\?˸˗8xUL*nQ,O4ogP7I ]=c$P5|:1b[;gմ-kwR^\2hwMKqZn4=Ҳo l[EL%]:23Ayc F1c硽8*5e%C|x}_&ÄJe dn,sj"`c'6Vejݡbϡb^T\)dz Ȭ`;٦z<(kz\8yռ [amzc&ylBTlٮN&="2W]F8*;o]FbRTTڹlmF gN;vRci"v\y0L[-ɵw2R/q[/.H|HR+cFBيPrݾ ԥK.ͮRdo@ht0B5CNaE eQ%tZ-Y^'"/zS6uXd%' ႻG:5XM ~TSYt@أjZ__007Gft>EsPR\{T呲<0<'|ce< Fn {'CW (ڵ 7NȐzsȼY=Vyfݧ۟yu #Ju`:YJ%ۂOJe@f`Tc!H9hɡ<'>g%!P*~4F_smn74$W)zTh4ڝ8?Xv^-rcޡ'i?k1o=zX|+FZu#U(|EXYaޑS|&rd7 |J*2ZЩQY}`@0li^(R\!pWe PQ~*H)ϥǻhh§L" .7l\N-SOŤm}HMksjv||v|9S֒/U幏eۂSO=v1jeLX[-Jz6(KZcG*j8eTj#w=u= 19Omvs3n̯X eڹݗbfUN~Mk$n<Αt=ߠ]9|#ƮA[nEe*adphm 2?X!eo%⺃x4lc]5K&0;wSC/z~`[J"}@NJ)b"xPS1alD"pCqR`yG/ܽ@ewb@i9O=pV%,]:O?I՛k '6!~hQP I2n x-L=Հ]nlD4h֎EG4A!#QK{,mO<2,h,`S˞Ċ׮dW>/,]}}Ȥ >" llj9@}Xx;C'uf~U =[I+NOMUӫP.iBrl*SmVm½XN.6aavUidYJ8E(& 8ɠk%6͚;Lz8*zLhf]9p?6g l#?uLxF>gO:hknc{(p6yłm mٟ@ XpkR>?zƮLͿq(bҙÞ>Sf:lR wݼ~u+~{}~҄!k2ϮdKzc|S{voHeEwJb"tN 5vH#Z-_;.P\u \<+K{PТwP3E{nj(/N5?/n%ztrdݻp12bO6ݣ^>2n|%-Toxئ1%_6֡&-4$%iO5S$.$0$XzRf ADVR X GH Y %~EE0ޑ8i*H%R:,A)" TQ]NAudj4VG"/gҝP-կsUx|K>-<{,|#ܾBM]Eo(~< cYp$[N17oeic2̵rgo/JK[uu?=pXv_ׁԫg]Jkv\*Oak"RcպmP/繷 jO1g1vKO}S z=D]-4u>mI TܻئY=#zԞV$>J+#ɝBRރM_4qi^ۧif uI!KVk̋6=3㥅+N(RW Zxs/|SZ-y~wc4:ŷ%#cůs52t=iH˰lp^B v n<+ڌkB^Zj,^5"3#ĩ#QNܻĿ׀F֚5+F_vO{ߞ =:5ވ}áhc_~ՃōabچJgmHww^9C~I:hxxxV3ӹCCCCCCCCCCS[ٷi?N߾}/^\W;4444444444ek}* f͢s2JCCCCCCCCC Q[9<S!S+ihWU)U :hh IDATihhhhhhhhhhhhh? ! hh~8APB8.3W 'F"}=%pk[# z ;# ]¡^UCA }_ʟD bJWCkJTro(Kcd"Ǿi5ʦX 0Ҿ:Wi,kv6u~}S}xoi }()f]pf\VK{wEUQui5^\+8/id,׃WݹwM2$;oZkPFlվ -id -ނk`Kt5F+Vˎ5/[_asJ+Y9ftޯk[" ߁ R݋{p",70A!K͚xH'"PpKqb31} aj8 *.ϩyux4TQ<}Wb]1ώ @ )qaI݃vee'FSe`:}@mDIa+紳̔0Dޯyӗ7茰c?ݩihWmlM뗞x&SIEbڏ0}(kFnvz'\pԊM-uJaa=L3vmRf< |YUa\e2M785NiV,O~3gf#v6\B5-|sVȽ:Úce<7Ch>M+}{y*ʖ ֎WK:!Opʄhʑ+W;.أ׉13,{v̎(0"͇/m̈,"6$/Qbʖq~Ou&2G\[;rOT{`^xMށHA08OD,h8`ˑU$&\2kqՆ&X抖h<-JT@@T4telbپf~էVF.>~ށV8vݚ; V/܌JzǬ@ g4b廃g . P$e[ 2 , d "*"XH$_&_Ed_ !p[ |u&'8L&O((ù|H$qsڭk9~:nPGI-K8gױIG<ŀMK~Uiѹ#/Sql95C*9hN|.CWpݛSLH~< W$qYLP /3 P$9>) ~qE<&Jj@( *; DB!E; B)gW}nmu t4i~.}{ %zoѪLp6h1ǔN\K 5SAԶ}zN.IEЄoOyyMBANMx%C{wqk'cbKRܾq&%6;NZq?wywljnq{ԋ"vq:)z/M \^~;wn>26SVm"-l9Y_ 6L;Su^f2y:Euna ;;ߘ&ɞ|VN:n.wG FOٱVRf_;ز쉵!$^8ӢLa}ol-+maSm(Rȯ ͩZI@ kpy2mGΰ}Bر놑A <(y*.ӯSMiա5(1THwE.bvpF' VW螚wA<032u&Vܚy4r?6IRΧA\ sމ1T`Ɂ!:Rz6Xm pgg]N=L {p 6kQוr7f'dsIBDK1 Dba!Gas(RkF|߲R42z}:~ǩ*~(V1 qG/]i-7, 崜j^q+M ETveNYvD,GT%WΫ" 5&0zRg$Y6INoS8)TM'zT۶;#F)=zq×.NxXcȔM+Iq4J~|&}N];Cz{̰\6x[E2i=nwߠtp@]sj1u!$ٚ~ ~՜(N|VۼݜQmp4cr?z͉lGnW|ڃ~/^8c"F T7 K/y1g\hO,?yҋy{bwe\Fe7; ּ mUs=7ʳ"O(7i5wJz':/ ݦaauPyʬ^]mj섉%#/t8p3xkϑٸ1Ӎf-X?c=vg(5xr(x_l+1L^ݍ]DQdʍ#KB;qÕÞ|:rmw|O~RByuᎯY @⼛>TwL[TП iQ+}f 0\rTbY2K-+mpXopkNԖ@eӤYw|Fn+OFS5Y*;/uYȥ =;s)%e+*S7tQnwĸGi~Ac #sFq1t@Wm=?jZ6r<G_*͞rţA'͝% Ei[,i1IZ]I^Ai?gK.FxoI/rژݻiQ+~R;U5Uψ K_ g;~m` ^ow%molPJUAj,mfңU>wG)p_+"A n!7A0LLhFv i6ц}N;8n{&.ʔUӄ p=3vPj]\I/ω[tE?EN/28X6u]fط1XPew"<\8=̄s"].$ ɣ=G2?j["ȼ#;’ՀU᭠+nW1 WgŢB?s,5GLW:J.Se^/ܜrF NK+3sO{VMn0o֨ѣwyάnɒ97͎ȮrJc[s,۬7־S^25&kh#TOP3xN}J GW^20(.`x#k;M cf,J&#VyoUl됕MO_xx}:? DʽB7'RzЭ瀁,U3`N<̢ Xn:ʊV~ Zl45(OhrM|IX%\t'V>"eS7\ߛw1*4d-Ծ1jՖ)fO G-kOx$*:IW"ddfmA/!S戽He񌚹;nCp#14ZOk4I8F@Z@5Ü:BʅS1`6"R> qŠ-=&c#ֲ(sO[֛5e]mklE+b$iں_śWV۱i{¥a‰ j×\:7dק<yiBxonOxJ (aa;/v0`?-Z*H6f)ݓm=@0XbvS1uv t:h@i!jvD8 3 I91ӮgTcLSia8Cy!=\Y}zz-s6ڸ0}.RACN%wF> ޼yead=lw/JV1Yh͒uyęjMևW><'Chay`ơ} _Cqm/f^ /ӊMVdn u~oPEjʱI߭S}I y#J?ӥ(U?r0} z5:JԠY\(`X!Cʨc=u~kZ,emcï>ZmҴO5~^=C[յ1oF)/qh~i)0ʔ {\mU]Һ.<;Ұ1@bdL7$lSd ;nrxt>Vʿ4r跉Zr [K+y|8ڹbKDʓ#;(gN ^..Tضυ:^@,.)R5: cx,iT2Ro`JPds,(RT(OLä( ))Эoh1 ԩ2Q"8Ij`!ґZUu?T:G tS0Wy(m0`RV[R ?cF8C"BXƕ HdeE`s9,42"Reqkq B] P+XFU, %(JF" #H~rBL j\ʪ(HJ*SV2.p-dm\Kp|&wJD-80EepL r(b,'URq|*DKR@Je"7!_x irJW8 J+ʴ?X0a+gTj@i2@(Rr|_SZrBgK;icd l.%+klM@8pHB.j|&F\HT!k~)br&(erU2<.(SJ%Z 0$e2}N!jH64 RO(H$``Ҫ BaL!VK+yZm1|LZ%gзoŋ:4444444?heSy5.BCOq)bۆ=n44?tbvF{5wJCl6#-w~4y8ݖDg MQ *F MMvPihhhhhhhhhhhhhFBplC D"K}+ ^/`|Whdm۶j/R&ĦJ*m ~Fx; U :isBvqzH d(99\12RkMcQTaeb 13OdžŒ̴IJO }ܪ.\ Xw>T$IՉ1C3VUuƓOZM&N۽U#:cJu[hQȑC{tjnɊ{I ;7_#8L;9DE&jZ5k%`F,3?y2^ˠk;M"D&)K#+Iֲo#mӦu@2#:)GLCIwiZ'˼u R{2?``իWמ4 "57uN_.m3hҸ-rIiyչ7S'ohnjz_zxY6$|ɯ:.?CmڴԶNd )ѲC׳a|Op-ԶenlyM?9=[˺^e+kVBwШ)1)?T=lߙ'Cas_߀}Ri{xxxVbf~OaWӑsV؂+ώojXYJg9to/90Е.݉-sU#^d7q n5myM!Ĝ`tCHh\/"1f`. g̣bUCM<՝Dyt> IDATp7 2_Ǒ7q`dfK>;u0͝m1Ը=(V&#08ci@D&Ni¾~!8uݬv z׷#Ԭ}>xxSf~ɫU\|>bv+KшG?Iջ3L{j5+km|ݢ.H9wϕ'vmg6mO}pEÀ!j<@n>o1Ɔ,I G/ S.b5nޣGߋWzBv_5Oeꮢd~F506YpM]j|AGo?v3EU<~ͭVV؏zzD⺉M{9+6 ۽hlDߖzՃ{v+Z9m٣6n baw%S}9_k #DȥG9StƒN8 ~BzrSļ#{<8U Ƭ<1g;tp@͙,*}-jE>CBM80n޾7^_uwmߴ[(k!Ou+B}C-{)ne'dtl ݼCQiw hhʆNF~BCX■{o9m `QMHiM/˒:JRr:;+WkrS0 Xwm?& Wwmw<(to>ȞBHTێmzI4U`ήd 9{|tZ/J荙C4 G# -l6YF0kh ܔCT=t@GVe̒ w\@LPemyoʹ_"y7t#K.,B]+ c˫74e__IdzΚ6M_Px8 R X7|B#bs$&WTE5&X3[fWvRedeK6fhv3/O#h6a]/>z_cw/qm[3R_$5:ֳ[-MG@mpލZy4 wݶ=ۧ:&<\Qq{Z6&.c`S ^Ƨj\l齏wS1 4^ƘN LJ--鋛 %$cF+T8tɶ?] }6\7ϓM 3Y; yL5ϗƩf5;BoK 6nM 8@%KB1'A^G5}@kMVNp;yBjeY<eelP*Ӳr}Gh^))1c$J I?9ǡmKG;4&fgW^#XbfwDRJ(*;GpElPQ[YtaT]]zvqfO ΄z6QCl^.>e NJr)i )P;ǩۋtRTo(ƿ-a0Z9 1R w[woN\p~mFvu9VhIe  ŗED(̹5ڑ;w]?jQ%ׂ ٵa qZt^(>Iʫ:HɋM*fHEe@*W(U'v6$@'UllđY -0$ɗtZQ*ŷ`+>ėlFQ\g3ۑYH̫x׾ņǏڿw6+m+\U6r(c]_~^ė*TE9,Eh_+I>wXA w\ה]]kjB2erLRKi4` _ק۔G)% &cJR_$W(%)7_FvƼ 7Xph4)'+%3YElGML:f@Ԥ<*6u"OE9wk;+ h5*(q[+w}s5νaaaaak'&1ñ%Hỗ!df)f Ygi4llҎK^}0fc$`H%U.amwLt;ۗ#}b500Վ1ksׯʿIaX`{a{wdS렖4Dn#F4'nX?i[b1(tJpoʔ8⊁PJB R !YԯQ&]:;MR`ÂnOx.\N1йCcNyQdVۀ_7T&fB#kqҡfTB#@i)`5 u)*Z|_$c7Ʀe7aCB߃W U\i-kfH1c 33U͂>}#g?LL7ewt E@R.@0iw+|x~(ߋPF=ޣɋ'cbC/v ]nNeh ҋP+k#Y,VR7voYY{g[ϩ_augP=DO-OU) 8u:qmP"TtZ+apQTyQwǍN Q~5tt! a0Ev.^F6OxGZ-a`nbgxstJRgib``*u~Rr\j DB.@~՜VNf֞TP0+uхtQWh@'765LyH:m>c9wj @|bv1JCL` \̥f䢆p%7@>cq綘cGܽRS?tN{Npeiek2jPj-0 @ 9<q&ܐ4dj1|޾m3 u3j#>Bz{AG3r})s(oL?a[Ǻj ] \vQ)* l ,lܭa:}&ɻu,'?Œmlqmd.(M:m)/WUȸ]k7`sO)/Nm;йVx4c29 r*stwrԱ6yأz:[[87<-:$7/3n3c1UE!c1U%'?w2CffZ5x<,zusOc jڢwGQ_~vq3׵uoܿ,yyR}k[[73tFU{pO[}>4zldөy#Wg]5?y(bF>.l\C>(gksʡ ˶ު0`fdoc\~Ӯ]7j!S=+kk{v-vo}-l:Oꅛ5nPd$䑸RU"k;h'h P(KB-4us0WiA+ssG7߾}]a`rGX 蔯/m-X8~JɋoZz ?4*UݧV-]qL0䰽W70uB5f|;}+.>ep>cg$sg7D  ;zG#z٨:돾:nR-z~^XtY=e汅^v,Fb8^g d4u?8bi<'sظ5,z ut멛/-H,%"tѺk'_Np^t﹃evv \ֺ[~{9p2ٶȾ['8' wQЪZGW'5/'Ȭ 5Ґ_޸ "_Zogw:j7E_W:"53?BN71MVN#Wy+ӥ)g%S@pufoTQP16::1bIuqrq E/9pyDy yxd_- mXg--?xn0w;T+\w+Я5Gg[x~/Ms|.6s;.6$_9݅ دSκw| @{.oy0˵!fgqQA=PAqppptt_75ũY6G shpNĿpZ!ws ^NE)z LÝUN$ZB ĿZWTK=ᗑ4*@!Ow?U@ 0TPA ?ZR@ @ "@ Tk:FE  Ǐ~X3q㾹TQ!(@E l'\N 2X}dddGU*6v6b k컇췋ɶq{LqR׊{ju=zan󭫶avŽ9,Q_oa cݳmf>~>֌Tqn)ўǭvFܚڎ[w{`mm0׷0w=j"8pn^7-1!|gvۯ ={T|cxIڴƁƯͨ}鎙c&L g(YE@!*D &0k]3}+;r CD#Xz޾q1YC!Q¨ g=fs[1Pȋߑmj\0U,  g)F_qd^?*Ə?nܜϼêN/HLQj2s7"_(y}zT h)֫gL^?צ3Z7y<'٬ך'wdzoug88ºYݡ :6{3EB54kAzi\NM5xQ&͑-^݁נ[cG]6y¼]ߤ7ρ1hc#Yǯ3(۹;O^xڭ{omL=Gw 0ӮyjuzctS*q0n dSj2[ ]FvKOQ\B!oY7R^j=Ye~[{1 ;v8A^LX=<·:jY IDAT"5mZ<=iRJ+\l+(s-0:?:JLTsҸE#BYh7a؇Qc7xToebdɽp⻣;/;~1K)4U_]3kiPu) ;nYRk6ݷqۊ18'Y_iyh3gY.]aY3RoqtZSgK|E.9rnܱV\@R N^+.2Z:XNVwL)*č[Uf:ym pw-ir|mymٟn#KEBFϊjh}+n<͍6_76]jФa;4ǚٙdc͊sNqA1YkN7;+;tÄ VN,0w^|P*P%U(7EPRB^iv$)bhYpHi,XN(4A\M;Rm6\{Uo-88%p R8Cɭ2g7yZR[k5g9ji)}}bҹ˷woa yLM (r$pӰGPITb2a))`C2nǗrmp,Ab 05^%ȕyDO?H(B",(6cUc2?j%U˳K*LB/DE@ J AVd9ׂGt)d:%lj (&͟Y@<]J"WLԸ-nCYi+ ^)IBob۽ɤz7nY>q Ar&.8M:p]q?ppp]$Wvㆭ4|5 !;57MfGZ9uϨ,lnd zSY"qYTKN.XZHEC+i#?F!ϓLP Njl$tիId4ۀQ6f?$jP@e@s !*d̸q_z(F-,p0G m +(BЪ川0 p6'ʉ;x0`=,O|N+!czw2X$АG50&Kx[aPAe ^!LX@|̨-V =0 `HHwN٘"BӰ.CW|ZifSn݋ *Y wҘ~+ԺVMǬs=7mYE./>?5Fhrniݙiă=Iۑsb4maH5v374 Lj 1SkĥAE-6鮍O+7l L…м Rv]=yhˉ<ߗ\&}{.l?~~ NU.Ert) S >hߤyGVwoRcO٭{=ٵx*YGv>3rxnsg=|jWS3`,0O[}*yo3}oJfxƶܷtR+n-ywɥw߶!fy4Ń7%7;O~di9ifG4&/Jw_}+e1ח уnw]r 1`Spp$O]<|CybZHc/.C_@ ~8)f  r(NfEUf2eoPB DH˿ΊA^)X +,(Mb @*'~JK\Bt[#=%4Q5M}TTSc,WWRRz\UEUۤYSbR*OJ9mȏ%JL}*@Uu5iHOEEGn`V>^ݡJ&]/)&}_<:jZ"t*Dm_Meiće?_R:f-\]\En̦(-<"Y72kdHj9kծ QRyf`kTEg$dWբ{w](JIǰ9]p} ٪BY?@kʲ0+S\V-K!+{'_@"ߡݟh37hZ(]͆sH~+\5- PsI-n+zȫsf4#qV gkhB_sZQ5x<ƀZ2K픲l|kZlZۓ;eK6eEWo«aLttMS| {FRܼ9V_7GðKqkW O)Id@7X7F ZAE qYFvGpX d5A \K_\SVe/kuF ~$:pbwElF]_ߖK=ǫפﺇ50|X{1Lp|aNLҞ%7V|,)~s4'խm;pZ]7FB Uoe]|ݓOu|[GC}VW,>tQbuUEr1gko]tX%ύ#G֢"K{g kof:[2~]yUic',;si(59nlnj:=wkVXYѣGYmk~Z>77lR[j*3n?Ak^ӫ;,wrb+^t8&sFߞ?(^ `Wf@ Nowq, pv =jA }<쵱s/.ERgٓ&3lM4>ټcQc5n۹ѣPѵڶQ5t iUҮ{ X8`=ޭϰ>m[v=RMZ3_fȷA4LkAE hZZdG2xcW ʼn [`jPUԌ0xFň4ǪAAZ 2w92&1+”V+ʔmI/ '(kn旪[5M|!ƣzW`F"C|/?ԮCvF5ZXJ"@gn\m;zΜvg:A,At֦y@u>}M{2ӹG׺o>#w6#Ca;is4'-]5Sћ][K}ŒM'|}xm'] Y5;ǁrzo#⃀!C@ 0Yd#>#d"֡? Aa`U XPXKL~NRnȗ /5(WC?.s9%.ʁcp>K{RF;&i4{i) ~f-gW_S)4PsʢM]FI4Zv̓HCMx[;m9 Y>c;,򅷞 ?|SCj}1آ\DMVyi|nE"E=am=9_u\ӄ53} Ur=NXWdeOʪΛ51LU ޒ( x.YZxzdB[yåGn܆=ۙf|Qߡhƨu/Sn,\wjt%}/{|ݟOx w-!ߥsBh7w\g#[ݿVx0E$ݲ#22N]t9̘b 9T 0 (NJk/A{2UÔ:$ PzqJ-Q@V\P)[pZ >iL,Zg[_|PʔF`(޼yyDc.CIFԌO\к8?]߿|A-ܵQ֩)PӔ/b6~·,PP ɢl[ij&ѫKK߿ތZaxҿ,/'N(0β7%$I`$P%WKΫOMt*ǻc|7b9Dr`$Ѧ9+)'@B lʺ.xw5c>bb}5ѬgJN|V3\ '}h(4BJ94_}l̢:58zj Wk;r)('1츪 HZhػ$QJRĬ7y /XrFNEXXG+0vw%x,`0y{zt!e`$ p "09VۊK.oFs謡Y8`2%R,!EQ .+hm(@E T?Qr aUOSΤd03_g*I U`Le5$g``Wʘ̺vLܵwѴ͞5ߠ0oMƜʽrv#\ilBLjJMzi:T$Xwv&L up֒s ^o?ۊS]3eBoؔ΋N(Ze镅˶2LPΥqHuߏ%_Ӊ4~3<ᩐ8"F瑕폥ɔJ#fx5 EVDZ/);a( y6ڂҼ$6m(P+LN3lɏօE p0U5 fӞ p&2.tP„ӭFm 9%J ÿdSEh‡'uoU!w#0#'NZdm^ TExy簗J$߰bK_cB stmG ͒_\끧N$&pyЕ'lE.߻cYSNnax_c+TF3%1Nn8{sɸ+wI?;ʭr)uk:;_5;p,w_̬Fwtr繁 J_~Ph Y7ocV O*5s閹R,flQWR>|:E-s IiɛJ v_Ex|KTj6$Yuo?xIWwxy?ױ7cr̳?f M|z #[ >UtkN9 3@>J#oǝ Wbly Fyښ^5oجeϾz\ZEvīZ%sNw٘ݭ 4=ZiϢ#uEcfm[}~qT %ןXXВ%d}ľ%}V%0䪰IAM[aؕo7nD^8~-tg~ܾ9 pU xjlU. H,@k;8+!IG 3 kI͍8;4UY!M;dBwѕGNXOh/@ wI0Ċf6!@mg 8%,(@E @~hTZy—8!AcAS|@ Q)@ h@ @  @ ?nn̒O ם !RTiOe>e*ûL!zl&ma5H@DdM0$V#L^Bv_G[ne݃^f]Qfn?w&sVN7zlW>3lXoz{z/.4Uz\ڰfAv Kqqsnהix{5 m;{Zc:o&o/(I,Y=gx;;RP-???I]ö__֙vc{[TZ.LMi=a2$?Nvg/pWPkԫkCv3(;/9լsw^ ytٷ+[xϵ֚V1Oxکt;AM иWT F@NCX)i$}F?pjVo f֯U56E5 Y͆98yw<.5F)9l}9T\-4ۚmMiZo=|=wsJumd@>7?VsNI)+j֚ȶӖa=\Vw@@¼Y'H%%Ө 3c:^CnZ6g.5޵o]밿:'P0Ar#/3tQv;Wg9zsE?͜sö.]"keơvAo7so _ +N0=(m\ ۼPysjuՈY}uw-;vte'$^]Ѝ04<6S;Y(aO<7/96G/y}tyΕqOx^!mӆA_oR>cMZl43Y@ <Tۅ & BG?R@'V(#kT;BfQĵT҂g zU}BaK]SJ~np']ғ$0ΈS_Mm SsmGZ9k_^nE8{c׀(q5;~?TcX9%X~ղmv҈B6Q>0ې]3Iܓ#'p_eLIfRdTtttt!R5D)Cf=yV4:•#J:IUn>)}#ɯI1=y{%$9.0ϯvʊ>1W`DO9[qƥ.AFnpt&)〘\LkthښOjUY|fYk1y nAZ30ktPPKxM?7V=n+gx^Ӡ6 8K ~zmZ'؎X792aWpCkB5b {YИ:;l  yc^ ?AE uYq0$yLn$ab|V&t1U.Lh`*\#Wbfa\ǓGKˡME _U#VSAMj(0+ әꭇ5c[=v_k1@ٽm{eͲ u3^nP5lZybAXk,[iEN1bS;.Ȣge7 ԺV)[,´;P[w,6qS9D8Wcc8f8O;#`0&'f4Mt!{ZW)@]VN ]eFAJlas̳$3} M8ۢU)oZ OZ3r}KsLϔO2xGIŝ -Ɏ/MG?xeʣ;@T͚&3Ռ>WS95a&毝nJ)`亡gLjpKď T{ y})WSS ^KS`/Y8^ٴrWȕVoR9cڠǰ.F80 36cQ]ݍ.}?Jc11d.V,+d%>obKM:xպMySeo%o4b=(#?E4XZFIr;c0ہCIy}{MKIF@8}\DPS[r&S\-vh0%3;6a3sy̤|Ǎ{펀˥tQZ"UټJ+!u<8{=6lH=|ȎF<YYcN<*#ZqNxNe Ob|?rN_rN˦Vo4)9xmNAӎiVᒔTڡ{RR9UmPqR22 v4nQlCeEѮyv-,~HʌӢiDZQ^ULXVCP_X"ErYLGvn9IRS@hVNVI"5};ŕ$xml*WA'm KHL|σԬ7n%63r$*,KH-ŕ"aQNҫB`%* h%Rx55IN$1$"wUG/JPˇVsIbfDR!9sGcZ ӺJM4}7N9oĪu]g6ș> 뮙-GnLhnLhHT3.(%B cƘ;} Lj5dazHP7$ apxŢ@:9iw͉i޿X($Y^rʥ2ki"UP 80l4" E5@/;"J?}/J?yqM6ww*CX/K ,MncA\Q|QRTt>>:6FmUc7ObKڷkm+5^u3%bz WLnBTҠ.RradPV \}KoF=pri kLkIkYv*FK>>f6+ͯ *d5-;3uȻw`ʡBp0L&jxeſ[2h?~4Ab0ythbo+˸oZ@YjS  VC.ZxeF1T.grןƧl( ǃhs PAxM1|ZRi[&T(04(p2`b`kHW^sLI*ˋ@df*B- ,ꦤ@VR,IJA)fJ )K`i>Q{57VD00tM9J|φ;Kc1 Jq`(~W~VIa6wR(%ҟ" fKyMyA%8>trhQ4h˞ÄNRS3ô4bP ID29ZںX~_kxOa;۲ ݄Hs$+Џ٘6]_ãM}ٺ-?玈*̢4"'ʡ(ڧe./+(iɨN΄Z2q .7hļh2[jBʲI^:FxQyyuYQO$]v>w6V\- PO9 (HeZv 1}ȸ[pڞ`闩 *fMU[cB @T`O o5+߿UVڦ*ѩO݈ -XrqmmR5l~LIB,]rjt.TJ}̲Qݗ?uca`HUғ^'~/^?8َR^=ϑ MtWĠ;?mh7_Ut„VFͻ w>J;n˥TI5m#QY^Pw[NIXe[K+t"&EIVL3swQNB\$:oHg){ϴݻB0cW6L~ԭ(.b9 K~ozZ׬Ey_EՈFQ,q#gN+WEtlɐvn(jmo:WQ/οMt؊w^Zoh#%@qNJ}T٩kϥ:$7۵d/{gW3{AQVLgw>[QQJAZrBT{~˙3ggg̙]6h=;v4*!G[(J8gu`]zf\N, "`0 guB Qmݳ4 l&޳z\0 k&?d!(̒@MMX!:@!Z9ce:,,ɝ%yX <{zzӫҾ =tjWO֮7}CB72ҠbE˻WBF R5k_ܾhM 3CkUFU#[:zTXRZ6«{^Im[_C +z;>|=cnjDH*5k\GTEV䍫Q;Tq\C/ߐ4Ц$kZsJۺ6r+O<.7)^:0rD%9{N.cɛ {޿zScFUiVߞaY `jРAia0 Sf0h~f_?:ja0Ij>n+ (07]v (Ox/`02ښ}b^E9Up\b01}\&h84  A`0 _o H! FU(T . ?y\XJҸ@0=x`02 (0,z*K`0 `08@`0 7`0   Q2b%i 4D$EQE_CDΏ*h\#" QEԾDz_ȽIJE˟R,c; ($,ԘuvDrJ"rvkϭeb?7߬Z" dw;3̫WXa _[ IDAT c2lbM α˂y#6e'(ԢހMհ)6dY[ةB{&^cV ֬L$ tFYZĶ7qP~ۚ_3cǥ(|\>1ھس\.o-%$Ȝ ?Yej/tn Zg z#o]n v6/ Pmwljc^9{L)9a %?6G\o:U-:=րVemϸL?oWp6/Oֶ3i d9Hu2/d20N'=6+=6H*s'dBW(r~Z[Ώ9C"@*3Rj'@& /__B&r)Tm$W dR0]R @E|Pf2cPb{3Y Հz"[슊}u"lKy")Rfo2@$ o# a/Ir*csW!BT*i ,YLܰk H$Ld&-xkwÚ֮{rɴN6>!C}:ɩRg^x5.m0i jԬPr@زjRt.tto͊(Qkn;nnrrltc֦K[φvxuE +>Ne]5{Brw#߾ *^x.mFňױn ԅ,Qqǩ"%~nwRu>&^3Hd?Y^^U~}_舃* ;mJg޽\s#R=VˬǞZ;8|{^s~,Mo$#5ٶ=P]&yn3/[ 1LHL[t/sd}}#"=;doVMz~]8M8mKUlcϾ2sgB>x[H:+pvs YD-C87O:1wmcs?6p}sòs]tO U_0~)~Sq2eJBͰŇYO$_}z5n_:s6R[1jd ̟{ꃑRS-5@ZOX 0u^իf榔}+F;mda% ۘ?v7#DN5|ȭKr;cc"R'}h2m@iЂdضlon4%2B402!SdӪ'a斨3~S2ssusyq6yNFvַM̚}MBIonsY96 ŝչ9ź/ػ[vk޲tU7EH-۴|79#F:I7s#8ap`J& ^a({DJ+SnTJ?_b>ui-񽌸B{sAD{/ZE4+2 >x=GWJXDWѮΩCE S[UMkO`nƯ[E@AVB ,bB;t;Y"?(r4_"2fD<,Rը*y9"ο;2ZM|m%tZ>1:4%7{oeƶ´K?'z7k?:)9q( Sɡ+utro%`^#f%*JiBP e]Y0JNffvJIKV[5Wwl+6J_>/+|[.YvsTOF1i6nԙ$ 1vpe#lCJ$8rDpCˈR8/j=f]xkۀxÖܼvvy ߆Ճ^ 2yQDb%V"@MO$4|^ 2q-W}?KYBy^ɧJZn IL>ǩ_:u˘6Lk+)p)?!gju]ʡ?6ٵ>RRޟ{L#X`ٛ9>o VU#εksZXprg*G{G SۙT%.ɮ@hU&&-QghJe_>uĴKY1^#Ǡ ե/IJ_|OjCl-[Yujg酫xo:PM =V"@$G E4ӤC15vT%5^\:r&Adenfl(AXƁjcoÜSy >hsȊUdMMMH EeYFsb< yfTODpd2`Hyo[1R{( 1(WToc2UEEq%] cAiԗ\ z:բgǏxQ(RZu*.-հoKIW2uRނcnGW\|z|-wXɩjˑ_eOh3bFj75f_x!mh ۸G/< c|/O7ws{vzdy#7}ZRRRRRRR#tJVL+gv1z? !<9iޟ;=4 |51{GN=zv=/_@qξجq><- p ST S=DgGD6<$%+2̛ȭ:Q(b77H A/3М9`t@֝d BkKˮjK;OUI{ڻV$l5?-߶2"SeQqzH-ڬ8,up_[u32G2hT D=kxD{S!ko~nU=*qHx_Wqh)ܿxY:^R\f*[būۇxLMwoܰ,c>]sYx!挻$'tY70t kؼrZW`9g͗[ӻuK9W_du*)6oRfjfnez~ȲY~&wTe~\l #+Xn6w781bFG/x-D\;=aRG "cCOBN>JwWM#6ݷ/5`efI }iY$+ꣂUhȏJ;Ig/!́FC"Mm!=TLm*`0%. hW0P9*9- V z}eOW|E2BgXXұ(X#JF_*"rE˨ڒO(qHu R@gihH#YpxJB_(AyBBDI$\NUB$kr|)XeBzJ&BhUvGHDʒH._D鳔zJ s lNVs,\2gMB>R(07"1"\X!AT"PHxي Թ|Gff[l Zt)8$ҩJv;E }1Aq|E,W):TNTVU(TyEԊl͗Aeb]^u*J0m \H$$<@pxb:El/$(XHV蘲qBujRs%? *rxc>dZVjt )HD(:: EbIyi<*3hc]=D6Oq 5* BXV/7"TWȵ_olCP$t A]`0c]E:[;|Ҽf5wk__ֽ0/`0 PIajJ#G YeY1_0 `0 Sj``0 `02P1 `0 T `Z_ "8Ro" wԑO&ઌ`ż>ab0.V 94'D|HS7a(>\>jٷ:e@fWsǖn˜';R84eUXVg3bή8_2uedȼ͏2J&q9Sr).bLTgHM֫bƥ[emj[IɄ{/dШˤ#Z6m\:PfѤicrqG$;G3ú26=OF]&4dBX}uWSjݹ`Y~`HkvT\ws{XoJ?aBMޱ20ZSI./8ׯMgfc̈ 􅝛oD´TM͑[[+v_ /㏛9;КJ=v2_=t٭GoH`Ȧ-;3gs;o`0_a݉GH,cCsi$vHT\T#LܑJ k-Pf%z??{vطCCCCC<0pdj5DuwSEI5QRo\,RΠNfj0ࡼo ~fvA_޽R*]*SעJ5_nЪC-{GJ^kߣ}4m]=8U]ލ[o߉KU/ z^{bZw~N`7zN:3mFz}=HJq]|,9ۉB DS+?O߲ڷ(UXa~.SG7I}x:c53*ۏt=(|dclKLRxF[ }2!N1 PiUA ?+8ˍ?rH)2ڡ"diEZ9i|xd%Gjt|r@ ծs::`ЎC\y eTB>W_?sj 9k]?Q.2!As6qDGqչ=}Ik#誖"֜2F,84qEWKZ/׍h~¾mیYuv^ya/ѨxJn-ٲm> 5fkKz4 8~3 ܲqaeVoݼrv&.kM,9weP]8|q%Y'hpvF 7^#vZ I[ː{8[a_wڨTTÕ+szQ+*ˏ۠ N{~^2^?z HVM+tmi_/#0Ml.> m^2 Epj˖ 'V4K@Y4pۦzz 9j4r mx k@9߹wˆ5 66n9”Mv^b0Q$bƐ9AdXT 6HK,TE Ӳ\b5Уd7թr'L3u$}ďNG2q[n-DWC~Ax:ђç.\1_=H9a(ૢ3Ѭy}n;bEQsr{>yơJ#`YDK^G6>:6muh gc@nԙ7Ow2jh:~'CjH]ٯw1cE+OwxB #|b{Hu\up985GO?5҈%-2mh|;6:Ь/@u;/:;+t[[q*F%}Z}~.q[;8'']Z5-͌$Х*d; 5U"ֆHDy8T#ȩz<17b L7O1Sf;W*3iFwL-7#<*e~Yeݍջ+ IDAT;G^2O"R[6Ǜ|vJUuJZDZ?Bl3^~,Q@'mTOuqn3Zȱwq@yCfmc-=MY a?2hY!!~O[3Yw)Q #Hn6J L$- 2feB8ijZ>hV͗Os;}4RcFS>N#y2ݯgnz 6k0XbC3K[&#@.)NX+ЩAh`ciaec#3MjyxŃ"nU Y@̍x*>]}Zկ S#ضŜ ^T zyՙЇ'LVy88|5?gww)eO|y{W^_ S/nꈋ+ɵK.u=S~TDtWn3yF/,}Ь!1v>xa]JCMt{=iCN~ĶD*9 6d?M ﴡ+ks kSCZS72quSO Qb"+\wrG*JhG)k4{mKq6,LER Z2ڝwt7nI5"XXHBIelk5*2>;vg:9h>UnI?;f~AGSR*ʿ7?޽.;Ա?g/?. n8 AW@w"֝=mYv!g>;'xPafڋq]. 5+L&F$1/=e&")@an)- !ZEbPrq\Q9{ڣwLv!<3y;ɹ5OWY=(}9j8ԫKv(V*p06ԿVѩ)Ie3ؕczDYJb4զT N()=6uxy.TQ9)=)Jn"!Rqe"-;w,ɔT~(Q@) ʋ >1,Z /DX#Aj#[YK5>82IEmN[ND2$3 !Fa?/`0<dƃֆtvLnH$v Bz*HcH kg-:I*y1"Ґ]MA[g?xȐ ׇJf Xe4ubC70U%gSVU]]}vZyq\y|HfhhAailgm kۯG^.ڌaM~KqWbd f}oWw5w[:D>y"T,Vڈcce҉{ȳNKH5lUt ~XhC)2?c8ڤ}'WK;Yć}HEԢXN> kUI-/X@j X" DQtQӖܝ4Ğ?V'ޅ#&tum3jb[?^o]#īH@7mBnV9;+Z}z9LP}<_.Q dmڻJoc4l\fh*0r-\r _(H!O{gtimaYk_<X S0`wiaUe<_6د@>D#L!L/L"B̝zl66hZTef2@|&YebFnC]u@|޶t=˱jYwkNHK YǑ$U_?:IYc-4n񶴸=׉}E{7 'ok;s85|S9cggθ.b ?z>www,E`0%Pٿ-[Cwl ÇfLzq0UgFe-ڵk@@@). )eK]C\ޝ$~0e_WQK|1 )n2)px)?> `Vͼt)T1nR'+0 `0 T `0 `p`0%?L-Nx]ܱ}Wla.@̯]18w_ثGFcV`'*5O^/d'NVW P1L&HZb%>j {Bc;}F%]D-aӆСKg"iӟݧ|*|6;VbJHڿt%M䧽oiQ2]^djXЈu!o`_О];o%fh zyN׭ۄ]6Է(^7ݹc}l>4}kZ-cf X|­vjOP_xĐ>*`TN;O_T ҊعK]e3-#4]5= W{J^= }]W, +)L{u_ձK|{Cs5HJ~`b0B=,@F'<`޽qJ3XJNg QR1oXT}$6`ukWkcoLv`!O#Ӳ 4HҲuMdHC͕k%nr<[qv-]81s" 9!ߝUo8+,bv:?Ꙭ/exY_Д 2Qe#wKPgdjI5jV1\] 2d@-߽Б mZC/@]xӧ kQTkʷ۴Б#O?gKT9}h1v;txo#m{7iڰ9ؼ1|yLdfǑ{ٹ7s\{9r%|yGBLZ='Ԧ{FԔu[y@Y+NwF}'Oj*?uȱXZ} ܲk ^ELs,ƭsUiBk9~bךR VϲҬ;^Y7 -_9__p蝍r$. W8pET o\^6e @_DKY'YDn iǧinU&Ɗ [+I3#f_⊯ #̝U&tv ?0u}撲nRÔ Dѩ7)r;{)âᒞC!ȟ{yx5 /+uOoH^=tʹ"Ӱt\~s뮩&wrFfb^˯tۢ5؋z{k!tɤy͹,`d^={u跦9&Tv}{r="lw?`u K,N=v:zx8cL:׋I&UA^\iҵBm YI#cʨv+z&ނ =~fэIbN۪b^gj ʴ(5-5pp1ɿVzRe|πū4[8Ψ %Ng`*7S<`Ut{& ѻBҟlz%DK9gw<;QXsq#0Ip]U>Lf1,9m@JF>[ *C 1nyدR ]tK<չG?{9kWt7v-߯wϮ7-]u3M֪4-)eYFRrŌ ۦhn)T  =!`5ܦʟ+'E0lF lneI%mWIOH呌%Xm |豞붌leqn!]U+w2eT^3ꤼL/'uH+2sEllWkO?gVMcM)AOd2,$'%%0sr6 yNO1io=|!XC7{TtV{Ͷ~~U(7e{ ӨoxZKu!%9).]Ƿ 봐~G!aZRcHxC6GG{-~RNG2z1$`4@$$+' r%mZlFE%"Fk:V_)|#p#{ YEk+p)u<]r4A *Az=eeg )GZC uH 1-gq<_N:*g%lBdeXf@Ժ7:]koH '1ڈz h\0,04M3,Ky&! VuM= t] s6M[ێga^Л34ZȌxH%_ 0y*Mm6;T C FGR$ЩT۫ ÖjַfHbh(R`d%LPٙz|4so\Wuόs={)["zeYC?JH^8i2tTia6V# 'p[a?ό%zTzULUРuC1ZwԊtMq m>tڜ 呅k51:l cJa@R\R3ϠX}NB^h Zc3RQ\a7N,7_'zTD8u$ƌԱlY=>}Hܽݐ}…wչ)y4fʴKŕp"Eؔ,5ޕCdvb0hXu<̽ɹȥ R/ ;%H0r@\$0}7HG/Ό+JҘh͌~\̙3k 5&&1QN D% oߔّ95؆z0* و"na1(ۚ/AH.凉@l跟œM5}-mNln?hA,ޕĹqKO뒫Y֘6s[z޺SP=ԻYYYm:!3w$_vP9l_7ǯkEEL??AfE(;3ImR3KKG8u8`I7N5hcSx,6* zhn`31uG^2̶%&}'ݞ/lۚ鱭 '5} _g*gG9ኼ ޷DJ v\; ΜLn,%26ŷ7Ja׆sv^=W.rFz:Ũ7F{p7I>XS'Ry 7 kϞ ص3,SW}ʐ;7#2>(@&},J{*/ ;cض((0y S+em޿E@d>wH볲cԸl|Q= +@+>}no:4IK2`(!]{I7k+$?*Չ}\()܎u%.}Ȟy%ᬖhO O@|$.̤KR :;E &ҥ1J xHMT P($Z". #]G:\ L+rcr@VxYG[jLJ(OynT1 ')&1l\"JKOJ)Vr1E_]?yJT"%SD%E9e(?cl&JT!V$p= +(QXX*+OOJSJ2D"Use(Fk/P&ۻizEy1TrIFZt֣4Yg$!ZXI  $*J zh֒Wrm!]+z'eh;?L+VP¬}`⨻9zz)W",&LɝGvR]dE&?I-T0:5"cY,M(xإgJC$)QX\ib[uq^fyb1eaJZR&H$2Iq\\@!-IP&HҢ̀ˇOGʴ~ )ais"n=y:C Ğ^>~a700lWP>_%>y&@[+'RZBqNZHIcJFڬҔRDŽ<| @ ~e;Ttٜ6Bƃ.r)zr+2pv|kҰ9̓Ew_ś*0m<؎ vl~zu^u~fsθ>Kq7]kE ްt\ߘrfM۵q736i +x񐙻Z(B}#C"mN+hc 5Dg=1](\UxF6qvT jL]wZG^v39Ctn cN8pVXm~ˆw,5>xzvQ^IZh&L{AGB҅]U3REI6+0&2=uF#̻/i\q鬗{zFK9 O3ne[Wiy5S+p B"?4@EA D 0sƔtaba[Bu|<4G8t^V{y@CxgMY0WPj4jhk^{I=}o\ͽw|Ԫ&WGKivştQfnsOj8E^?ZŻ}ݵy_v|/+T\P6ާ 'w\߻Vg=[<)4ז̨hc@'ES6nvL݋2бjܪ5]<%E}V8SսJ~۹m[pECC%sf ^r] *RixtlmH|1'ny$ ?;MCOhP4 lGfM0 an@ޓ;7-{ N|]}AbJ) ;zb! .1%T*=a뎞dł~IIgPKS? :Nd* '8E2neY; :9چN}g=Dp'-݁Imd y Pp?61 l%a: Vǟq5(Ӹj1ò,5o +ZM@)<6/X~5ha_s^Nn];v)c:8=1zڳ`^`]vdkH႕[ Ԙք'ǹh0w`˥pM P҅e l<Lo)ז=ڲҙMe n%uoZ7h@|ҽ@2@AB` `b 6F[ c8ꯝ0: OR0p,bdl@@< aĕf5GJϣZM޾heBB>}O\94r)M˜ υ1%k6ub]W竞@c7xwfY'Tٶbyʫo} ow0 M{5-mVtDbW=wՁ{U,>r ]sVt9p-^sp16ӎ}Y14Թh^Qb޾ŽLF D,I-z^ێ v7m7.Wwnz?)+EHk'̐q5X!W5bdY)@*+J! 1m88|Ƀk2d W 4ي/,qz Zzdq>t=|Ϟ. iTz_<.h;L(3`QGɁhYrɴK^KŋZ4F''L$}\= )aƣ: ׅvI9,@ )oG2e% 80cDrbT 44 Z@Q@V4 U nV-+bl MC9NY0{굒&WP*)K,e_Sjљfn,Z0N暟 LA2w9Ǝ|o4|HӚ_<RT2fs0}a#0b䖇1o|ON}W7u9 (rOZ<ŋgRpّeWr'VmgBR,dŊ+J% 6 '1k@ff"m;J0f;G8C~Jfx7vYz㶝6Z\P\Fc ZEg<4y|ԅ.(+ZL fkG/ˁ]ԥߢA ? [(4Nb7,[椒 )~Nj`(?:Au;1 @%S@Ib&t cf6DJJ@At"F@c6ƞtfï\M/>at uٔ:$-=u0=I-7Sˁ$ɳO,׋RT,c Ai$H_:RÀR h H.@\`7bp[B?\VFćT}k&phXr2䐓W:s$o%6F|ef0s%c7)_%4iR/!S^UЯn7 ׅ mg9dUG}J+,RJdc ?69:Y{*~]UW1S?t2n9#J(3, 4`V)laYg0T6<ʘ4Z"bE'g$EGXW0 еfԅ3_PbnAeFU9_{l@CY]eeF$;_|o⦒2JXlل%I1vNLDŽE''RLCCuJf ;rfڅ>]{߿}zN%r Ye; 4MSF;>l@3֟V֏;fʠ|N1jEE˫n(bhrS@*C)hippgDP-`-h5p渆.]#*ҽEXF-W4G?ylܡg]ĽR0#0$1*]Ae /kactz4{ve ).Af83I #lͫU8WPU(KD'<7o\|%B,[)0sbH0f6f}ÿ__8vbi8Hotݛd0s-$INYJK XDbbH4ي]vXnAjnRҀ$d0Híu;ys5ġ2mO.OƮc;]d\fƲ\i v5|H`-:ĥHQV lA_ (tw.R,TѿMsnH&Nw6zۆluodl"`M0 Y7p=" :r:5,A!`m2yw&<7*U{RT)LTݜ&m ЭZMM4)*5_&S5hޣ,xŸFNJl"\[6 FG_zB,\5! iuV o}Ŀ @|b.^$J6mgM؏~}j8wm 9D00UA%:x2Bm5tJbm "}7<ܰw.H7-^Zwnf8}{ˮ*f U 6W۫|Vm~M sxTаnoB= !Pjq/J`M{'X\1R RoέWio2zZ+n]OA'mչ|!#$lѻWw1 xn,޴·l% xR)l\z0{ᳵ^\}gʨQ7w|s2ҼYn8gS?> Sj1ˣe/}j}svnv~'OT@-taͮմ8'[Μ'@cvH qͻ6C` &}䦗uxbFv}}ǃ<}JeG79 A%=q驂V;JOo((B}D8zɬ7'v>KGVDĠ"@ ;VZUб^@ @ @ (@E ګ&Ϻ} e aޭ8hoiҠ{S}d PҿDek[ߺXm F36H+Z{p]#vOnӎ^ ?e72WFӏUHt`v/$F$@~}@[gu?XYaqG_ ܊:e5+䣙 IDAT:qˮ:[߽G[kV&.9uF f-N?q8 \A&uf~7ّږob>23zOsٞYuڐG. :k9akw.ko[*f aK sj{v}/ni냗|ao OzؽOi' ]"sKǛX '^ g6,zAtuM_j;z9b@b- 84xx߻=еמi8O 9>Fzd6;6S7_s?]97pPS/nm ]U]Ś %ӣNǺ|!6ϙF5+ Xz785K^ ޼>G`d[CC׏o3aIn,8͝s9_cwNmm 'ZI~Msvж#HT%Ujfrtk&4 \뽔tqN[_|^$f7r)i_q 㙜yn~7Md ?XSօ\laM#C2n͑C4@ >Y ڲ5iMjFusL]Fڈ5<~s1-w8y? -ͅaRpe7˾ Φ<iQr F&~d]枩q4m*!<w.Nyg!m'(uLmkp4f84~#fmM]9nY^8tZ ys۔ R4?:۽d84 ndP?~%ʙUVCW^dc{ɤC F]_MBL=]VR}u[%vw t L٦W+dJU;#di!Y "-s-d$Ks'-# _^#o?MK}{7\7 CPH%%b'%-H@+KŲR1tbؔTyګLPG }=}q8kV2}O: h݅G[&aԝBJkfҵy!x*)Ѩh n=:+1_VL f~eŬ+}P`IؤZ&ҡSvjdwgs1;z+_)8j4+Y% yAԵw'k*9XR>wG/ڠL6."^᝶u.? .3!j? (@E բJ ^Vx4(@V4R=U?;@S@_g`Ao?nQbԳwca~8AKv˚FA?Eԝ/R$ &#iFӔTPg\9)k|':d]ls\5U(V'Ywc(ZD^"2i>d& 5J!,Jne5&PQ4M@h H g (,t)*9|'M^!IK3+;Y~KJsiΜ{w\K)VR2x/b*ͫؼz'%w~%ٗULJ&y}|:aMI$q՜ m@qZZsOo",]jt:)u?,[@ft̺\:JTR p ʠb42G=h mmY^Ҿ@ejG19|m-^}yY4۰h >%Vc2L!mmy#~|t3dJBiITr՛:]'N8qԹGYjJT{]֤o?k7bAEjڲOu4l-csRceܶ}.N$9ǜ'1,=Yѷolײ.KϥcWE@8`lbiu-5!2"6JƚeEC-8qnjoM)X;+&'Rye@0 yFz61g⪌ @Z;rOeU_>#*YI 9M'oԑ>v0n\"RM n7=GTg92o1!skR# >M{Wf|2kV%ujew62sɃeUw .^2ԃ#?8PV tČ+<}&w`6jb=wݵmcnVS濺ZQPƽgoѴ]X WKw.=qHSgE$V+v'Z`,DS?šL"4t(xTQb:8nTIq)pgKoK]fĦX~Qk&rh!xs"ˉ/}/7L-_q썬TNCķoJ8[2cGNURƟ6gbQ{LK6ӿu)W^&)f=B=zSj4W^72 dc]E ]1-6*S6݁Q`9y* ,o,ܣݸP;Wj.s\=7s;=˔ʸsGdI-%i|3=N% Z96tO>PįŪL&r;<,V (q)Ma!U-ۗf̽- _Sjug (MjƋ&o+DM@ 5:l=аZ& XmWMBZqjF90Ɠh3?׋Cg`n#1a8Mfߺ}t lS'1e ` Bb3+^ L)9j躏 ehh+^khh`,Uv7>#^^^QՀfPħ!c8N*XPC+J8ßU̮Hwj~+̦/aIh4Gk& 6 di)rYuvA6T{r;m;Dbѭc;$W)SRn\ ׿H~/˰ $3}Z7qƾ|gҹ*$A2ؚ;'&?E@U]n\ҶmWj@ôѦ=$)w|/~~Bhu{jXhx|a]ᗩ}uyrƁ咆LG/\:m;}KX7R=ƫU~4زF1u@ſ_x7֤~N 8tjAaRkbWϷYtY'yA"9~Bgmy7Ko*8ފ{W㻙ڄX"-e٬ݍDz[lɃgFtוQ `0k̨ۂ+1Uj y 2eΐV9;;A__Ks&J͐@^k8+D/g'2mr4O׺&*G/śiF-#SJ޾%4 LU]woei6m?c yַ^x 6CK6]ԩ/cZ׫f=]͜3?bDx:n8tr/INL9NZ3(,P]x0yG:ǁ$ 4Y@$IlŨZ԰^>ec__SmՁJT2Ǚ"!P@ ]H Vj;*2L:?[)җ,޼eIᄍ!E}V짯1|p^ UtWl[`x^|w~ "6{c{nb1&to+ ,ӞO Vw+ά3wHI:m~^oUߵ!rQƍپmIU~<q06vb$> @") +a(󲕵CN8r,qMa$!=?+ԢY0!(JɰYa㤹7~-}VL3оs QO1cUmV0?{xo'ܘn$@h|j߳MO?|zAdž(İ|bE8$0*lP K-U<}U ԅO2lmϻ:@!+*5>9Pcaj8| 1 y|3"1ywN_ ~IDAT@ VJЄ.)o: 2 8@iu_MҕԝdqQvϛ x0(J }_ 8ƛcG%Uzf]i^XaWSFNlDz! ̛:Q*| J/\DT:oVeb6`f;R1K;9m-:Wj N҂U9O %Tr7IȲSh]Wb?—ɢ#1x6 NT$BALRZ oW?Z'">%cm_\xj _Fi}v  ?b#*u:e?Gˏ8"!ɠXb :SDL"(Hr{w{^!)~{ǖve./^|*?o7KL@eEo,:eq>:q&m/wVz| ݽ..Fޚŷrۯ+5m2g2Ɔ|T=ad$RSR+_,-+?7_ֶ'ͽyo͊N/'_tOvὪ?D"L^w}8%n`E?̛ҙqL_~v.ȟXRM-N$5Qݳo|6r뻭q큻}GO7orƚK6z )卫wH~h6?./)|RlMsxS0azfZ4{0˜:ΟpY9nΘS~#s,lDhs+OzwkO=۶H++4=o$*NB $ ܇* ]1ِuT2B @nL $P47|%,xcD3LPJH?c{4jʶdshSNyS C%"x:naF򬌝B0XRi蔀﹮fDgOHDwm;%nhL2i7NhL%BA 2)'BuPă㦸IaƨDx軎{|dBn QK%D'2ٚn*@"ȿmBpM!ADBFnY˩! 菊>KĉX@!B!]ף/A%\؝mBQF!`pBW_ozܹBZN9vY-$BhH@)8)B!F3JiKk$`UaY&B!F3!D^,&@"|i-m__!!pu1@EaP@U97BRBctB#"@9xO^B!B8=,lIENDB`glances-2.11.1/docs/_static/screenshot-web2.png000066400000000000000000001064011315472316100213130ustar00rootroot00000000000000PNG  IHDRD@z pHYs  tIME  ;af IDATxw\gq w)b "*Ƅh(c jhPTDѤH$E0Ѽݙٽyξ]A# |F;99466vY`8::QYYyhiiihhMӫH'5jTiiiwJJJ222An߾mooϟ(!!>w\h"gwiiiyyyCC,m[[[''']]]\&!!2,,LpEEݻwUVVEeeeqqݻw;3779sfwX+GEE\r"""ϟ?z8yf. 哨))f*f+((466VUUu>DFFF\\osB----&&VVVE>#\\\+.K$(,,\rejjjJJǏo/^z0Tţ6mڔZ >|ԨQMMMs9i4N+W,z\LL\r5$SRRfΜtٳgvɀkDDAƍKKKC=:55b$رCਰ0;;;fnnڿʕ+xedd|I:!4qlolKKK:uj֭VVV?0`0BH]]=33$YWWgmmmmmr޽wViС#GA)++w5w5gΜ%K a˗ W>FFF$I2ӧ$9h uuu$Md2 ,08B5551LFѨN 8`|>k֮];vXݻw'N(..b tɒkkkCQwķog<<<<<<ܺ,V׉Ϟ{qN'jhhϸc#dm۶Q#%_!qΝr,www5xӧn]]]TT@񬬬YYY fSSӻwR#4*ڵkZ@ϰl,|UU痢=yϞ=2dȑ#GBWF溺Z[[?~̙/^f †/ 6F=xsViiiMMxiԩŋY,VJJ "$$4a„wG;;Kj}}ԩS---A>-ԮJEEBɓeee޸qZWTTDGGgfffdd̙3ABB [=zf{{{͛7$IjhhtbXbbbMMM]eVDDDAA%ˋ/z}>a{ɤx''1a„0}GIݹso_r7nѢEBϞ=NeFsNPIIIwSyyy&Mh...!&m۶Ԟ/b>ݽC l߷ܹS^^~ҤI`fW ƊΝYǏ3߿!4q!C~ڵkO?3R166r """Tʕ+ݹ\2_/^Y}N"b߾}Ҋ [|r;vسgׯO8\.>55 Z>nڰaCUUUnnի?zss͓JJJruu?~^^Jvv6%6l|}}wX[[+))9lذWVVN2EYYREEe̙:::]ᚚ^9r{|rw˶> *r>}:eʔ/AIq9!DѨ 7իWWUU92<EEEZYYsHXX8++:u*.WݺuZj_I&Y3c"##޽kooobb}[n8}Zd)}g/۷<ƍ&&&=JOOW}6MWWCu^Yeddgd2 XUB- <§^4"tiG` >?Ըff@MHHx:!)|lْr/^ܥS/hf4dgg3 c?{osy晛dffg,Z|ʔ)]6662f~ 111vvvK.], ,,,lll.\] 777ss9sjkk=9 ~@zYYٹs?466g9s㱱Ï?~…Ž>>>xS===;KLLȑ#uuug̘҂JLLƝG{{_~SRR毨077Bh…555{œO344IJzɓ' %%%.]"""n߾IIIxL͛۷ow9'@\\\^^kEy $''p!YYY433sԨQ ;7nLII9uԙ3gzl+slllpHohh(,,Y-ɓ'ft6op.\EkxccRIOOF㏛6m8qb`` B(88xݖmmmƍC1;v=oذ/))//1bĠA~G]]]F͜755!EJKK45U.[__/,,w322NsS$wzZuL;>|xԩ_':|OܥЂ$@9r]/_M3|~] @<|f6d3Пl9 s+n߾sŸ 6$$fJbc>3|^l60 AYwT__?`qqqǫ2[nahă'#www׎BJJjƌ؉/?=-gҤIBBBSL5kvߏQUUuww|.suuSa[[ P!B... fΜ|٫V|򥭭ѣG~ǣY/X_Ν;Gӧlv;((h޼y;VX!lѲՔ߿ɓ=vĈ{.>r84x8ʕ+ʸ׹\nSSSLL@ЩΛ7o߿O]$ѣG# @d>>JVVvܹT0:))uCꖗ:thǎTuz{{,̢Truu `+,,pB<;ߗmڴQFJHHx8sU/_v9*ݻx#++ !dhh$ݻ%%%=7aÆy{{{{{XYY-\޽{}=|֭?ӥKp: ooo.Jhjj.Y[z pɓeddo^PPlٲnܸdFGG;v,))N2dԳg:ٳ]f͞={pGnҷ4 fffX\NͣRӧΝ{hkkWSI;;;wjkkWX{-*kԩ>sssU;::֭[sqƥtwiii7ozbGGڵknyQS`0O>Me^޽{NNN$IxfBNNNBBB999Tcmmm?DEEq .ÚSdgg8qgJ$Ir=[ZZАnj3p W~\]]yLt/I T_wOlǎRγkQQQ111TJJJJnn.N3 A_f駟ƍm۶/zyynڴi۶mƗ/_RmOD?3Nljjrʇr劉juuG>>8%88׿{nll,̗ W޷oBԩSbbb x,_\xseeeӧOyӧ?Hj͛7wލů0s8ٳgG=~xg+o߾.'oܸ掎1cƨϙ3۷8744|/{?OΜ9sɩWǏ/..elmmommǰ0ڦx n3))g쑒"I^_{ |!rx1 ?CZZWRQQ~8ʺeggH4ZZZƍodgg;7neMMMϡxS>`Ģ2|pmmBkhhhkk;/pb1eʔspp~uo"hs>xJ1bɓG1rHeee*[o,aBikkO>CX,ӧL8_~Y`mfiiI3o޼#q???xg>uRUUc=Wcȑ.]9ydmmm.+ӧb,}rbxp@YYYWPPP^^ӫVʪ ZZZL&!//ʳ3^^^{1YYYTÇgeeӫ7v9"##ϝ;;555'''jFFF|0` 篞ٳgޣ!0_lll\nZZիW`0tATG:p a1عsgrrEjjȘ1cH>}yݩ}ڴimmm=Tr8QQFl|; \jUcc#N411OMM5667o^aa/^ˬ\ÇYYY镕v9w"+O?mٲ?eT VB?v7ǣ<8wܜ:iSRRjii2tD!!!koo мyΞ=UUU]&//w?Ο??h (|f{{о}cǎv%%%ڛkii8pϯÆ ۚTẃNTUU>OJJ'700|2߿;JJJb2\xΝ544B1 tǎ;vիW/_ˁ \VVp!C;؈놆mmmk.CVU[[[[[ۛ\hSׯ;::6Ͷ:t(ITvMOOm۶`!77իWaaao:t CBBaIQD!!={8pt(9lZz2qqqQXS"|QVVv8 ;z(?ֶ j:ΟE5}~zǎm۶Q7믿"---˖-[jղerssT@I&N?}4~>\GG ٟ:FrFz)ӗFUUUQO {>xrL&u͔R풌ѣGmqqqmddsNjA XqqqQQѰa]ן={?}w^g!(<9 bwFh~JyyyrrrPPPdd)5#%%y۷oݹs}w}7sabbrL/FQ]]}K.1rÇ93ܦ,,,;sŘꢢYf%&&8##}˖-nݚ2e e!߸qc׮]/^0aBYYuɍ7R#mlggg LS]t)..zT;mll֬Yӹp\\\ll,؟FW[lQTTd0>>>8%88o 4(>>ֶBmKKKرڵkSNKOO}CE#LEEŢGE٣@YX^pa ɓ'MMM4NFFuyyև$Y[[[~xhFV\\ѣwꄎ0YYYii鰰?L&so߾!h4\DDDjjjSSNqΜ9䗔rwɿBBB-((2jIEEh!$//___%={v֭ΆWE#l6?FÇiwv9Ȣ 閖;w숈3g΀h|!̛7o߾}744|gA1tЫW<fvF7[~{5dɒ 'o޼8˕\t)3f?"cْmmm8ԀNp8T8)))6MSc2%%%>A:t$򴵵\.&L@EEEq\*tׯ{D_"""ӧOwppMX?aaiӦM>w'""2sLkcc-`bbŋsrrnz)eeW^QSSbŊ={0xa###EDD.]bz(}:IaxTݻw$iii OsmWW׍7s7˗c{!f͚%KL:Of3gBhҤI=a0Zixɓ'=ommBGFFĤE 0fYYٶ6*%?ǎ[hQyy'OI(py⅋ Vi2tglll"""BK,w\55oFFFo޼a]F*..x{_0t:ݽRH 77K.Q3 #S fϞ￷3f<~ɓ'lC0BVZ{U MBHޖK43`)}Օ׷q03Ce&N%KdEd켵xEgmq}z,lF oݺUp Yͳ{^Mrrm3vyfE!!ot{.lۼyuN+'K<~aϑ)} $$$3244jkkCUUUΟ0tPiiڧO:3&Y\\\\\L]$++ZL &o ki?/{hHOQɒ'b#kBCj6^݈Yn\%~$DV2ij;aà >=BHLLl˖-o߾ gX666mիSRR,--VZ{%KX00pACϫ#&B$ 57 "#(--upp@eddhii uuuh%@,^`@+P䐈U8t⻤ o!I瓃$f=To@~9DzȇW\qss믛NJyܱcNj/򔕕޽sNvvS.^fMMM7lP]]e+Wf͚ r(aIDhÙs*rBlIWփ猜C=̊!.:|lcƒ:g}f?>jjj.\ܼw^~"##TUU}:\ڵkhii Ɓr]ʮ_ͥ?2!M!µvn;yP q/ߤ 7ZykHBW__,pZ8ÓnCo xNgu9x.}MtE]:}Ѷ@f@֪>F:kU4A m4mO<8)0Cq?qB ccF$%ْF&?=<-FLM7+P조ƺ($FY,psssaaaMMν{(A5j^Mtuu[[[KJJ޾}Kttti4%Ao޼jii544dgg#l!C=zdhhX__+2/_ĎxƱ 1jE>|nt.Dk%,DDYtǨ9iuI~o^\\K##;w9rbmݺGusqq¼}vt]]] ,Y`0tAx6BڵkFFF<oܹ;vqㆅEjjرcmmm޽;88|w^UUU*)ZhkҪUI/z6sI ^-ͨ#jڑG.6Y`j2~e}M=baNJJ MNNڵ_`KBBBTTT|||AAu } ,,, vKtZyy9ׯ_#DDDrrr,`jfG%ݩ9!!.sK7ʾyX@@s&MʚLUkii9q"u\t +s$ cIq+$8"vۭ !BH<'id쉱MM3g|aƪr޽Ww tʕ3fx{{_p0Isuvv4szz{%QSS#џ^G:jsG3#D q8jGGQ?u>wwCex<!$!!}&;;}̙3KJJ>|󄄄HaddcO h@DDϞ= -NKO./45e=kQFb|-(( TPQQ` xy/bU$TdDd?10w44J-!/*n@l{Oi$11qԩ Z_,i7v4eOiDVVvԨQ3fHJJIE{W1ڿ6$IyycǎQ$C?ꯃC?ҊP-Vx _ARR,111*ڣ<1HHHP+C:3}+VDEE , zzzf7n"$$d2qȌ3ttt𮵵!Cz>ͮMp gΙ3F hIIɋ/JHH 9j*+++ŋ_x m6Ȉfs+++WWWSLlkiiK9|1$''>|Xvډ'BEEE۶m[dHFFÃtif6=p۷'ZYY;3;w?Go?DcشiSbbddd<<M׮]/۷QŒ| p8lz !w^/6@KK+99!uVhiiY]]MMY?)S|}}ܹ̝!BVV89!C;/??%QVVF𮜜\gMlٲ@jwѧOFuttihh|x,!!鉈<~-000 ȑ#JJJџȰaø\.AFFF$I>}yŊǏ)))lnn n f͚2ؿppPBBΚ1cFkkYRSSqҥKCCC+++&N(0 }XΡjkkp$ɘ~o߾544vqqp8Gت*llɽx{ئpuu|aO8Ԙݝݼy0LwwȖ:cB |? eee&9WZZZLLI ]IIF!h4(ǃi'IڵkݻG$IT,IbF+**BCCSLrGBBKa~I/_޻w/} Oduu50߿ڵ$ICC9,…YWW$I*ݖ-[H4iBHLL$ɚ$)a ÅϞ=K~KHHȒ%K;֛fffjjjTٰapE1BHOOtСTPO3 :D'B!4rHЬYB%i^Dmܸ ogΜvJ100bg=rTT%%%=GDDO_BBB RRRt͞= ,Aw6&I;,@\\}vww~!6-..m<~АR7ouQ.A𶂂,X >nN3 & PUU600hkk{)ATommmnjGDD,\c̙T~xB?C]]]^^MGΝyqƏODNN5n|z?yCgϞ1Ghll766jll,))QTT~9AuuuO>}!v***}6 x(EEŎM6 Hqqquu3g$""" 7onhh@X6<̈́]kUVVBx@V͞=/S<_&4F DC( 6 篣"ߋU"K,~Ԍ"$B޵Rqq"A&.ߟBl6;669mOBȩ*x !$qlYYYj;O#u ^ PA#%}j8d2h4_AAAw🃍b;B4hݏ[ChB2 tc0}0k֬ÇO<۱8x=О,w5h --`u{Si7e!D"݁Y=e,Bq|bUB#̏n !`;,9>Ѓ>_fܹsUTT=z$--=k֬ 6P<9# B"4m|YR\jB!9L-B}4ڪ\SSu˃$"_ B05"to>)B *C(32F (| xBI&/ h˻~Bk> h]Gzo~?/,޻\I~庺:dccWs3gμsʂ&|3ekh~h!4䍔%)C4zt}QQQ˗/ Ǝ,M#BVT9Tfh hHj`?ghۤmW<47}onvZ~A [qq)))kbbRZZijjj*))$d2Zjjj555g344|3K2_8Cr~sm湙- _PW.aݟ? l1NKO=;P}@GfwwwOTSSeI ˗[YYݼySHHHGG !`0.\`<\~͚5"""YYYvvv111Gζ{`[F2#DG<#37*b*EF 3UdEdޤ}1C w޺u+IoSScbbpϟ?)pHuuŋB999_50X{HIfAe6w6uu**x[)BdSkSO' !at8㰞b EqN8uC62aw 555h@@vv2R,:+9dU1jG}Eqpw!, 6@)'DTłnK Q{ (Mz9n?l.0Ѡyޱs322FU7VC͵ ꟶ, J>|vvv m\&#PTJP[ZZL ή 9"!y#Gi:-'qxlU[NN%d\8x\tMݛo 'ZN4fhykg7o (w܏? ` Μ9uֶ7E(ǏTG =OO<~\o޼III!kc9Қ%͛m5yxm|K] nXuqU]1iWQͯ1ޯk_# B܊\cq^E1R5v# BVtvGQ;6FM;O3+|a BUBֶ -9u >@ `0^Bt@@Dqq ͖YTTlvYYYcc#JUWWR^x!A! Bğ! 1cBHOO N;;;3FWWݺu˝Booo.ѣ^:th׮]T˧Lڵk.]te˖g`oB]t??jtɓZZZ۷ooe2,Y/ sXX؊+BIIIܹ377w֬YDM2%;;̷nBmٲEfrҙ/\@Ko|455SE-J;w̙3Bqqq!H:mڴ#Gv`:V3bKKKРAJJJ[|>竨L&ñ/))?sii)%^NNNLL kaÆydJ)));v/`ggiӦUUՀ}vZp͌+Xww:ǍS ?o ӧOkiiM8^رcUUUҵn?dff*++;t۷=<<6o<{R*..~GnnMӧOyF!1sLt/_F:u*99رcL&wwD<bD3gΔQ333=z?>^|yɒ%...!!!vvvW^kfv)??_bjllwnn.׊655EGGX,*;җh4ٳ{/c}_pwnLY,V||H$vڀ >Pׯɜ FXӧO#?_4777ǏlH_UUUUU34(22ܤO>"姟~)?cVV֫WtttF=g>mڴȲ*[[[GG׷mgP(n݊߻woUUգG222(ʓ'O2222w^zz:F;rHAAAuuuJJJ;tZ͚d֭ΝmR?&S^|Y^^~aĹ.]RUU/_\|yQQB`tԩSMMMqqqIII|strl6Bh>P(tuuqF]|Yz 4@GI<{|֚J7n޽2[ 0@[[ӧwiu)hmmvf7oy{r8pۻIljjjJFݻwbb"9 FARNjooI>Vϝ;foo/6BҒ),,,pf:ƌlmmx<[|DPhll O:gϞţ9Ή'444dH"l]].]ȡQ>}_>99Y xxx455 B]]]:rqt!<_~s̹t@ ppp5j_0a€p1:%KٳE"ѹsOOO8%L__b={s:IMM d|JJJϞ=v5kkZm˖-AAAY3|8o@g#ZKLŋessTF}}}}}}IjfWDz<By^MOO7oޟ:(//jjj>y/ߴ.NhРAwmiiiYSSFz%NK3&Pf|>ڵ֭{_ɓ'/_'Lv*RcccXXXfffnR;ZVbWmmmLZ>.pNȭfgAA۷oeG;LLL'nJ$쪪/_N2… |>ѣuuu6l8x svvƳX`3f̈Ǐ,,, IKK:t"n3 fff۬,6 '<;,,`8qBZpB]WL,FDDXXXڶB=NNNjjjϞ=y&NxÆ ñD3_xW***BPQQrrr"H:grrrqq1^600PWWogL3>*:qĝ;w~TNNƍ҉AAA'Ol2XÇ+((^v mWa B+5+/.>B-t2TJoo^WR5| /!Ώ;vvv>|I_55SD溿̯T 2Rf+U~J$>K2jf&-˛V1U7涕[ϫZXѨnV`( ! %K%!!J,MΛ||GN\LŽ{H.]hii!ʞ?NΎս{wWYYSr?]t֭֮tlmm}=Bg .n#CY܌QߒePu|sUr PJ?.>1jAP'IPTT\r%E#22rCݳg3gΜ+WZYY-]t8QOOСCNNN&LpuuSΘat6uu͒fDEZ$-ՍmdonZ^ZU{fҘ;oDrbvG?#VZlll|||BΝ޽{VVƍ׬YZz2ׯ_HO \Q{EZ/.l"[-ᇆ禫ȩ ԽaYaaDyQbW߿k׮^zEFF޽{7l?"dx<H[xAw8@'=(}62謦&<&Ap8$@,wh5*]m׶Bnni,D,W:"RPqKjJ2|ۈm5{;$ohhQBB***2>}T$"nݺedd$1 jXKn2LGGN[!ܺ>s="j&y>Wu<}$FHB^?BwsGMIX"wfNNN9r$!aݺuyyy86իW=z ''gccxUV-]tǎJJJ&&&ݻ'⤌KU֥!qn  (!$!B-K_6c|usHqN%1]=;t\.ٹ*)))((رcL&QMMfkooА^QQ=`+ǎV55S]X 3";o iF=VKI+qlVYTo9<}D-5]V"i+y_V{)|`W QSCQ'7|i?&/4oն -_"Gl`0|>nll$:|YNN.&&f#f̘!=P///wLݻtuu첲޽SF)3+&&]xO>sN|''Çgeey)S,X'J[rǏ隚#FRSN$@[[2""bѢEvvvx"uyyyCCC:niiimmM@uXz?\.ںh kkk ̨TjJJJ;1w ={6BB$&&|܁u֔@ ҢJBP$444())%%%EGG#̙cggioo_RR2sLѣG]&ƍoH#ӧO''P(ɬ.HJJJjNNNd =2ٳg?'YhرcS oܸ/hffvQrGA>|'رCf+j蜅;v숊:sܭ[T&Wÿ; [n橩4N󏯙1 :@~~~^^t{#(**|??QF!TUUH#󫯯˦v"맏(>nnn[l!_N^FQRRBmܸ1?? xayyAnn{3l6 !$//kU===6}UZUUaaaSL122@g}Fym]]]׮]ӥH#BTTT...jqq1B!/zE!?H؋/BxU"t(Vkf*/bKZwt?idƌ{ѣǫW mۆ7H#`llxM}vS .d0'Oī---֭[n]dd/_ZĢ IDAT\XXHV:::82&CCC#"",-- mmm?'8pLhk̺|](*,lmmeh?ti߾}eutt*333dX,L:<*l6Od2eXjjjx)PHRə444cԩx 8 jjj\YYIΖѭ[7)Aϟ'_%~Ԅv`0\]]===ōf{xxxxx0 "//?f̘=zU'''\ک@Y˗޽2ӬI(+**B! bxڴik׮miiWPP|X,ֱctuu KOO/..NEEEIIԩS;w̚5kɓ'?{={gönJ522SN>|HDEEAlԵxZPhh(A|Ѿ 6'.X+V3g^??_$|>|hii/]DDfϞ-޻iӶnJ_~A577ǚJH)))144D1dPqq1.%%%?&0aAލ/Ǐ4iRpppJJt}̙3EGG^L:u;JݼyV{liiIo߾ٳ EE3̽{޺uvϞ=zzz eʕp |b ~tD;yƍ5k$&&~y|0TD{Bn@B$rl6B)))!JB$* =<޻wɓ'KgLNNvuuţ,?߿sF(XZZl",,,pfFZYYx֔={5kH״&&&ۖ-[fpހF >c)((\p̒&L GSSSi4No<. x)s=JKK tݶOکSΝ;wYYY/^hnx溺0% }HtttRRڵk)Jxx8m_ɓ'7ƍ˱8{UWW#*++¦LW}f\Vb!lmme\.Qdfxxx-MlllX,?ϟ#D"ij[5sUU˗/L.=ZWWaÆx>>.\`0N}T$"nݺedd$BDuuX,t֍TIsWկZxIclU(i+p|@@h(6.ȫT甎< s WwU·j/#a0|>f766ot,''fB3fhcJ;J:::xw!vgϞI׮] gcƴ9"࠭uΝ;fܸqW\qrr>|xVVi뫦FEUVV2d2.]t̘1#MMdWWW1uO5_eDDĢED򆆆t:ښG޽~\u p8NjR jRRP($_ 0a©SpaP(w05%t@ RBH$ihhPRRJJJF͙3.33޾x֬Y!%%G^vM,:488~ǑFONN. @'t={A"r8FN`޵kWww@rvٳ-Z4vXCC7nK'=z\őFBÉ;vJzZ:3@d2wڵcǎ#Gչ\ӧqhnnJt?I,[I˓4FRUUUTT "/ȠA޽[ZZv6WWצ7N<9 `ӦM dff())#vEN777-..NOOTpNi2F޸qc~~>NH#5yd!SL񩬬?ݻ v5ggY$h4HZ]]IeeeXXؔ)SÃ\7qkjjxA߿fϟ#vjT*tûuGCFf̘gϞ=zz 9ضm"/Olll 2'OՂ˗?XSSɓQQQ8Wdd$^ ,,,-//a2y<{37wTH$ЩPMdjjڷo_D c2D"DɉD"ߺIfQUUe2BLEEOC***™e'z5d2UUUʚBjjj=\.WNN!$߼yCn&=-޽Kff&ACh+W ?C]~h絵>|8A}َ?g8tmCCުA244 }k)Ǝ:g;NџI 3|O' Q׮]Éw>}4B~w vss[ T[B6m266\vV^Ml69},A_~3gZikknݺU FEE8p=Yf8 hiiegSUVI**H^J\.C.]JP(յCmٲ H |}}qr\GGG #Օ555 x̌+ӷoDۃ![[[d3NII'Skccӵk ;w.plmmwf^ dvN׷Д/_?̼!@|~9ݻw;tЕ+Wtuu%VssѣGq6f«{744ŘmzzzCC!ԐСC/^OR#G#ۀG4h7mz6*ԟ[555g1bm6ZsruԨQ[nqssqIي...<ӓyٳgxwsukkk#MLLL&ߧ&wLP |j*ƍF_0acG~ = 67ׯݻ.^hii׍ :.N ]}?rDD&cǎ}!EEGGl߾^˧V[[{;w)i2kΛ7oŊfffjcw\PP9sfeeeaak>@ _^UU_~iHHHKK A&M'?wqYGGgƌA_g}f@>mrr-OCCClrSSֻڵ}N8ٓ&M7oLWFFƆ dzwү_'Nt|-[0 'ӠCᅬH޿ø4x`GGǧOz]ON駟^xwߑ0OOOݻ/vZeeQȔ 6̝;@544<|>as8. pd\B iW\TQQ{yW\!̘6mA7oD%%%,]3/a B999A"}Y[ʖG/}{}游8 BBB\Z$%%ePx|yK.=ӧO 牌߿NBBB wvSLY``0xd̙3o8p qʔ)w@޽o <{… oߦP(O<]zz: LKK{)^-))۾}{sssyyp__~9}tAAA\\ܨQj9???55Çկ_sNcc111JFפ ״555%%%<͛7:::7nFffÇRRRbnܸrBaUUʕ+e^gz wHB555ϟhii~Z.yyyoŢR1LQQF,IJmr>VVV]tIMMőBBRfpM=I&}wU>}'l1 P^lllqbbb6>sε\ kΚ5 /oڴIIIdȔcco۱~MNNt>}_>99Y xxxqٳoZZZz{{HwW#Hƍ/^bggWSSSUUpB.bH􆆆B---9v^NIIqwwOMMlt˗/jvv9,"O2775kL6y .R˗/0aBvv~bڡCf͚qwwwmnnAWTT,--ţ0@P[[K***Ԅᔗ9G,#r}V]]̽zd G.!5|\B鸇 Hh46.,+!!P$b( "D3Ɓߛ#!!aɒ%8F+(( k]D)tPIIBy{*x pIDATBٳg VSSCaVUU%v*8«JJJ?W7y`OlmmqGikk+))Ƿme˖ᔛ7oIQVUU,K[[c!yyyxɩsVMMMdGj<ɓ'&L+**޼y`z;;;77KVVVՅSnݺ=Ç}7nܸpBpp0ϿsNYYƜ9s(Ÿq߿M8q޽2GRXXqׯ_C!++k֬YT*ٹW^+Vǹ|򆆆vL&ÃF!x<ȑ# t~eee///???2y%\AA!$$ 륡Fa=555kkk8MA//y{{tTWW#t:fN]]?GYRR_M6>>Av/cǶb׎E={[FdddOzX]]aÆ/\RUUן8CCC!C߿'xxPE>HܳgOEEE;zd-BPGGɓ' pȑ#'N@ZXXܹsK.ƍ7nعs'3i$yy-[|R#F8qbnn3gBaQQc~~>wP__/xrІ Ν;'$5{'::zǏz|ݻwzzzxx<7oݺE'G™2eg;HD <ܐtٳgٳ'66VzRr]]ݘ۷0%Kl۶---a2wޱcGLLt@[GGN5k˗e,}u8g`eeeggzWN>[:>s;wΎBΝ;ɰskCCCxxE"Np8qrr*1vVf600HMM%B'&&3ƒ+'L0m4P~"##q"BIOOƖ,YxbPDD,ꩩ\.޽!lٲٳgĞ={N:շo_6F߭?iOf}/~bmm-YS(!1G$B655EJJJdں:EB 3g\jU4ڳgO--!Cܾ}[GGὑFT;v,UUU?GpCr %##lٲeqqqSduu-Juuu555]zX,8qX,ן;wn\\ܝ;wBcǎxeiiiݝΝ;`FFF w1+ V]] <_SSDx eذadA!.\RcǎpySի׫W_aÆ쌌 2`@@@FF~b}A_ !gDrrr/^xoFgx<ϥ^ё`l6յk׮ϟ?ﴒk׮%ٳgd N> ˻jkkv1b"9qr;Q?1q8{Ν;WzmTTBȑ#TXl٤I*++6oތBS|ceϞ='Nhpcǔ=iG,=z8%S3VzB 6xyym߾}d3g,,,'Ooܸ|sx<Bh8}k׮%ӣG[[[55M6nnn+VHHH c$0LO>b]v֬YxyӦMNNN8rBB9,k֬ :tÇɲ'xF1jzmSSS1hii544㚙|fիxY$m޼6<??m࿣G@ݷN!fqWTIII6g?BԄbD"1̙3,6D"ۿcc#JRAPT t:[ +G?0=JiiiSS&^544vgi4Y!nBE2 '''ݸq`,XݻEEEY,Ǐ....::555T**::|Bee=zfOپ}]ʄB^eҥ+Wܷo]~~?{3 cee5|p 25YE"7|# ǎkcc#3f̘֗D"NϞ=ɤoMa2FVPP077W>g //ɏS]]ϯCױߵvۙА0(]>x𠱱NumfL&Zlf(IENDB`glances-2.11.1/docs/_static/screenshot-wide.png000066400000000000000000041405161315472316100214150ustar00rootroot00000000000000PNG  IHDRKITsBITOtEXtSoftwareShutterc IDATx}yM9ŵ,3؇lQɧ )EmB$-SRْPDd}I2 c{>s;3wS;}5kVWsN@s9["@k""'!c8,<GDD D0uD4&~\c89' d14Ɯ -K\&H߾Z"""Ƙi1, 4!2$Ź8Ƙi8}bȾX@" b隦1 -2MT9꿈@D3΋!&e}h|=sԣ˹!Q}!"0dĘ:ĵ|ܡ'( ;'1&h1@ʼnD,l8$q918q|>&Ƙx;/䍨#$CD"rHPޜ{Q޹|xqV8BsZAŹM[' |_7wXЯ{b_&AxgmV՞?_0K7upn?) XW}QeƘ0ݧlCDc(7u]GdA3-ri F&6|kCbPn]RφSȘFĝ*=Q۹{ktt[iZ$Cq..Q ]L"}$ͳm]vڹRn)5!8;cLh"x\r93e;c 5&nͳ~ _= #H%Tu"h4s D10t]geY@ p{){j5i(&)Iˎ^Mq[#9Oد=I$MqNii0!51FDftLCt]51t&eYb*9 y;Dq=ul=P7 CR2s2-"ɣp@tY:Y+G*p<+ D0 牠@eCbAt6ArV;?dLȪ~B=Nx<,T6S@dp]Cjv8qA2@/g 8‰3ۣ-s ahCdɳȿ'rLW)ds10V2d6!sPl72}mrnpDhc<`#s)ؽ<+SہᢀdU ʂq Pd=ct%!r&=D8܊ݵ*<])=iv\igj[)IDl[}'e&e#& exm_ %n)E/ÏqgKgv@?)%ޢ R'!򧨠{MpE˴@c#<<0!)֡1u6RdO3$(mVw?PɩBD1SAb8]:v*8b$C᫦i 4-'/mn.vpgU ,]4ڔF?4A1 g 4iyNq5MS> G*QB(/=p"Gt3!ضL C$BuyM -RyCyn|1rrEi%\p[eَBh22""1Cv!MӸe` (ҹC;N8p |0P5M Ϋ LD6^t \&Pc"ieZ6M8wc@j!CCPid~/UMtCu݉Y(eFH%/~ Fy򲦘j%RCd #_;a@T+eUslxLXr夕Oюgg^$lkOP.7QGK6"1;) $5mvH1~?{r!ϑES/j:Qqj2|i&搜9p+iu81CI$q| @7mtR.G!:sAvdS:%M2)M!\-'7Zfoߥni/?m"Q7DXnʾ.)@d4M>9ƒJ^Q[g6KԔo$e.)7+' oyCG%E2hGZ=i;EP y0;$ɡPD^(;Ndo=6_~׍mf-!lEB> 60d.v0c }O*4y&!0L2|fcEaljQ9͢PqKPV(M,]Pf-14c,K*gKLBNgؐۘeMgުaz!p+RO썾QP^TP jNYD: @]bZ%鿨dcϑeeBC-Ad~^_V]k()4q)Ld]@/BHS0rHfAr\eYL È4`ׯQ2rYHO ƘeҳtosS@/}ʼv IJivᆨ 8qdL0L Z40tMIyvLáym2,fa8Eyi&P<*u(ӎ+eiO#_%G e1f,\a I-) _}xPĤDrC|gO H"jV?";$B<[weUOtEz#n:WD☛)UnTMWD2DdUP+&gfx/(+G=PHLBurۤ6 saq=~&C$pf#qA" $IF@`wvx%[7l9Ky:peq ߭߼urJ*W GߛxƝNפknچmۧa^Ę-ޟp喭k76EŮa|}D`U]O~oqȍh /e^+SjT3]g^ۆsv@yZ@;+  Ž r۶޾}'G' O28o_iNe2J>֨.YaU3&(f\HD@ΚNBSh lòukjͺek-[n?+<ye1mKyM]|\ K*=F=.dzE\[E+1;e5't黇b ?6sB|Uqwwl5{`ere{ߦoZGZ=Xnߟ~ߵ`r&e ٴ9k9i `L6L[?w4%Iޙp]شl;M|uB~͊};?/3!(m](읋^J67*ܝRFg:J(OiZOu7|S -x"ISOƘg.y uqUWL'I̧lB Rs\Dȩ `zS.Fev&Lc. - }d&RB( /g GCYNȕ)AedE6 w!1 Hgsrk6Ub/pPO UM߷$crssrDi(fg_M $fO(gb2 jf[3rID Vß:z}9g:CE5TJ*2Y EVS;D;3/CW7%d=mJ<5_ԋe ho$lS'*tWU'>V򉈬#kp*r9CfYV0$ n0dQVc]~7gT^g7jd=E(ĵРӖs`|^2>[|e_>sc|RX bo5}hՎ[vm;GľzCbmuZ'wߘu6ٴik6m^|wݲe햭n#˲t8jNg)%L*"CLEUjնʡ/ץ %VH~ƔhU\!(pEIAw_pcL.toŜ'7zg{r(Fa}2ޝW[ їLN _OCcnC(F_eď_}/}E)8)~z+|ұ. "5 !1Dj.WKNf2una&;?Z/ͯ-ysy /,jnfpy?;J?탁dGr̍1#::v׽{aGQ{|׬R :h3<5WUSqd4ʼ0l'grՊkUJ+xq {kOs0?}oi?yr^X !>PӺiM|Z7PeC~<[]ι(-qXnPz'#{tūUwv}=b6q=oUJ4`@8/z4_uX|@TG?s7*>aV#V#Fo%*tԏ1fpXrİNq~VնGusO[ʜ: e7ڭ3f؋G_4g~_P_L3bAZ #Ƅo~s|h%ݺ0K1$T<[zn.O6@ީp)|Yr6L,fvdCM=ZkyVBhA7iqYHN :u|̉D6R#*l泹l7i$S2SP%0IϠa EBƳA;ۓg5 Ļ+b%L }rܜ@ @Lٟ0A˲8q1!"Nu:YZl+ESd𻵇 ><*cL(i* caTd tMmHNZU9mռ>)L|5kU:s5_?YҨU66qIO_3[5 nSE퐞K& 3םreO%tد&dvRg+0rcw8bƹWFZ?ISAarͺ?pu]ck/ӒA)ڤ?<P̓f޳wio5)7ck{6y5}ڕ6}eN޸Gax\PTr0J4ue[=cɷ_Y%I b+sIy~?ܱ{OmwoEܬus%-m眑.mD(C@2J*O'~eñ?|Qgփӎ>z#G8DkŚe4U.ŞWMo!.dz3-[nOc5ID%s{q?no=QJQg,]ztkRɯ5lɢ 5vΪ0x?fڥ+.]u#gw hǾmMF R sT0ьO\b灝-=m *=~7{%;eÄ04Dp,\5K3߱gџ,,ȃe ʭ^rnư69O;UcC%c '+{X>_aׇg IDAT-~4;IuaӴ,ߺc};׫#^uǖHHPS,`F; _qCi6510 oldG!$%Z̢rK5uTxDj/'|P.J"bwghk_ǟ(5xlr/7wgl8CDfK@|ug{VQ<*?}:p6b@|Mk}F_yo;#x1Vxu` ^׊ jZ0PXl-ϋf> $GJXL%SJsChM|w#{eU*eK _=;ш*{$!{c~.YtIú),8*K R|]zLohHLWG}t;l>CZ&lTNQ=Xl?jpj^n)N<}bvo5-jٜn)^ {9^/&t۴xiz!EsY_W ]ڝw]`B%PnMe>XtG(wuT_H{JzOud:3)ǯٺn۪'Ѱq[?t_ǡġ/Fy88wz?pGLUAG+Q)3N\6jePЭD֖qV_,RUx zZxΉU` ,d8ݡWa8g&^vs mt2 kjG+Y1؄SV|$1 *1UW&ZwhQSPtBV^|m̖]G }4_v;\8rUֶ$iإNnvoWl]?>\mvڂ#V5ODU#P#ҵ..'>5<)@/]%>7u~ѿP&(4]-qrHoͺ K:nN% CܒXd KYP8!9Glߋ};fo๗;6]/&CXgGΤm6nis̩+&L_Feg MU'،6~SgOry`,}i{N] ۷aU3ϴ\T3uzrߑ?{_pHc哗0jq"-_GǬں-b.^t@E9ڲ`gwԢC>4J۱Kuj0Dlφ9'm@؁=sk^\1Z5PìM5E~=?\wيl]j1i톯gA8- tI{;SR;g{6x|;NɘVNYe"@t+)-< iDz ~!RBSK?|3nqZRnWW(̓iP}|t@,|3Ӧw]%lB[5"߾t%싹'0I CQCê<{S8OM3^a+7FlV*.uBqpxlEU{݃6{[TWP| pa#PJ"`^8x:soJxRdff DƆ:74I!0ƀ6N*&"n pfgVm?Pq-+gNG,[0.g8p.Z '3:s XӖhmq&ۺz:D@ DF1 SiUG7~Ȃ9_h'Sq9?/.v_۪<ܵC;vr<,Z?yL4;[k+#Օ(Z$o;$+ߞN!nOK`ZP4A7eϭDOƚPo}N3sϛyR(י3'?ݴ왇Hm?2UJمgsKf%=fIc5q?rV3Y"팿30 ܣ[@-W{Ϛ$;9OsL0u,U&*#E>hq*T?/X2c[C"FIM;w{*}1j3pn%g*WWJ43669(6y" aoZ=hՄǼ3o_BVso/?oyR^UB~ d 9y+pA:'`%8[ xhgK?۔vwΙv yY{9qn屉;S!b,4~7\n_hҩ|NRې} 7@)g($Ft\P'TڎJpDm.qK 2zvZ(b>TC1 .BXGS@b:U@L,'R1%_#0ʉtְJN&G$'eDe` rM0RcJ6A@fx+%sN 1'7+&/SZ%bK|晕?z3Yƞ̍oϒۼԠ`Fe˞hgKׇmtRsg +.?4MnydЖskƞ_^޿Uy~!sFB0u PrH3~pП6oqaS<[lÔ"%_?IImw.RL~ܥ5yu_0U)uZ$ 9qo,ɽ!LT եD d:JBW)5+hL4Dζۋ *^5ւ5M~Nŏ`\h.}1 bKF_qMu, Y(VZūeݻ8=j3gXIvR9_:ɥ kUzkz^]ΐm\Oa5 n?DsQuiuws3kuJ ^Z4 @D=ň来- GbEiDhe9yu ,ӶOf{xTWD:KG]oFoYHb>lvDb>@殏:waD9{*Q7.o;Om$qg8'&H?.o3L@;шp5"KCЄvn ~tOjkQ2s7r N<]u0h!ȹ|矍@@-mÈsʿq5o$\e' \cL.7:='Zc_#bCIh|_t ̣EJ9pdTOc me w]G<2{ѥIU{ YsùvkcmR.+6?. .ZݣС):PA(:˞ KѲL`(+w)W#UOnVv dhS" E.[(|T>PJ"g+I=P~$ F'WJץ M͖r YȤۍ"[Nq1bwDucȣ0Os&Ʀi'd>_1nqFGs-p㏓:I`)J6Uny(M bӫ7Rڗ,3`9~ܲ8xA4d:L#C׌('e%ELnY֩4F6;Bu';pYd,SfF)wغ{Υڿ!5#5$9ѼҬ]u϶XL!@TƤ vՁl@Dඟpec}0d_-7o/Ddt3/MøEYg];Gc_{=â608:́txR10FlsO8ϟH*d[,Ők{w_e떬)P;b1b&J˲W}l*^ NN}~kX@zB21+];TߡF,n[܍Tkض杰i(HxN5n3;U/# HxM\cuI5{QS>~1aqѶ@NDZY/JNՕRd@#cՙK(kH;:B\:>jK^(i'N8kEkQ-chO2%(ɮnϹp*ĩ'OsT&TH_8x,@XVLof2/ o=E@>yJw6HQ83͗P5`@ڙGM=vL6gkvP\D-]g+7ܹw?s̱ 15La/ ^nWE+Xd}eYJU*!Qmy>PcYaT\!GR/v=碫ߗD4p&=.!)).γYX]'Aϐ2F6hV͟kv}dﺧ]aQ~iEE*|%o{$Rxw?[utwi[WOկO$n>M!SQ3~C!ix,<~D&{5]ӣ On4'w DomA.^c* i)ldws[ɒ1d(41s,.~켮W˳E" ,0ڣaiY>Q2;ɡ s8V  +UT" 'E9vCY`VTF,d`  ̠i@t^e`?Vд-K,zFfP!L˲XX8^ E MӢjs.s[@sBDŽeB3IsիYE6"zĤ q/=gL.aoUJB0mь/fisVɶϦ] H,XU7'Ylƴ9y_"٢ZsMj=5.?p.‰e$&15ڏ͙|9cHCA_l[ ܤ9SR3+&^UvS*ۼSl6 bJ~ސ*Ϫ+ܾs'5Wܛzv\:}҈Fxa(%fS_kRckݓssRɻ*Wi;m =T)So6m͗(WJ4hX9ml[E(H;ɍ/3|X\'R⡇DVvhmЭw@@-tjUU(ժW-W}i'?$ig,ӂ'h1plO@r{_bS,>KcӎO;wVO4UvD ~=W_|rt}s+lڱN8vZO?i|e"oL蛇_`+etf=p/dO7^v%{ɓIf5լYFߦO*z);mF|ÇĀ^ֲ/EU}qP"۾O~8kttSy,>:|y" IDAT{W3/3G~Ȩٿ~L%ۑ^m>x{J&4}mZ{۠7+[;y]FrύV k-Zp:_bN)yץGnWօ]FJڠLߺgާ ԮuC i](UǃڄݠWJJ eL1knj߂ӹAr2xٞ;MyөArA*D)C"˟~eл}h-X\!|Sx;o埩g=9mC{Otx3P㳘R׬Q=K^f|%6ҥeu|O$0=?^%ZjwԨq{hgU8}Ѳ/VRk(/C=23U^b*7^B{nMgh_nzG 5yO6m;e?uI/߹A*׭ܱ9ɕɆeVPQqm XɆݛU}YsSKM=v ӎ*ka5[-"0)u(܄cƮnahzA*PTύza%R缉\$AXR:~醮hN2`?bX'-| Jo W| B)Q6H젆* P`ii"/gANEM]Y |>E0e9`09::::&&A R"ι%ӳ!6%0|iA.aMge|g*J\$rB)Jqĕ6j]– *$Aqōh`:RD @2Mι0t1Ɖ)3d[96MQ+Mr-4iYDdi5ݟJ:O5A(o,SX:z]ySOxX};z?w׾Q=wx޲cAی V/|>89Sg`Wϭh;;$2,[ޮIJ:~(6u~#oP/i& YԿWIBΙ-Lๅ uSʾ^y"`ڬQ?ʶnX\I=BV~9ѐ7"'fI_ttϿR! +1:aÅͰ m ms]I >/mDD`ڌ/g` ~{ `yPxBvYT.L~{`ÛZY}>\tCU~築>iQB|1iJsl_4taɏ~6䧍:}t+ߪi/Ǯ>"M_A4ØmnA }’~ֹ߶:Kz+nJ u#.>lU']6e5E&zuCr%|$FF:X*!~`WFnhWU |&>jFF3OE ꋞ_lđ1v3p6O|rqhO :3 7|BR"M\uÇr&a&S~ģtlV'RԕJT7_N/IEAk .5 D&0$fztRmBP4]u^W:sLpFlhV1@i(McAq[A#bv1db;OJz6C:b)S4OJt1iXtPp9T[ h,]Uv&cB"¯)0QhCjfܲ, `t~nmc!ƙo}00?)uO+{u-TW~#C>qGq_/3#lMddkSԩO}!mLSL6җ [m[>9o媳fM YOmq:x-5W-:PYLBN]FF: +G Vc57{y8ztäx6(ޯk-O|eUΚ5opNDQv`|&;?]}vql2q[%ChBJp;%&}gx] \jrC)#R#JfLT 7KBb@Z9V\[-QR񅠂B_vz]"LI[g/EƔMm,)aOs#$ykn] isYOYz;בG8"0MA > NJ=]CGrW/H&KRHdMQC`q"d!C9DeY\Q dro)HS]mT1D0(Ti!FtU}^mϟgWE'栗Ώ}W(=1q˴1]]u]4&$Wq@X]ѕ&~ P8|Q>iiӲlTE:m8@z;PpYc2 I xLn5Mu@C/d_n68'uAұUEa@@eAZbr;5"z!;":3M7tW3_6 7LXPKnK+:خN~^c7 ?7~^4J?7s^dnc߬EñULU8S 5;j&vGI-8y\ #cňR "()%'1RQ N n 5iW)W_vuWRD(4RoH6Q\WƊ̑#,垘,K|&k}k Mڣ+jTFQED@ hbOF#1أF(QcA "(h(MQڻ=~5kf}ιG~~=e3koЫC 儩Kh*5QEc7Ä^ 4ZFvִ3|G ND&\qCB4t`rAwNy8i916p.{z&6ɌP?D_AhȸEG@U$HeǩhZ/-R>Ͻ f?x- ܃G?ϻ_÷&p#8O| FI{n>OɈX:uLhF"N>꺧O&)â/5d4U tS?K޺⽧I=|MP@4Yc!Ff4 hK`>WQ)^lIR.i-e^5 2J s Q:ޭܝ4'4F, h~y:ęi10%qhЄ6G8u`§ ox6m|";O@17K87m#Xen[皦 $6!3k¹99xѳ 1AZcf {nkDI-,"@4u5|bzDxܴ-POz N!ڠW7J񗒪bZrs,>h "r)R4V$2ocޏ2{PKF! E_:NQl&<43)ǁd=7w|w{7+)iP5ʚa|Yk, %[N%Sf]+^l@ߗ¯ ۛxכ {ySHH%؈0Xt$4IH*ҕЂ]|cfmHy4i }~)U `5{ @t C1!{FHbFXf\6㣢لB*8Ȩ5O\6r[*Ojҵ(Hb'lY`&{݇%$hjÏd?J qX&/tWY)⁡xopyK^e Ko:;T'̮+-fk] Y@ן/q q(tQ1QVi4MU='-4z4RPO wԸ ? sޓۡ@At MM7J?83%.2GAvY7y/.2cM7}R\И͍y@d|f_GxYYk-qcvNv84"O30p 9 m A T)7 %27DM1XȪh~ʋ2R gy!_.mֵ~h 'H7DԶ1f</07E7PXWx\6q"Zn2d:O1҈H@^w r,\@ސ:;2`3|Hf+4DԶM:QD#70sF2鏵/P""^|:ZHs4CA\`EۻNxXt_yη^WzCIp=RnT*tQ[f xoԞg_w5f D41Q h/Ti_t9g2O(B 8a3OdQwv2"$IhIr^!2cT21'j&PGHFJA;5/Z!:yf`؏!`"c0 V 2T,H(Q*YpJ.P4P Ro &|d!w@g&:R@4 mnqyfõ#b.iɹ1\n[ Y-YlR|L&Y6Y/ r 13%vCrBhL>in@ݙd/0E=!Ak9,>33ιwN(㸡1l8t(>d"V9$ĥ)H"f@G7TzGĜBe=N3. }Cc-:*MSRxb2"`ED ØH*`}۴`cpZXnTكS mGe9Dljk'nY]о)\|3u0v6:$=y$0Ȏ [+kCJCHsD)5sFZ ՝;϶Su)Ø[.z:~ sAn1պ>Y ;׌f# @.4꟔ l ]@RiC<.)ӳ95H^BN!'J8SLj8iSNlK ˹{4Q%B@èAf d Ɨ-9_=*HxM d9CJR܉0&>j"@*~51۸@1^rHF'&25Abu%irC\Ls oI`W; / ikC d=1/2tp\h8 P$rE4"HFN(QCAoD֬&/S)GZ&K}<Ɍ{A=[}QQ9羅.>#L7XG8tw$[Z\pzTs iD_qbwT n4^1BSOZ8SAϺ4Gxߋ%MRVco6( B n鈜dSU݈>4m"KF3P`M4PL1T~4x< 0cMD1@S]pn$Bu4nնuqO1RjJ]8(YPp3p0Rwp73aU{I{XVѳy{8{X@.3%ʏFwD#エɒ1 IyklUU!vr ĮJ(>0R:&l7أ{*L;2)"jqvnclđ\{"%XC 5}F_( cGR{6dyqA'3^q3*=Tkљ#ێ15s='rDЂH+\>@CΉ&#T:sȓug >=s~a',H0E}%2wN^sBU":c(DƁ/q\I@g? dCcA1*>0${Ɓđ8iʴ˝T Rs<[7>{cTP/1[If1QO7$ZNK® Ź#NWucOCj% 8wf&JZihkxS:@h/B(pPkHE%2:{J'h4{}D[gvfO>-Dcżi -JCmdPB cmx)OI]UUM.?[GŨ;6nuq$jRp_]F?m\;\ܜo#ʍLVf4X`y) ,i=0>Z[رp9vp0| Bd ƣ:lP< 4F0:3M"Dm|UWFQK)|>QbCD}6E@"ZDXl;\D[ ޔC+լ~"πĖ9=:Ht5wBW,̎OZ@U |U#9 @< [u2L0])l9P"0㩿Ce if!iw#m$z%2t(+3gJ _[0w@zKpbȄ?4SbaQb$9 &-W&)E9a (e6 W_ La\<#D< kx#TOvJBPx,}Io\zt ,?fqHOgÏuW7zKè Nhvasb0 U&,$A kle9f1Dbxb6]&Gn'58`^5u][l(:(B5=Z<$72F(GZOM9X>/+lUU&N9|=iT͟ 3@D d,ψlTpf s-(4M ueadRzƒ}nJQIY ]< '<<` )XL CEU=e#Ng^F) c@'4JMG2Ilq2Za΃#E!)Y8`XC{1*!( @ޓk&k&4@N, p|>! `IdnXRCi9;ˈD 7DEHIH$#G!0IӴ\wN`'*">/ Xn{Eح*qvUW8qiIiJ6䔟D!ܠI[%qeB.7ʗ0M&6<(6ޮ\rμ" {!I*DD 3](פ %:{ *Ylp'\3m̿6TPShnT׵i# 2^dgG=w 5 ,KeH8ImԶI1&ؠ1*,ӹ 'Ĺ>RHU =pHh׶Nr]-sRPUR"R7,/YOR%(lUu umyQ}_L5F/P]׈ r2h%Dֶfj)ݠԌ8|'RxO5(٧PTcUX҉oΩ h"[$hCР?'L޶wRHr  "*襳ř+m=|3nK}2&Y-Cwhp݌̚((eQ%t,҈)^bRIxKA]Bi%!f 1_G(b;3aͭRd$~ARAƠ)nzf W9x[f4†QU}aOєdYlEd*E !z-{R8:Iؼ ̼HH.T\DqF2&$H ur d`SCaXJ72RBÓbTJ줿ԡơ$PƄhS>iռ0Bo19B:J7dǚmPB)Tvb&ӽ5寧9+Cq9Q~JbQY<(o37u]4y ҠR'ahNZ764U&E݇(EѢ5uxkp^0j{i/XtH=D} -ޏwu-p>w)e ϗ+~b;6CV"6~@&iGElӂĪ꠳m9& ySj皦(R DlsVq՞WsBÊZ@y=WUU׵3J cFʸx2, 'ϞsSF|Ӷhr *2?b%ۆѬO {1:!q "`R0CFyAdmڶmx6* `).xal-MLq ms厑?8\׵B+:[l#H\뚦}R4*5L8$f0F…3$6hHI[H&%UX[HDm@rZC._ʕɫYB֋sRΥobҙu*cuFu%NQ&Aڙ]mUj['Z Mm@]UM'՘N(HM5ܨ o$JrV_Ybӧ\H\)oU\m_ضz A\@nƐSeXY- e2?z륻cmR?5IxDWf4KmMT"I=9xILf4%M4KC4yVI/qVnLkb]s"[^2eL6wGIB `bd} E2IKU9޵ŊLh*k  &)Bd}^IڦMD| zǮ+4$IƘYL1(I4PgSZ+\D$ifr_ˈ.Aɟ#0lQSiE,PsW$r#kmմn꺦Z[=1N$ɉ4wJ#V  v-jYB%E m!\@ņPG -QSQ='y`d-eްݓfMJIvl}9E\S@1Mtupfblgq!]iJ]*O ?!u^x f!d5>gCRF?pr Y2[| W5THK*S1F3I7 UVے(و EQGT;2;G>KT-'(?6TO&*WH0qv:[ocfY]G03l2׶+dG $h+ň=s%a}Z|6nu&3 EԘ8%BR0$X0VvY)38}m?0ۇ9BA}6M)?0>R"18E'GtAL3iF"MՍKYdo[~N>\H4; su@Pv/r=Pb{jhE7/ uf`OaAZtD0JfkĜji5ZǠtJi R rGE }P82Sf'p6-̮Te5BBBkhT~ E';B]Ò-Qj({|p޵_D\J `Lp;gRFj̥?}yw` .8R-H&Mu\\R#p'/,,b,jcN5 []r{S6:䤐hSG@d s= 1?B:u撩+9FCAbh޺-.S rJE¢d3RQRC#u.1B;S E"!SGUIlNC rX44 qxJ3(rOdvlH|s8=vC_x5/T@ÜXF=ruӄRبOfT ΟTŒqdJ3QS3BQP C@9yAO85'B`[J2Lp (#S{KUTL_:$,;]#`mV pqmi@./aG#6]޻(q4AD[Զm1l<&&݇*A/^W+-mnؚ6&\0ƒ4Xyy |(Vcb.K^LCcnҹx|fϻR lM1RVlH}S=<_7V˄V|K$Psۨnbh-VBeʦϔtP{ߎvyܹlxW@ flR(eq(vL,BG%=Dېd~I7Dqa۩ j/)/Xc3m;2J6z"D99C30 e5\]Wwu7m40v~`ޝ-"Tsr q.̊px7S}__bblgNZ &Њ:SJD7.pmw(/TB@0[bn܉":mŸbob[PgNHt aA0uUuΆY13#~lB>uh$N}.Qd&fͲI::Tb%F&ba",*RXXˇfSG5[qFlk\W)Gtx} `Wd:[`1;KR6 OEKI< ҜzNVH/̦ =3tM83)>KF-9`ۼH8O#I hRqrk' ހQx\ g &/B@P7i1+T\rԒ5,jN8P<*YueQ$R~yu#APfv,&!zO &zãsm.@_o5*h:'%_^dNjDFDJEç~""Ȼ]E ]QPY#Pe,M˧oz<|( ~aBڜP"ya:] Ήxp9π{䋜Ng#b4_f+L"25fvMn:3wIĨ?=e=Y8@tηm 3n{ qN6t/7\.-gup\kU f`c &jS_[1Rѷ)< I7\G4A&LB`峈!fOn{ DOg3͸Q@C,ӄw.OG= ^fl#& |%r*mL VqXLyF}F)9ZE\8ɕ^H.,, X)s'6R[`0}O9Neyřޥgp`B4nw Qc) #䶠دH6@l |ɡP:夜|Wf?nGobS7)58,iGTu4͖P$vٷϾOP#OE"\ SDad UM<$0xi%IO/ 2% :JC"63$ CIk Cd~ڇT"I\Wwl@ۣV8GrS:Šqk]abL^I4Ζ.L$޼%μR%O>'qʀݰ,PFw{%Ƙ zD!H1H% SdN)PD͍2B>42W (Q2{Ҍl oyg|qߞ' TS>MND۳J^ 0 gW:Wb!CFB@Z(XF!6J&|w2'=3yG'ds8H֖&mƵL9!Ov􈁏JC"=M}-(u)r6B|Gkjv(ab#a $= ЮΉǠdB'^EJBΉxTrg8GK$~N /ASU1Q zق"h)k-ڪb3ޘʀA眘q6TzhMy 8IՖ;+ N8H+nڽQR2ka`& Y-e21tAfRg3]AD}/9ްPV2at'''^V1Btgwބr,]^ӉA߃=ZRټٮNʝBI]{g, qVϞQ tL-. HҡX<0fiP4}D! #fx3GˬH!{u帤~8iҫ(?*y533x  m~);!oI:Mk}c.:w Ҁ' 퐲emQ /Y0NIc.LrΉ(|Rm[crn}!ktv{% b 5rѯ Tǀ~ShCd xc<"c+K! 3,WMp@QJ:E0Ʒ0t*7BouK%bȵhZ7n.^;Z$8r '2cϋ C"j&L&e 4hZX[(c˳dW%[U3 Pm-ki[j[hۆ}:2{N`dI7|]`_J(:mo}y2 ,"賃i >=ZozR)͍N ;)#1Q8I4 cENK7hoo]SrM)rR:&Bf<"VWLYq=|-2ءa |RDc<7>`L3LPe8IE9؅'`Jrm-V"^-mN\$Peډ¬달T὇ Nm/ڑ!lٲiѾ,Z;f5AZ0C:숊_V>1β21NA(5$.Xdl81►|7tM3fPcT0>Ksy0d]xl(8g4esɌ 3ڶqmpBdnCAd-B`_#q|=I,,Dϥ/=iIA frz4ߠ)2 C[#*,J(>7SP9PĽ9c6ԨyJ76'x-qˮHyΓ!@UUuUYm~1XJAR|tAҙFg<0ICzAQ=cbP?,ִN4䯱͵mB<1%(W̆)GlDCKf/yu`4+l*X韌ɒi6͡eq.G%FC;Ut:(N#mEeáC@ d͸qRDL*K{&(T!1J꣧.Db7Ƞp@g&Pq |TZ < r#vHifر ȷMrY:BP{;yv9I,G)(&ʤ>*<P3n󂉅#Db;eMH|hGÂanBL/ʑ<.82>iه22hѨı'xa,]գ$*']wJ=/j$;)[xeG886+Q,F5"&7Իnǵ c#"Bv"3P#?XHGyq[С%QЙ VNC!MA$@QP!Jy'!Aф*<!Eb)y\\9 GDe Њ 8Dl%O"PfPUfտ(   *\z pҔ8:-,u}۟t y0:CC])Bph8 ,AM:҉ "5ve Dؔ>aV'h~~$>+Z/#\\닿>#z?/Ҕ9M ){V(FM݅IJ4!U#vRq}CYQb.KUUU]ce h!+ny?ۦm;b.epF8֑1뀇r`32ā4GQ]؋H tґ/>%;(_>;?ni8#Xz-JMp3l4m۲ 1; Ĥ$JᯚC'2y̛֬pJ ${ k 0wӴ̜O͢UVm֗cpue2sn I*,,MR8\Yps4fTdnx H=ŦTgwTo($򡀍4SNvEf8$^LZBT.IɥCsey4~=ASIlt.i2}@)ElIqH51<ů9A||XyfÏ}~[{~NVO\T7?~_ .7>žl}忾qՓ_ώ#T>}~g?"\1oO~9_cw4N)#L/ig_|}WvE?¯ڽWr,}g]xoz6Xxg/>׮_R5hc!k*/,?:( $ (_@hm&*o^tF{bІ˨H$@uOE3K[4ZfixW=YCՋ ,fZǐ+]T<~#A=Embus㙫[Zu+Ⱟܶa]w_5Shz4Uum+kmtSSs#x hӴ-mg^q?VfPU>~^xѹ?ǎ{F֩Uؖح|vg~]u3?onWYҳتգhܨh477͍FsznTjTףznٲ+/_lţ^s.3;n!PJD?4uiգQ=2)]Z[UivܶdB5 @ ůHXh}^/ɺ~r'G`w/^ҫ^{knXo+>_zW} PpiW/~@EDPOo`cܨ !֠'Xc?v wn_8]Wlqi74WWUeЀ[7uUW?;}~_B۴uIU٪2U '9[C tnO!F u1Q1̖w,+ːkzUW'ɺ>t]ݞqܧϺટǟ[Z5GϺ3>{ܾT4`LXޔ~m/Lcfǽn^Q;g7՚W_0n{nϼ"Pr "[Vu]/[6WȓϽv{J&)@h^aArC uM4ƵN: 2)ele|B!kc:mÏ䨷Ꝟ6>5W|Χ4"@}ƻ?yܣt_x̋^ܶ IDATヶUe){J)Jq1kГU*H*0--KLu{+V+rDꄒ =7N;hreަ"ӧhm ,,z` 8{@_RJ:HSnHKvͥ,  hP11NX?蕧}cJם;npW|A/al[H&9kQ>D4s3ܕ]z}g/g {_ۨe4Q$뼿|~+N:OzwvW>vRF6?r7}d=QEJoeo aڔzϏ̖|z˾_ؕIDo )7X"1 k{,rI'G֟/ƅ?޸;v:dw;xxmG\awU?n;;~ï6M:w|<9_uGsԑuvu\7g<Ï;sӣNx-5v8h?6Kp be-˃ &j}wN{h{废iգX[|f5M3n2 nZ zVyCVv=ϝo z1[ R2O 4FDb@R@ED p x3g^pm0 ͖є L=I6o:M@b^aó^7#Xc+H:+]M4ڸڦM3vdx2y;L)[U-ܒK>|~+^-ew^wͿ:/]G;?l9eko?w ;杏x̦O8{' w^>|n1އMn醯y7\/_O;=t`ӟm_|g/ݴO}9ЪGŏ^{?ܯ~Uc2ñ__u] ֝Fr(!φE(/Y)O,To/WEҡ)T伧9|HM;ǐ@֤ׅ5Ѝ7\ 0uHETS!f忧8^mB lٜ0*}ok{ ZKL=`Jl|Y};.6k_X '>`5;O7/ߟq>G~v㷪&n c%)*7G|.qn '翸o/#\7-yXܚ#=u"~.|m| g\ze~xվ_sFj;Ykmwmă=77ٽK=yأ>`{]uCz^|A[z4͍le:GgS" tiZΛ){;~s/켯|߾c}ʺZ/|]z?{ګ_3ϸ.lem7~~7]wNv~ض#`h\dm9`j^q# yZ~k߻K=Vz"O&|Nګ.₯}u{ﰬ;? U?"w֏;“ܮF˾u`/kc-|‹/o~lWųMvm6*[ Hh\8 Q=C.bS)1"{Ӿxo/; ?oٵ\s\./\Top_|/)?9g}ߩwo?ۨb:%T9 -rOK0"ޓJ{t׽鉏|ⓟyYho-G1z[l{KӅ? 6{!Z.`|n( Q j}g ٸ#BbopSYFz eRAb>&7Dh]{OOe{/>?T;/W\OO`_5 7j :Wg/;>u<o~XqKfnGOy!AĿ|>lq-Ǽl*jr34m\Mw9ßݔltW>1!+􌷜݋~|>x& z}gϺ+'vGKs~ҵW\uwO~Nc6 Hi,/HWz|x]Y˓K~tؘUkw_w-c-]{VmD;uPM.\wn֬0v.{]1Mw|Mc+~vV}3)=w 2jP# ;jS뀗7.HYCjF7K&i^p ˓!$H4*c`j1u:d]3CPp g0;pOy( o4fl~bdm 7uK|NuP/T!y̓>Cl7=Ǎn <3z=}l,D,bR :ӣpCb5yMkr֏}Smb@B]K,Y3͋N9?RÓ=_X]/>/~g>Q8Տ⮳yq\@;OO;i} ޯU~͉'/CyG?r4=̳N}ޮ#uE4p_vnc_O_K'}\B>a$T~\?=.ls _u ںGD?_=99l\w;ꪪk⠝'+6O?C;`뺎 d01 *(|T޵ֹk"AUemUͭdyS~[/ෞvƏ9-ɋpۻ~~Z,G\S{nṠ>8=ivH0hԿ?Cv;/ {"z>rK?^paG?kWo>2'=>߾Y?s%EH\d 'P@1E0ń)YPA$KwQ=3 {|w<0;;]]_h="_5=Ξ{vfDqY&E h!0kG7nˡ9cLKy̴c;7HW1D“FЭM0ɶ@89+.vEְc,=YK}]ۜSv)#VZW&ܓ5n~ns:wND`3nYAqL0 ѣvOH:l˶'4#d` ݱ͝ /ܟw dU׬@ZԬR Xv*PUWӅ|wms[qDŽʮk3Xi x61M4 'hÝ`+X2qRPiXѵ9}wիN5YsvQUFޞI, UV<f*>͍`,cV@3;s/@-mjԁ1|5\|Eis1RrS:wjwrN#"ڜL3 K={#z7q뱏Dш {QMSm2M4 }n;yk-'n+A=3 >ܓw{. ¨9@&e` |&!B@F5৖wܼK3C$dٙP|u:sxJКF=Pm׿h3HZ/'̙hWӿ08 ^I|MLJ7fG !3;5+mPN[; Cv];o;+K&7-6yZ^/6f{dب"׸>'} 렚G#*^^>F;&(*NTL m>R~'.{)R 0%b9Ǥ%7$Ppl#J>Ȫ[K mg]|Y9>xpϓl/x' UBCO~ ݯn=o緉r9,;[M+W?^n>^;VNbb;g;S7.-E_`G?3tښnZ0[#e}w|림ZoiΛ w< !3;%B&~;_~Y~rIFQMuL0 ǽ7ak;fyyW]r5A+ԪHW/ݴ+~Ö(PѶeG*5zzzaHӢ[O/N^V5,_lj #@rMv7en]naF(K^ LEXG"7FZ5]3BQRiq/'/:xၘSw"%E%E^IfZs_ē\P @4]7Djt.*Ɲ HnN+b) ('U)[hhnFZN}[8!˨R.\mF>}#Un)Ȁܶh$,쓋_+\5i`w}_¦hg*>3t`.2 &ڹֱGLݐw`_s|ceW0!.M~i߹|[fՊ`yLdEg굻M]`- EǛL[ȁf!U0t]48m۱h$b:a^8ٶmYA ȷB0Le ==+@S_+W[5i`w^[xRfYvn3im!!"ůBrkVLmwolЮGv4oA1rzeb!,!@¬51Bf=5-2t]#Sެk-[k;sha f괾Zt8w4Ʃ\MZ;s3EwXBpM? maӫq&#.B1 1(` McԒ'W,*]۵ytΤ5C-jd>zwy?~{5"y?p-.oozٞ_LխA=HQKU^aٕR>BPj:-l +fmΫ*jX .WI[t9<0_E@R2 #9|)KA5r6cX,fZ%:Ɂ^x߲hFR/u|ˆ{7N)uQr 8xԒ}EC[}^ƴAoM\cu?7rSv7k4MԉX*Щ3 1#IkBg[v) n컃ueqv3QQF@YWhԼR/Rd7GxoJl>5ݗuyq1'>EPw3;" ΢C_|9tJJ+2[U"!5T~\Rr>5L )2x~N QRh{۸$,*Wn7\dtlx R.4 cuEcaߘOq @;UUIqQWD=߸J6D߅kRtq)/ zl?M6T;څ3 zy|rNNNst!衃pڤdNfPy?˨cgk_1ꨤV!]>ls1Y)^i֩o&uӲZ~j@,oDf#ׇ /_ UI벳=Q4"#rƳ⩵kY*Z+L6O!'htOeuMe2yNƎ+#;ԅ[tXȶG$z: 2,˾'*@@q׎[כOh骲MQgN9MFor?2v[{^֝UYg8AW\g,Lh &MvɎ?V?N\u{wl+09iDcUq}ͬkUF"J &mjW\\םBlrD~^>'PwLbNN9/ag_-*ٻmێFVc׿A)weտA {STf!" AD"Y~\ҰYŝ^xMM+oەXz&OE߸NJd﹧>h߼&zaO@ԸNjjnK{3=m&qR:R -Ka۲9qj+YkۼA)wy6㥗?~c=ʷ$rÃ_7Y6;Ow\}YտFݻ׼B -iupNeٶ%Lg* Dtjz'rc,!^v}7zVi-nonz IDAT@ܽc e}Yfp(^G9~؀cd9I,@]\^GAseٜ;JDj{֯D]ZAz:_|*V:+1CFkƏ^{gԣQ<־ܟcxkQ+Q7N*L Joz/[qPt~һ.-bT9[nw(@T*}/?pjLG,2df+ԨM_~9yk^TpCU$ BWD:)(v6cMj9n]p{MeHigs߱# f̡3 q'@`Y߈ |ƟQ=[:ً(/ԓˇZjƥdB"@Q}ISL-C塠UĊ-@~9sÛ:UM(:ZY  |}ǡYN9Ǹyb_ޮgj[I1A@[twLe#>I_[ +Nշ0[9V`<|ݖLenw:餦ә"VڡD㳫$ Eܵ 1!u-!ϳD*y9&-)`iV`@gBe&UuWa0" j5r Zʙ3]ciX 3EMdӏAŅze$ 3<'KIT //Ji zp@Z20<$U>ߘ <>w,^5`.waSw])${됛;O8HAwze!(Kp,&V,O;̖}Lݱ$vՀf~X5gߚdi O@u[6])#i x%C 59Nњi5_]sU|kȮe2;5ȏ_Ja:L4:NNbnE(r7p  ]yw}I;F2'Fv|2cz\mqL2EB-f!Dn\fi@ PªӍ$5#VhEU|؆7Hk !d +q,*|D˕7NcSDΚ(T%f]0mw*N*zt,1M5t#9Z$47R@ɨ-[ZOXXw;4g^7Of|Υѫ6cTc}6eW4a[t2A9L@z* 1-Z&@";QV?\:6ILkijN=rݹ.=ˍ 5)u[6ШOv_7e sqM;Mc#'8R2qb@[X}fqbo}CGjssJr!W Tw "R3T22R51f`ۄtya޺zUY6,ذPfZY7}<7\YιKn %]S)1+VrNlnz JS 7R.HzCb歪-P/q?ݥT(ZڃZjRE'yB޻H*ȶM]~ fԻK2ޓ*.i{iY2(uNa|v`Tq߰yaéFe]4Ozfj*giKPt)[{8Uv$.Z>޻=?\&soF6;8 )޽X˚UMD -4Σ&oS{PJNr6Ֆylۂ~CX| 3+Umƴӧ-M}l:,;*6Rg_ <7[ٗR5 AӲ/4cǁ9pF:Ȳ3(J5NIa;y;/ wngUP/W GumI!_ϗ&@To=;wuvln:yeBNLN,ێذVr"ڍbvvP1 g0-;͜M隆q"|V{A˅0r /Y^T{Z 6yvjuv+]h县vƥ)!~<l6vzm[L 4#e%21/Jf4s8ԨS~yÚ]غÕem>A؁[Cts틶<:cQu#V Nbј3e.L;D Hu9>DmYi[j;o߱}{Ʃ}/HC=WńxUAmKh ZªNvXt] ]34ۇ}d?~_f]аnF>}FAC|E ZwsMߖؑH$_fR7*GV._sof ~CKr`3Ϡ{Zg}rhW6St|suu-{N^Wofv >ֽja=l8@QU)(}M䪾[g:mιqf|˿jgWiںӋ>"S'h4|̱]xl)!Hh5xB2y"[iLȘ&Bgn\⺍{m,]zm%i{Lǚyʶ{Msj6gW8d~_wvjnظ) 9 U"!邑4iʦ_wߴrܵ[TĂ{}|N[{eckjpnСmwnVURt]Rhmۖm[b&l&#D"cHiY& "v$ϟbK:coqFV1S~>X]]V{>eݯˏQ >զ 1OBDdwl۶=o~}ӊ!|yǏsk>y/d]<ڷp[OԽl[9; !O>UM|󰬈.*NTrdݻwٵkϮ&Esd b;'}#fv-sw}70✜pEd%ZctJHBh׿\꫽ 'mvȣOteh#w5N]tORWv C`/W ~Փ<嵧 OmZǺ"MDjب{`g>^GŶyjh=]˛EDkUzea'6Oym1@5|/tb‘CllnRri*_?Snqw{?0-XKI1)c`pBCYrE=xHssHReHuWےKF/ 48mu:.D@RiЀ Ֆ`DL$q Pz 'e =kF,Aj6ޔ,;u(ziQ +?ގ$?/e{UJX [3||rS/;v\;tdlgaN_2w~sC5IvbAO~C(ƽgzz pI>Y%kG~oW<SR6h= q@k{&^xWUԣGL>5o楧~'vQK gfL8^맟<'<4맟O~JY#~`GOQ#iBy!{&/f~dֻo|k蔥~-G9bM! 3gȥxF Z~ß-30rifZ=:g[$l﮾t~SG U.ײ5Sǖ,dn/v*\stӇF2ߗ^Y:0qXq l[XrթsNE|w`E%"Wq^o41W7A<ڶm'];WP *֪[хWId\ xBw Dm%h_ {t̋;S2 Q_:9>Zk/Z,_8@OwD#zJO{!vd/z}D#3Ye@(N/?Px|o/] C} O?~37Z0o}og_ov||PG&VY<\<@1DsO6G擮Eܙ~ GŎ1nYs<<(&{@BbC&"20^4tMgL3M&N-#>}= c#7s˶r}>h{Zm}%'ޜ= #kȈ !{D1Ѕ?"IbC4-1C"6ao7שeW\Cў}YM;eߖ|E;"%% 2vhvGSӹ3w!\pul^~B#nٶER@uea/*&$`H<6L\I<+󠒹^ƲwnSfZA[F{SZ ϼ8ERڑ}yoK;`RLR -6]fr߫j|׏=oA6)'V?y1evFbf-:Mh5Olz2Twqoh1|V= dAu!B ־O? ;bry=zdOO^}z2PO]y+\AD3>|왒}_WĎ}Q˟yQQ9wd87{v:S14e>Ɠ0v2w@ءnߖPA1ECqj+zI\~4w|OOTMq%E"@nX(53D\sU\g7B/.B\U hln6ٖm$k$6DIcU!+ggPӘRk}:>neܒs)[$s}gz h"%mzrTvrTy;0"~W(*cՖ4 9.=( sL)! JX1 ao--נ,q1sG "*AQDE>JFȶ-"*?$:%aY<=Rƕdw_TtIU$t,_cץ9[|@GDDv0PlѓI0A Lӌx\1r8QudL {]A 53 W8mۜDԄ1-sn۶MuCuC-s)id ŇĕHuvD@&HjJԢlbX,FKv+ႅg!At.E '!~Ep֩2Fj"*k ո'>\ika=@dnYdۜP8 @ā۶{$;( ]"͘&?5|k!ͶHv . :ض(xtP{D } BPr0UOM6[srE9(1& <܄R8B4g`ӗ Nf뺦) /aXes4E{Mp%2>pIA@\wT AQN=RJEs:/`jr(&0хet!&Piv:Yq&%8eFiRjHJkWfC@vkn[$MεQ2,w{t䶕<|oza`^I"YqT!*dP%of(s5!xfF cb6B-%1B/29)>/JMjJWAϱ]^<#: +uaKr9.&HM)r^6@IDbir3O3jsivr{Q*"wγpuw@O"uS3I=?V#oo3cSw6}cOF /Z&Lzt^OQ 1=7I\.-oVq6J 4M -7ȃ;he9ŢQ%[#I4Tǎ'ӲީD1m"qZF$7@BnT8TRWR-Xv4!x H@@dmY1!,m0MeV,-\c U 8J}VTp dH$h2|UM)a0L 4iLN&/d"*Bey̌٦X+9JDD#fS!%qo9fȢј/Lږ*` }n鎘e#8=,ۭ{%A!k]~N#Lo]-f隄2[14r@@SrJKsvD.D\ڹ%k$0. snLns9`4U*JLX AJLuazl @v^2O2Ux|ڦEXWtc fK "Y"la }}ߜ!=gL27))@\޵l>+ߨ|⩻z%QtX#(xDVR;KM"CTjsuPTܒµSpW5Hb*xdW]Q¹MĉJW^#W짞L R!>d*TDV@(,gLqL(E(X8K&VgMTE,B8pPC ՐA 8* ^axQpWd' [!M%;;ϪbfI 8?'z.%Q6t TMD?Ĺmjcm;P%M/Ot*Zv(LZE؈H mrSZX(bo(da@= Ud˲9.A\e,tt/FZ:FQę-.[:24\ŷ7Xr@fn#x>>ؖm&i A2 }p1LF}r`>MAb+'JƟ^_@U;U)cVJZQazyO@| K%JS>J+=jj= )A֓̋nP>Q ^RHU\!_~e܉VH2!ĕTm_QFbj"Y''MV qv9t ,Y&0f =*J+, ضE GB%8齇aƘ*VT^eY91lU ij|&V"ர0*Rf^N% 8y=c"M%" bUjO iA.661NEf,&=i cLc"|+tMODJl2ι@2N?U:D *59Xge襋ttSu4c*Cd # f̊b$\R*JĢ~ Po-.'dJ.5bFEDLBLca!셕B9\d\6 lA6d\G jM.MpKC@*R]B+ +he9$[f񢅉NG*ɩ^+ rz^+z))+y"%GgP0TѾJ ,X;#%x=IET<%$RG5gq ȲF=*mw Z[ &5ɟ ˢ $ d zM-LT :Ssyo57sWY' N;~n[ćf[AaҶL\qO{+QBk6rѩrCՉ ʁK1s ;T1&4" =P*)9L"ѥZ5Qݍ@rC97TOq5Ȩ>0sG 8IXNfEu^/ZZz n9 Ȩ@;W{zZ͠޵F5sPnӻlpff{`tx̚A+[Nc99*vV~AչZj9)ltV}]5T}jJZ"0Rpe#Gek T9,oF:Z59dPHA +.C:#L7yx|WB_:[g8?gylwVYpeQԝ/rx$VUv ('J/LÅˈpB?XuMwd۶i1Ӷl/po MuQcV̴L˶m Ҝ^aBF(HũɉL3qNB!09M'R\ݑqm6M4M4m&NHiWjMo_ð,juݑeF Ñ0`if,DF y{/`#厕AeU+N RF8NIapRq^z85%fF@@zC|us5@ "P8:=ywٶFM[FMnEr #?xGUSRRBFHt]y!# a<U4ROLǩʡTsWV8i0{ֆ6X8NIIoerL$d7۲96W<ɔk.P;dyT4L).!>M@ʷhq˖[_W]§'[$p=bz>g8׺x<.&ha`b;H1 ,<__(ȊN*Hf xh₯fkNe"xYʒ{ָ,ĹpbMxg#n eqvɾU̐iLl&0(1NUtܟ kw2%aeu~u.i !J]j򕋗X0wҰ'ZePe",lԝuyK}V5]5!C5r{A4`1Bphz _;?wقUˇN̓UuICYa>m@qCNq͓͆zP8-Pٺ|0qڊKV;cm"upQxf!n#D9C4tݹh҃%RD*+)r~ FsDH/0}e*ps/C2e2SRSa "ff肑ia@,3-˧LOEz<@',d>4l̤yW8k5)Y!ol?7\qMm\UiUn?ش~j1e~{q;ܶm[8f¡ m۶\+&FEs"ɳ:{i+v8vBpJX7 8µe:wN˽GT,D]ЕrDt9u'VIWs~~|]f)t9H{+~_q5})qI!_0wݪu'vѼR*Ko|KcXasƼ٥I<ݖZ~Z=z~i_~?{5**^I( ۃ-@Ꙛ|Gu1`ГEe!ofۖ qm˲be ='OI鈲=?EmX_ԾA4 9Pizٔߗ._lO_[#4Ӛv{mK.[u e{l{/׍9 ̥oU==L/2S-}。\,br)1p|}8wH09 +D$^(N#gŠ@RsMJrD9*fLYH:%G-䉔H*'8W5R"U bffj!Yȸ0wHB,xˏ. ̸}8r"c:@tRDrEga>ϸk o¡0Q ˶Κ48|Qti}ZdAk V۲RDT :yyo7 Qw*NudAѹv~dVH `#_=y =sb Q{o]8X<ћ4"/Q]#Gᥞ_wo9'O?"3 lk3% ]d.רO?5omK$(12&u{~h1Q :=vW>ϱ g1-Lfdϗ774M˲|"C^2 Cܱe7fpk3%✛iZ)ʛ|o-{")]lNKP1#)q<(јmۺ!DF~ xIcĉ,Sog_7 )GGJ=# smHmGjl(4R76:yces35\pno^R974 -"ƥim0)a4a1 9%-sunWUHYu]}[8/ǜێiFc }b=== 9˲1l xSѦ"RZF)J p飖6߿ыBeV!}>``EbU:v /uy+4N?`;~Jex6 IDAT,a+fi BP1w*e'Mwԉ+Q( `)8 A0,yPP(,}h۶iYHRp=Au;3w{ɿ?zVuc1Ƈ+G>:╶{>|9G_wȻozfK_Y=yڼ_輬 \ɵW56 JJ25'JK;i.7KUC PjE1E%}NVG [,ɂ R_J@[DD]Ә,voT t=;H$cCɨ<{dIOH$"Y(;g0 W _xU vH"hQy|īpTϱS_Rɕ-RӚEAk*qTnRVEjZb+ 6̃|!#C\8UG2+8r#w{vÈ[dq[bi: xkCp)o 0\>w\\=<~ꨡ_>$x5yȩw}{,vO U1LUX S*MޞZhƣReӷiȿqBͯocE9bo]]UΊ0U'yU~`ӛ7v-wf >{,vbОl}}ns^]kðJΘDNP z`dt- qCjS8JcƢ;{8&*Zj؉b2S+Ͻ".ˆi=V#?h-hjG9Q~<5RՓyᣙb]oWxO/Q [\bTrP]7muTиN_.]C}}w\4M8qi}x)sMpI$ "*ʊbZQfL *sD]E3~"Ȫ("HpKi{f}vߛ]0wLs7](aɒP|0PYjF(]Htsqy|Jy<9;ʏwqs}ZM~*F+^q| gӺiҟ?zg('DEy6x6 k.*=qu,˲o1ݷBchťBsO>uʊz^~4-cBI/ 4{ ,\=ӎ2ץ s!u]Ea0-"`9Fׇ>lNDDϽ|8k<|cl l1COܬk2~˕CsANjFпwV'4e~)/e/h`??g8 jy .ⳟ5|獃Z ~oN^wo=nun(S[/)PO4-=P۬͐a ͐2l1e)͉,4j.(W1𑬙Xdy~ڄ9h0䊓7 kƈ3h&\*`:HC߳%bRru<$7Ras㉨}ڐFqHtBxj`DO=>8rw?pv'~Y'doc.c#|#߳t&A&s><ማ/ 0Vso)Ç^4ƻ^]UƏۯ<綟zg4g)\퉬fg=;ii.r1Zy s@(@Nv- 5?aw_ ScwCW,y&oĽ_#|ÏߎϿcΙɉ <~^=NU 6~T?Wwi'n>9^$ D^7o,̬;\V?U_ls߮,שuu^U>{xs+_|9uOF4˥5sZJ)?cGn#׌G ;펛8kuVۮ^4cu=mף/z.7?H?㌫&o=N=XӮw`Jx童,ӾLl׌Y=f;ٶmW"_x+ҩ'!h?,Yw/'^.wS{nKaaQt٫^p+:pS5ϝfry:{Y%Ëw]~9<ՍݭmJt?) N:v],˲m14"B'NRNq]WyaKt?= Xr@!cv"a'L$ ݫm㍎2[R=([F?GD˴l2-CT`)c.ᔓ0e T$-vĐ'_6n_#0L˴ kU=p!_>:]>6??=rzAUjϟ۩qyؾk13̃%Oy'ou!vΧ{ۜѹ f-m $H ,ܳeٹY LuDf 槥˿~뎯gCL^R^| -MO8bk4ԭh뼏7B9r2˲L˔ - B[ڰ0dyezb Jy]0c΃? YQ[&mS\p~|ێa|Ôs:v6`.ۑ=vplNj0pcWL\q7]8d]:`72Ïnn*s=5}i'f0 oU>dnw|m3tlQswK<{m۔3K)+):gɅ&}hß(l ͋f~ϑOnvO]ug^ԗםxB/q4XOAOlFPw[d5۳uaK+*\ >ϜsyF/;!cZh4uv{Emc1߷\O~;CZw-_?V5w d݆\ؼhe-ɇNzNNy{=LDl *X }[Nɭ0]F4߂6Z1DiJSo@;"?^>\I z`! Č4z}" FmQIc E\y8zW`Zm,!.jO"}%<00A+j$0`hT@5POmK(3W3:+ 'Yk0 'Ԭ޸۹_Kvo[|o@E݆~d{6o߼g-o36?|~h{L} `e!}:`dtMg (2S;-oⷿcΛ[7FϞKo :<$mf&̩ݧKv^䉧?XiS{w7ȠS7)Fb,dA7ȘbAmLnzEPQRYs}YuS%ePTu|wUg_>߯njW/ª5oqީݻyjWsyu akKP~V?۳xx[7.'&hڷwS+\v x/5 RV`'?K 3}sЪѰ*J}٤3TAQ|\ ]kdQciAgz[;^~U= AeYf2-K)3* .\BH0'|g=9ni'߹-Rصx?M#/2W3(L&-rccO7/R-.EjC)׾|V̺ ô,4>6ǣ/[W ])!!W{7~,߼iS %U/ d3ѲKZʴUN66 "aM#MڕuP"md~aOH(w5g_r@arTVft0qĵ.i+g i+BB]h 0^FDZ fw,UKVYKv6mcTiMԆ:]]+[f*Yg@n8ǹWS6PϽ @Ӿo=M2fգChu?~iIȀj@; Ufqv@ǽjS׺P;20wsêHRC ;NW(Q"gIoǦڱHn͜Hk›(TPdjJC DL°׿JNJhZm_qDTeL cfNМ!L:%a6e@ LCw6X2>_x9Ae2~T瀕h7LSJCOӃ"&q PkhR[3ShhIIY] }j{Vc\5+wz2jw݌AN`{@L'ŌX(g=zEyX1<_a+Ri:>5ukQ]eLJmAmB~?CXfMJl,'giO:k'2`ffAisdĥ?>#ԯ 1H×Sk6(s:rwmܠwĩ<O}҇G,co>G8$ ,gefwh_׫ /E_TZf!!?!#"./sM~}j~Yi}9e%۶Ċ!,C0LӲ"8|W"B,^{yg~"AC%EI-DU(B+87LòlP-XV&M_WpN\]Ѭ>QR@Ȍj.u̐k5Kרy1r{^i$fqj>Lʹ2&cPq܇F̙NiGT`L«0Mp]7UZpXZ)iV6LSn`2,Oo} 4!L& .添ƑOnSSϽ+mmk-_q<HPC7u4_c,`KL:p^=_wv̙ݲȬ׶E^|v~U7\"ggv{6Np𕤨EoAX ԇ>xi/[Sixn~ʼwyܵxn;6m~0=>i3 F 8X~(:Z&y{P.rϻMZcheivpԨNiW˿_~qr(B|ggvjR|%untMy="[!.O3Ÿ';>{qζVm >g7^&+" !LB581x}@x)MqݔV@yP"z%""Uk^pH-7ߐ:a10,~:tרqɗ*FqYu Jvc+DHL \A.#RA5TQR7,DJx5nYɖ}iQx<4.c^Xa,*r#c" slUQ99I.2ͪ%o3(Ɨ D>$Fo;T{yEV0+^^wƒ~T#3$ 1j[MK2g0nYYwL)4YKAcTLY}."W`kA0B\Q:kKqsEHH:oV~To.PR({(< i!3˜"E˺ ߈ J԰?z]z|գLwU al@^{#.F_^_]s=Uf߹mv N7~[g'kpOa#|RbW{]}êCwuap{92v @":.:Y7[ q"hD wAA93n,')K^N܅Nя|&Ȼ=b*CM ~}:r+e1W{ *ܭ+JY kZۿ j٥8iEPVR!I) @~/CjFuzGo(|QQp. aeY&kJ#A=.G&8'\:I>C ,` **8~)7c@Go・V WAo7?ܵ:eٶA< {7Bf5 *qݛVY[dh0fL2ÐŽ`r"{@dZ`*"QK$(HÔ~($xc3yO}p [⺮dEz" eYDu|Q9T_]@(3M_<[9l_ԤxpOiyJَH?D4Lw]tfjL_œ_9N IDATu8gTוBfLlZ2M=ߡHAHA %̘?Rg_ 5<2Tr8i".=6ӧw]yӢ{_v( y_ȻUI°{ w|pׯ,&RKzFl߮t>w~tK7 Mkulu͎ʘ|dn4:rF<[₇m! 8Q1\T(:Uw"в}pF+=@F&<2 ji0"o]mmvXjvAG6vq~p_~)LҒ$oU[U ѢODvmYfM"ɥV hf)v3©Lo1Zq ^=r䇢 뽦U~nqf&LrI ~'94Z5UʢVk* ~ea}/U9SZ۶z@nQy]֘p8  q`T6 nԱAE6_dfy7={m|͕ qdo|gϰ62ƹpʲ q$F'+M -ktI -}2`i$D^2$! ZJSi øKq!i`AKv~㫵 ̀qaU঒GH3^\c1uĞf?Fѭ͑ۥc8&/R̫KJӰ+sO|xWWPib !૨"5FLЏRt†٠ oa(EZj)9h!^Hih3j fC"MPj~ anĜG+GE!EjN9r:GQh(\)UDٳph`D }dGYTv 8g?&_bɻjNX=ʥHe ;U@Ap`)߿٢NZq5eBՊZ5{jvWX.9#թ{d>_]Re߼{̭c.ղQN{.+-Xag2zS.]C Js~C(;Uw=*~9lߤUKn>Ntls_ue=MŝЈ}- yw\p譗:~eu3[? ?ד[%ʐ1ùr2ݳӫiQNX h.;>mӦG{?9`g!/+_\QR1k߻;|靏_\7fsRkޛ[/ud랃owgch}Dm̫ȣZ7i}-c_xzzG/[s9r[ Ax}u]qd!Cq%_|D6mZԲ166iWlȴMR(}_;t?_/ ~}{4oV COlYA<ίbɓltݸCNܮC>'66 ulPB@W}`Y]{q.Jڶ+W5ꘑ7kߨQ7+M7V;yQҶ-t:1 ]a=q--{O8Q:5݂f_5wVC7w;to53?̰N:CZOzNҥ٣/}2飭 />m6-kۘW|d۶mղ,yM:M&5LfDZ^"5^u7aW7=>o"fOjQ`|wm׍~Tm<6m2*(iC,?0ժW/[V|xDQ ) UNL|? _CpqKdL [-eADµ ǡ?PcxbҚ,D! ;_?5\@K |@򁌄 I+^_M |Bgx4g4a 5c4ޛH8mXM f4B++KojwMr@,<SFWv[Eͧ g˜5籬[fjgss6ko} K} T8u^>vpq6Η*V=smU#6yp!{-.P=5)ʗK.u˩qy-Ay{T?5 f|yNhz|`ϗ{?)xD:puV6viw[q'' )1zֹl뿧LmW0߄yqy m1s ʤ%ẗnS۞}zww]Z砍__7=ʒͭMIoMJ=Ռ?pփ;?~ޏj+B"1moʹ.nqoMz+7M PgyBR)0,ӶmUح|uz/oX;eWvVCfX^0v+sn(۷ySw,um0evm3ʅT*:ϟ|_n}śO/W1_]=}+Q|k__DyQUwxE޳_ 2n>@:.YiSP`S<ͤHWf}=ryMP8+~w]{mh߿+@o≩,I+)HNN ⬦SN~ \1ϥsvw|jP޿xꦱwĩ}OʨOv_۲xԕ I^K_L{"^_Pv)?:^,AuѾn8sI]0Cºh{=N w=x ƀF`DZ+7ތ1{@q[IjPg]w"c. c@8i~%5Oۻ@$?xѭ$?BC4;l BY흷ŔuIaG-e˫44{vפOI*_lsp?aq-|!"C4;Z9Z4n6r3al2!]Wm֐FÎcw:ܶ5h4[lJ# JͤE5xu½ȔDza *n0vtnp10L t Q}:(0? 3-RePվ_&׿E E)eyG#_ҧńH?p?qFLK8{|0fBP!G-7&u"H.^zWCtyH kj7Ę#Rz(۔ݬzH3f2qatu]gJG¯706Y2Dd:ؐBW07ЭaG8 6b%) @V#jf""C.nLq  z\0-d .Ɍeyiq0D2aFǓoתάT,sϕqPAe"c빞z7J$ <;a[-8CZ7s=qӁ2"O ?c\Z~+HN9^iQD`aS>5R窜g<ȒrvʶGܨs!8RϯemMpy\0!ETC$ogoP_(GJjF>0*d FUg4zZ-Fu:JA#ȹ'8WIòXh9vItIkn)>Q?%BBSVXaV)f#kاFbPQWq)u.1``,g?Fdà15]G?=zS ۻT-3i˃:5J`[Br GҐXMwiBT1D3duWlG"",x5lu*k1z 1}Byo}j1f@ܖ "dW2 (k3Ds𔹆i2J<c;Ũbbڤ`m&'0&g0#*1>u,J@,g tZm텇1703zezC|WS<o-H|6gb#)u 0ӪU`(Vnh1Y*h8~ldfQT`r([ Vd9w]do=&R4Ő!;w6[2-6b 6%?uDR+B%a 48{*}CDTgKd+# rL e"am۶I&&3)CRbkq&,/Hq=u]I'P?d;'g(I#mD`WaH,@ÍHALD$d&fH"jzYdWַT5%,fZ͘G3(,ǣ _FGE/iVQ8Ft{ !d! ,cN?uiq9~1w'ܝ_j`FJ{TGU,!dߑl@~ҨSA!EGMZ㫃Xx7 ؈ &~ hlې8uYa i8 jL-(,k10@̆|/^%|+mk_}53mG-QXhfRZo%eWdAʫ/֭b6#49٪!2e< ACA ˏObd4I[3+VzŹP"!͚E h#fY±23ڬ$%VabMBf`M֯iK` άFckyupLݡʗ)r pnw7}YzpZ1 Ow`c(9eNSHӫ#'DYw+fءK<0}`82\P}!́%| C.qZ.okt f"m!(HAER\$0M< liG0VM27W@\PvS ǥ_$`oah0IYWT?๞ystH sCMS2fҀHm[I'0 2q*?e[B7p3hZmنI\tqX2/Pi BpLvd$~pyp _$291xʍ QslC*/yh*#dpxv*ISx5oGib+MB`LF+)8!SE?@l%v!ē"8ZNG- IDAT !p`~Ic(9@$O\H~U"vvY9Zp Etq1{  џ ɋaOݔ۹BpDb0&SFaNiț@HD5(Z߀TQS gf2"MihXI!B1v:3aqu YBK9kW&oX]?È9/隯+ nTqT d̷-(՘.,zi4V3M$ڒ K$ڂą*QnҀh%Y䈴iXv[J/rb"cZmYR ɹcn Ei@z"g'1wKiIQ?ŎH˭յ*V0 Q?PO&ۢ(]D$DJ/t*kD ? 8_Ui"B$ Ƙmٍ :0\qq2-8_N`8wH}`GTSXk)T|uϯR"fdrN{/HEGg͈v])m!8l׎H{zv-8<uHkGn8v.rD:2Qͨ:?O9`ڐ&ʳ7 >fgލGJC4itth`J qOp/Z wV -;3F?!.uɬJ:= ÕFC AT/2 !JYĐT &3|=RD4 Ɣ&_Z%Z ʐlg nhSH R% bࠣL.Ôy@@Tk 4cY\y 00B}JvLC#$UČvƅaa2\>q0 ;Dn3L#dqu\"a -۶-ي['D">c@`,i \J~Fu³La0y{EjaI@eyyDu H A4O\ Tc]Jj+2[d)ZNiƈeF,nʹS#IjGD?0&郢(VhFT@ Һs3<|pd~ж}}N4E!z:W@ Hp#Ia&($D KMWd;GҏUv!zB0VLTs} DRuk/"zgE.>[ln! CDfa`wk̟FV^m?#wr<пƖA_2& |246["wV?+~">#`a3Aұ}:du 9 4ن0E#*sY28aٖmx:-SQi{:Q Do)vAιNbZ2fkd" "cxsIzp%Plu ghۈQD= EP]"wȔ`dԊR zD'iё@ҢS)\߿f5^P n\=Y+ !;=&[Fb~#s=!0(fOsG ˂K\T|ѸW:#""s-jWfi<<U㼢RiSd%@1Y]p iBpS d 1 )NR sPS˶ S Z~]I1ιNU5^j*@l u):{ QZ1k | oOCp 5+6D<qX&JNu kjCgM6FvdM:!EЀ9m0* +m %T}R& !B젞DK73 0S$Q 2lsvv(6 ağ2%%D;&,v>-Aӛ1dPhTo}($Hp.%sMEmcedWnR؟Fޞbh`AOYI|1ut :͐eB=;AVDddgQלc_{< vSGr[2+ŃrOU3vЂǣ `B9>"W@)5nYTp:DCLk앳+3rUO`gp,a?DzƬD0ZN#s\<.Y…Lq2P&  }T9rP[ %eD2ÕLI~1d[ .vAe*'aYv¶ Ô)BzIJ ROF)8Y:m)Jgڞ]B$dEg+iL! saP0Rt|mc.l)ÀN,>&;jGnb1QY%;ܳk'%#w2 xY(Ex ?[Zo[7~ӆކrl7?E"166 :>0]y :hՇndXi[iʭ\w=Ko3M2CNx:y\Ԓ颖e@tRp#B("h +x]*I܆\2dB0_P a, !\u3/nji:6

ptlLm@1BMPDݗ=ɁbxX\a!Ø4kugSV; W58\NȿKl!C_E,zgPS&HoQ0͂vنgWo Va0ayfFfHeۃj|/Qv纞몍@]dhaiw$H3N>LnUHߜZFGlCC| : n[!F*/&4dŃ7Ɏ]&WuM05Ͻso{nZ|wnhT/pjx/m_).7&,H3if0P FO!SfDQR[y ˆyѧCbtjyJaPx =bP+\|yɋWjĘ򡦌C eXhŽK@ C]gLd!we?z'TSo BqK@,]Y]^^ku?ѮS 0nS* !ϬsڕMmolc"Ui\ 68t D jT xgQU|u<ϱ9>%pyWbr4'wǂ\@.~?p.Q?0ڟvSt)N$o]y?n!GަZm_,>ew%.-m5v?DM):D3esX{Ot3Vn4((+bk ^'o޹ٰo}9qv#eɸ1qv35Kv~߮B J/#*c P3OT",tɝ#Ҳs/}y "uq=nϪ.}w~A o#ܺnᄆj?iL#zG)*deXG[ HH?M b ʖ޲, jR\}߼o!m/l[T|kqI@^q[}aupqpl;a'TL$ k8ws啺SaccKvngL0j?jxUcpVReLȳH6Cd).s 0TTRDDY0O!֤-X<#`U|ty1KR<> _9xsG'^_ooԙ4!U/y[ZnI=Z];֏?7{# ~n] kDgAb-VKܞE}9h;rڀCAgNlΕ'cj ZvJK@~gcQxO&t >sןw۷`)Vr9lKBR}[Fi@=2e`0&1P:Ԇ fj(+Q"uQó4?1V Yw`\KDfZ^nҽܱmZbsv~<9*gô/>R"TSMy[Iͦ½^ &o#=ZV2 >:?[Q 0 6 ba쏴մ.>hi1e}jCUSDL)r$2V%Ʒ}W-t?nSSN!E [Nm GGx8dWh!F` VHNV:̖!3 :m{VFZ1R`Cy|SvvhtqCMõRR^cjXz@^cLw7{%!Ćϩ*S|2txtN; x)x-d˅E8א?Wj?.ˑcneѧ9"QvD%A~ejwtѕ]YطCn7ig\d{gf߃ vwo)2_׼+Wh hڼc7no{Nc4=LA68xDudS|e%6^*]4Mt]WpA*إ Q{\EPX0GS6bD-49/?xC{YQdTw߉䜣(d (,faUk"(kEEDAP4!xowQU}}~~w{[]-2`۠<<9kꔚXG0<0,1D"\s# ^'n1@j:4P ߝ89E1(ԏ<]ɺHy.WihSjko++:Ҋ:蚭麮i" /_m3C;9Ո k.8< NQHqDat1it LIUήֲW. )SLS"Һ<ۨG{*[W2Zv5Ŋm0OT wגxvvǖKw Q>~ݻќxy⛅u7ܾq}N)f2E D^sz.0R ƶd"0mLЀWԏ#}B$[_e1\B,7-HeG;!,Ehj|_`Xh1Đ9Q`lP`te2BCѴnnIad{l=?UQ0Jנvϔauao U_:8䏇@Vu1dU3v8yL,;hhP#5"ۮUW}d'e9uci r;W;!n2̽s`扗q5VGx۲~lfn~NF{s;ew{ν ߗAf6Z_#ı5gmΟ{lM?@N>>~_Opl}IWN Ofk=[ٵkeAIR/ԢǪ;GhVm.~ٟO/wEX>jw߶:zwU.xƽD% c_{py=pㅝ[Ո뾘.?8nh^e{4_aPVvN3&+zN9yS?߷4~Ol>՚kc~#?僮n?Ⲳv"?}G|ZyBpbuuk-i=iuao|d./ިxkڛ*q"VOҼ8T &ɯg阠iOɍGSMʖOB++6v5 ^ۜܖsP=lϗ?~N9s=Oڒv & T Q )}1δ ߏNS?uu_[х*ړ z6Eӿ_\l7\tϻ>@kI_ѭq?'8gX3nzznu翵4,]L'U.R˕Eث֮ę|?jYI E0R \ Bl˶me8~ C4d%3s/=@ IDATKʷ*8{L94cu|; [ţNp9躵~j=u`܇>^O'vl()((s&1UNeBpϓ2{xQ{n J]޼C :᜺i6H4ZWy9?mSؾxXHfݵ;5ZhJjOWw…V^M{υ$ë@5dz,"h)hAF/iV,oHZrҳ63a>(34<0p@@zt7v+Lbr6]|u`/g>Է=c%5nʀ݀2V1"AaϑA-? Xrv8mdʈaA6J*=>NKWX@޺gTwkEID+6UoVwkEqe7>F#G|hp0e3J o{۩k9lIP |Wlܺ,_Re5ǎhל_w}sڌyv|tuW_}{λZ9v~Mr핇>k&XQ-c)d){ȓY-9\vFhrͿK| 'Q~Izw C;;' =<ۖ|מzvfթca6} ]6}Ҩϭƿrlr7Ob.O,['v0l7<qGftl(~C+^ "9 BN-g@|ϛ֧ՏqSc?V(Y1KhHɷc:C"&y^ %&ٵNeͯ~_Y6bΈPxaO~68g١P XV/Yc%B\λe {=5of#ޚ#[Ǝ`s\L"|xhµ/ِ6" ~}Os]qV }Oӻ y wk5:Ϧ_26qC 7p] Εw^{ Vӷ7+nki~NCm]%۶&Z|S[;=c>g:LW@j%~UWh>*@?ּwn~ޅ_9W眦)l  Gh a'A}Cg%Tٔ*4Ԥpcab HQf% k7 {!*FsZ( Lǔ氮$Mi !aaM* TB&Y=E="F.!K5盷\qX0@T0D}%_rXXW头kӛ:crb%r:ވ J~-^Tv-,wpO{tjeqb˚ڞ9Q=gFzi(#*sH`WoR\'vo]'wsgwUmw)e,Fzle)/U*]Gz];ލ3 ۳u뭕K*'u*DJ4 &_ u5sǬ(7a⧯5HԾgyc,Zw {r My>zÕw(Y]F hWW̗a} RT4HѤ&]t|[~zٝG]=92F^i3nӖ)RSdWӇgO* U]xmk{Y6}qˆX*Pz?hqҔus׌y'}wC4З ԼA3]Jhs*MB!wÿlBDqbH{Σ?&Lʣ*N]m`՛Ԡ˗ٝOoe)`̨Vr14KmH!)]^ylΚ^+ŗ+\5mb;LR.oVKZ }m`_Rj$v.ho鞟Qi*&  4j\պ_706'[Y'b[@p uٺ ?6冀/k`4 .7yΉH*};- v}G\?\/d ~b[~ +WB))͈ܠIc #;kX藃i s]"Z, VQXz^;70P}FMKVOv|5c6rɛSA 1Q=%[u} [ " w q@ 5t2ubFn@5󚠒jOa0䈁 &u'(0hH(.{H̩{̇o@0*}(F0bd ڈR~Os~F ‘9\&"DR:%! {cs Jnوkw B੒UDE<HR,yiH~yyt!NPPoy?펵~Uڵ(et|ed|Jpռz7j9v%UZ^SkկHd@TęVi[~Rbl*3m*}`Kޚ~_^C|?ض}EGsͺOts?]ܽҩIn\N-$0І&"E;<fWazvc1 =qN"2uӧ1dhK!*{+W%(_@B,75O+f6?gחh[(ޡUk뱫7zu}q.b$ `a_qZ]|/s_ޜ?NJER.mZf>kƢ夝.ޝ {MU-3 CFxLrxּ]:t!x/Jmj;9.yhYbdz˹<{RDN7w^ٺIhW%D"XL A7ljbh1 !vݓZdj粳*#nXMg\Tlo-eկ ~r(>CA," Pov&!"$r漱?df!1Uu^o5઎E_>D#8"^M9^(7ു۽Q6=&2OD I5v+a2 |!4}kIi9%bOw-VŔ !fnDY( x1&JIRtWmFG1FDR }O흕߃۞qR]2JFR:Bk]%L҈$a7AG[NhϏU)W> r=͜ gDk]3:&5:y݊zO!{[[آݔ8j|_`__Ɗj>=U"G.[=O7CV;_G/&{}CO!^SPޗsӫ&pxƟJV<7g{F}x}E ]?2{T|g+#M K%,B˲,KByP0ƘeɃI rJShC@1KI^ƪv\5-_|y}?7\ Q}kV爎 &0^)8`rb7Yߞϻ٭•=69F'߲,"k-1`Pj+/ 6*ue[(-qrmxfcg|m8 $\$ 9 0e{, M㜓Zpն84 &m'-=vPMoxa sT&"ƐY̲l@]d̶dL*lWxvH^ZBYJ C1Q˧\ Y`j_^NLDQj:ܔ5x8mGE-0"hѾvbWn7,+hЫ̛Sn|`ŚBa>Co~0AV句 !"Tkذ^"9*:*VmMdla[=NZV6\8V -c;`k|Pֱo,q0gYA^\6w .? Z(R!RpI9C 8LA Lg0َcf[VFujr-Yel[66cHa5%nO ODK-ۖl$&|bY[nŖ,˲-fYY2 TPF|"Q;˱ V5AB|5}V8kzvǚ 7uZײUe-G'TװAl47A?T6ݸn$֨z 'c!!8b1q\-/+/--(plFoA$pX$e eٶK˪լ[ò􌌌tf1a2 ݷf״G*Ĺ*ږ8m)c%lXьonG lyL)JU! 4s$RZ!`Zp ʮ۠Q*?N|y\AɆˊӇ//#(A8VXM¿pˊ1zêlXO=ò}emrI,7[֖Sڡ`贇1[@%efY̶$Ae&jubdZo2 俥?.+Uߛ88TA^?l6gmYmI4y01 hW۠al; š_֮:ϖFf)6$3Ϙ҉Wr ȨaY B$ NoP -'V(BfYF4AL,vCɛ]iv1 {Lr80'0՘~C.$ލ°6Z fTIb? C"Gל yLHZ䂟:*K,j0#6[.E.5 rP\'Q~G2zAu=t-kT1`5cHĒ\;fhP$:<(Ok/W9~iۺl{J?qxv# >{KVޠ]߯M{,x.t.VЌNx̘Y]^E IDATt@SCq6:Wя?s0>e1B#?^~=v+|Jk:tts(>eW.齺5 %sCf+.oDmwNQZKnՊsm:iMOETo -xߊ~y{G9c}F {!92s,>b9 4=4:/9mk{^_v.ۦ,9_~a_~bkW7&cDPQQ!k` jw%-AnsY95/__\Vl_]Ty'k}/kĈ\"pX,fbMQփKg|Z6z"j鮞K9HF yCٝ.V=qkv՛eӇ xuT%63&T@XZg1E+s xn^c3$@ok6b{ssn4R }ؼ<٣ǔ%$H!|,f5i;cUkVZiP0W2urOsyyDZjS٣TLL3||\J6}GP3 z>O[h?|K&ؾ䝩wɯ_t (f\R1X^[׌{qHSjcmON],'?fGxL(_<ʷz}SQ!-RQq;E|$vo=}>͝QTSS|}{l?yo`hY[Z7U`82l1fٖs^U?=e0l2d6}z#\K՝~t%WQӆ]mͳ_p}zQ^PXkU?A"o՗O_,Kߒ&^S'a(Za˝ΓsEtCby`y^<3AEp=*]wuo\MW|53yw枊߿.kH"P FaDw\ǾT6+jfx_.0Yogf9 ^ι&8$ U%v|M;!`w37Xy.M[pE,'1@ !DtbNZZдvDY1!}8UxG]7?8z\s ADA8s>cf1QaSœ<2'vM u"vd?tbը}|[MDQQ3uzXYdvBP IY8Wb쟯{np/U;g>g8Pʧ_6= 6-7=_wwۧ'~tB,OQnJ͏ӕ+Y,0ɭYSbAjGX@T q+$Q6w%E]Μd BpOEsƉ?{o-Lt]>=fBw*:"QDp®idW`#U&j^N׊ըUHp.-96#&ܥ7~nӳ8Kwm}/o}j>2 P'^|ٳg764,P† , Nxeyt:i==EIdY٧f 2%^oNz n{vXP XwZ m +)kۊu|ܠ];tSgHiY QH ,Ҡv*zƱdX*C*$cV" 2k xT%Vݪ_R( Hp!8^nKO L5&bHњl$t4{U 1Y{Gah"賾1E~ PPUOVuA S턿ӆI2dmɹ6Ծ /P`ȉþa%QΊ@%+3ZZiZ^`5_o<]Luy\.8{{9 AqO90Łק7Ǚx20neJ.`e{Jo87;a`;SM |3?Ʀ*mIO\Yr; X&Rʘ/wi1tE=d.I4.HA/] 2IGօؤ&8mIѶmqlP=1J{!pD5 '{k1<^r>.#bmXb@BX9812'* 7zKD!cC\ϓ:p S-BϷ4VL+鯌f Exe-$jH(*^}h|wr[珕.( Ց~ 62WD Z0U@~a2uɫ:@7[GuRo5,2Lw 8y6's /Q %**EasrIf=*6S/GB2$!+A1RiTxӲ@~"ג) m 58Tm5 z|zwics KpIUnl4d0UPHD ni"!_xJI`$0#nc#VO!" L"c|>ݗRC=9£)caxE4.*z|y_rq Ulc;@@'"eЁThi4jkLsjoEH)a2Plc'C;P>2KLz00P dęw lvj0 (#;۶c3ޅAC-]/ Ai='86g/2׀?+˱efH$T 9WݼmL)d(?s<'T4^p=s=k) E#}:ZS|_F ͺ ցCJWGD&F$d|Md,=u<.הEAKseXp#_bq;F%]x)E0~ IQL tV/j` DjdƹB1 Bl&:}l=Oގ } )ձʘ _ZͮEsd4&ю[GhUYbsoVDo}@K] C˶%KǷU*@)ԋcX_=!٤>kT2[JcdmGoRuŒ냝!e bvP~Ia6iHrh \ʧ҉2 POu Gd;YӤӘeYB pl fdb>B d_f*hY\Reَm1vy0n]3dP#kT e"+Oc/J3Y \CL:~ĉxQzz)e!sHP"w]? FVN̮:$7 2N)`FM2JZsoy|43B"l j&ET…4S1i(c& ㏛/#L F2T%EވaP_JG9-E2R9-t|}9BŐnsUqRoEÝ]bp:'1 ,$ }VHAaڨK[D ,RBbn|lJD P^*VMxDZ 3'o % myt/x\oA\OqwŠTK!S_K~æ_= C(EDGjBl$YA/8r$!ߡB4_K S4)Ԏ%6P #O] ց2ȒO72OLj6R)pa8SP% 7 :6 Ԍh{&h.]IVt.hPȷsc: )W Sڛ _Y GDiG& " @z@L0c*Io=A@j.bowזD̍H}\ѸF^lHL$E/棣,J@M"\05liPqZR923RTu]YLIC'DL-:./a` +9lvJn'Q,4u62{=@"/mٖ`,]5CD".89VF u]Nljy`r@*ٷEtdfޣ_57?lPsE }?UCA 3FzdUDm yd^a*QZ􇤍7@RuH6X>Gቫ5)@?)$f+SA_yWȲm1Iqś!S%hkEfA&B! e\: ݻbFʦԔ\2&I2AK1dҴLo9h l'g{8wȫ!d 49>M!e1f<2FU"觨ٚ偊ڤpJU1i8GsnZD &m:ܓ/#@{M$>-G:g ;yO$b,CƸIΏP JAӅ`زZ6Ii3`fFa!Y€sAIth i F?0W9m[Wrl4N0e"'u#T/hr# pdCJ0Aƨ;>l5Xz+"Ē} ;yxjV塀S\p.dϭ)F`VZzz"8Bؘ_%shH,ؚ_1et\>qH? 50 UvDGr ~Hv6ELy}2dc#"M^FЧ=/[C<Z,'ݯJyhxA F0un;eY|L\?V< u6|do09&\Y6 ~LW'p.BDeI@A%E&(GqX,fۖp+<ϓD$8cyCƘsZ ?c̶-˲et/ R`n˥G=U W(rd,H$B.ufd-˶leYfGޏ纮 "۶b4bGWY\ns=0Ѳe1!D<ιЮ q0gC,(MsJ Hbh[Qx*ި)Hb{^EE\²&^PԓPCP<&$ %^(BV%w`7|I!?S8|"e+RK1U*+LQ- %p.<%:m۶ Z5MNu2h>G6O+#)gY,3K_`ruSh #.M'[r L hO!5ntQ.ǖe#n Uh^3s8q)%f T638 b8\!֠o XS[ifoh5z&p (9p2!S}w N,2D%P9d' 2ҥoYg U'|u^A4BfxL o'qU̸JǹBj!siǾ\d Rvն-a;ECbJ18d^-e_)c,-sv@˲D"6D{BrL^4ޯ'h#mscC$,(%uWW8db1˲)0T%ÞUe9}[m|Y IDAT eFRMJANgl]P2Ln -b(E=q3l2kbd˰eYeKsxҊPJ/Jsw9 RR>{o8XXT|:sٱvx6[{Cd/P?/+`TadpR־Gj'1ԤO'KV&y|J\ˬ=!ApStē@a&T (oE5*MEhU7_c_qJe 8UȽ#vLb#&"dZ1DZ!Qv`)>j]}r=73a$$d#rLUJ[K@=&Ο/]8mlKv#H/Z&|9reZauoBNwMGud_Xb}zKa#?+ͮ-USɑPTf7Mm$E2\/ EK![@mَ,K)IDž&b2mۉl--jӨ$|8N,=Is,)r\KH c> # oJzjx۹%?#cHzT r]<ד&%8ضm[mH@2. ß`?-\S9DZmY-˱mq'H))CeYL0˶$y %NWffKYr]"ND1'ZBs!46ԖRV3!-˱l)^h"bRdRˉO+~UV҂fc;N Dl\hTc:HN#IRIO;x=sO9)J(<ϋWRNvl'^m#2!PehfT҈n;C+;uJH( ` )rco1JC7ɞCy"zw;3##--M--xyvh{_W-ykf1NRfөt(06CMj3t>6㡀R1,x)gMeϹŘzJ=Tvl۱lY 4|IJ:dAkqE%L}!4{1ՂD$z"޷T"Oϟ=ĕn]񿞝53" aVݡ'o [J')&ł F+7Q(!2ݓ0T 3w0!, 4_T\Q[́bz"4eDvG^/z#MjM#C΁)6RWYb0>_e&ҷw?^/5fhi"YZǻꑳnp^KƟɪ}onhxA)/ R%) &[0# Foׇߝo@TC^q{iS7uhL}Eq'A% "tQt0 SMrT U#k#r@-äe!Cbdƙ(l]@g?ABILB)m CmHL*%1)FsnRPk<:xď{vlv|T%K#@!3*͜8j3'd7eٖ[UD A"J[W.y f~!7T83_ꅮzn܀Vr`n|э}j=m{C^qk/ 흂 [N zO^}PmjUmyUld!h[Tֲ,~+ S2B\5d9j,=ݴB^̅X0MV<(;(CIAi PEzg16cSR&Stjo熾sxy"i-6k|.߻ WЕ~KmM1rV>bϩwr*1c# s^ň`D̮Y0+au Af{G{"47t:|gM|9fF$݂@"7A1&]rnY7}5"+m"Z( sc Lڌ7N[yÕ.pdZݜ`-얋E}G"ce}Ov~?@z:Sؾ]&_˴gҬ=]$"%?WlÕQJ"ccQIW:x|Ț;;yG^93f܀-͕d܏ Ӻ $N;eM)S(pbci=ݤ%}eu|_;ro=3;! Hq|]ϛ6i>thD5>P+Ș5Ԃ/(G@1p'62{֥_4Isȕuuy!02ɀck}7֓?Jw3fNXPDyħ[)Js=ŬVW-êVef\0x8g$ҨTQANئ0k;R)XG=pCJek*u™_6݋ܨ[$ T[#1& BN>߶ G7%iКKUû%nJ|"d0 ̉|TPf?喠%[cW4Ǣů=\ mz)߰|k ]~둭Ц.NU_|Џ=?eCo wDZ9o臑9_sj#V:qjhS|6qOR*')Hl4KBN< -َvjYYK׭|;Zx`;5}!I!JJ 5S!ӍVJ  a&ץU*(NAi- &&3pY>ᩘ ot*9XDZqo 5dӹM:Ϝ[a BŅ^SAI=9*no,)ܨ=@őBGoqY/_amةwpֺ(&a?f!uT':8-cnR8BHB^Gwm@8Duoy9xQ rXL ИOlLE֠D2X!0X&d[;z&㉖Wy V圾]A 1L͹xY>\O2sbjt03g/ k3bi2qw寸-Jf^o|Qyh^Mw-{qZBK&"BVd+s*@R$ؙ/n4>菶f^ѣ&XpC{P[f26ԩ%+⾅QYc%yVb*:aB7/nkQ]פɍMZz Iؔ]Iw6e뺁@&l '1-IWm6Mk˨z+ǮPKF.5lSp,(xմ˾uDRr ~WJKK|j;QѕHm޺|k|ד?>=xK;OǒhO?rۤ.7jѢ ֭\>o )'KG,yJ%Q Щ2kl\ЉCխx#x/ G rC&|2'9'5,($`B%}_ XnCjʊ}g]`7t~'Tdҩ4;yKn8~=gĊޙp?_y*)+Zj J~bv7`YguЬdsep.wVԪ!9Q (m?xWչ_vrln.ɖa~nU-Ӛ<ܘ}qBPHJ j]-Sn#`fʑaEkb `C6r*5'oh¥DX"A{HoδATO+(O(bC)y&rmop[?^ :*龷n]u=놜{֭Ɲu ֳ{%ԩ4^+w]}28:Kҩ4^{ ")c)$kܺ#S*U3cKKKcqz`Iae WTmvHL :[qcđ?0BDٔx! {`]=K ;{5pӕ|\ Cq,@@pC;gb04?߿WǷ塯aϻro$#V;zU?xҥfjz8#vm-*p?[Lt+.ܯcI߯WGZvM2_d,(&gi-_.Nn~Th0]U4 Jrܰ$a^OACu# at;ả*\~wOuOfY O?y^i'9EQ\+"THFѠ=v7l NZߵ3R[ƭ;!}Z38gGҡ;w*k{oaD@iFU#w]=y&eZjՍ:8Z,3)mrƵ3K@_U, OG߳z?%;p#n w8VL8`>uH!H; "(̄%]_>|Ljy)+js-óA@ɮ޺){x{}P=ɟCɞNo;RJh}W}ݏ9o+z{̨^d$+m޲YV\֐_]Ch!?u?ykxQ;'շIgux3@}}&?!f3ƹv/ ʯY%ZncF訢(lΪlem-V}f[u*]=wz" ;G9^u0bL lGI*5> =9XSc Y2Q!I&$z(t,HhsWk TkEHDBJkhGZ@ɓ8W!@jjZz Tp"qRt[ paj87b[MiJO2&pSaw20֖ưۉaST"ڤg-vu懮WzeGtz^K['+h` {аn[qu'7}gid<6a1yz}?U4G-Gt )z_|nazi;ԔǛ#kcv0-˺6}l@yX_[|/=qߊ{|~dC85)|#LAnF,XSUCfUuj:2TZ;/wlv=uK>Zf{4POˠI ᔅiDK%(EV(kK冚̈́A"cR8(ERKtA$̄ȘcJKB nJ7L&@d'i8UnsV";T>r*%BK[*K^s2?{̠]cӢxs}̩ϋvb e΅͏}_{6dE d{ѡu8i'uLr1GX!%ݹI篷Tv 0Jd7f 9O\5AXZZZs/6$߮ '",k6Q';_lq6f,ɔt>3ۃ\fm=ˏzիa]ڿY +vhe'?Gc{4W 9j9T|EXvoO<[FM12`ɷ HE69Eq[^yϧ8[2}\q7GZMN_AcϿ=goNQ.B@`4{.~0IW\VϱUmK^9_폾2͇mmvۺ#ybw;)pɣ?^-`َ>~veI=b3o37MIMI6%f'|1`Vv%|hm#4[ï%CLMu1v{ ?xa 9#HD<AIRW~Lj 8g-9T_͎~~3׆=?e w:yN:w?;oם<(2خbq{6U\~A2B8c'|ٓ{X76CYH!navow˿;Δ+uy_ʗZN~0 t{@vu$%Da*yyT*ge%H"fdhR?h ؅ $)c`2y~%Mdae`d JP>ړBJ21YjZ<ii5\2)}PDGC2SȋFx~dTE͵;-$7Se]A2e $<"D@t>_r毼vb.8,Cmo]?l׭قVr{-[ZjNGuɟhPkdJ|qs-}|GɟTDP9߹I1t6C'?1y)G?8`vㅵ_a6=l܉㗮m6P#7vYW<G;]s>|[#79][P̯~YX#asqBql3nP}׃G|xe9R IDAT.OWTf=5v>jNv.33~=M,aϦ)6sY7l'"8S} QIF5Ҷ':xyd=}nChzۢ{=5-_#*ɔK$qy vթ3 B05.RJci!!H6k$%mT`UjT[BRBQ"D$ ּzDŽ"U}'@}N;2x缱/|_'SGߗ;s|ق7y#칂X &VjF\ 0ks;R@(i}CFrgL rimɽ_{٤U][o\4ƙN]}ʇG|<;VT.Ny.4do1R. (-2x&d2!bic[~Xf -7 B9IǝpN]K~vK!Տ M~5N`+>a-lduNj?»ީ<]l3ͼym/~_c<vyfnEP, UN$f{xG~t擉& yj=`Ŵ1gz&NA.-aż!g^8N6XY! tWbPW=:Lഁ9WZ a?fc_erlӐ O{OS^-oOk;|KʎiSKqKݳ5^ioV]|6-`*^:3kV:!cВAKWj]&vZwUeG}س;';aؿ.>-I=6xvzȞ7Y3^o˾ \2dOT(]f_eyg4ڦbZxrIIZ^t<-ҹ0G/jIeuES@;CbǁWT [xJ'RIk UNs_ m1c^NY*xuz 폯C($flg E 3~|J$!;oB(ȉpSwD]MҁӅK-GȚ޸=5.3u +0MLǺۯWIMwQ# XKة-MpH=ִO]z]wٺ[i{+W5a0|^L6hEհ&_RAvjǫ2SG}X;Kgƛ|6㧙|?72ިՀ窦@4;kN>`PWeQ*=tn`oqȕ߯rXTHrf $`MKz~-s3﫺|Pq ņW"#iaZMl; 9W6D9 87ג$DO L駚33&@o:+h X$1`Qq\Wsu&c0#1dgǸ߄#FD#r=/Q 3L&UDHemܤ2{gst{Yy QsD)@e=Ӛf=~C޿ՍnG|0g } Z'rs 3l$b\e*,z7]E@tc/x[PU0l1RF [KeGk#Ȗݦ[is#OP)_đNP6)c+ }lВ75(CRKH7YjswMtQ ?rs*rðNx8WTn!@GF﫨Ka"Շ0![{JW|݆"xB~iq`zxsׄg|#r x~y&6]PdZŽw{wZk/:&3 Y xa?7k#/sϜP~F^=o{_~<77I*nk]Ҋ7|+TOoZ0胺M8˚L`Z}&h"!( 4L6c~ zꈤPJ80qvy 2Ri ղL.tXT 4Z]ee~yݶ͔.&޺NB]'OV_vCsG-[+y$ǖvN!֔!JGcB!cJGWPVÉoy-HlWbԤD%+>cyz$ xC7ۇ X3*~@E/8đ.~\8:uM_r5CYbSHTI=ڎ7YR{h)#bYRÑPݻ(p"=E"u"ˁX>++`#/\?Godmx}W/KA q;%\7/\8F4i ^\p `qo(k?r]Z(khkMhamWvY emV|ӄ4nzvt{/<ܮc޽_mnװq>{Aq?xCYx>\_;W =ʕ&lXa[ndn]B z(,K b:2NK,M"f- zy\&:_'Ww? U EAJ)F;V{UuʊV (!!a3kdXP1nCA{XM(Rog mU8f&6Ncq{~pH)v+Dz*0C[FڝYQ]^i%Yw6%> ĬPJx7'TDKQHb!r< f2 "P;![qA-u8}S]H B]U+#"ʯs%֪]v۶6۾ŕ^:Ӂ~fżG![ V-#@daY Ծ:偬ÌY7%Q Jv8~pͩ}ZQo_3%rQ 80fb}Ϛ|@aRI6gKd1T70$ߢRʩåaJD=Au+AZhłErvm}/|}>mJ DҡUI1@`rw޹>o;0R GQ􃥥%PO념2Bt vFSFuyY_vISyk(Dj??-F4Z<9dɗMEsˆm߬G_xcъ?VԑcL4vi$ZʀIH DܡwJ,,ôԿOJʭ*"ϑZ$g.Yj= $HuTrZO[gn]8' +25@f%jTukmjM?xe\}㇟0dĈk-q`DkTΩtm mAn[$ ZV>f:aAd6th49.tȹhZ_so%]˻I`RJ \" ZDBǮN<XF~ikrmT}5xK$#W,PE2"SX&g<^kUe^e \ڵ. JᦈxPYEڊ޹C lo?NA:m; tfz1?˶vΞ T~uav4[|'LS~!ʒ+ Y$26MS9hvs<5ruDmMLLz5x%(o^]S X^^8 fkԤ[`m{wX[`ٛ}ccojӽ~?ls|>~)A>z?'hu߮|޷mu Xp;h](ELlvU+yCI2X)ISgyd2FRő$ 0[ZÀs΃0^\ͪ&f-QFx Tpo mC`,\!e%%0dz$4 ʨ5gQ$1iʨɈ}ymSBkW|BU#.9`-w;;Wk:{v6 0Wrd e"_0@?5 ELf4d{#vեm>|Oު]d!Z=W=f̙K; 8VW !caa&Ȅ< Gs(Ure8dKlq]>e2 &Vگa1҆OrL z%88w-l]w扫sMpL2mU2"BI6f4')9uΐ )XڙިO޳G=wxҵ.Wi'^[?o>c^]:~aW})2]Ozwn rФFL䀐2 K)"TXHM 8՞^>;n_5Ҋ?ʃ}?Gt TҹSYiECwc(_-Eݢyͭ*ܲU \cܱe[rО8׻wJ [+2skܿ۟1vmۮǞstP:رmYRh6b~ޫ//طkn=nĔF ԘcIN{Νwe}#U߾m#b_I#@ec5YE[cZRn[wEr/&5@݊\ܜ7^KNܥ[y~ KWQU5j޼k"-u[ ӎ޻}vx wߩi4"6'h+B8|dJKJ+S.J 6R|]ݭk3ݹsvQ;L]aaWշĔS'={yρGOD EV/wh/ r b؄M8gkG_{ƱözY7][|m^[ڢyKջW=16gvqc~։+"4$JıHz윞k}{ުs\uQ{gF^{_}*B?kZl(NX GA\sڟ=KX0 ) p:n<3;dZ;謎;sA|2u/abqAvo)\ifWYJ!zx@IڞɦHw^&V 98+)c30k8cF)U%ȳ`Zi1,@MGĬo/42h?RI ӏCO%uqƁQ "\.reRF36B.grzH4$B"cHRXʍ1_OQ1e04mwkV #+r# _)o}Q%{˺VMnCe+zݱrݗ׭[CbayfMJ12,O' ]"1"dz(`)Ӯt,Xc^ S/-ϖ[|iL$w >gzW+>?}Ҹ#ҿgۿO9q夋hs땏0kG=Q<6>?oF ^{]p˙\;w_,{;%};n{˻lPwva5y!|7o=4Z׾=Wr_=;,q3Nw׎喁C^]"(EwL-[0-S_-MZbq@`lq񍚳oXpwŋ_~ڜy^|5[YvK ӊX&I V'P4&*!0DfjUD(Rfidj* &%)nIIQE N(c 3tC4A~`IxA;a 2 \U$Q!Al U\ IDAT[ 3MV}>"F·yrXSc}aq䡼RйIo(qOf<7-Кh!/}]O]Ҫ9=v3.Ib:ʭCH,xqyKF?Y_C^;?祓߻hͪ߼;1)\rvt<a7JBM#?w!IJo-Oveҟ}\T3)(V8#Is1PRn R=]dlH0_1q MuS_}; h{jNt=#O)Gs?~1O>bH1T H&'@OT JImD%.1Ϟr~;uBM HoleqH}Q*yf{>/vς0 1re_3]bǝ{g5 Gڧ1s#LJ:i~gG.qKCZ9{Cc&͉RhRFqɡL*&_JE}8y߇N\^w9A'G.sʢYNCNT U)D'O|9縴IhD`kޭuBNaLc%O5f3gjtT:=a?nU<DzT³#!&E1 dQ%*&رUYd8hyQƽAh;@{q&*w3FD7NXpfƔV:!MuDc!""V9*.{;ZL8m7u񷿅ǩijbG % l'Гz}8+|۽rWNQyTok*hZ)DcLDqEyTG ^bNAtKKj!?CyD "i D2BZ&ORp;}+>,. €+)AN.Q,b)ђH0 CqM\7#ΫYι,T4񝩘$щ VsfeضQhES0ڐԾɃ EcV.M\Ǭ W/,I搛ə HH$e5gK׌z5Cp r2+m^JG8Z$I{ :֘g84 T3dPA8sv/h=RWaA4d[(-?&]B+/&2 f2Z'>#@S8Q}.'3ܱ1DHV={*B=;/B*{)S@ ֕Nn(ʑs$u[' 7-9gB(-ws>ViwcycPڭ$$0чɢ`b௦)ygLABn[1G>ϴKtRJA ȅlL+R GQScI=xܷ#n?I%u`zDtFR _ +t&:0&@.C"HszEt&Q c*R#l%=̃\ P%L\jI O&$ bo4dr ɾ%h& ygH r##4D Zu %'GbĩS鏵TlJ;a2Uvt@e~'@f PF 8:=D+"mg.$5PK@;_ Q1vrĈ\nGƨ pG)pU}1!XwvID_,X+3Nbܘ1W w =*{7<8V V-6"%l8LK:YNRWW)CDDh U6A3w&E $壼2pi#O*>ȌT[Tm݇ ՜-}(EZs0#`@|y=!"I)z}.6nRKI+Ji٨`ԞvPhq Si1\,b3 *(uGfMNVEtyq3LtOŷOLGyB"FU{0>v62$fcR^[koom̵R0}#hgG~eW wpN17IKfd0 b!gʢz'e$iE !g~" d`nfg1 9[ ur_}[B/0l?bN>#:Bb֠e& AjO$g#1@tIh%U1:p`f$SE.Z.HI h)~r`RBG-Z3.l?/(6jqo)m dft{1ԞŮ`/ӌi|w_LOq/vUQCKTKN hp\Pqsl!.z&p5Xo1qJ7 S1"@F]w9W{|X< 'McL H8$#t9KZmJ . F|lǧ> WH&:V鱪qn}hɍwjGqX%yL9sYr0)Vڷ Z} b;t`RZ6RJXTi{IR41BVUHĊlCl pUF,RHΙL&CՌiiqI}N O*J'X:emaU;Owi%NRc ecs!80/\qG<0IЃ3Oq.R WBjgoɘl].ӤtwJ,14eBw@J|"e\ndLz<%dZ-GemMXNJE^8pk37d2$H~u X8/Pp"P/Fh` ;'ɋ&&uN %J5&SERcVƫPMaIIVqD bsePӌ# 5GG]Lu(S]4IT8gaLjqI!CB$ώ+OTx5cuS?n2RX"FUtP7pLT"e3XVzdTu˟`n n?|T2 Ǒ$In vЍ%BQԤo B?(W.RIԣQ@Ǖ&/]!'bH{p7XZJr Τ8 p(&Bx8Au j4IPi2M9K`٘Fmԧ%lPⰀɈS&A"K?r <($N,,{ ,zlBpPĴ׸6SRư)@^w[mVHJ_'QL\)jDY!%Vn^h) 1=|>lٲ(qJAT2C8& M>@tɫ\XhM2xDQű H6=$C-wyC*sArn5[c 5xG"N5n Ȱ"68(̑}$Ta\ vF\5^9M:oxÒR^H cc55ѤH'=]-tkaB(4Rs` 0SRZu2u< ɘ(|^ =0 PAqVJ8i.dٌjdci_au,D>SL&f3 g^ i}nJ `)W:aYVvE/{n1αm:g!B ' ӄ3ƍYii}}}9_6|>g|@pGJP~9MU[mt)E:[J[;f }6N;1PxzLB5"e _1Ƒ s%Kߗ)i>AB +dhci&nԾL$վ!Y$c(3'6Y1KmhiɶiԱP*(dlt9 m)BBT̺Gе?V啤 4H^̵+OtxhvVJdhV<mz\R* 3_ӺH%iIr m7RB\NmNIVp؊BmT.5L:'5RkVʮ0U@G!P KvL1o]0v~֎䐑J(D*bkf"]hS Bzɧl0uZGpffNmnёjd,It7Re H*e!_>!aE$ țOm$J F/=Vȴ14WĴqJ+qd0B cΐ>8((A6 )B%3RQQ&Gi,S8)ЈDQ^^G, `@t KY1T̃ D&ɝ#EoO@@B 8S|2t쑱@qbM(+20Xť$%QSQKC)Eqs+r;+*91i*Aɰ\s"QgK%%%LGմ}ΐE(E$OTɋc0[j-ipٜ5Lס}S|>/3 $. T +IMSѦf)(EO_>HPr )N)6vq&&I+z7;KBi@15-,=+L|R*Rz(J;1c,`}8{% p%C'M 4h59[zĔƂ>Áu[+ešTWS|qW7aϐstF['\rvU ]S[WnXL,WBץ$ʗ5$;ki8(T9O? ŀ(8l&X(R5ӌ."/h$Js$vN$20`Oj"N `nF4eB DYsxVt=T?.QIО,/,a.k(S UNo8;6H.YMLaYpղe<JBeAJ!\9{*vveZl ̕v`Ȝu|bcjT03uNwzi )Ȅ*aSE7DM/q<],NFmNCɔQ 64׏W+`gVg ]A t h.>`їabMgRtrT +V/[GBnZL ql)h=@JՀ*Ud D@o,jlg(2-P\HQG1BZ'zI5SP$eW81NQ cCu qʱNDc5P̊~0\5G"L0BE  MܛŁ5¶"TDvqXqLq < VTy*h:8(]DdADZd 8vCDƙ}9ӰrJ2oL捭qQF)!yj2a&[U췴4!B(ڜx9 R*'fl& 4_mۯފgH*@}25q1:h/AG14*s@ٷcdlf~Vw\D2?E'ݡ-U֒,XNܶٴfrWF@xii "syUq xf3Näm`clJL!'0yCrD]<=7z8'Z7$%Ah#WKUM2VZy3i7`:W1A /(䴷Qfnc,hM_BX)U"quC"FH ^cq6`8i q,,FQ,xYh9k1%+`hO'i cI -ҽέ ~X]v#/*Lp'(͔B (=b]#0NW%zpnR`դdA1) %Ssy"s&1X)Ҹo~G'& 躎E)W8i֛2RM\WLw4@WV1pa2.lM?>y] ۽e Ι Mm<ˆgӕ`*a1F/yglU m_@\_дdFP0./wk+ s2I<Тhp<秳'FXz<i? %F%Z$'i?d*R8=MI|h/1gE7Ȼ@J)XıYlt/g'RJe;;L}X%;& ndA_F\'-15wE :2T!?s$0cS"P娟0fR CוP"W*3%&x lFRRR!i֊̥$gg*%9~zd!2TcAW7$k`a5GTDL D(tfAHeŭR?(W"ՍO =m↷ +ƭ vF=K |U뢗!i$*4mkb.'זXPDTQKTf W2B!*!Q<37H,hxvgcu5Rl$-ૐdX3LÔTMX‘4YҎ4խT6-rCݭGI)D )>Z1$˺GTv Ճ0* E^=Iy!"H D\d )AwS2][d4 IDATaxJ=,!d͙*$:mW"oȥ,:4s^5[cSE//Έ]hDpc ՉUU0f 1`+$h1IԈlaj5ӄ:'ES~tj8D BqFHX"On0J`k]Z{o7@]R2jHg=&;&m?< b=(K޻0cGwA|K{J/jtPC> s &t2 RK] b;ˁVsHnu%"E' e]VM ȃ•،)/ڛ9fF ! qs xp_/;^ 类]#7Rb/v^ w Q-rki@˭yJ.F/h l喤?YHLB{d;|Ƈ%B2ʗ"oEt_BI;NQlV$TFv?ikT e5rޏ#J ˥@)d\]#v%8u`-dYУ ,I)k\+ˍܺԨq_3D*?/ + n$8iY}j4'NcZݲ U$w5$9gڽHq|~|㈊.TZgz@:c272ornAT;u 9T%I',r-%+Ij>x+NJ7@tMŰ ߕOX#Be!Eܑ lCd'6P0m.C>ksOaUo 'XITAcN~>QSrP,^㏵Y QMz a hlݝ&>d v{jl$55?OdK;^zf! )N7 pni1X@Cz[qePE2"V@5Мmx6 /3*#Hz &:^0z;ZD;X~p}`pMESQ Y]qlENҮɮE6)D8Jԏ qAJ8Hkx||~FK&㥉=P"2ytY)SzpM[1G$`EvRV 7&" #w Ia[+[iiDr?KކyW]:*9Tүs3 0kB{?0y~}xO}RL܈SE@236᩽h -h[CN6 !tykJ`<, (xפ@EVS%d#geLHiWx/*ۚ !w(ble2cmf+T l ݽ_W_/B!Q@ AřMs+~h\֌VK5kXȠG(y=64v[ 6(N2:=dAe}EY~#2p1/S0 ] + =!,^hn,0Qn:ȠOq "R:@{?t2*31[;|z+Zu|=b][mPgVQP\|3h>mcA*Pt8Bui~.",*WH@M<-/|}}iT6&sxKn845o"\eU̩LYx9~}Ϗ8gL~P;&E1{$Ƽ%muc~:P%_%fIdlO8S-ABƴwWNϗft U:HԱف4t^bZ/DK Hl#PU"'X3'MK#i>OH,UI;{ڽs~`Zk,NAXae¼NThߑMU"8FvZG7 qQvG+(d{Jr,yZZJMqaI![lbݰg͇$['.* PMneZ쫗s`D5],IW_˻*wR~G{O&-kӋQmqef(aTF-vn!Ï)qz*WE/aSVObexyҐSb;:5K "\j.0&1 SpEYKzb?Y}!`L@289ꙃE,a9xe "01,0EA;EEZh2ͩ~*S iR;b ,@"qMmCl/c%{HYK bPcHMxX2SYrі/&qB1NXDO9M Xa@]ݼqreڴ{kNI/ngZ;d4EZ![:ϳ0L"-#TVc!if/Hl΀C&St]Q:.ݑ͇cy!5#6Z fi/YfG)oxsD5n!iX`izV1v|{@ ќO=۶ЖBrj q(&"[Xx›^n.+Ūp,H'P"mdb .{BpZ__¶\a5x <K}U.j9/;NdYi/:V2/Biyju4 1N({4b#{h1lw.F kNDړiBlqL5c\#Ϡv,odW8Mssu0*|F'ku/GHXQc5$UtFhD"i#d4 (NNi&I \s_-$Ndv"qͼfn~?}'[QSM/,E^*}hɱ_ι|x꽲\&ouȿkYa_%32IheZɂX lUǦMxA H>]El3~tBz27q *5Ǫ{#qya_qr @`1sA_7.b\108/BRW7;5p2.g@r P%c+q6;17Va%d:?AQ?Q,m %,S"iC5*ll L(wbX^BAUT=)^!XF2[c?,咙NF{z?Hm}1Id6ͨvW\?]$WWH!ȷr^p_5N>pm -zG֕;D2~"'mrӪ*Yg_p?ޅs,m/'Xړ|GFJ\T= JIV똑8iY,ǣFLMR%L| %83::٣09,6']K*G2@[?FٶPEuzs2Oa)Ց}WswJWj\{qmu Ԭ# zԔz)*O:G˲x&)Zo9ԊTe*3Qj81$fs=A!i.y #bw]V`Q! tÂ3Rs#q5Stdpy`IB-;:GD3zD8UmehK\/rd"tE_saDx>OyL.VήU+R< p1p~ܕ{qT51#f,̺ީ=Z?.ρ:;4_"^3lJE?%K(\en]yf]Npb[PCGi~4t9`sT=[LW$>Gĕ&Pz"*I6n1եnk$1]} ҧS5jܤ8ZbO";ũt%Bc%(Oo>KyW˞Uh)BuxL5sރw#,R7Tv^zߎzs11}]Xj ԵT-mgz7}'FM?O}[Y>oKVYǴ T֚3<8մJ1ܝYɵqn6 C̝}ُ #fF3?*lDbc!@:ӨFPIC7]@aU> /ס:l}ZWڌ9eMk]?ϿrRT]4'V= Ep**(? ^<=i|cLJf yk2,PO^Зf!q,^m)9 l!ΡO)Yg[`7*faoLak8\ 9\]]Uպ{u~!>v}9L T^e k"$8f F1DI4"H,|L+SGsPY".\OC4t;>K~M^nO:Њ->4HsQDԦ>lB9ǜ  ]\1?) b?_Զՠ\4NS""-f4nCAX٠ZAx gnrԼݜA5[r#[}eDyd@.%$j̚p缛LYb]en5_Zٚ8^P0Da9J`G֌7氆J_∈_7 U),~sGXژGExrk [+d(N}Yi_ʱ^jvW{h}s= +#{,.nHߌnMw!oZyοCQGVj v?aU7U}Nkn#n?8*2(f t͜fcG+a]鞪k%hOs9wc$Q􊎚%23;|>j[qF%lҐ68L+*8Be[O&Ԩ](%s2B5.F9(wsڀ$"=>>>?>|@S=q~>') sL]$S%j!Q_I ֱ%Byj+ IDAT`u<B`a>(.Y!ٴ֠`nx§]BּŻXUyL}u:9&\T"R4yC&SkZj`Ec˶ZgjƫXh-@JMѥo2'$(‚3ٮKOp).BP,e 'l5d|O㗊#U;1:nlJ[e'bHf ,`"XkDUu׿4LYQpR#ˈaLWV~KT00_CoԼ[-f+vH",!aӷUfn¡ˋ_yɒuܿ !\fCUMr>6?ր;MrP%cMx3jHG(«wo=L%[c>_F"O\ ۇ&kֈ n F0-r>9x2ުctE{|8>M5:Η%B>q[Ȑ81b("<9&3D;1.iH<6* @؏fD\1=z;p]G(4/\L:@ ߘa?!%"ƩePMV‹vYv5 5mi0"!GE_V%ҪL:@,d3D:6oEP|YX;N)h)V}lfZg{"nEɶ9\zty>"zo__Zo%%sYtzWT_crk+ ^~[ /ȝ)"4n0&5eYe/$Hgd hsh \~rYg/8&?FF2Ɯsr6;\:^5sSUuTBf DO39^}֭feLZJ&"*4FlP╇Ѥ[Djf&ģ9UW ${oo J,hix||DH2)W\9963af(ص5kE(,+kV?z/ޏ[fل26r"޷XjaoC!a{Ԡě|mC-9-:Dg9rQc*Ws:~(4Ho,e/35\vֶ+K^5' mMkC/AHQE-̢"-Bm$ZʢDo; _&S۾;Rݔ; 9glTfJũfX]]uSl7Rq$7T^#0cC$9%ܵ^p zkScD5<)hM8 %{9,ҏW]yήGV90I+g{0 ]{l;BX<zNd@q7 mZ[Nl4."d׾?KAicLK^.tIhM0{00yt1ks_Z^{n%bW/SBV״0XBJ0!Lql9Ix*>j4j1Ӧz< ^2]Ok~0=19TE?jZYAQ^2}c'jQɓŹDGuYW{oGzLn2+wWЁ}2.a)]4IpInus hW 2է `g8zm%CPΎvh([ȰGDD_I~;RXKsexQ>͗ |zS&ԏx~)\ѹq`m\ˆ[j j%yCe[{afZdגPskr]BJj___| auM'/M EM2zzx(-nOl\H(e5f^̘/ ~CCmrϖ,ƴ>f[ȥKl ôjmcmzaq>dR&+1k9 #oՠ]nUV/bk`}AS1VơM9S*v 2c@g ~'Bk,rLV5(e'Ȉ)?qqYJ1%jPHMr&OKLvy1eff%`׈1:lHU@U@5[O‚Uwӿ^]v+E0!Ÿq׭Ezk-r@d-a!oĩBZ q#HڤZK$txx;Wۣ^#np-dpe9Y^{9Y4\4)v?DQ( D,(w湻 ;T[75_[I5rJt 6k5bRs[ O?G͂\@Jyqbưxv99bjlUAv?)e){׵X#MV vC轫hse|YiP~Jxma&PEqbJngNܮ:l`{#` ,e(r55i*XSBLkԏC;2:|q!LcnQU%.p{)kc iR*77HI&s[ﴒ a/klSecvaVօ1)oR?+Bи *]QS8C@e'Ȁsn wsʦEMF ׯ_hn%P.^+&OAj6 (LZ.. Eń2K/o"pGJˀꃧ)p(iAvvЕ'OaB<f] s@urÒBDۧq]`J}csHhOu|/ %āK`jd\q@l~ɓ7ogi%d4&;Xbp)fŠxwSWsNq_q3H3 2;5 k #v.TRaqJe\]H3(:ȜNYqgNb{I iYN/R.+Fp*&b<L M|;'ܞ4EV';F p_Wl~b4'}v*KAVϿgjX0 _f +r(>`ױ2kv ց.?czlg~?}u5k0$]\+5ֲĘ|&Aڜr=P*OR1[=ldDuL8/Bz;JT9W~Ƥ6E1mcfAUjf̒ZVދZ?:s1%B3XXy,T@B)i .1ڕP#;]YO*gBsq'78{:Zk"L;Z2%cF4Ɯs@kFh+z]wt,Ib.-WqH?QDSLԚ16mR& S!Bodnv,ѯS7T:0wv:3[z[]@2/=F!+N[dc8 4U~uA6XQF%kVWY[;pmX"K`8)T=_#M #aQ \8ZӪU~'Z {!FVqr[k+*Gy'09,L%zLf[Ib^/=r>C)By̋'j̚ P˚ZY(Q!sVf+BINFsy-ns' ,pFGjZoyBE7Gu-c,f!dU6[X8"fv6.ϑ!F<25궄E\^KVGyN|F~aT^qYGU E*,|> ~D-qƋxS Z%n2(C.\B&nv 7#tI@ Fʁ-qGM$ĒBdډ./˒yBNM̘+ %A)9AQkyh. Vki`"8 LC 6:F@t%@ɇ9)T<D&KLC HxڝB.sݵKȒWAlb>oHD`hqesqד@nbV0$ \uh1TM ?6ݗ5 E<4U#vsLɈkF"Is4)"ݺ.]YPϱF ˯ {*Zn'5_#[5b!DzNQ ɅIE>Ύ{M<{豝ߍ(g]pa؞ؕVQvƜsiR0BjHM^zf!= m;*%D,h?-֏N:dc3A͵,=ioJcN1nv&/ <´>>>,quqC%EHޏ8#"s;nUbZti1[?6t; i+z ''<Q)=eڠnT/TV:d(Ltͪ)X. AzU 8tʴ< ]܄uN2 P*-j(Yؒr8w[A||N1+T*'ϏOD T]rp}@\b<Ď4rw7l5of;֖UJ\'0̆ް!Q8q^]Ԝ"mQ}v{B N@JX#U[X LܣY7ոUl9n9]8uI"JZo.s0`"2 OFbeH.5?*~5 A&/@oKoYqb^U?=l 18q( 'l1dBICo3'Gk4konA&$le3`(XKBMN g,S9E%) ϐ;V}"P S+ )8}/"M^908Ȓ?M +-R-hK3TMۮZ^\RZ1r7=]}yܕf%p۟ *̂(|sN+9Nk-6C>G𛩩!`kc~֟n{A;AO[uj#oUV>hq_z`ai=?wp+0G'n SZ1yΥ]Om/- aB4K.S,jZjZ8¾}$DSjux5#jL]Weqj1LSsQyYW-kۚ;x E eM٫Rzo DyM ~ʔ1[¬z!Zp1`qPZo8yzj,dr3[F!QÉ۱iV[mMZA] VC8Q@H(itӎ6Mk2 d0%U1/!C#nW2\ nayH@%*/w-G [k!NZu"`o n+@ɭD?a\]O~=XE$7 e.ō 'Fx4' dX 9ِJ8)o~.|x t"Y O)ū1b›tVO7KԷ,ʹ[;[#oM@Eь߾$ rQ @[d,$Wsa`&G COܲqĞF]٬gFV %޹o!NuFhT䅿LZW5#nɩK\XL.9Qied}㐩qVd(l,l|I, IDAT!U0Z;ajhKWÝɕidhW\5<+@TYګcD 1U4&֍ 5A%)+) JN XN}24RE ߬3(x5$뼻%e:!MD}XB߈&p$-ŭeT[lkI҈'lXEnPkDTZؖcwg-9m`SR{ b+o aA*t+UṕV#vd}Ε(eWn󐕧gﳋ^Emg8XJMW Dݲ)-f|lLufW /7,@m R// 3SD eSF ճKdkDϮw>E4W3.XBxi>Dsl%uflI|dҮ~o{_%9 ݜxR~/F`vX 5!sA9_uVFϏK\)U8GT4B>K̢K/ڎ~yKYnRqfDeY6+DcLMZ_{#j]herm~t[Dԭ1jְ8C:X8G/#m Rݰz'B6확bqtjPȔX8eq@jf/>IFx<Vɪ˜\ƀ,<`>󩛝}A8@֚XT?ON47V"(O]r/&{w+$ j'U5IjzXK'9& b7y'Vf&hVqQqr˂dxk)"bm,_O< 9!:84)ܬM[DNwW???uM{P]v @_X6#+5FkZ7ӲR.kx:9Sr YLuޠF y6jO&fl l[-QC"ՐJEwq-z?Z +1QFK`|Abdlës+l A/GɁ Xf 2GMb>݉DxιawxEUfLrOUrF?CB86ư-Bx!3E68u}f_k>)Vz ;@vc%]uV*2n}&Q*L /.Aw(_e [")EUVo&I_3%!,',5lbkXObyꗬL'/ K=mu`닟eu{[. ;p +CG QZ$GwZR;K{'B`75-u􄗁P1lCzf%$gI0ԸMVB.zi=qlGoDNjK,*;N(UZ$ }8oC,"5ݘSQJ@mdPC!:,g,N 1RGU5,#[ڦӔmW7ᢊG?1lYq65I۴vӛO!r/QkjN'5eK_ rGʰJkvh&g^agYoǩE̅ryL`!!cL&*T_ Yjsjy♬Mf 9b#bÙkSaҏ% 0:iIr.4SLb̕&`x'|eB1S3gE^wۑ r, )0jJ}\/p+_fL">>!X}Cl L"i  ^mYDPOV]uԳ;NTԧ-612~*,L7@ҦJ}_ڛi@w7mfi]Eɇdsgq[Bh2DV| ^EծKՓ"+òXh⛁.vI {Cym^5S,B%7f/~^/orb 4 ʣ,f`+Po'L?|Jޒ4j{BKsưꃐX +j3S3} 9+5P0 V}#|s=yڷcs,m'JEEb h99&e?9lYJz)ɓmq=>mzZpҊۉ|>] -F!9yĚ٫zqbTGIBkx<;-=5#Fg lt|>9x o9lhDjZX}6O4L3`e;jKeCoO#4"QYm]Bv ԖF=Ksd!X2RڈOulld6 suN;櫀& DҲog kC@׶Wa1+yɒB4-Z?o%A/{!܁?;)TAg ȍJ9 U"){bʇ.\ D0I7q`S37O[ AܫL W[DcۻZ;9Я9oŽ+)+ոʶ2TK6Oh8*<}bETD0 L2;dmCEJx+cv'enR:DOzYynS.XVؐr6샱LvM$ -?a(z:hK9r"`FQL_|^c/dԹ6J::[\3ECW 2u! $l\ȴ*\v/pDiz{ ȚEZdS!n_@AQ*!M2f\^|ဒƪh#Pn49Yobxu0 #|qn&Uv7`"#͕+~Ɩ{랬Pӵ~wmr%"ie&1D{" sT ]ҟ_g1tO$_AN-9FxwVx?n qsYl\bjsH ;[ j|_!gzd'TŚ` ]cߪ>"$)lXXsL]fF+FƄيՁ f{s"Q?G=k \qوl25xy>) }wފvE!^\*$?UH=ԟ5WRn\^=`KUvZpPhzE̒ʚm?(BS-f 1 nԏ>55aN%.Okݏ)w1EJ*Z<`xE^+%Em&͔AD<P5Xz$ 5n%=]*rQ]yz^zRѦӉ?&oN9ujxc‚ײ<1N|m"H3YN4bfZFީwl]Ցk3ցV x"fYc,A;2kiEO7O[b-D섊EOVGt4p $"|>-81d֙Cׄ|0.PZhwXGy?IGz+w\N0:~B" I;EB+>V9a//kQB&gr4}Z{O+/|O.}J&7@ʞ=8A5tΧ2P fΗ]Auf%J4R9/قv4A&lK&r<GЯxVI -͗6"V֫%]!fU,[O=:9 p8sĐZt/5ݭ.VR}acL]U |o9xx DhuaVWfXBBS~ˉA!X^v6uerƇ& kx0_[ b,6Vv=AVu ҅  ~0d)tT$aإ_Ʉl&^4m?ig vڠE*N=Wq,%6q= +=q9WcyOc|~==[Y;|81ֈ@K!̢t \^DM'2}>LLsZyӯľ"3^ ˗ܒM*B? c0t5@ZE:EϼK;;EֈX;fNo-iNHϧ&<N:Bͮ:Ch~3}r'N>nFJejD3C*lU֡?Z2Q"fΓA$(⅒ |Dx<H~I0dLb^'a98G&EbqF6[bTF]\pk8dӢԶ1'qqB]W`N\ʢI JZ8~οKu/k-E޺&sSM4vMu5'8&a$ DtÁs_mnпka`] Qǜs `">»%.*"oFU "0_QfbfT<ưS!ni%0Ƙ8qN9#p Wv R|N_}l FxԄ8Zq<PYkm҃KZ{R K'd9YT\$Gar V!E5e`/5Ͳ޶U#E_x,3/*z;ldY!qlr]u@ֆZB8Ωie WX׷18|arjc]!;OkY.]{ wn.Rxta{KQ?;_?-~M^?)};́!(˛Ct4c9_,Q ndo4@Bf~>:&.:문@ 8y;:aӪ)Yr>1䭀q4P&OZCjM [WѲL䩹F7x|nm0o>LCzs|&2RP$ZM?J2)l?tb8X}nW4Q̀ߴe狯-YZ ay<+EZC "13\&ZeX̔YmCBr轍q> LItm!+PU.k: Z'K$/oSvX[SD"D1vMܛH"$Đ2!*A3j5:(JRj.b H@{{kǻϹy~y{o=gz3wWDǞA6:iqOYq|ZZЁ-mZKSƝjVkHDt7 ֢QrJlyk& Y!0Օ)dֺ^o@- z#s̲:Q0=9wBsWO"J) qDQC4ʚ8%H*.|MclJMјnƄ۸u U-a J vf2k+APGX)#"Z!>Pgw9Dӯ}Qh4~G#\Usc2;?=A%W1x J!-.+ a>gȳmP);^_xXNE%>2EA0>%J\c:ʇiyb?kگW}Ș(TQ|b@L ^;A: {ȧY"<"sjc@,Ј=m҄HFQq(.;61Xy v$l% L+Պ[p劔 y.Į7A J/XC!+(9ZË!rZokB-wVZT&[$VP+\:8 ikN@0c ((tle4{ yC: د( $o w2IA* ,l\GPEEd~¾-dՒi_u[& ^Ej@eih@Qn֏(8(%2] ҆qC:`D@m H ZX) ^[2MP{ݖ2F%r:hk-l _cW (PKmN^ܯ;n Xơ\#ӥF- )*Ths8Ux-bD!fDC3mÑ-Oy?IE<L}jҤmof"Vu »pLι6 # KP%ڠ0DP5 gРMƸ372+jډ$K#!yF]+O`eTIerEao *B(r`̧ ޝ#"(WG^ NBOlZ4{%8R*1m"a%g"q钙~O+OAL e;vhE50lR{0bΈ1[Ԥ–S#ʹ¾̋ .%"|פi L-^M _h=A,iMFjDvD`H)e"%) QVKڗ-[Vz%R0TBxC y睅Ҹ}/":" *9Q#M)h$1/| k(Į0f!Ax yt Hcw Psc$J! HkMG\7!+3ncBZ+S1|+#چ`3Y:J4\n2lcd$ZQjDIE\؂%<ϋ3AqIv:mf-l>>wJ"ht(2[^tΤ`SI0y\ +#$^w$RشBMXc l:R$*eP$lYhbU%Y'zW.I&2 BuCjmF( "e5mznNhOC#`+l(E-{y/xbQU7(jA+ T*٦EHщ{UcAe )N>˔1q.%E&khZ)mȇXaeeх*4gxF$ { oaye 8Nj=`8aQ ƥ"))8,/6X3+%9ԗmz3y5e=w<ƐozJ\tGǗtG)Bg8٭urږaً!kUpYk͟?I"RVmyk$ǎ\e/\J ,"(r{|\nXlWaiT5#lma-7֥|5=?tKy*#0Ep/(PMB:KMo4_$ADU͟g῎ wՑDLx.IZ&>#" I^Ff:A){DM"UAxUmDl̂VQ CӲ,#pg %"JI"j+DI?VB4Ix8-oU&bdܔ)Jzm &'JEƠQFāV5,ZVkk4J)d$5<,U`j9'ΏL~\8*Mb2d "U?ՙm$%/wW?C{v8b]鬞Њ Zr5Q[YΆƌAIEm,Ͳ,ZLrYr&>S;ELI" &FHD| ˦eܥCKX'qb,rQjJɸlhFz](1֣,CʌM8n9JC,=#7zVbv^֋%:nhA{9Z%#bbSd%"3P4y.*EQ#Q'4|<.sWD"mtpC dxvVt@C 5ٙAYDoiuEGO%VkҺF!C-Z=eLM[3QNY+)Uf԰F0y1~R-F QVA-z7ʦ.<}u:Яߦb}GN~QNe+Ιl!P"/RdLeDT9 P6EA*nJ%AmeBLei<4MZ)!deB myQ`Mm֢+82P2P7ƫjqH*i%4 Qh_(SB0As) V#~8z L@`ղ,ˬBďcE 5bɴ9C&9<) _$xF<,GvMS1D& $ #-di[&* 9,QLҍ!f"VBbkg*P,Z[Z%Tv0)-1Ժ7nt"c* 2F$Ip,td 97ecFmYp.G pm2 S[ WG,Nؓ(p7U+k(Ǝ3ҊjYͱf֦} JEAjmmy}MBHHQ !%JʎܜОDl2\(\T[-.0`q.YyPDj{r)N$Xcqbxc$F%g ,t 0Ea2BCE(tv=DJѪ BdZezΔ D;͟=@iwJʐD]Y؇@fCc* sU! Dlرd"dH!9HSA<4v9ЌtCV}׫_J]|^|HI1 WB0Jpmcsa[$foH< >s"pX,֌KUc_ )S J\~(`h+` Y| 0`vID+ xbC;p[SۏkB\0Of`,Pac;M5 w;#Q.BZm$e:_|WIX-J)fdlO܂(9}P冑& ?-BSب06"9D%7\7""I$ arIm"<&H'Ŏs[%g sTlȇ!$R*@D$Q2I$@yQeZ`# E^j4M! U<_!Oo˓Jn:W"$dHe;yyu__*ޤ~X/x*+tI@'.jpt(-ױ)-|r0e[G@BI$tr.a0-Ưyjmm輑1!d{ M6PpC梷)B"nX**g V`#F!]*Z.5iDvH4g2$Nc][UN0l5vK6ZU\9g ˍFC'WغXu[oUOx!id[DHZfI oq£v(Ȟ~)+( 2R8Y<5Blhb^{t |2\ #5Tr4AWD)AV@zZ3Vʅ_g FS4BRB`iI7($!+TFK(68eB"/]uI:ޥЕQk]׋B3<3rp$ TnzEj6Yxn$[@LDHI $lɤ Z52݂/Pv[M$I$@չyK!4+v P(fC8ňH$UZ+u($2(<!˲,K@)V h5 h*6;3|HT@R`֧A!Ye*#+TO>⭵bycV(\JiL!a(/IQEU+*HVH2鮔DDsP3C8܅BoNC`DyD,H$eI&Y*,|Fq *w+S.{/E\ m['{$r!m*Bi;4ڒ!#ps xɒ΅>?yg7nF=%Kv,^dѢŋ-^8 kkŋ.^ұdIҥKv,Y2c|Idz[\p^Iꔿɢ%˖~?fe ".]ѹsyzKmnݹl#Zwu?ӕDq4 h O-Q L5y=$o>tŇo1EblĀ=FZy`Vh;032nb19ǿ;xq&޾mU"C2IjZ"~AGG N-Y,L+! i\I#nyM]7TG޲'XyϙxE@f-l,y5`:'/~6+yu,^ԱhE .\йxJט{-l,[>}(}+w;|Yg>=}kg-h,yȁwe6ݍ;:K߷CϝԱnΞ?ج'Sv7<'[dE3>\1S|dն<꼫}zyWAU}Q^4>7 (Խ*ICZJ+d;2ڐkߝ)=OeM U<#[WX7w_GH);gx~k%B Eu^ц"R)別0`geanZJ../5wZ+ޱ ڋ* */ * 47xvUoYp׸+DF+$ѳG[[-IS,r=j6wyohDB962 Ix m*3[`$Rp5| IDATSicNybA"2$h VEY?~4n/;m?}i&Ϟ5e>*Kx@}nx˗aaћ_C=?Zk_}Goص}ؓd&gM螯On4Uj{Y Pz7|1ǝYxowd6b[.oW|3F@ϰ(á2m>t=C9w>򸃏8#<Ź"/lg6m#?lěYL!e6Ab'??x a?{ˏv힦C#˿7Ɉ^[\ӯdS#_L~wԏu8usMD>l߭{ԶwJvG^ig~^_Μ1ue-AŅ~2Of|Ɍ>__3ɭ?{D=O֚roO^f~][$sӟ]=Auj"i|t_줢oC0[lc)K)N7} /83{1}U]?A=ږWP[L{G?W:+-+2̢O_|Ϥ9hHI)tWkc!u^ Hy @m\yQjB@Oąl.@m梀KXl}h$=o'W 0brJ*1.BVڂ &n FgG*T[[{@`bsLmyR:$I$I8=q&d4gaT]r!Op)Zwq:qw씞 9?h$:)jYj 2:x ۨ$apZhA%5M,ˤL֍F=sr`2\{? 3A"g1TdnZ+Uxؔt7w/Z&"vP+FkU(c5%Yfs䖍.6 nz(9G/\)ۅg)$ - "/U>0ƒ38%9d1)`T3Q P*sՄu;kAfY ZiU(!#xRy^D@jAׯ~`f ۘ9,lU)'i?$jQ1R> LLjЬp[݃ȌmPT:THZR- !$MTRvDR)D`,YkmiB.. Q&Z)](](೩( B v'N۶kcYeY&/~=PLU|њU(U['[lwM<`vμzt>{|9u|6ȟ5~]Pg|Ęѣ6޽GoF~3{9R|Ccj9 ,(:hujNVϜ1}ڤ7]#1k?HkӏCFv)Ŷ1 /Oma(Hv$"i8TF??DCǬ|4y\B}9go:p5j4T.q/,$!Dk/ Ms 3H~$ 9-Uv<[Jx}W]y~t]u{3ǯZ!?wA~s |oo?p6ov?xP{mV'>ح71Km;rMd0Cu{.on50I.fGo񚃶0OGWv&ux>`-*XN;<)Kb9@_p/=ˏ?vlXX!S/{S/؃WK^Ow={k8iOOu Kog_xN{<{~ቧ%q}#KvM=^s܎!'uǬӕţ^C Z>_ӟ=dv:{gbភ&4.?dD/O+}Fq}c'L?Gn>{\y9Clg\'M?mP^}=;?i37vmUizo/}E5̢WY]%}vUh6 ;E]Ko}]dUbJb?^e̘5B2t>diyLe>S΂iw57b(# a>[p7Z"ϕVB,͒$a^bb;sDIޗEyM]E@0zh{%b^X( 9K0`yn$IJ)c4)$k$ jh12_4%dU6PhB®)M(H4,u*_?YIZ>șN#ff*A^^%JjR1T دdEs稉DmS%H)4E_L(eNfs1 f5Hwb[_b(RbƼ֎@ȳ,˸]Z3CA@ r񵵑Fnm YKW!!CDUZi!DVR*"7d,MӌP")$y) h_r ߲,⹙k#| a[ϟm< a;y/q¡J*dr^[7zk I^s_-U y5}$yFn]Xg4-T{nnF/>9?f:Ϻag^@_=ؓoQz+Nn{R=:}8_=GfmS [} _7Aڴ\i>g8tӔ~~ݹ[BtCoL^h{_ǝ&w%/. %|q) «X/YzQ|c~~]1vONx9YYeOҦvm o=j,MS1#uF _ODmY t7Y8Ohrlk)\Y +$MXi-CyޥNmm[܁*[*]*,=4Md ՆuLƨ5КQ}i4i*ɓ (Fq3۰ mݴ,ꂞϝ3Z]_|yImL'~޵vpDdXrmc\a 7X>b ?g,+-hY!P"e2l+1JͿ3g߰J/᳠[~0bbvys? ۫v:KK?&NA`?<̜μhdi9gnCڠ4Dtl鿍_d9R) dOj8?Z}qqΟSP-܋:g{O\wۤA4Hzgu_xgix=F{=AזGe'̚3뽧ug7_Uwӟϯwf㏻f|\܂nӏP}£s)&ٛLZMp9KaA+cwe?8qw6Y j8o8G'L|n?_ۧj>[p@s.}2^:{ZW>ȗ}6q_h?C-֌󂥧QF,R~1f'Z)C)ER Tak(C&1@@1 `kdi.٥hIZX! LVKk|&IFQ={J)wikک@#^@ a)eM``N( {|*WTMe;򥲷A`UDph"`U&߶(zg~\8ZǺaVhy.YccԠ)ɕQƵdWR˴إ;hPZqdhZ"n]ۢ3^mѡ%1!RfYf?=1nP~Ғ[Rgހ_C&ʒQ^V\#P$IvQn4P8$ֺ^Z%iUY3*jBFT{W,J+Ve̱m[L]pE Xm]kǩ>תbNV0Z!2aYMZҍz)(֪j;t@i{-n^hR+yhMZ Q[`ԸM{5hL҃Ǧ˂ɥD@0!*Cpgbɫ0V$A`̰NiS/y$y9չ(0FkMl719 !6+Ii\έwvǎ*Y,рi  |<#bw8bϝGu, /&z8b@9ihs;⒙}swBTPQA6O ď9~/{{ϗ[H#+Q`d 3:*s*Qlh6}%3a5w~vn~K,\'K4@״EEx#G 5~:vF%o^4fC{wqwϹgo`ȃ'zE+osEqO.\fC|2儽v[kg~Q4;Δ @Y{whZ6cʗٶW/w\wK&=hfQɗn0i_lFCzݝ}}$2qn9%0b ?[Q I im[H$\0ɣ6 ,ce-tU (tz^8|F ) hMGH y᳝#bKB!\c\kGBCqy-0QR9I eM6PyBڨb5IZ%K2yJI6:oDTլVfnWBE$2֪IӄLEQBHm6XMp Db L޷bpg3mbلV]*k`(J 9D 8 K١B$M}fv>(x^uDy]jd[*H;2[Hko)٢B 0/R% E,܈%pVR"MJƔX%6\[Zrw6eNںW/[#69r&lyßk7is} o;f|㏍vkB:6O 9w[mKY-w@.>uXŪtĦƶ-$t>R/Ξ>w/C׭I7bD_>7*A{?jw~,l+s0x߮:Bg( 8nc @"G}*+tZI>Ɋ IDATx"MKh>fϿ/W'WúӐeAEMKE-uX-jey_z }=/,sXcݷMYZ_GVZ { {K^>y@hz 5O?)t+ҏxƛ fG>>8{{luYUK'?tn2{Bm6DBFafV_䦩˨ı޻Vrc/~w*OWO?^sGmnۏ>wMS]y&Ӟzk=7c=>oFxvaop&Y9-iSb+|8`1k Nɛ;@-LW|XsGhc.:qh{ ?[6IdWhWJ)e5qPZakjm>g~??avN^>&n*yN{_s{%@ҫkU1&CR$;Jc+MYDU^hFsIB 0!ϲY)J,\06?pežΪ63[4*'Rp*h¦}H9u35Rr)Z[)L҅#B%قbDT YaR(ʠ0" qL 3yzy?v:[U¸ I؀.Bܖ=7i+_}I&M8;O\WV@^ ?E&_0Y~^:d;]gs?avޙE"]o]y$!7_ϧr } iab‰v қ:^Yn _kG}{{?z Iͱ뷃!"71v#";=7]Ъݞ\zW/#I!z8G]Vam__=;Ⓠ@B}nٿ:04m!?8f_sn~8爒![FL&I3Ċ =2{,bѲ>-7Mh{􀮧.S b7m"/'k7o̻5 sIFx읏evl1[bzЭh򥉓}I~]'.e-{? 0_Wu_{o=;Ϟ.ndОsV 7CVkրΔ:<;}ᛮqzېCN9v7j ?_7o{,⬳ޚk1_p&ݗ"g<5k[ O|$Ύ7Xgz2bA?Mڈu;AcLq듏kG^[hw|m'?K3o`{mg箼wj{vnyOd7g?ߪ4{ 3ݰ-~Sf ]d.9vD;Вq7޿t /`aC^% >l*r#ۇq#Oq4$6>laÇJ+:@{;E aҿg**otv+`6$C#XB0hg+j +((TmP,8ʙc"/RJ IF,%J;vK)" RHk}BX䮃/ԇBY]z$IfzkdMZ$Y&e"w{$IRz#`B,O+Z[MtQ3~cY*rfCѺ`OSk:L)e)u./%QT%6iy0vT[RV# "6EC/)p HiёRHqs6P%3b#Bݜ%Y4䱐( (/֠s/I;gM8$pc{iB%c0>u!njlPn]_K) }!XmG3LW8d U.kQEQRZ!^@$REPZA% z-Sv!(q[e/h$j)B$Bh~q@\(q%C1lYoVv^j$Z, UQ$m'648m? \>ld W/ k= )eŐfeK`u+#牞h$s0"=\x2Ji"bcC+sA^haZD.ā%UuyO^;qn*.f?܏ט'y34s>i_\qХvgC+cy=^z .tTGp(3ZHM F$VF ,q @vd;|qw>_^?uQ?m|z<㵿:㯜dyؖ;fb_@#&,Ӕ@pFotq{xX~ė x)X{68IE߿l;/o31v.B3לwЈx?/9*G8':q׌ݒ1ajH)~#{."^^p#*gu{P҄G{⺱-wviw.uޑŗAoŠ:g~:Y2oUYWk{xێN| I A0*S6|l(8A@i@@P@ Nd41 "3P44(S"2` $dg蝹~UUjs}{s޵p|jX0@tc}^Z/1?Optyk+?>_y?W_nyLJ6w_2_{W=ӷw.='?oϜoƛf B/6]_aEw>;orqݚJ p..0^/ O{ԟǿ^.;N{ğ~0}uaswcӷzS?o>O}c=y6Gbg[vc#~_{Nq ;K_L|AsW]“/QX_~ܹgM?@Jvˢ,6Vuyf+Y_bf&I;,y+9r1&"rς {VyqIxU^GvBf;fS,;2Vg5 70 *0V6QňbY$w! apމriӘn ,>+ ЌS828WJIknF윷fzI+g%6x{ĺ"7]%])ݲK.s0(XAȓȒ(qܤ:E'wq_\z.UB' MfDc7`(9J䄻EO`kZmܭ~ Z q7r&%1@nh`@t%%kyy朕%)%щɔ H!/D!8t>x@{<`!D $?& A8L'idji/LΣ-HQpIh8\4CQCu9iU5aJXIɥ?@ig_\:z_1&Fe'kVrha= ח&z"fߪМ}gt\2ƹpx[V$ &M&.E͕s"b'2EݜB1Ӯ >Ȕb1ѷ>Ͻo[ĢdY4,LQEއ ʑznLw8/vhݕژ#V4Y|VP{)YP[RL#Ғ\r En>tz~%rjoD8wT _q+3]s[qL5Ahp^1ܸ(U6iV^"@e7O(5 Ng 8qbk(8WYtj(.<9o>;ݏ5%\ II(fNxg^.& \>:y֙g]JD T䑛fOLm"aRb+J+u?oJWy!S%叩བྷμB ^c~%eiѾYtQfm4+]r!e p^|g~?!d[JPh؄i5 @h"N-A6;.yypOno]cKij'  }-Z9@[=dٶ-D4Nbއm_):'a3ʫGreB0 ;cCYLRcXXM27>&VAISm;-$ 3Ǖ;5]s!EqG -Q4"P̿(;>bdM1R"`r> ދ%R%[ӳ[ !;A%貃N12a5ϰ aKDDRᒾ{*^ X2KgB|\@kщmYlKric#s5ݞ{dglar;F*> JlMvv_<;x4GOYE>,蹺y;884E`{Ox&WpyÖRIuY8|w9L0H8M/0tg.#0HFFP*-/y2*uAru3R3[ˊiR!fΈcaTSaG0y'jLLLe` c> Q0f:'#ef 5ВDz#W cs! fiwh%؜91a&f.t0\! P(lʋ^B8PtYW&hWƘȲ(\ANYBMCE_R)/*~'Ps‰nb"㪂 Qn5}κ;o Z'u|ʈJ ٪犂LI-@Kr\pevl{vDYY9qA^M_"YJT^oK(U!Db01FĘbV!xjSj^13WCyi9rDcL jJf魾.Ćf]$LnsJkSJ>C\v`B??<*}2q_/}q5#u|ݜ(N)|( 8/oz"owm5/;HK['grBV*+!ZP̒tG$p,tΥMB#+F-sdioeT%l W']s˙9W5f Ө=~if00 䗽LYXH.UNHP"@pB,d.'9Ҷdd+V݋Bw7q>g@.9N381E@>&f 0^J@at& (gIciL9DŚ&W )Dī@@H&a$w̔ w[r?zyɑHCsBNβe)RNF.>[;s\)*O- 2[%5 Zg0͌H"=A+m}2ȏL@&#-1sq2ɖ+t_ ?lugm[g0OD̫LGusdRQ"+€(TըT=и VR{Q 4w:NCCbؚ5u%O$%z9^ںEm+9ok[cWMqfLQs&u Z;nvC3'p>%N =jX'b34Bӭ-RjsWg88Z&R*+h0il<钣+u1I?O)5b֨܇;f;$Wą@b_r4g(yJ\^`8 U|hkg$i6` 喉[۲ޘY}AU:V=Ct!+nQMn\zD&Ř_0t[[ }e;MoJ*G(2-ҩ>$a A@UVƱfmS~YmIRՊ UU7cmh ؊^3"h1ٵ8o A7"ԳJPP攌=0eݕj]լCh(:W{ȡ%,-NG$Q;k5~֡y` yn@w]HH^AJG!'j^8D4n6!l"Gw a8T-vN"- s4kYFZl7bB隣$I+d*(p$W(M1'ԧ \/pZWG9f@<ȴ8 `1NC6FG5wOV Mq02Q]FIwC Ih|ۛ U@گ旳hqy߿XSVf FM{?tIqL덢/MUmh1>QyMl'%&ʖaE1):/P4}s7\^3p`Vw1xnKKmxqn\d72 *AfZgw{g>jޯ:i/ e#R9[8=镘rA1)D:t A 6gmNA#J}s4|/YbD!(z%P2y24(q2TB lK& кJl.=7;-خ p^cfn,9W /&74EdDVkCMiX@IZ#`G;[bx{EW*ɫ1ZS'J1HI|tѻ>$[m!1#8ݍ5nF)*bcDf]0(3GTTRVfǫIrр XðZʩдj@Kf΢4vLJ52^A$Z.3+_P7W3SFlH`:b#q܌c"9;;;Ύ8bXv8bX Ж ]bZv]B @~s s0 .T(m(Mic(|2Q6 bjr]uSj-^24Áa0d~ nP(D+{ԃMm#" QR] 1^eAgI5Qz+$3dʇS*ڲW'1ؓnq,|'GӨ;heMFa C.yQ0 U(tIbKj]HmtcNݺa2 xwY"rRK,,q$G~.؎Y0=G5oK91M5>8-j8_I-4Na˗ 0Wι)N8Is8 zgZiownaޱe-K,q8ȆqM!66śZJitBqʢ:N)NK^lxFdO>x)B~x!LyhnHvywޱ}Tm;Iln!5?$B65>hm+rۈv7%DY-,Wgbnx/ [ǹ&f!T$ D꜔}Qq`)mͰZ0(##yt&=b @-y \ JP,L#+J)Ϋ[Ē/GSaE X&X鰼A..DіqRJ8 bXw{>xyQrRٱBԶ1`,qZdh"D2\I(M V)^?,k{(\yVyOwZof'cPȴgN}/~%N<ϛD|R$n e`a6A9<VEMکOowxG?|{WG}D5EeHUo %ɠ!ng>.}tǝzʳcT].!A<d(t끚eq; 6aF5Wy6S.܆xKe!sl>aGBjE0ڡ!.3,Srכظ@-3Űzͻϔg6=v=ZK G[2Fl;ʡ+@IfHCܭ+İsh'@2D)!S).ţm,@SVD}0p5vnKX|r@WUw`D<0L؂udv\{f\CCKS/E$QXkV@`>ŭęg YcE l } A3i-nޯVaBQ#> fٽjW@!a5 2k a0aݳ&9rSid ltN RQ텠5V%nd)Q8Men{~\T32kD)1g+͜0ѵT}~bxs >9k68Įdn:ʋ9ňxY2'qp-٧=ؤCO'iN:")}Sm\ZO3dTRۄv,ue;D4IS#ē)8njB &f| aTJkt u dfR'!ٯ́|L );^CM٩x*u؟;n=6 - !bA,NL:NoBK` $<ԙziL-H w \ݟc04Y;H)lM҃=WK|cgO:C9~񨛝t᏾O;GeCS^?|^xZ8x_1au׿{G:u]O_G7{><q.I?57K [RMPZ`^sqlj(|#ͤ9'N{򕏾͎ЫO'Ώ}ww>]a٘0 x~{T+7kq.=~џsGZòJțzTwgkV"Ψ3ecXCR}\ NIT}B6ڣMZ>z@^>?_1ox2n j&;c,6JfI_p i{4q?2%y[hsvQlxCHuҸ=~ɉ=DLNPC*g<`UWR&Qilgcd}P-5l/ b-`̡[i콇'6!hu*ϜaAv!H|@@EpL/_D)Ck北 NRjf4Z+t]h͓kB%r8]Vtp)iqdbIzgZ`wwwwIDιzYs/0azvJC*?l94Nfaz^^9%8:;is0 : @x@cJ)Q1N# `>Z_\5V̝ɺ1,fta|}s#z \iAT}đQ@yKa>ʛek#V;6k}<)26>ޟjGX%_JPq6{GRD.K聁0lU_9%7$']er! CbU04M8 Cq O4Cm3UXrD0n IDATYAYG3\km+dNThhR%g4$(\ rI?r{DsS"SթZ7SJ]:m/w)E"P$ ID%TՕ@%h`bORT+%ijRbSЇf/HrַtK߳E )'}/ӽ?V'?n{_<~zЋ>{?<z9=}{=׾F(I>nSx#K?ӟ_/x`C\tl\dN{7\y@Vy2 dɰ 6RB$@Do}| bSc~? p=~zz#޿w?N(k(ϟ9QLWaTxk]y?^8O/;nr 1 ;]N~ןϟm˧@MamX1|q̞YFTH/`ɼrkr9;FK*[VEδ CEeZV35W%mZ%糩_cZ@6f np!C_n:?rHWl:K[~:")I]<[h ? x̲hi(ѣ `!V+n( DF!95+YTP224\4 oa:2s6rjW$Fe v dCygZ!{J뼜ԮC7D\5H¹]׫ MTmLy/q>peFr-i?O S 4n6qл CX3V1ūrGu~V1nvw7_!4yL Ulq'GZgZĨ0z%/-V4 F6:]N8niq3k#+II=l/]nz} 93T"TX]I_-q BKx]A rkdr~d4Zp0EX'%هY܏%~g.cf8D)QRuEF:y[eiK1!BCb0Nj>$J40 yq*WPY)w6{R1$1h9ϩ)s<+RI^R'ðZXŔb _1;͗$JFG7oH^&Gc:@0 !n!](ٵ'Ag}\թN QT!^bN1 4YNa{>rNnOvY~νg`ԟqG|3=9X<7}o?W/>pΦmك_3z]~ݟ><鷿%|ݠx8eӕ|}>\q?{ zе*lqwomnt3uf d:W\|1w>m{Oep踣NỾ|[_6q>|#IOeRsw7^r:Hq;>/S[9@Es@B\s(N'e7>!v(W{9GUIafXsЂϵa5apޛDz#UhqBaX !|}Ħ%m-/!&(0EVfPmy6c3鉐!Si7#n 0 ;G0nݫv1 C+)pGqDQ-yh#l@8Mf^wvvdFAcBtaZ֫a5gR0aD !^RiRT=ϭ&Fx >8X~fP:"bY;ժCD67M }mQ-M4$λwB(Ռ n Kۿm*#x[Qg6&<Ԫ#pl業/͗,=Dc3|pD<*AHdfMcް G9W,t m)FI i؋AdPC9 @A<4v{`q2F85%Vc<)A>zSƫLlq*vuhlN[dU*+G9"$u&yжJ`R~_7 t>sq\\N/\2p/'/ e܍;C_d"Bt8wq^λח^1KXS?sfK..$@_" !2"s*b),XPEL`qA#:jM-t%^Odx?}*@D}BM pQ4vM"ORnLHts(,,ă":`*E#7@s_ɀxc_0qc֬ {xb\FL{X% S#a9ٳyESހr"9r[(f̨G >"hh:R𢧱N" B,s[77J ;ktJMq6t\M!>Q 5K?jlfd6mC[a^Ŕ(j/ Mc~$4 0uvfDlMˮvK87&oDTSujP^ #jM diyh#A릈AQ&ڔpCtA ]=*x#l +zK'9K3{еjt)q3RJyh[p^ՊwwTj5 4M]lv̘΀f)L._K[׈<50F (].ј7c{-EU-?oJ@Mxsȍ>n8J/քX ]Td#3V)%S-ąUdlÒAMh<ȕ᫽B^g]xhHR"1 X&8Q}8EvτGsoaAkk59&Nb~1#Bpb4t4+Gs{5kTɸ/\|tlz"s%7|yh` {TKX ,pT{.'1sއn_t r?gոdHS$초[_לڪSD5o<7|{~i#@eJ\,ǫ&2vt7.=<޹]e_ KɃ90kfq" bJjpŗQq?ABܹx{!t^$ynUNjE(\G{wip˟=]pS8B/ 2#M0Q,!|b?f=yTcxN;~e>Nڋ$'NyKˆloFhI*wڒx8-Tmry3s?˜m1ϽOtPy$*:9\FU 80wv0Ĕvڝ6zXNqSJPD1f#XєVx.1Dҹƅŭtб˱ML}OXˆ[SJj=8qkTf'$w*VK{5:n^Q,1~"GAЈS4 H;8}K Wj؛aBC1zlӶՅ_IƼW+1j'SJv)Y,Ňqi`QrMT? -nA@D\6ADuȊҽ{&׫fQEu>/EA{K. +×XsBϋ\T1%&B<?-o!STEC}B2/TeQɝ K#>ҺSԴ6QX΋BH0qqvOkíI(#3_~wQW|ѿ ?z[gW8˯ݧOx3[]nyԸK?pSu[#/U?~O䇮{ySvuj,km03rܯ۟x~ <7勛n椯(o#Uk4t {7_7]';|}I]B2*snSٌ)Ļ5Z$y1tsqz]Ȼ'䃟pk|g_RRJWڕfV\>EQ=MP|5P]Jཞp BC@?,`I v  mS{(_FwAǬp/a*[ xF)HF M.K)xͦ)E%ŚM}Ursb݌i;_4c@fUEe ،i€5,=L mMhK"݉d!W̍ i)9}p^E>[Kݴ30buRMiR]Y*ƪL]yp2dSS3LFؒ̚iK#V~ 3/f-sgyv-6an [~Kqo v(27hN2^ܤssA*Q)QJQ"͜/bLq1N11h_$f MVXhhhlE9)tYG #yCœVbшZ#`b ײ04M9/yY.aynˈ‌כ.y)3W}yEaN}Oz#^z5ܓ03p_p?g`7?X ͳ:)O}Y;W<}|c_QH.xv?μ۟z퓞΋RV0`F bEeax$ >)낸G+h:9|OonInl9X&OW2 2]gyk/5flg}S( {3v4)K M"e/HhP;uTŒn2Jx9|r9P4v)7<_]u[zIE$q{˹[92}RsH)Qa" zB6T=eV ˊYrKv)ԗ--ŀUnំSE!2Ƙ:R$*Y< UnD4J`덁)){ R^ jPdfqEAdW\RL$hbc9ĬD`JӨggŖlZDiJŎ8 b$ox*kG$V|͝2Z턃D猎#cMƗ"% DCp/xCi͆,bH2Dz$z|8m^MMEh;60ωֿPXޕ'4ձE*{;q1hms 6&1xt@4V=|eR@١uO˱FhX4ALá\FE"y 8 bcHSQ8fSLD9/Dl"a\;e3ղr!EY!Q֠W9S7T34#Od%mF9S$U2Dr&SCc.y=H٤e1V>ߺ!TOJeJcP- IM 1v%3,5%N]w8>AFU 3WCn^Y9g֜@#h&)RLR_]\,}1 *Lb1sNMK2-Rwc,APRm3S>fEwm%x4C Ûٗ7vE242O]K$1Н T~ĵ-!4똛&ʨtҊB/d%'ejGPsN>Ͷ ֲaIkj=rb4c."ء1V"8G#Ȋ5ibyTd;Za""LR4!J cTI0q`YmbZ1tZ:t0 fJ7R.RPClvއ!0C&MBXccYƂV# UG\K 􃺄Ҋdݍ=;u߲Vj4]XuČZ2;mq/TĆV=ȶV$$*rHU/kNYzkD2(s<dlw,_O26"Hd?hЋt$rsecj=#r pQRWYpPu+Q.4j:eөEY/gi5z5%Nh|SWVԦݜꮹ=#h*K&lzgAf][b4m-gN:`Hen붩۷&~=A],qsi2~6j,З% B915Hhz>xĖ`E8Z/P2ȥ@f[ %VlJr4 Qc]mgތS5CΛ#)i:D,n0Zq&,!ɂ1OS 0h6Cl=sc}!T2p\՝9wgdFn Y ƭʼB4NL$1Llljv!͘8Z,3X~@,,IgxBwdXP YrX>H g=-ƺ1VGhb;[Ypd3*b@c[.٩L :iq粮,YR:>ʬl0-< ZPL8z0e'!w8'eN&6SZ\+R/VRVP :/3 %W7;xTj07.kK\QAN;Y6=:+&Xo`1&J0Z%z0Mq#})1;Ԅg!?Nroh;!_0DH8DkMkˡyIK:a?{ ,2fbPGRYȭrpE$fcNиJ-DB"S$wC<F"0; Yow4 Hޞ3>‹ iD*R#ȷma@.lk+aKWhU܋ԉwk)8i樌B!zfk6k Hnf[6VqT*sIblc&Uo#RMEXUxclofۢ3ըt_j~ ovP(ݜ1ҒLf`33ާxNgXx or߄RXx ]}e6&~:5a A <XJ Y ^vrʐKK/ ؜_|I1SVcxBP`>^ "M+U?Lg&E}M BECn 5m?X3 ^c Z,._;S䎺єd.&,. Am5fK=pk\X, l59ٲ498ʉb&*01q(j5vїՃyϛD&nW;3{6%'98#!xe`oMKN@F)p-c0I{eX)Z9%}*5 6Wp<^'#K tcpb7̓4p9s Yg`ANiJ(6;ҿjn}ťШ %v9F`j%&C'}2K(!<2~8+^=X C1FbrcS@N|A9S&ewdec+.5jKs,p[RVFS6˩={$VUsa+iwỷХn\H<֎gSÈBD4irōٹ^tjڌq^0 CH&I.0 ]_ w婚48Ih}Y0u|PJG DĮ;}|dptϩ@IAIE@*(%(sU`N (*Ig$ |wwݷDz|{v:|bK 5"|.VtX1W,yv816W ih|'^'&p3F-%eo)?NDօׄawp#LVQHBkKᱪLe*r@,&?eʍuk"-ƳrŪ2ڃ/rC *@\F0M‹ӫ,kjskn[Xf[6ZjS@@F(S7Vb[G/:9xr̫*[@@4U5k+lKF&$Ph~@|S!)ۑ[\WZ܍!,$-K'[P2I}G 'φm><4ʎ9J"! ۊ "2dx&0 3VD DBke dAHP$!c>!Yv V*]JZajÙBֆd1uf5}]^UɅ0ewFFfڀ"0Q?H&,%CuE$CwlHB15,É8Qپ2QYਐICP((z, 0wA4"* Zr'{@#2TaQR @Ai2rUhDz?:Q1wxq.L%jar /ɐ9lޕ=gC1zpN~YO$𐔃]5X,fjbFi)b [F$'lM1 B$BpPj4՞1Ęm{{qANI)V <SQPPĜf1ιw]HJw*mqUhkH4\RvIf2ZUP4o 0Rjⳍ'-)S!Fv9 1Ʌ5 k R]e[J}E$sD:^u)EaC&*ɰߒ1aja¡Cۈy I[hnPAƴ_;Cl+$d82U9S4&皒B&щ#>_~#$jyя ]iCBnuQoҖI3DsDh1 82]\A; ,"c;{cS \Xd:&k,}r~3O C5X(8vYi;D%cѱ\sKDbcxo!80B j|[86a!P "n&Z1!P TxiIG=eɮX:~>]Nʳy`DF$D=&=QANAhc-M+1nbY:F;RA57meQ:kmg/(PLr/68GTFk ! F%Oc%,px Cr˧iƣ?C(@ZӞTHȀٶ-LpuHј. `8A&h3y>smsQ̲'?`,߶- 肩BzÔWheDOCr,izl-3lpE| Q=0z>ET'$X+qPΤItJMk3"< F9PA@Sxby$NUE ]<2Ĕ˶dΧ $jRŸ8 -˲X!zP aB T_RB2&031*e/&ÙY=&$U(8mɘ+4{װmr]-$lT߅:Dz_3RpJ"r`VPHE13Pw03w=6$!J¼M|ucY4s$Yyqd0drO> k( c`z@lgiF72Vf/OC1DV>.o. H*UIC~NI۲mQș ==.Lа/ =Ռ).Gf: o#@i_o!PE5]Wi9XS>qו6zJ :?ǯvU\ŅL2ц:>BCo0E4c4 <E\(84m4'HFDlߜ0s2\.hgӖdOCDVw??V|Wr@-HG2}VVO|0m5VZ6'o4ƭύv>}J6`eZ{?]vŚe߼PJ1 qL o{O6oP.d+wxםN{[,HLR1CT C/@TI^%3E N%2|im<[HP: XD @a/&(jǠVe2%']QXX(wb-  o G&aUjcV'X")ё˥A[zzㅅ I(Ѫ9e J&m)5mPrl43kI#kWY5F\ε%0x0=DeZ=!2ei쓙Řds7Q'Vɦ{syBʈ)9 "%wf.\2m+]P1?_$3s̟~KYDp/iD4~a;C-O…S>yό퍽 C_{W+"2tubh Br45{oTfX Y~\lEK-\}&-kj:ŊUgreUKKَc;DZDzmA 1DZUl o(, $5wDVSeel_. -Y૮exAAaAAܹbUߔU3_l.y7O(τ$ʑ6ɂ UekƵ-%MZN[kMֹ^;Yk6d-++kW#,k Qʽ/HHզ?y'I"(BE'=ӵ[F%=߳'O9~#;譡n8cr"QA֌-FY[)zO8mY/]<'{=uy{h0xWޣÖ{{vvv`!va6yqJT.e\vJk2;c0!46Np/2p3 M9!P^OU[zf0cp0IZdvQVPF&Ie}#4IċTh#0X`t2=ӁEO|xʛ_ηw :pYqv!Jp@|ڋ&s\R6G02nO΃T41rt .C1 ZamVɶ+?,C> ItyZ.\ɘ#Jy<<|gidn LRL;>\R!}/Ee4󫌆'}MSրC. }8M9@̨wKcg.yǿڱa  XJ2]SR#ڛ_*#_OHy@tŇ,)sVd-{?4,gu^;r~wTЮF /k=O7K=tV^+Uk˪/f.]>^S)mӕ=Pp!Hāc>j5ɨiJ]Ұ vWWș;W)^O_b/FǓ#O9s*{+3dp <6YSf,a!n #@ZlѬUm;I="BBߟ2cY˾­ S[3w]6{ĠO}%( W~%+k1__Ɏ<_$YdQ[g#JBMLF2^s0 S:DdaՐuDh'0g̞Q(ˋ4-”虂kή8 $;L:5 @|R7#eF '\xƽ]W{n\aM//$"@~AӬZy1tj6[Ϛ7a c6&{o+k:|Ycۖe 8;ޟ:;׬իgOxΆ lƚ_$3sIضe]/}׿%olYzί}9'kiVSha*+6b? A`_fN}ˏ{'ػ}-kkX)q=V V<<|}]Q`@ED"}A%5= umOq-lDoܰaƍ[6m{ ld,#Js@|F[AEdN$zx< $q7^hFC,+Z,zb=/Ke)?xou鍵2$>6d';TJvG?{aR`xA2Aswm^~Ӯ\A'wo\ae\2ŢLx_KصIqTNcmk{n%ő ι'Ju#zq.Rju:~̵.]ݨ~uSt…<. MڶmG*-7l#͛6o#Bz;۞l޴bdb%*w_ll%yζqܰ-zf"ڦ׻Og,YlY_N`PdCpq!={߾mߞպ)ҧf۽r Ȯe̒y]UdeY픾l9w=Niup]_.6z@4;؎۱e+jBpcv'},rwmZ_n[6m޸aӆǼK˞UcN՞VZ{#Caz]׬-~T˨5 XV::u鯛<흧w6nΝ4s 闏^㏧/{?7%s/7JXXbWVv3yƒUKWejhFu^I˦q3V^K7VR T1s?ұZ,a#z #"sl˱cqszǐ3I!( gF֝-F,IALx\(Y9 k1TeK?kɐ#tPh۶H9 u<}0 >߫/zpM|ؿ[vCo>rQ ęEU "BDu:36 MIڌ>f{,#q,M#b Q8z!. teK.n޴̃2Juc_zXro>qq:MZ=`/e]cyoXk/xm*,\$D$ wO/= J(z[Goςum.ql?\+BpwϛZ]W֭+o:I\@BsK,f&'}ލ9,_`iWVւw{r#UV7Ξ9kkIǗ5rm^yΤW>^B'TE))۠NM*VJ|LdJm)ߔ+O+yyX{.905dZˏ7Fmz5bm[ V !e+޶6{SbLiG6l:-Ը`^F (;[X Wl^?M>9hww91 *vnt\4=]Xᶮ RY9Owm{ _V4CUJm/BouS5l׆9w:~]9F*RB-fv̉9#re XD;58|ͺ t:\S㽗~t2-}-_uGZ>)'iA#yV0u&NS|ϧ?Y yuy/{~7vikd4ѫ62ATJ_7%J~rot>py' c4DHĐ *R+5O!.B35ĽeY,:lyn7ܴɯlֽero-c%ޚQā`<{*m:+1͆HeSֈ6ch+DdLNAM @ fIvE)m$B j˕=!S }JU%SJx8bc!DА6!E3䲷|o\YӦ-ݝ'3p.-scԄxO7tҬJ,kCaNeOVKUKANMxb2Rm] `=/_{hO@M)!J~ͬ?zgS\{2Dᶩ9)J_~__V8gxB.!"[Z;ۤg2j5mۗ:]U7XVZfrRo-\~[u(Ғu[v۟~y;[䴋|6n]ZY#8>g̷>w4*,+y-Y?lyoM[](J1Ҍ^!Y#PIlPTPR3/TBџh\_= rg 8rWZ!!,S9E@T)BliDJVzxSAsqB =0Z-DB[@ L(~|h#-8MA;2^quyǶؑ&o&cg=yY+~Wʸ [zR\/=ylȁ: tcD(HѴ@@qhSה<5w?wmі5o=5a 9 >A&+uco?`׋衣&0Ca'~vKlѬ=GuCfLҥ@$;aG~]>5fVz'|O4u lo@f[35Ą-C栤3}|i/o<>nإII!"qXJmX+{ SU{hOKyhbf9}+ȘO?rG|9vp.m Rs ~w,m5ǚx~w$G R=r̯/=sQɈ{yv d\O.<|ς{;4!N){E*{~><5{烷_Q{8cTmպ* v5u,>AIh(Ea%.$CfX'P{sKz}uuXc3X 6Oϟ?X5Q@q΄Pg(; F:ID炜mGWTlq /]')g[6e΃ 鲺`v|į.m\o3Faomв9B??MixM*ž=iSLX+q YtTel~Ǝ4_W-}Td Դ7`nȹy. Rg2^s((7kӾvDž#WhfYx 6_(YhʆEߌߍsŇ+;dx3BHA̸d g=_sӮ}H<<142\Z^ݲ7It9~, 7gSJ̵r|*~оC88(cXgg@eA}zwCsLҎV|k IDATiI3*#N;㩍[ ADou)t,;Ew?lIxG|W#6"S=MOcݩѩ7ǖWl~uۇ?NX7yKLA<`.JS?d@S;P[.nzx嶭-K=4KN*7d^s#־/o޴e}n@{3 U$Ȳ,J4G"[7n|x讱 Gn* B)7, WMܢm#ѮzK&ؘ,"o͛=h~e.o}>p~/0R mTcs=q.c܅8/[rPWN4;0ӺSFan5_vUۇ?N&OkГTS"DBLOdSevC@0# hSekޛf͌'{35hSIezlq'm%S7y7KIbN,8mٹc=GbSGNVqԘw_r.a y۵=T'-o3m A@j ʛPΚb`3tne;)K.:e;>f~?u2-8iAM"@Uo ziź=d.(+Q;OD~hs6()غj7;!oλ%Z议?Ӎtޑ-@]ضn1~"G WM:~hRc-ܶfGUjulrĶV?vVkk>v  oG?>px5 pYuK.I4[IՒ]c7R8vF/#O,~+=owϾ"wti~bimj!0LBa.%[~$"Mg N2cyl/BX.(aR`] {:2WB*_1 c^5ԬZi =s]7FUJslfv*xU `^IPDFly?}W:?&neNF>h߬vr]uS7͗M2Bږoa#W'Rbu|Sv6zd#75Wavw=֯qZtDB An [m|fC!y 0Ny Pb]Jkk! "U'=u]u%H9'joxa6[);k:." 0[?4CE>4˲sT:ϖ4S~x<.pqbKl|S#Z77sǦV{ ]\{#7ݡshdv{iWEl˨Z~:U2RAݺJ؈Gjh\zC9!!D9s\{}9J_5F9Z=4]\zW|i)d7qe)ˊ&l2Ԯ[VtʵԮ]%ܵ:Qnժݬk:; ~`ь2w{=w+qlsNK]zo?tD]mwqe׹]ӌ#r "5ȡ 6#o< %{\p(-A7~6;v)s.[_zڷv(}e,9ȃbkwq**ԹƦG7/4((`gQ '5-FI :qXSrS~Yscj.in/d #MUfh! ]Opa/y?O}72bҤ6okSG2GX6ᓵlO#?nS =~8D-c_qKؼpҴMޭ,8\1xL<{M$9cBJjiҾ?pѱ?i' nÕ^|ϺC|?bcByo=?-pm34>>PΔt L GC14qL5O}B_}:n !J ]u8H!"ٖ [7lz` vB)bV.:n%_8a&癛.[DŽ]?8O}C-~~bQtm( -^0O&~UG}4!8eA5LұO} ֧I٧"laa+T)cg; I= :eYpPtҩ,}K4yC/\~lsYxr׌~dh>Nio=A=qvdWz=UT/}ـVHcؖ9h{D)y 5Wp 63-d(mBD8ybI1rpݘ]~;jW^{ma'@DTXXF9Nol"12 ڶ,KB;^MO|W}xՎw7əeU^V>w6L5}o'AsY ?ɕm=8nj 6k}8AZ 5_O,*%U&q }vԝ\ӡH700v C G*ߋgNhFY T`FR:B;N,U %`$$}  I?)\Y V3u=!8ce[)w5}1LIImzv,FgWBfۖ,DSDȘ" '1ZOP30ӵD¢\2Ni#IY(ӅjDr&7rhpxR[)Jh BO(.y'لϢMg[@ g1<0>,Ţ"h'S[k^W-~VP>Dѯ6\i' Dľe,i+4eC~ɕ !W'YK\cP.G `% ${s=Q"?l;NJJ X<\YVqe %iS"؄{0hh`_?JT^)gYsb^~ٖ$ dPhGIVt*u]kв,;,IJoWkCF@qu,+%%&/D^C<"&kDp wjd^0^XdFhAHoUa"d`@7bŊ#wKVȼ&eQG%r &^{gKxlr}ȓ_J[YE p>fˑɯ_v{g\"/hp\@MŸOoB"ٶl 8$8f8?aH<7#: v8:Tdtd`GrCS[lp:Y>J5)#W^ c)(XSV]  zgNIH64?eL$ ^$Zκ~ @f1mO--> ʊ88mٖ+kC/wqoJ?YmyS3Ƙ`Dxi4#H"XȘmsʢYU7&D>QFtGh1rKЄO^ A:QF6 #̠mBLz;( !9W G Qe2eT2!SkI -feC!$i U_P ŔdpYhuT3(_ҡ|9!2QBNXNHF$& BC^` ebQ"1}k$h zT[tgt:]îⲚ7%0 <h$j<Lj 8YBҜ-{`EG(~IZzPS%j=$2YL!% Fohݨ;b0 U(E* GfqYRbmɄ_rP21qT9--V:OT S1XEJ7qЏ.#p&"s nR-9])'D ]f~ 2܍ҸR B˒&Ȑ۶lyfu{DpkJixjPB-q1( 0]EIfw^ϔD9C LM[DcR)݆<ҾJ^dF_iAn6PE"(9lE/'=7U[p攄L@²mf1qw]yjw$X|hF9W *ƏB+)C ]PT&@|uBRkeX&n$d@nl8M00RQ R|@sFa""c H꒱N&p 8^2.ElM3c#YR|J˔(Hs$ w/|.qhʅK3\%H@K+@Jԁy !DO"o͢7Gs=ږMqe[ Y.(S9]ǘ.Ch{ޣ!pw@Mse%VL {orHD9j,^"Lb8zNԐ??;5!OPs YЛYb s@Ef cHtz ?-ka#C!(`ߝ)@_R|02$)ճm3,F=.G'tDCyX |o.xx\p.x d3vv P mK6N?rp9/((-CH|ݡЊVaL@beI#ιsA*mَ#y^)o"qν c۶#vTUqϓEaӕu},07wD IѳZ"l>bŊ5 d9U =3!=Bӏ&B> 4A&U1eS.[Af1. BSmpvY\ᙘy-"4٢d&;"Kk%m%MRA (zf%I(2(t IDAT]7a3AR:5  lm"y+TO%zuSEa?ΧT ; <9%9"ڶcYi0w]=+R$M/6pu?6%( 'gF)ǯ9 jN ȟq5Cr 8?!]}~fBDV4,F2.RȧX4*mj TʡB.mgԞ+7([ 5ۡAcTC>aۧhy\p*- rYi$FdoJO? _L=5V_18M`Oi\d }eJz\b\h ٖ8pEs<9a!s%B&e"] {s.3 +lG1@{n qA>ޖz .79"U#o|)Dhk Z~*_߄m @1p{oarqM=aՇ0=BPtg?{-!m'tgAO;HwIdcLVn@!}?ү?%`ժb -T-۲l[i< "*,r8g>ALT|5 c(ϩQ..9bĄ$kD*f*"d䜳 KXX`ݝ:?zf@,lOso8DT3C@I2} =o5O(IFm]eS=ko_ xrB8-?u bx{1't%LEj26$BE hݠ&Ԁ }0XBbg/;A PaHKpS^Ca>ޏ &,ӫp#xL% *f 3FP_Dyz0- TήS\!Ik.PZ0=#$CHP4J[Y긞?''!Us8Y,b\d O %`5τmC@ڝD˷53 |YNnja_ Cq.&~+2~T\ǕUVQkE>yJL. )!E4 Qz牀SC_<IÞÆ-ʶuLoյRճ#"b}?dߍxjVsXM >SlTHZzPhoڇA7+&aFF!5Hjg e(1?q:3Z>ڣŖ:᪛.S^zPF@ՋIXG@S"8㼇n7W&0m-S{rԙs>얇z!r /| S/4Їuotw-T\}&Q+QiPXif)rE7H*cfgӾD(~#{W} 423/|+Z bDd0AߟP2Z}:$l:n,Ţ1'sb1q\"O!T:(4ɰ] ̀#mwSz?~mEň0赐aFj6lekVOꩌ1CYϯ2$@J|貵뗋_~Te]|Yz6O|8nܟ-8_ZV$%%5--55555%|-[zdiulo39'n~h⚵&[#F*!iۖՐfWCL9g9S͟x쥋޺ DRL8CLDRSRS27~UkZdeׯXvU3RRR˷#n W7n7ްbav=3S IJG Id@[켶>U>6d R-@t @ .]qW;N,*g]n1J7%1f{p.OoBtrf| @g 0O+{vE &|<;~աs] C(ǁ!5@ٰ<+׭it6``U˾I'b{2d>Z ۶l)QixϷ#p_|4]N'DNx&: wa~>L`Wn:yfz򻇷w%}(,Kcd|On"ކ#$$шhk7 } _t$Ow̝tdM2-u+ObgX K$tGn"ΉCHJ6\W#Fء?2Po4GbFԮqF*; -NHVY\?=1|J TŃx0 t`aFddVY'=Lte}}O~cJo#)eZq}e(%$^Z; 2w0 \aTpRSy,:d0M?Mu,LL)\ PRH/ZBXifٷo=j(waFyec+chp fR_^%|Cmc,zEjY:P~֢[Xջf>yWn$- 1i> }ɷ_t8Н1Jqj^QO\n7dK{lW)ň T Akw++~}3!b$οw4DlNi[T+k ٭qMG|d0 0=:Dy!rΝ$]1!&(^q( *$U8s"[NirwXo?>nKCwG5_%L.AչljUWLja8Ob7ޙ%OGw|O,ptJgW&?ZKF\~?dfվݷn-H%Ozmm>; 4lIZD қvz1%71x&iM>1$kC c1hZ&7MiH3;J:%2~~d2?Am/&Bkam5tSi]30  ݑ-z͂s{mrΩd<Zߜz2 sMdff^buV/IKsL@~hgC`u~E7Ͳȹ?r};WN0$7ԍUCtի~f20^tyՂL\o >ɯ~uu"dV芪ji]&I~׍W8gkV/Ʉ! UXdnu#/5۷"m.'] SմSwZ3L2S(pS^Q<@srvjۗ}{TA[ol&gfu/rՂo#+c1cLQ,DKI={~k[߱=KNꆎym9e?}U+G.;oܳkJPf|vO}2m˿SV{W_lnm*7Zrɘ^uOl峞mVz?,[4q+忾>Ox/\WU3FӼig}Yvgeb2eeV]=履FQsF\B$δ.moX!gde 4oθa/xV"9m?`=kO~9wO jJVֵO 5a7Dq:N6oO#{GiUG}Ӽisfyvjq3˓+V(SƓb9^ˉZ?ȕ!&R^/>c{$!gb*M/ %q=8&Z+ﱱɫ s~FK)䔼aHsd['}ayfv01NE,;bZv?,u_V{ܷ Sf#r~k[[ߺH5칦ˋkkee]+qg[;{yn#232E\ FFqIE O׍b1~sǺchţ:T?EwA4]0 R 0bƾ=jG8`No?JĶ;yM7oڼm_)'Bi;Y+LzwnY;WLT!óM'U?&Mz׵YsyaFl[3 [{br=u]z81'߷uϿ5]*8zuŢQdNԣh׬Yz5F/{̍Z fhH`2=DCz1oM+g?&#)iiiiiiivJ]K@F~BTH[:?an]4=Wt#Y5: rß?֛{onJ94-˨K^`2+we9Mkg ˨BoI{ `^ԑmW걜 !_7` WfJCq;y2⒵MR" 뜛}Q p/ŕdDdV wc<5+sXXewo)2^_`(+3Hm|980yUJ~YQp Wo.ܴavZ~nmLOv`!„>Һci;k_y ^9172++_zM*]?׵<+|R]LJn~q2,~~lggw`rKZ\7۷<WcE ϣ^y;3xq=uVpvg|˕W;}93w7~|ygSsXŋyJ?z]-k>'3/ַ1~[L/l#]v5лqx?{e+z wV^vRΦ?֭{,;O6Jt/;{to]ƂX^<ݻ j>F Ǐq'*ߑ!(êS!";'ҕcaG񉬁ހ~}[&LG(,ؐo h\}3.HW<_2ij̩~񀜆H;"X](S,H sʢh,))4iV3YB^K.ToN( +eͳ\^.s,#%wk,vx;Oj ̎h O$x:`ZnY^PuJ/p"儆)f9J/+ b@UήPlvW23*u +.cg[R,٭Z̴ \+XN)<Q^+|9-K=sW^U5W1۶3LIMbiB|_*]׉F1'vNMK#-ooE .98,[ږppÍO|:MFP#28D&09&=}RϪU|jm۲m6MD::.nSy{pg?C97_ ]vxk2m U Li RP }>`Q[V8Wo>^i3W#HSIgGdp?siOK<׿NdzkJ>_o1( OKPozyוȬBGo:>K.S_l)#C;9[_'g>UUON^׽5G\{3 Hͷ\^`^"CVxFw"w hm5o 2~y@-Pj/.P2 PO.+|[/&ԡ,)o3fH3XAE%'~GDv;ӿӚl7f[쳪vf߾qަbϋ[X^UЪ|~׻dTJcDѭ~ҟiְ6ײE] twZu,ݝVЪԢsY&"bbYǑ)tOʞ[ʮIʄۼ7uk !3[[3۹t3κJ{qƹ"F|B*:5 i%!Gy,i?hS@1dfgJ9m޽}L9+8)63뮨' 5֢_% Uh١et#fou[wGض'mz%˷xalրa36sk7?[)ٷf"?ؿ9#rn<Ǒb%W ?_?rĖ9-uɹ#yS76 cM]i:Y5K ,9s˾}8 / ~ΰ{N8%]uvؿuۭWyADw~)6(ؿeޘۭW5(Ew/׬($/?|ꍻl7ntٴY5^-krkg C!6i@"s?sl\Sp،ɱ ` D^u!ڶ-qSb]a?#vYk׋2ʝ^- M[&Ԏtfp7tXu0"-l?,دGfq|/@j5d@80¥ P]nuR #;JzǗwqã1qc1ljpWXyؖehtEmb۲p 7|0c72=*ፌ*pPi嶃zMvP1dVf)]=^=w=M5- qѨZ(:]XF;en2*ڝ_Z;\㸮EwOUvUWN'ƹ='~"LKbᜓz"cv$beN#1"2-Ӷ#6X,8[bYum՚ͮ=#"14+֬GvqHUkZ;gCqh4Ţeeei)P]jd3m3%%ImY¼ ӭ,#;N*?1+Z(M,Dzͻ-wϽU$(z.W` x~b t=qcR=+ߒa[V$bDmElKr]׉98XzCM9*COfm߷s=%Y88cȸҥicV7`@wDa)ͺ:+z2 %ţI!o$xNp@AeBzKu{ LЯ{a !3'SZ F~ͻ-{[l?:zԳ;w B@&ű{W\~ȕ xb&n9v.?qSQq /BbJoMٺtʖ~яo5r6YIkaYJaޞ6d-wch %6ie$~Q$iT2/MqD8 B }WaV%cQZz\+zȘZT˨yfG{ |J 逸^O~))Y3QyP0{؏4#̦w<ې!(~D9+E܋(ܿG].Uu6xlء^v#n~//R`)`47ku~vUA$&(kLc;WZV[,( Oy"qc,;My{C e[DuOU2ۺ9Gx2삫GTYv{ڛ< p=TЌ9"a0 &9!ކa 0uJKKѨ~]rOڿ;W-!@g~H 7U~0q2s NnLJOrM݃F <~e bAri8wLOA"= spޓ CWɄ'$*D֔8v -P#D/b'T 6)!ؾ py,NѬ tmُ=r&oش"ޱ=G])q nʅ_Ek9mݮQ/N|k%DD@(Pu'Hz "&`unA,ԑ!0 bƪ1=7w'20I?m_T!rmzʏ!@s1~|' P?y{mGixg=%'Ńуs_֥ Eo:]Y_KY3zXŬ t zk?t**(&^x=Zr9vi)?ι?FI5gD́}`<]YR!=;]Hie &N@$y3_'^n~w:g w\㘛rӟQC7!5Ν}W>ڗ}`?SZp&^̀RGKEHkXΙ}:E.<*,Д;w֋]k_:xJ_h$d)QZqެ~jcj}Pt:IMC(`(Ti_+ Xg9ੀqx\KCQޡVʼnLmx@D@ێpq]?=豨yamvD8K_hr"#ʢ/o`UhpYFӇ25?IKbsr]'lJJJչȈծ^!8g9C󜘣w}ԺC)/nuL4L02q8>U`{xזJ|dDBĘ"`]|w`RAu]=GʎDf < $bHJ;6_i_ 0LJPʠO60|E HB=Yҳӎ/xS̈́“>IfË.H{ne0RkqhbYs"cVN(倣8CQd=ĘM(P%@,"GDKOrm=eوȬXͬƹ@ sknOUJYigo?z;qՕ7*yVƶl?pe諉YIӌm_]#Tjmk.OQ`^@UY@Ӱ aMozc.rl[Lpp$@ҙMӷNbq1]a2QY['[ $_ 9LWZ邙ߩ L`xhYm[L%𣱓F3R7Q 33GfGb z]n#vXr,9L3:[^ `jqb#i)teّHf%p~>vr%ZiVNIM5  ô#0ojbXD [Fd'O*Uɮ "Vsض [䘜87iR7j\2I:LvN.;wRWs J/,eG<<} };uhߩ".ϺShŇ\Feٶ-aYa211}#Y綛4eg'axJV!N nog; i*--ԴTN1oEqUU5Ufps#DfeGH$%%%LN/L{wT]w9܋ϫlF{cF ϩhٵoۭk _/KnթR.]l&/58έdFHJڢL c;wGs/8h׾*!s*YV$S.*׫_koPZ:y2QN 9Fc&|z a)Qٚiٶa2pG{6@^5z,m˱j7VoaI %Gִm]"m?nY|S;Ǖ-ʺ_u9YW:M@´-3%aMz׿PahMT> +G`ٶIWڷu^p3VeY年V[XWݭ7˳=z rEDUӔ0ʗ~[ny޹-ZR;mrJ~LZCf'Oޥ:e}]wxqr?_%o߾}GcE wW,~D !,24E8iYƒZ5mĈDఈvY.M:8N.tygm_cD繱X,kԭӤneS79IZ,+ Y_w_|љU5Chp Y +.a2aj]dW{GaX/v{K׻=9i[T>˞xmüx] Pp4L˴,˲m;bv$ +U/nazbw\u0 ym;{uIztsWΞIo)[»z]Wn7 G]Kuݫ;|P+LЋάNOvv-gכ?uj]ЭVOZxH͹X.QDӓ{IH ߈ު^:?ۣzWWF.{ ׽ާeob/{B/;÷ 'ξzihf_حc-&:>h5n-Ĕݞx]Ƶs5ꆖE[ #ZVO~ [5>0z`/<8xq鴈aÃLᮊ0p -g(Ċ1uy ~+˽GE?ynj!F~ ?s8T_i:'Xb\e@U7 ق&|b53ٯ<=phÄz%1`:qv~[/1O?>3& 6S}OD }$C+ QJ}5f)tgM.^qc;-07+ꌷ7wqѯKǏxAȴ__]|ץ_t 6>c=yl#Ia8wh[/#;;n2E Dx|ѻox=ݻ[ZMOޣ=_4f5-0fߒn4xAg@mKªsדoa?m,2'p[Y*a019*91C)Whz63N|lGw DpѴI8|rً0JvxA;d 1 JҤw-wy1ȂVUw`nɉ3iPɦ+t$FQѿyG0<<\4OgGeEzaZP1מ_s!X4I[k' ~t6|G8Zm;zs Uy. '24M3FD񓷜Rr @Eg|ˮW4p^ BZ<A[t܆38#"rE'S]/֍#ԮخOp{/_f z_.IPg\OH nD2Bmcx麟_{fȸXѺl[L>|Ξg)Ss?)O'k/L ҈ (y$<1#B $b;Fz6뵧0+8^#wGe|;7'Ս\i:UBC($g„ kO&}@_>c~ mғ#vEe<'F֌ |-7K f08e@[ Ȕb2jtv t +ZeLJ[gτ ~Uz4$&6/dk|jb[9.\emqnk)`T eJ=y:%r\w9RեobB?FmMGЏ bfcgq.%\]!/s9?Rd>I݈|Vرc{S#= rh$o3ޘt $&"q"{.y|Q2E1"W53} mP5 M)=*d~o+t]֡7SjYNzncF5 ÎD (\@D,[RyuJM\IAC'ǁ6(}b-lͭYsH=?J3 U$-Y#wP!|})XWBghQb @Hf&1&-<'0ұXu\ET~$t) %Y/ XIIAĒ} B4H$LIj[? tɑ!v. (@2[C h$%U #8qƘa8yrgLӲma6!C,Uؚ_h CvA5œE1e8(٬OPB_c2戏#D'l1v#.1f/8;SQ0ST1_"19?f"1誝}J=+Rcl v! W.~Tv~>,ݧUuGi$uҴСOFm:B%Ӆ <ݍ$:|u5?|_9kBpIvIÈK? @"$Ԍ tMUZe0 f.9Pp3 [0z \9ȉ$CՀLO*mp.WSqűNmF)I$ɐ_iaĉi9Yf6h|s'lCt1Ͽ0(()V0%siNA%IXQ9xF?hJF+3?;Ί">D0%#sDŀ* bZ]Pw9UL" QA2HFdAafQ >yapos702P%*k-4GޓjމXh] Wx 'Z|>~cAŷ9d?IGfX"1{GsH$-XBd2!6d1j1$0B1X7xYϳT*Cy0p.`lVsd 1 Mæl/qš17IrzO&LJƚ3ٵ%xiH !I4SA , #2AN at8-%&w:!#W"N(PՀ-w-Q\Qbc7H*ӀXP%+cn75RL8K"y[@" =Ed21 DgPєZlE ]C{!#%kߒg5"A@ʏסR,5EM\š :mjUy\ulT9#_K 4%k&{Xj] #bJ'X˒ (0*[}UXGI!4DCa&QIR9\0Ε6Mf٥FȻ@+l?K7~+v&pdJJ)!Me =<>:Ogd$lWM 3!Oy;dpɾl8^&4Q"%Wpt t(r0}_u/5OٺDnfOےe2 ==E,Af$S5aڥchޯ 9NE:Sd }dJMʐ3;u b6=Fs/1)C|_j -#ؘ:dMbj> f=2ޓ@9.J*bK>BgAHg-Llfm.*1J{Y>mi&IF1IF*Jm= !Bw`,G pB3:7Hՙ&ut772NZ¦7SґQ+=2@֕R tȈ1)&7 U@zcz :;6hb5#)&c$&h!SiKYLڃTv`RHdƐhQ%Uj:AΐHVGROq#% Z;QTb9Q*S T1-)nrr'ÿK+ AN$ J.^/Zt @{DIBأD^g2֌ԐT%NϪ@j*Β!V|ߏkS lU$hYt=[^,}5M U:I9cdmXZR.lA>0BLmwI$4Ag{Q=_0[x(S9 !y:Rn3f8"w>z? 1W g{ 3g5 H0-k~X8kY?,5ys^;=3꓿(owJ|E""` o-?MX"oܒYXcLzg?fϟ7擿80I@DVpulܼY|z};L{8F4&{%gfN~79 >d5L;?z:9?v̹sFٍ|vx#n?srkuĬS# )E1D\󽜼ܜܼTnNMRANkX<{?,Y?,7Ϭيh;卮b܅K,\2g ^୳cX= ,\ٵMxܜ:߷S.3s\9~;,})\8I^}44=*'b%gzgf"j>qtF5g.߆'|׷t6$^Hb| @Ьu]E'oޫ3^^ţߝ~w3=4`տ֎Hh2lR'qE MW%?w⤻_xm]sFkEƥz^Va3lyޮ I8dp5/>{wo26:W|}+z$YخwV}I5RW %yWUUKc)}:݂">:ASc !?,vjOQT S1#1P$P`oUk4*C۱[$l:q0̎n!y!rs*}17X}p pm-' `U{X tPꮟ}fj/ay]l0~bDIY|J~nQƧ C,s1?KrWq<>eygK E$nXyރ*+-'BB~`61=N3 0캗û'o[}k38ib#ϫ\Շ3ѣ6s(*}VD5DD^rSOv+Cɧ^rȟAV>y3~sP%;kg/WN'^ۺ$ wΙ| ~VHTSAlFR `^WI)rEg@kѦtէw]o\\Yӎzιw~ ƿoM5:(A-@R o29hY@$IRߤe7s޹qI^-+|guHB$ !$8:-ג@jXdPIcUj=ShuPOdW M>8{yˊ. 89 |884<)BM+BFY1yZ}vvF^xelt}>ڦx{{#J"(6VP|!- zU+x/.eJO}>ߏ ܱǥK,[dٲu,g H5䊖g</irwzaRaMvSװaqBLoN(56zߔ+B;oq3gM~31=q\-0kt^I CO4jdHA; }\1m}n~%r3 qO]gssqWdl2XJ 5˸Ě7#Z A>3ko>qF!9Ʒwܟ+_q}73g>%z5xYgN:"wIkkLMKo1eK)F>t̓|1y){]P_Qz6yG]|pA<*N~s'Nfڇg3/{u1ە0s}8~j٤)Ncrz8|VpV_^{@q=ӹ8@K:;SZ'g'm4P yz~8|¤#߾")$wޟsΦS5Lx;';˦ =ސ?mFD]UzI)~))?_7\•HUj3 ԩ}֏N*>f,hȄD$0 Hq#!(ܶ}Ko߹b˯хq0 #hBH)k8-o[xTX{nϮ>w:^c?镭?>='zL:<镇<]gpfe<-=@*6T]rZ^ҹO_7m_迱irR@z7 1Wti20g<R~`ZbF3nbҪ-Nl*jr`IݵHL:7s7b푔7SM^3yhC/>}_l4:g N?K֫@rEt:]V0@CQuҥ˖,[d,0W=z*;leK/]S1"Hn/: '{ qQ޹&/qɬ_~j:+M%J"SMRZD$H) &=s@C a9|Θ.H\GIL[ѴUkg ~ vװß~7g޴}y/ .<ퟏ^p3͞5sS+}rF2պˋ'-'xR~GΝ= z䋪iw0p`%TɼhEe!c30v*lDq˭ c-Bt@T[攝䐯M7TIG> [Y|٬Rs.:ejF]/sgB{p)0Y Y| : V[şƥJ:$l6α aYA#84 2wiYCZP:~gf!xO[&zZ5i!N[w;wKdO)f +l~de36 Ms.>U:eU_vgcAbl.m>ŪEB%&U G/L[;t~`S6xݓ|:>vm}ZqXi7_{FHZѢO_?Ħ]O:k^[xñǜz̮@_+ZCק7^h,(95u9<.d%ֹe^̙~_N.2^ʗ)}ʲC> 'xgۼŹgICZL:=ua$U(ugsu^6@V].y*4~։WS!pܢ&ckl7v]%辋sbL`͞=#L tV8rD`5ZYRt/3?.>m<Ġqs*rѥw:>܅feB$rkS[v"=8"!e$)=(A v\ [QgR9QfӜ%eE*Tl"A}ڡ}CXǧ>!dR D)t.SXpFQfLj́h)8Ǚ"[/]| ]~ve/xg/,A`cRD6XMh- os?ًw֪cw:!/^Ԁ֎~o>jO+cٷ]Ttb^`-tND~ve>xR qjqUT]uW\rn7,&'/`:=w9/D'띲(XcՑl,x(, Dh `vf/#HH!Ml:=gMOG6lBÜDt>d#WerԯZ-$ qclT>Ǿjxc7Hc~mf\vt7LXa>oL ٌ~5|m]|b]`t/6#Pt[Rc&Y&a6꒐}Bz}~3V9\oTNr& ר]l U"nfn͐V|> B:V:ZN}XQ-k)%nC/{z'4m%zx/59-VB="0s$7eS)!mT4_cq$]9$+WT~Rg?)ߺ_ "DCMBl-He( 1qI)Բ_{ ξ_t)ܽt#,{Hxd$G7?\::\c;4\-y{dn(ڳt#OKe/n\R 'p31R%-%vSz!>PNYN:ԬCӆ9\kevo)݀e~ޜDƥpr"JC3beZk?{>x8Od<mYKJ9Z)̆[ty| iq g ءggX;nԶe>m"Vpp6;PfO x{|fZNi]EI`\(,:BQ}r}ql 8j Ͼ_dOܛ&cȊNF^}؎o_^VqVR`W.ΓR,2I#2^LOl\GYɃ$Jg2an^^&Q$tFin@V5ޏY)Nl" qcCw r7=wCT׌ۡYq>R)H)I"{sM{ɑ=B(۴KdUfӠ%Z~GG[ (wǺN sO7*Yg:Xy7>fG)Åה&b}$gWim*:$l{h?cbԏ ~Y I= ,D53NHn*ݙUV/@wld ?1LR3%vf_-7p0JIaā)5 cr zA7~lqZYoǞi TuZL:D̋\{^ݣ/(luJ7n-_ltZwP-|0 qu(\uswNy#~nq*LWm*k%ԑ0$0b, j{bʝ}Y(}vw=A;#ʷ(j[EJ!iӚpz7A~ԶO0|V!ۺG4|W^%'EsXFJ!ȖPPBJq֥]ZINzYM.u?[)rqn[ NnZcE6v_)d&RQH\*d#A  [ Iw9GYe+{\H EBdBHs a3$U,3O/] Vu߯YQBQB޳ʌR4Mz38`Q9IYY@sNQu0#PJ$]?UM@<+ a.ܹ@uwe_s߻L=lUMN@u&^Ӌr̦&R rayHn71L8qAP&&"9ya:>SO8}x㠟#QG?hBxBrw#`ȳ.pºF|)dΞԡQ2~X:\frѸU1"dBT;R<5&4N2%@YW7cBt&hPgd :P?+*dDѨ&ymcѯ;@p5 jx*T@YPqu~ͻv[?\ћaǹ{R<ʚLʟC]EH{Lj#sh n^҉?- 5r;[H䅡#աag_RJeokud=/:mօHRbaq%58,qW#5c{t*ReVVrdA4//H+luSJ"v`W0c- tyyXV[MA*`aH@,HʉWݾ(UIHFڋRАӪc2 CD^z +V;4Q+*47Ih'J(k'.kx=C @9BM" CE)m|*w8ooqx!C .\U/q-_96'jS2KA{[ ?e;h5Gӭ$8P5ۆ'mV:Øǵ"3&"6"z3{=`'R ?JrrT "<d՜*L!Ü1ӿo=I8H)d$R )[l aI!IUiQ6#X1|f -puw`Ԍ_ 0^6mhZ+m-rV_uw㛵8-YiSq^FO |9u |A!ׇ3L6dU]{R^٫{5_QrKZ=m:kum(ڙwOab8ّ6': 5ҫ^{=Ec[OCGHNsZ5nqu_sްi J=V)gSnn3,KlBV֌bMk~rVwyk*Fzۺqs~ClSU821r D!˙29&~K$O[6lzܵw[s)[I3zv?yq8)D)5$Ŏ5?px1Ew\Q\nLbu'QZ8߿իعv]fީnRyNbVgrNuОuv9{%F0ӬC7OnOtoH;f>]kH%of {mgaml/)kںe&5̭۬UVj@Sz?Gږ1}qH 97#ԜՇ.w9<=fH۰k"1cJ2NlK{>{&7=䱹OiHe\k}1-ڵP^6o)>r֠SW@y7it;jvǵΌT HH)TX%{\K 5G:D&yX)!q13@@zZ{,O׼we8: nHJuDRǕt΂G+TC:H~* // /3҇-*\79V"X wūk;=e;~1%]Ohq\A)>ZzU+3ww>^v!PZ.{z/u-NelT(\=G>LK$Kfikο5ݞƿ㹻haƜo㵅[&=d*,8ר}QSk߹pcOOL/Lͯ~z?F{X~F.{q|nFrIz^=yog uarFZ ItB9]E"RN˪/UATY>-9>P^s6d|^>fhI7g#W8kC]Wa$WUii|b~AWldnT;ozDHFɨt=jy4c@{lo۷DHrL5̍S-izs#0`·(=zϫm_:{>RJ)*&"wZ^z}S>$ RbM=3+۞_-G<{ʘȨ" Yo g6x#Yӯu֠[_m?}VJ9"FRp!RA}9$㈺l*Q֐˚ѹ2cyIΘ(X>s[ncۗ}ׅZs_4v0' DZy)Y*bisJZorG o( YdIS XH(AH" $CB v{ok̚9rs{Z-P|Ԙ8f:ދ誺ّk8`c)Yx28(ד'zMM;D(H /N^:c> n[kW&xf $;׭,(ik(/N%i )2WtЮ Oww=!Q)TՌbC߃G#ۓ@64$6qFb 9!v5r<Ήǵ|+!:dr!qt3r_uŪYw6q5f9*1h(@Oy;R"Dq"e:1-W.b!ݻw˞rAH2[ofNTpf^.#@bBn®y\>Q6<Ը8/B脼gzP5cC4S:5^M{*̸ .DDryh@ZOR2wJ1!&j#-o̚;5;Ul0aofd'SIw4;,4*`p֯On[#kI.>kB2'xS"".d6a"À]Řv[] p26#ob'ITsofu f]Xkv%Cn8.)dzeIMpRW!sX3ѹܮUa,{rJ 'π >KUb#Oe~shf272$\!I5RRN)"ӊYv*7Dɇ#"`ۡv6\ߌr+Q0-9;RMr¬NgĖPm=z0^TGypok'Q0)l>j tmk=I #l"7}>Ks~=qyٗV߾:$+"+VŒvv-G9YӌX*l)B];8d?\gר[̱ϺGӚxL8wZx͍ gImsqXEmH:I]*&jX@}OD+ŨX]]YYYAH4,b@M]PJyuNd0D">?D%Tq}S<,_ЌPJX&Eztd>$vf |XfEnC$@mAvkh"'RPNPܔS5D>̎g've}@Te(9n%~Z O 9m -뻕ϕ~Y=:&N)V˨=,[d#/s`s1angZee.P!A pmg$y cvwbtXZeC 18H՗GSO%ֳa:WUI:idN`2Xo&'y*S~fHޯ,VrQ84&Giע_]pU7dvlhZ/ ׳"\J'bfVa@;%Bx/Z ȂL^-DP(6ޕ!GmGTcZqOS{ 6k: k-|jW9͒-,T~upuht^Pe-\_S'U t`;51mClhW5 9w/ǵC{zЂm:"bݏo^/.{B@Mhb{$a!MK[p(߂U9LM 3ypJ8gl9wy]76 (<+ɶؠ5:\B;˴`F e'pX&1C#3hthZfkAT 2Ѷ yjbQ"Ml%car|MɎrW.I0,!;jX0NԮ f֦O%T?c㹰 LwsJ#b}TG=W0zI_9'y{ 9//{f* РΖU#s(ҽ٩ .%|nALZг",io$֦P!|Bb? 7 ݬ񄘎F[bHh4ZAN\%8Hu[T~0=+AF+1%!Lڇs ku^hz!xu$pj4R!1:{LsEƙ{9GT;e:Rqp< AE;V=<)Auv-Pa?i#Aܺ ?/98u4q綊6zCɔP|KLz9qL zSmPRԜÌ `˭r,Y4Fϊ감DU_;~fd6iD3 lݶmXq0 L@DT*,e= 3?8=e8 F!8/A4nneyctbV 9K0b dVɍ|O[O3T1#V4Du.'!.3{-lH4u(-e`jM \7c~?s)CЀ$U \{?22'Xr^xCbLEh 1qJ4/zvl~F_mK]5-M1[zu:]o~kC7 }LId\#75yMlaYCbي[ٵWָ 4?nmv4uq+հI7s~0lL y&&JSse)ǗT?@5~ִ&tP*âFtbf8[\9e$[Ek]fÛLmS ]nш5- g6kcQ G0z`TŅG6"NrU8k rߘbjQ-+Y7rq:O=tR"Vڞ$ckcGjd*#?uU=Őh#< jb:!,u@2/8Cqhd4n7I)5̏,5.X3˱%"{l|=rUͽ7e /IѹѬ Ϊ0Z[.64·nV=ÃBk˭܁0taeuO0OA"r/ Bqmcv v#:BVs@hg-:BvYRQ:|\wrk 7K0el>1ː>pYI EʐR}J)x}jOZnmeSec1(ox/])&@v]X,to3Kzú↚&h\#܄彗J5ralp9aGb_`kQ,Rdnh/hb\Q]%*•%1*>7x w1UX\*uI!"Ce IDATNDaL< a-nۖ-߱c![Zނ~|LZƷlb'SRq^&*T:CEDL֖1[I7o: Ξ9e02FW*GC0BBZT3dfe&O2=c;TL'q9=~9e`:9fgZ^F!3 N6[KP}*Lyt2R94+cO55 lK [~dfsXXF4'4̄?J"Ecu32])@*\A-5Ќ F;p.Ŷ= K2u1KnNbs&܉91IFm)uBg jO$_G"7{\ @܈N{ƒ_s΀ծwZ# 4*f|;3qΧ#Xda|-6Sw95Ohk^O=aqv4kI}?wigsЌ·Sv'#_@f ö_ۓvgs>3?.3:O?p3'P]|Mm4IZvJ{O3ǁ S'qɧ|/ۇc?>}Cv+nUVж{=?cU$2:.D\6- ::pjeĒW+ΤmAc8U 8TbސR4Y -w'`hwl w#Ƽ 6>ZZ'sF詧+(#Ǧzn{ G)`J#h3 ӯo6&7By:Rʢ)9bXY]u!Zˁ^? 2n~\.U@*w.onbX8.2ιBln.UV7:I|y1nFha9_.yeA%Cкڭ:ytK5Jg[tӬuf טmFA+[Vt3N/TʳPAr?&)"\9?PyAmS Z9+IaBsgL.(f;זKVWWΒ9)Ĥs[[.bӏ<c//^W?~]9qonܷ"Dj*b)_ƈ-8qqCaEhe0R _xD.c<:$I+03,n)U`6"T.Gpĩxx1!7yK;YaI ff(v٘?N ȒBMSMFiٴ+_ SaA23--6[Sx+#CK셚0dٌtfLpҵL`=ù(8t<^˿ 8՟Kﻅ] 9{}O﵏sݾzI|S^OO<鸓?xGqB,ATG̨p14'=oȶV-]{߽/ۂ+:rW/8=_U;Ly2W_ss}_dKy#]‰}3N;+x,(x%sf:G]q|z;}{֙_'~=#꡿C.{ߛuyzWsȍc__x#s~̔ѠUj`Es|Sd#u{'ǃ0Hu6|ɘGG7z`VĚ̆ieKǑ#0M]G=t7+gUL̵^නw<Ғ @oSE_,)3uk%6rre<Щ!'[9(йRr)2 qJib~2!1>C8 RkQcbVO͉V{ׅ˻MMmW]vJ0?VZ%tՇu TcيȶS5Ӵ8ی v`4x-.: gw ݢ ]|˲BM*O[i\KnU\3lkLt!喻4 "a׮]v1V4Oñ$; N1~ݘ`p}Rirk6TGQ#T0bj 'oBgpI{NPpB$Rd,OtÒLĽL…OG8N?xq,` #N>eݗ [ia(ɼbnf%K4tN]3EIĦ0gwsz?5tʋU9\?y5ZU:~:~~oǃ򭣉3LZ# 8lsBU-A ي@FF( 'G+N=8 q4jv~Je;vn6!;Oxo?/,}.xo>OxGƀ:l]> ^~ֹ;CϻؤLvOn.7"49nv>o?+:w;w2p)v?etC_%C}bG>3={% V+u/zG~V'^Ƽ'?ળoxث?Oqap}[Tq>_ri7>哯;1^{{p~|NݡLeFC`쩳BݔAuPd+hDefvbGު|7p;S='.[컲R Zt}L÷mCwa TF-'flfD6;Z2 &]i{1t]!sL}W)i8DfFT_neeeX ](p>%̝3kTBRL*ÓzSl5Uc/!ơ)ERJc\.c?  se?,A^QO㦰R֪p'0C|’b"`s 2[ xu8z{&o QTֆ?7*(QQ8O&_:~*1GtH.i"C~2MZD1GhQmmIV+kk˥ZQSbb>a,Ī[Xrf6R!Q&;$I܋C(DqTfbA!s@NJo@(o,7#R7Ȯ= HVsڱr4< ^]KZM|d&a <;c2.c. /_:ϖ7!-9' *ϻ/\SNmy͌h\ykt<8TA^&}\!%+ Hq?o*sF [˖62M; ܜIFJU yZ5]~p[}yKʽYrn8+:A{x؝:;Qշ1;^p%~{N=v~`ӥ'}ON>;ؽ#'s˫vŽ;oCXhZ ᧔孠y+ayx^ϝyyNر~@s_|_}_|zKxb:OzX:u_}ϟڟ}0zx!Kye| tiwg8?|)0w{\>{O7<|_n>;+w9kW{ow xLJOp׾uU4Wo>K.8]ou~B&VAk/k UUo,lڃa'Ȕd.JYمg57CŎG }IKd3<‚ ;|hd[zNى寥{rN|EqVFs!"7۸n>j*r`79/esLwqN-".Kҕ˶B^",""%0 {kdAt^G^Ioщ!Oz]%ficbaQ8ĥqȿb!40k)7/absqy(o"Ř3C{a`m2Qc(!t[ްAcr!%*K) Ð(Kx6󾐉S1E(lI B_CXF1рaYt.ՃuoKC=#me7yB)>$.XЉhaHYBU|$]"((&S?B!62d n CL1jRѡp!kt!,:}.NtG/YA%&(+*%ʑ J]6ZCSUSfG7YL *[`:a8XDJ7xͣkA RF{>>/^y/?ί\s/z_>I~x)ZCw1/=ay:!k/bo]WHVuʯ<*}-aXEU4M,_i1k@kjg.]uߊ] )n&#gة:1wU{=LavUR M-MUb;q;Mg֐[@Z5<1p@]K1 CW;/G&d s~DbL}3sЩs@KL}k4 Dq}@W"HI(Z\Vs&' >$:8 `5k*O5>s&#&B̆P^jnOQ]y)%6s68 -:D\.qW6f~;lGҴMbrS` GjcaV#eƦ'ϜuM8"H8ZxV`(ET-f.k )"GW +<V3R6 ( D)kVˉ_%Gi83AR 1YS[/t޻aR~-K_;N}g,t)0TtKZ5;B;lvQT0[_&/Z@dxll!`D<} !V!g. Zk&oyY|˶so!3e4Et-|JrF-({I~NʞS7l&20tE6*G熇ܐj&V]#̸2Ggԍ眩,0bWo /?}sww-U29`_=^yo?^n}ߝJu ,BH;/ __AqWY4Rsqsxr)u7SF  y'I'vy 4K*Ws.et~|܂ӛ\ܯwvV6lM;)uRzSc?po=|7^}«{"|8xv^/3m쀝L __=:E/=?呝t`6q5wGIGʴUfYn|1CF$tLKݗhgOH4,l>LSW *Gms߻ se2橦C*#".oƸ:%ƕ+[Wvx `q D;/8]\n~z'aKw^{ˎsyN?vMȤ ey_v8MPC[P0VF+o"U:\AMm2mSqZ./+{l:B*..ƾ~. 1A=.Q F%G%*Uw$F,Vk]%"W0 "Ry|}9 YNsY[mx ekk%hGq8[b uJN4w ysǿ}>~2G>x˞zn?u VeF`g<pÇ=Gvޤ" lucUw/G;X?8'8Oyow?#%:!ExD?\q|mK-ȱ!~q'm.iލL=5O<'C~p;FƩxaҩ!*+Bgkdmk N;b5ɫ(Ĥ_7_M32l9g%J^3>b"왱ݴShu+S*{ZՋ P.NЅe#Z5Xx)~ٯ-R"WLbb*3fr)h)$ʮQj4ɮʰR1 Qj\$^T ʼn(&Qr<0?M6N`*!^J{syBB..]NVf2>xT&:dr1WőxA{By$3[ޅEN0b5 C\puueu*8];ZBj\ 29(i\UDdj5" Er+Psy0 XxKJYo(4#x59Yf2Y9\r/rKPY[[ڵkm6F31M~ϔ՜(eKujuNz)OFLE%Qܯ4 4Ŵ[t{@œ, O! M9{5}<(auBmI·RJi(%mcJgˣBmƱCg7k,:|dh첌271֙YJVјC,hl`JD M(h܆:i@4 =بhQ}#F[X8C?8DI  BhSHo㖜!`ֆL)҃WEWfqw(,yIG[%l 75w:Db0dƏMNȾnts Dn~-W~㮧]%֞p^{ϿO?hs_w˕}ͯ_>/9D06pah׾oLw7??|w{e|;Mb@ٹ }Dv;1EC@deB rYVj?gV5iMah8D^.b7)NQָ.hSJǪ ѩS@)c >8ib̄joU,r '6nX^chhIT`Q'хDLҁ CYK15y]$;378čڕ OM`R"kBێ{!fWiШp T^ؚѵʺ gI qH$Sfv-[ /1F n$cH Oʛ '+du+&B1Oٟ/Z<ƗN3DK0UΈ̆,@A`<)|:'k6&a}0 By$Ad<*Gm۶˾zD)(H!.:g;] K! ՟]|"DιlgBQ'bAHx@*!1a;g MZe"q҇ЅXc wq!.& J Φ1r1 |DI|Ȝ]9DE ĭ^b1{ ` Ջ tպi51&{SmyMB=&9-{#–T[`༫c6Ϣօ=?4:u%eFbFXdr>nXېKZY3z`;HchjG1@ `#/6k2!ac*%\3ֽ{xR|#mݶRo5=!xHHP?l[Bs!q PRՇRsD}RK.n#jOW& Ӧ+ e+,&GqZ¶PAGPPZ,.믾1%ox6NNZ,ib叵b)eC_]YB@% x|L̓2diʊ;z-p#sbI2J)80f 쎭EBQ)]hQDiF WƬ " Z^pu3gΦ[^ X-Uv葏w}?+0PfK $f֬M}Ƃ>wDld.7{)I-[z箻iFN#ӟFV!ip8DC cy s H;A}RJ̘ ,S7 vN+yu g ml%Xl 5yQ%y OQ Yj2u[1mx&*F,lg &b3H/RI]bIG>P:BGY# N(e:4P㉆~4@#7MԤ!z @d =hzd.Jk=zO-Zw!0aː=|xH4#{$hFQ:.lq{A b^ Wkf:_z0nb3HUh=J+nOt''x"T̊%Gy#uNؒ$e1eɭ)QƵ++snݺu]va` !taM"DPqoy CJe.Ix8a`\%-tGHI][C9fԡh'nhO$+nS?30f3\pX #gB3LԌ`61lB[? a#v9[kܗ94\%ŵ_oXz6MMhZtHpI)Z0*K@Ȕzh:/,tq yV:xHO9J46Y!.bee<7 eIaa͕O[b`q@&n}]yL/$[[/KL}A:$|9S˱(oś37#0tGtqm<ƛ 1t++g2)Ka}Ma>mV5p«R +!\O)CDeG&ZF`VJ9J@))\5榓QM2 6堬r<*FPITuOXٟXstBK%Ёeg8&VSZk:MPCךRj3mͭ456=hJS=uC/^X LQ *lv՜( eVOuBy֨@֍P:gkˠ>1#VDVYU6n1`bRx^3ۡĝ+N`1Ęs~aVP՘D3(5\tn' ̖3&;űL4 q6ZQ_{KUj+KBi9JiCeW~W@R+NC -ռ +XsfHZ5s {>h>\һNT(HΡeKS+0cͧa  ql2H[As 9Z˒)sZ\VN4hSedIwr~y*bf~ 5s~Pʠ 9"cIU[ffZ[_YY'_CI85͒wJ$G$XAĜw]yY~s.t 'MlQ|u%#bYk8+{NLb4 Id$"Y#BlF7{&3-qblzRb.[tλ@hC ]p'=Ŝ s:Ab,b(Dfbʝ,gKXСsb^ʯ IDAT6$y~Z(ȍ Gu_y.p!$MPVdæzr" :q)iD˶/̥&L*Or X 8=%`ne, ֌N4@Hj}I~w\ʴF-5Y3F-)Z{e e`jm'WԽa-J!vU罺8BHɑapL1(o"6(18"zC]^te(̄΅.h#EC9‹w 3ӾلrދУAo)ƁyE'LEbB'7?Z1457% q-/M5|8KXg^(Ү袽CI|q47ZeTr$G2Q" z#rQi0DR"fq/DzDw+ diͭ'MzJAkL f\}$8킛Na$n~6$D)yW-};R "V=E]m &LvjvBbOIJPw04+&ZyXCHŖOw)SLz:CmwU'P# 58q&REA-jXdS1( 4IhTKk7pu5hF,]u;nĝ OkVDwP!G$4EH:µ9tОu KEz6|.&ߌƅy ) [ zC}wyn _0\D_^m):sC3<&U+9CD J-c㸞+]#xL:TY4"c,_0 44ds*a\< 0 ҃}',LN>繎miayL8g&ly(S"Gī~k_><^b A"9Y0 MVC8a +uhlcވ zABLC15?g'% $p ' D A‰"g5%i:P/P 9u:(*[)O5|McAe U Sp(rs<}wB^P$hTL,rQB,ˌbHD E2+}P*BiZ]%@ l'hI5>p3O1t`'-h"FsWCR3% 9c sGcofGZt3j^AN!/l lPLˬLc:Gwh8DnZѤ]~E;*$D !iIҘ=q(u} >3-Н/u$i"ze*F. 18czP~-]+,2CCqP\%q_q&Tr>#JOjB|,r-`mUEڬ;Z!(*Nߌow ow>҈Be;8 ї9u rQF0뺢O!gzw-EPe1?O%|jp#UY(ef?y4aFH 4n=f6= w1Ÿ[wݺs-W0Lv+.^‘˚Y3K* x]\We2cY& 1`Bbt6q&‘tFB~jM8'CX%$vvNNNnNTqq&NAaPjDzv4&"\hS?rױ윜hq$0 s=A\O'M4Ms׎ٶxBkl8w̥6ܰF6al>Fc^(V\3x]De+Ii.+-3>O"Y`_21&,ɵ)BA,Rꓨ u]G2q8]! Ô.C0/'7qͥqG,m:*>8"Ƀ6-QcD|S(cHNf?j+wasQX5dC p ȁ /,aO0C7+uc T>R@H ZK{ɷoi𖁨8GN`YB=QJ #pzɹv ]|syۧ_Ύfka@!5`߅W/?T &<+y G33s^zdĄ>}wK.X#!T-c}ԺlDtMSZ~2=}yzWl8dS I~\l/۰aن 7.%"$`ڝ2DLit$>VUbyc;q1"@.lyeѦ/ڥִO,+OF(j*OtPEy^n٢qw`eYeR@Aov[}ST3U  ,'cv]?ڒIn[8|R0A:& %:1ޫ˶s[9|+@}wI G)I59~[q"' <($x;՛ Fc\(O)t8K3s0HO ?SR8safBB͂iA0G}SlˊX%kײL2LS9Du]vh̎Ŝ-uCbL43^"%4XNy|gq9#7] B<U )qj"_R" I @JbL=xhZ䁁_f G>oA#R,+^s6Hѵy2@Iך) IޙSe>s˕btO .}GX]='c%|V[Z~SFS|{ώxs,snK*MQ/w#ռOիzƸ/(SIւoK$q<ƧFl,ؙhJ4{{SUt'y{{G+UtW 4T2 Bng^ZfW:q{pUp7G0 ^y#"TEΟGLWo~x٥c,\}3]A__Ϗ@qBP1)I B#2MQ2 %@וbP&[p/`"Z1hVz`n& ~p;ޯ .\|)VpsU Fy._·a r+w\ gODɦ9Pp=3Ncql8Rb'_GAMDߋF\Oe5šH ံm〔"ǻ8%\Ok`k1 eHvӬXOYS#"`sU ˚_pdSqVj=#ƨBt/`[$^  +H8>9sqoZm7&y,^_enHG; }_V^F5!QJ,.0QaP}GXt|_kj TzՋ}g?^p׷ J+聏,[p/t*oG1ַ|+VNw W-=]]/hs.;qC3‡$t6aM;w-`=coT2X,{f-{F䅛m8サHBB2!ǪM2foWʵ)؅#۳{ߞ=q$lkNJ[WM3lղm[ȲJQԤNx1i;w_9glL!1FXe&v^v?ye1'nPjZX"O ph.+4z⪌k~ʽ0 !M4ԹXry?YR+VMj6hŦ-OR6qDX#cgZbLs*[,2MZv~}-: y\J?_|ݺY#Q k{{mÚ[@OOM_jbfZ~EnRj$Uh;+VmH_Q֔ -jڍVN{gO̿K"d!]au~zWBsF./XcšyOdrV_4O uڴcJXt#޽uGS;=ϋ4j7lع}gSVٮ~=o[vZ|i뷬Y݀֩9m*9"'n\ QͪEN|_rPB'sJB%;rnigsOi?qLts\)k;B-eb!tǔ]|ƅA̐ñP~yJ _SF Pg6 D])âjg#FD)PUq )] H6V~0_>rP8_1u"=ɴ!BU0ZeT n8Xx~o0wB׽R7Q\8٭/ D1(+B5ocM`U285b|tW"VЃj\|^D9/cc"R4CBJ2,]i!cH߫Gɍa24\]3Xa.V 2뜄 YȫtY?RQ)|MG}٪L(KRƧPζe(r.@nw0޵}KP?e9 /xTvmǣ !l2t IDATIƳQח+W/aܓhE 7Mߚ/R+`hfif&)Mz31b#I -;ck9}~T+ȱqdS ;[t{6w,Y[%;U|ۏ=1Wgj]$Noy뵉Cux9++IXXE^jH zģJP>VR3ݮM|7ʔ,^]?USÌwz6okۇ$_:V41t/͖Hw¦}[wmLBz=z?5=@E χ>[/^k2m@lwKo8zǿe[v5l/S0}a⃽ LFjpi" {.ctj+9I.OU8楺)C#Gڶwnu47#y{Y+YD\[٭U}FdU$,Ab}ֱ](g!RJ 5 ӧnx." H Kzr}[!I#*C>` ]('ގz=ZaWx8NÄZ|‛vD]2V0Pt*/vi1{Cm!PquR-soK1>lwA}{9r,f6A$(9 >æq8"-igOyccVJ!,#ڟnwu}_C|cL߻e{^} SCtӤdٛ_hլiVM]ɉF 3KUi[=1ȨZmy̎DJ3y4%)?T^Wyo4)Lwy5սoy!/Sjtov@ Śv}m(d/{~?=aޚF/y[wө_j;DD ê(;-'4x B TZc&! &$$tta@7OsNŇWw\q\u=ߦ$%J2l_9+<@©0)=uEbZ r;-dkecD :R+/U]fPP 1B|\ˆ⼟- !XQ BJ(%(;2UJ( \z7<[@ nuKLU+` PB}h~H@{8an4~P5jAELHj뗷恮r(@7~kubp8bDG1E:eZIߚ+،-8h! Ǣ;HѕEFpffkC<8IE'5+)֤G]K6o^rvfŀ1̌Fl5 ?|G%aܳ]QpdW?ܒk4zӇZ*!\gq`VlEm\>~=KoN=WqJzԛVڞ]0@7*ᥓPW -:|mWʖѯO4~d%߼#\b@R A[4mZ5(驰4d9hoE_9eIi 5k[Ofѳ;Vmʻ|JzCsaշCߙq#Fݫ! \ `_;~5sf۲Mʒ 3rY9j `"$Tg-y"CD̢/?#>3G*XiR$Xsmr"C`DR19.c䆊-l3']7-wX3c熳JDG3~w>sj߲Nhج),O%Q{Bw5M0}o^#gNYة>_Z੓~?~OBfMO 5*ty>pѲ靖@׫)_Ƌ."dQr b싅N^7q+{*Znhrw7nOuyq['~mGΜسDZSGr\. ͊b< VCvhZcΙ.nҫi1=l?u}|RjZ"̙|:svya{?^TֹC=MN,^|Ɂ_,:լ8QDc~FzA~_mcy'_15֪yP# 5cH4WDĪ,*%DEwBv/&2>~{OX!ԿAUέ8 %NW/ l`2.q@"L4LjQtQI^9"Tzq *.JA8aqh^61ZK@` é~J2yp39--`+$8pR8 vrN\\7 s Wcg瞏$U% ” 1n&do>sYs j5YȴTùt| 8]Hr衽\ @sL4zBN̚|RN)n*O_u^΁]g0哗=DαA^2G? 9`,c yS'ݹ#)X,Z6k⸇͟ڐTv|,bf?3fέ~mݩk3(`Ym:ecsiY-E.$ (n`OgO󫹎 ><N(5MSrRʖO8xȊ;?lP0.he@q;(c$' FJWoNi=sQ^Rr 71Ns=oZɼ.Yd1.eԠUves_:9V(gu]] 49K%֓#Д: r_Z7^gi2 \u\ιL+UY8nBqCv[vQc1DkCP$]8jAZl1&`8$pů~#{zT^׆>|{MBMt\UO]=x{A-X/sea=r9p{BS >T߫fȮkBs+bWm9;Y6"5{Hisc _!-r1̌"ppeV7R VIJmuu+rbx9wsmʅjДJuSl YoX%xBs018Xǒ"bT)Ax25 !6VJS$iS+ԩHy>aӠf4v_ۡNjplz?E06 ]ث߽Atͳy_Ru$ymo)nqCM֝yF?izA^IA8yHɸiݓoBuu 2P/Iu\k1i\r]-Bƌ Kxp&T*EU$eAj0^R7ϭ@.Ow«iz}u|W pq @n*({#(9aYI1 <W:RMU5kq*U1?˿e7ׁ' ;a\ʺA׿HGB9TA8v Hԯ`ɁY^ٲGD{ħ -T&>鉘\ r%/N`#]WU Y!mӣxw,MˡS# ܟ@8/N kRD*& ZXxC:%N|5MUBn32d]jZ9xWOѥu@#K.|@B5pp3nj>8"$j$wtx;~ lMSBޕݳ>ߵA^HA}PGCRqoݺA0ޕɊ)j/U52}mzph:w9 Gt_xYcY vl'/qߌ[4`Y 95hK ׏k<Wr` cgp󜂡w  rdzeg .j ;y:~'+ hm_e/MOi07;z' !D"yvE˦繞epg;淞j_0 5<;f;+p[i7/vS>U0fiYR"@ U DZ&Ԉ /3];w G.xoV\N(^]c^,P=ԓ+q.N ~~xͱ2FBP"3aRB'R|Xt(8Ȑ<<˕:!0?q(!;[LEj&rG-3ӶU8A.QUg nCT@}+ ԍ| L Dy(SAKAwO )<e!%RJk?"BH|M!gq"B9Qs-}pƹyy@ à!{ 8 r؎y"T//N"L 30x8%=9ʏ %Z:wC)LLfEn)g"=4N^䵫sjR wǃD.Ց ʜ-4D]A武򐰻uheG5ؾ3oUa[:^ o˖ٓڮcՈY'kfk'^bIj >E}Ps,M(}7N31^9v*$I{j;יQOX^~DJN#O_v;pc.%N[tcw!?Sl^ցS^Dԯޭs*JIAR6< y)76JW/taw5*[JH P ?,qc),/ibKKK-dTA^Dj+g.)fvn 0-Bjc:ф%K6/MݘT~GYGPӰ"iҒ5Sҩ8MW:=ak. ~0sc6bڹ?3suiEar3єvymsNK-9,|RhB%K2Qh՘8+3]=\R%)8M9Ug->q*ZR2 &Tj>x6 # pĤ0iRi*w Gt/f778ϩѾi'kW-lPDBRIO !i~9k1Θ ι=G -k1qDqKjDJR78'V$B^@:uS͘efJZNN 0B w4i`&T>~U}XluݲClVZ2j y_+oxajb"ɜq/ 7d&&F IU7Д2n*mBTq` '[>k[6g_Nb@xPHU6Ik3/k]E;ۻo{sxXty>BᆍXG凑V\8ruJG/qn^ dpN)Le %5(Y|"y_蟻8VKpmc\$ ȹ[3뺞wE6*Iv,l;#NfՓbBRRrraxAt>AS u=4!!XJ'v̓Ixq<&m۶cBRtb.3,PQ7IHY€vLR?}*ڰGkۛ~LGj!r`Ӆm;ݖE:tnW=_:<^W3[rEe%DưZ%E8-)纎$`F%X>{ #fHb+ IDAT&hY&o"RٓPUɥ#2I`}ˮRrp)ձa ]pr.+a1P(?VQOSjh.VQuRLșthlQPC,ߗ'LJ }oc x1:\=$!'Fkڈ{W+3yNxX};~ W8+zy&'i^bʰ(=D2MPa낊HB! ~8psj4-*So!'NPbJmͱK:rDEc  5AD)JF3]x3m&Ptd\ 9wlqEx=w/|cjESoZݺuԥC_ҩuUW?w%v,U wC w?E 5zGOٴlɆˇVr')f#?X|)'SxM7VR"")zlۤAFysd.:b?nNg- fCh!gj6(n-::Ϙ$ӯY֖5gnm`7)[̓ۥfnp}9'Jy*7gHq(A!aw9r[2"e`>.u"yaPV+^ b-NѺኵziXNA#sqB._ΑmKk_- -Swkhj,R,}Yϧ<^V5o*lzෞ~k:}#6X?) WQM5L"sqAbԺVG^xkjeԺK—3y);5d-Mm i:׬TtL:{U5̜3:s\1cgO;XWm]hc9CjeJCXH;sEހg)Wf瞫]~۲,t/;U5+!iRY\9|[ޘfzWO΅j6JNJr\܀uʖA vfABbOq/=+ӪI)0LRV ELT6<.t5U!!>2}rOzs5h5!>+ӪQICb/+y'+q[VJw-JtݪZZjbR0(K3T˜s渞'< r(cW*equaź=}sҹ~YS~Uѯհrr7o7Ee;n,[գ/O:{$ztŴ&Mm=I(BWY`͠^馶OrgλufezTMoO5H a2 ь)v}r˝T,YjJYm}+T3yaD" 씽'2L_=Ivl]hRBB :w3 {sE\T"9bvމizZ,ru:+sK2!]-츼lUpHj / sd1_I?ڭ {*TkءЏo`tjկڑ()6##%ZN(%ˉSĨyLФm #Tx Obv4ߩ{p^4d XT)e"SDfiBG4jWx;iܣ%G\xZ1uM}*}' 7~F73c?׻M& >1 ]~õ%V"o4nwnNu{8_9FL9(E{Z7f,֏)h@syI󎹾H[ްg,h;ǗF%}~/; SKgglD \]Z;cϬʌI iR-:9>oӟ.E&bbKQ|;?W??nfæly`/s;=wu^$\8yp=CHsd=?řX[sMA`.lI=~+}d!BOo[S 4ìPjKm6{|#|`C8b1/~csM+ Ǘ}2لÜӶ=HHǬc'1 {޿Y^&N) ǖÈg 2k }#ſp?'=1^ziEM;s/6YIyFp3׽~ S&hd9o==ts Ďw|4aw=[G΁]4}ݺ9@Ĕk0Wcljp{[x(pbpL)B!O ><9:kյ#`ԛ3ּzIy ?Z;`;|;nΞycwusv'rӋOVKv p"gI@ޑ'ᖬQrwwGrqyG B0䷑*~jp~-gyuR c̷ rBBB̶cv 8W" ~8=1%($j`2[s`ǃ3O:  \fu/=#QdA 8 Fbe!z !LQRG@Sd ڬ8_pT@R }=E/ P˜C9?=CjCW e>yois98y~S= DG(%a x*"sPP/Bv̶]ܲ,4=O. ?xI7sz0 CJnQݺT% I6=+g@XE}Н $46S\{ZS@ٸ""COEF$n*T!"G 8isB=U+︟$Ԡ´&ae ҐRIG@6H'P6JPMId* \\l&Tx#Tha 0εU\]rg2BBIVT?`q4AV׺(q/TjADJ7gAJ_HґChGg L,A#1xcF(@}xW ̼ ?3ɥa D:Tf!0#eY99wg \'}u]D4 RNnTY1A *7u=;9_{slU(@_ rj\|+ J*CxJ?Vs:8r%'R$GJJ<;=TTPD&TED  $! !S={UQêϹ&_cvn{>kUl'5%HJt0(twsJ7䅓@&y0]Hxmb2nRrE8}=Q)atA\UxZAbܔm.q?ZÇ4-Pb{!K#TUmОڐHZD &%Sr@ K%7sWO\ۂcR^ݰ8wpyD+I eze'dL ])% & Öe$p3%(A-#gxL)M6lٳjBsAݭ3GfKb J9oQdB݂DHI*l"9}ATVU*=zU]RLf¨\\$6s%Dtb\%W#&fOrĨ27I &"ۦJČL%;WZ$fLn0M:xtS>'?u9 O7ƀgϦLܰ3,ŀpksw?|?_ᣨgw%?]IG!-{$o,Zޢ-gz9o_}oدv|Lc2՚sW _y^V0s C 2xEQKՙ5%LI w (KBdo{RNN8m;W]otŊBID&hw/F%":/+"ݤʤz%@= c&u`{󘶅]. Cp[y 䐀j(]JVP,uPJBHQJ"W!yJ fnq5-1('O~\6>4;.SKO<}ޣ[b#f Tm+Q@Di+]H@K:r^89t"VWNjGεk7@-F* K}vʇuO/{G֖-vы qpp?p%APhbZ 1Z)VCD!ƄjD4 31/:r ]ߎ}I vAtE'3Jpkp/508QQy.Dד!M!/*X$Usuگ8[>LUT=ᐲ4"Wӳ57xPKb[5 ) gnay=Jҏ;CDT*%[jZ&m*,ryȘ@0axzoaO!SS/~ϋs'b)rzn=odxOꟹw~s#M7WO`== E`n;;;4O*9q0\2bNY]N%81.Mv> U}$ŞSrտ<^ &X7qk%+H "|j@S!iQrK~| s,]!PwR:C@b8.qΔq"RfkȎ+73cZ%F5G Wl !R.UbFo^\Ruڌ~ ?ZyVΐT55M 5l *A| &M-TwVK"YQ݅nd)a7 CR$RRΫ yjٗa i 懜 8a(Eh/> 2Y M}REEk^} EpCJe.DկCy[e W(cۭ 6,d'j6! IDATprcP,)r0'y6+1k)̅RJdz3O$ |ڀ]/D_pGGf1:Jc%A#%U{aĒ&j(z|dOEoIo]6{u m/p'|,4UBMBA}Jp;m1$޼ywakz. DF^Y#G6Ð!` t]Bq`HdD6G(+3LR2d\{k]N]rX7[y ”js\b5$rWteCպ5\ PbIC2Z95Omzᅞ0̲xH Q'j$!n}&*'64̅6Z7 8R I.:J)9Y%F(B($lS#8$$íyB0 b"HJ]: 3e b6b{4M}\{$7.8Nh=kUTF%{DO0yV{J4hz(!ne‡&mxRڃ ]SW j#qx;7Ox?&iqqփ9( 4ֿxh_ԥØ-Tc֊D C2; lMi Dagg'y*&9YD^ 8*刔FHu jS)2pq*LrV1#Et&v.EaV :"SMa=X ,@l_@k`mۂh F_ӄq5Qb*Iy"x>4aU]+ey]k%BD ,BJzsU(P}%.H%6mZF\.b郛"-L8Ɖ,JJ FN>_ULĜ1{Igla %lبP#ԘMRSs"9 lhWۓ͉KAS{kj`TWh!qT#/zIPJ8 >:iϹ'T禃kϳt]ZB+m--IB/Varf, 0n 9#z”)qf32y=<p lp/M 3&y:V2T yQ-P%-pڄ8ΰqK]OCVR<]Gu秼rtb ;s^Ϟ # PQ|5!zrj-1 PXaCtyOJ2?@H$HQ 4؁NDRR k1Aş*3ךҠS+ZlDINk-GyVHG ~CZ(J[㵷t HLVvEN̯q&xv7s@XTe'Gopea^!_Na%G6J] ԲDpߩ>&hؑ3]{ex%M,Z)Bp5vdgǹ5W=0juair`jSF(l\M&6N5ncod鎛Quf"CW+²"R1$|9#R\2E8)㐇G;,0Z1չ,fY`H/bTdVˮ-ǫ i"AT3WJFVŪ,Oq@17ݭuYD$A,R21LWP!HLzo DlpG>w}X}L8yq댈iaȐP@sJ;ZJӐX̥y%|EJtt7ѭY%2*ǼfY#ADnĠX CQKQW2[6-cFIG qC>s Δє8`BZ0zf5K-(U8@ySJWKedJ.dswC Lx\Xcܒ(?lt\5.: h_bߜ.Z V:TzU6.%Uڵb9w0Kjf?Ȇ>#!, IG h\HϼquHO2]4ۇ mӢΡp9l(5dѶmԨbh]=nsCbDHv @Yۍih}7s`JY:<Z<0I,3F+\N9ag3T%b]4ljb(Q|L@ P%7!3Ͱ1mH-5J(0p@yYZعˋM`VNk9)\)c!p)Ogzݡ!ƅgw[ZjJ)\% 0 f }uXPluF OokܒkA47mY&C-+6sԬ0]u|$*Z4{"s;ۺ/G4Œ!?r\>0!)f? C2[L|BBNxj߈[ M vT3ojp"ِ ۥsHp8jހibq;DF&("ƐnM##_̥Y < AI0"%\1Va.)Υ7!踴=Ⱥ|ah4xbBu*ZLI5[, 4O<cQ-eZؽ'4{v*l)"Zf p b݃@̘ ݽlBz״w__M55/:3SVw{{{|}`\7]>|胿ǪԱ(ݠοi:|ЕW:T{d GGcǟ)p'ዧ2]x+| N{MEj@Kѭ-E_~}g}[^;7'E@}7F.MQRl8?X0 ӼebX^{SG{q2/a0JiZ' #jyq) 2<ϳj}!gwq.4Mb!T湈֛MrN3sJ9y+"yH+Q\])<:muQ)e^ϵ_~-rF7`C=uz bu$MM}G.,Vf!Ԩ=; V/~ת`-܈~)W>>&D%Y 94޸eAXF*$6>yȃԈ{Sy0 "+Y BH:|j=xpwwWʍ-pwmnos4Uy(CNJWV8f?8Dd4gaYV&-#i13ȼ )%U%IR :=(elKMImϊU*3YVyVlUPP);qjJt4S!rB@M)ɳJL̥*o`Ee'g0BR-WDcn% gwx/ϮwMo/zy{ 't[A??Y_|w<嬗w۞p?z ,C|s'?wewEZ[n}> ??ppmܷ>畖!Yo(Ɓ `DzG'ѿ?z\H??ij_t|%~gMYbJV $V@vݘ2Smoz,*{N8]8A$ٽ{B3ŴP3Un.VթT.Rg|{L(QUsE ֆQ8"܅]1r,_-?6bO1JR:9.wBИEc|Clee ml R|\A1vb64)p6eˠR'I*23r̖aDH{^KQlX[Z/{<ɹg}'THmDzp94C8liMb*3OgaTD&98J`rAOlB$4i$("&z!y@|Ao uk\7ƶy%R>,0Ð GZZƓRm<["C秦'%K?whŦi,x-$R0 Z*z.sɢrW]53ņ -dU_ ?)QV9CSW\Iy*qtʒo9Y$.whvT+ d& t&2Ex]R/#,cop|3~'g>Vw|LS$Oww˷|p{ yҗ?8o}g}*sx"0|5{8x+?iwG6JLˇ! GLJ@yJ)"]SLiT2znqE2,Jhfs區M :>]HaYWt}C(1σnYy湘?H2#Β;-c7q2搴Ykq@ynxjV^%- R 7l[i{98Yʮi: *or$M9䂓"'f[L(nT C g)jEb L51{x r+[Ɲ;Mbΐc1v, \AyR8˞l|J5w?Lm RV7JNrN*%G7[ܲ2CE>,O&aqqXj%ʬ*b?9XѽQaMq ^?w|?ݴ '+. nG? ꕟ|[?t+~f oJs2~LE!L'>|<>~oίe}=o}o;EHݎ U:q86dž^nȰ&L"҄؁~|Ο}qK0%.}ϾZ~?iwijN]q)wlrY0ᐒO7dO~d-N.ԥM;;Ty8W?}aO}ů|Gwag]~w[*i¥_mAu|%>N9%F60oѢ9'zߒmXRB豕m3է%2%9 0'rDZ X$ońfA)^Hޗ,۵pasɲ%G.o 1Q-"7}uƲʁ+,f"|Mq+H$AUtV)7$x0r2ZZ EVQp1lh8N4lX4!ڙ-RP.‹Б_k-BVzYZ'2I㘇 F;K!lk)DR&G_($UV#-X!k'6ŇCW8Sb"Vvq?5vB(AK EL: G<R]?~}H%pՈ %}0EG) 7}Y*"D\d 8CY]o x,bL̰fq5U1lkqy IDATlE]~>Py2ϕhXJWsO@6ǻZуlQWRSIvp-b-[G< 1V)̱^&/ +W!xw#܇7aǗX4lXf6&[Jյ&#AWv&V*<aÇ42޿|"aX80H^}yf(7XrH}^nl8 C%K_sloSA֚c# &׺$ qwY+nB)]:[ɖS2XY@yKSmV,!Bh!cݯG8ܺ`4HmZlv.]'"8`\,ϝ{xl+!mDb ^{>{3o?sޘȽ˯,~{ADH6 =qt^ï;c:F7<p |\p o|l @iF{b.,~l4 `m5R0qD x>_*v?~k!=׻'/2E}PxP$JSJ(*.'^O~{Nz۟r+ZvoG 3@FĴsS_{?/g>^KQf7Dz˞VM741hAY*D" O dc( rwi,E!Iܾ&1$&"o[2m+ga`HW2q$cȘgZeMB\-8ZuHmO6E 6~hJ.1$r&7}rOa>h&܅®2S0}c^)]mA 6oi0NUZz2%f+lig9nk3U"ޭ&J6-A. FbffˊצU\acQYd 1KB)^wRka"Sԅ&Z nAN  X̚aE)'{4Mʌ8PK[y8IMF[M%vuJN !))AMi_~@H>&T \&ypC;:{7<1Ǟ~?~مI篺M˿zK|k|傂8!E4 _(x~\V #:+̌N?lwӢɍ-v3?ЍΕt]X_H[>Szuh'n+`oy(~HӶɼ8`Z@G)qe`J0Llo2q&- e Tg-i*򲰥'Wr4\QG0lm>-tEw˄_wIa{ﰫD|ގ%1"0R0!5Lkv$9dSQTlvPxZ7KKJNY_=".aa0$LZ+0IUSLNHySƖ[!񜶵& ?'bʌD/8 VHI_GM@ŏPr4J5vjI z E\UHn>bs.W|_3ݭʯs˨y?.OoXˀ7yK?㪋.=F)M.m<^(#fXbt.#s7.sxejU&$ Z`f`NV΁ q|2J0 ctt@ʔ`7 8`j]e~s' RJ%K $APC%hs$M.\:uUbH!cR gaWJ~qhl?#Z,UR+kmƼG4(]r.Zs0h)m< -a0.^+&{o#76x$ϙ[{SĆ=az^O2iZXBLjB'}C#d7['zGHŜptζ`<[A0=nYwd`Z8Vqd'2l!ȻJ)\ 唥JѾ~uH䦩; V؋aOfD,1 ]I< Y[ФCǔ[ :Ztcnv?H,t=GiZ Qgy%GVbMc>=J6L9_wTmZ\(H ">xxI? D|rYbo%&5B䰉Ip=%EF3 oxf sg YJChqXF"UDh)L9'LiMVs`BbBL,PgG4&llY yKgk \R-\[#uβ+U =I`)ըv%Ϲe)ウ@ },d~B4yTo\'O:ˠ[kI PuUҺ`{EP|x4to|闯s .zٳ:KoxcoqSwygăcn?y|\η;m>O{ͧ|>2C͝= z-w]~˾x> O8 |K3p?̥/z ܜJ8)`KKhY%d`kUūu.K8#LcշQn)6UFLXI> Dn&v;8iOjqYƅݞA|؟FklB4Im![&Q! 1[/HL-/dy~v[FLNB6 ku~B ,qwV S)egRUSEQ-sI2x*y]v+6mWj+b|EGy%܅Ъ-{+5r{EpǺʕrL0ˣfɗRuL  `6ȏmP9%B؞@g),H;UiR {j}5%@h#f6ߺنH}k; tKbC2?8noz[M]V:fn:˾"3cХ15&`aUSfƧVSi~S=!0 )ebҰ6kfhnbV|F&ƇCm ҁ}y_9?:}K>'L/'_yȷ_k맞 9%yɓ[L6O /u5o @eo;G[Oz].:댳/>?S79&Wy닞c {X̌JʗZIU|ڤǵU}zg_c'ϽڬH.K3Сr}va; 0-q̵Rfz>04 C,i^T*`Ȳ^D F͘M9$T=5Jz$rEčD9>r`Ĵ5@m>1 >\j:/P^/Y&<=)&K`{jg\OiZnÇ$zKԖb9#LjeZK]OÐqDT9z{|Xdpj-UVLu x ^ёE-|Hލq!1bC7xGQ`1 ~?յ'ɲȃbfp-ԊIVe0Z!֮v"_:+V"+btSN(as4<C8o(:^`xYۘ)a 3$CuiSC4D lNL@޲HsdJU+%6ڑ,EҊ H!d.g!nŰUbZHK R4cCIUʚ{t6[jF+R I)+dìv m*p-S)!gsgga)GYВ,iP0j썰_,J$ey1Zc.ëo~g>z/5rUU"?@IdB$ 51k pEs@uZ+Qofl5ozѩsړrBPʴl24ɐ=r8ݫvw#r 4;^t'Jx l4IUFVW&ZN3uyԛ!\n-q81gbXO9Ƙ,&6JOؼKvdyIgz%l+3ҹP,; Et @ `0 \)otB=HKCRj{@0(A [1 ːsֱDQ@Ʌ+1yj3${h[}Q'6<0JC.a̞p#)a޺R̸H0)$'blXD,BfzvTrv0;a)XDMQcNk64Dַgqfv}Qoq l IDAT@Vf y?.j}lf}fO#bK!lr(j4-XP c:Ri#Lh(VhCI@$ۖ.k_0$Q7A*N ]d=qzst.e 6&\H~4}Sa#E4盳d3j-6̡R`hG" qD2ͥF\F>(0Q3,. )*ݒ=p3׳kfxm}=/ deoO(Q5]*|0XM(YHMX'J]Pm.m}gFDFݝDK)Ç!V;뽽zR@FICǀry@ʁ#-#AM#KdN#btKX _R>*|llpFUTV: HLs阸Kn?7/xPe{'&a"JwERwvcerfs 8>6bMzX۵HNjw1"ioCtbmȼ*M׷"]C6O%)L*$6[eѢM.s kovV\qB+D:J- kըad`/ܶV: b5nH %%R)%f.ޓ,7*W,wPm%G 픽=(Rz'K켔0 )s?#rNY$:KﻣVPqm@L8G4`f12`6ȅ{'So {.%"(e`q OWXba-N@gVi~+G0=z//z_̗)IB'm\oJ~P.90dVP%2NBF^c4Շ2ʗ?nf yi(~B:dEhR)Hb,CۀEZ[Fm! XLWmnEK(n`^~YR5 Cŀ­:xoޫXC3fh/+ǐzjA_ 7&59a9W`rAlRN=B/ g84 -GD| 3(7[֒م K;Հ-܏)egn\$^M`(I9HjA!:wf 㘇A(i-$mf$KK pZKmrΙ\UI(.=% TC S}ktuQv_o.URtu2`Ob'o-|0!^'=Ka#2gI Pk SɖF5hD#.!gM~p)ZڄN;i'2&y-)i H΁jdMLSJkt2"ӭ2ۙlKPΙI{È7#IjmݘwCɕ-TWdLHB7[{Z%]>%#0'0$ԁCOI,'t$F\w!ߝ! vwNe]V(DG=u wWj-AEv! F*]ر5 <82դI?-cf$[&hͻ}34p bl K >D̜s"bA c#/-R5*#-! dQM7KG̙xewTn8i^jHb9AaRN+뙸 &%\9a2WaIJq%l3Pf_ǁ_xNpۨ\x= g  [$lB=\iRl;gH,.j!4x6Ca b-ozB;KIDfxɘZf叨RR "ݣiBGVՃHq%U9Vt7I09 FsdTiĜƄHPb 69Lwս}ҭyo},MUus޿dQ4-uUuUuu"՗ R`iFS`feJ)^ muE l~ < }֩bꄹ"!2pïUQYIaR6u5R2J~GIivsB_mgŗJ)Ch"qb\z60R2:da;-86JyGa98n[r~&3iO~C1 /bۉTHBMEW+K1h J(hB f8S`N3ͩ&i!$G3;$CQND62[vN[f] ][ʦ[9AaDHD5 ijY2q~w2P࢚CXHhƟ iʶ !e)XGGt:(G/N6f[[% 7aCv@сiv%?q>ۚ4؁ Af+-#=> F=K T5+# % \cN M*L ؙ tP}S(3S!%PIa@J)NoB'q0lPW:<փ76X5"q̛Nvxl ")X1 n1ѣhIdEIs`6af@B Sr ̺:ph5J!( :NU(HFY7#_QѳC :z߆跖}5 ,!1z.(bn0g+(ƹ> E@,P@d0MS Ác$)ƛD Xe`-eޱi"+KqBgAothbc|JfTqj17>F׆^AHEϷan[ P8wƲj[+R=/b~ wbVDa{OgBɪHKMo>AcG@.U(o6w]j5A,2 }wF2rlڸq*3d+ā8S  JAy1ZlK3"8H)XLiFOޞdIQflG$Gghv ĤLa] 7O \8jehBJӚqO2[:i6w}<7XV)a" [H^zH(#0Lq!NHX!d7e3(rFpn 5 !\lTIad, #Z;c;\Q[Z2\JGR҈vP(B!ȥ afiRBauRa-TKXTHE6Qȡu=_EPJF_-4p׋w_pgƍ =w;N&LO#O`JdɆ{e`I 2QL`a Ǘ glqߚpͫ@}JXta$;cE̐: f8mmhKQԫAYO y!Q&(cLbZߨз2̨ 9{8XN %RVM9 PtS5nZOE1$j9K)3YQ$52% ĮJFkr@M;("0 v(MN3"+D UTHQAaY09Է3ŋ4LspZQ !OQ3!ЙR"e"3*' QZk:U I)Y tP[[_4,-J|C*I;۬,$0tm'nEl њAнmcBG֠o~JocJ) .tBF7lr.S8:0{I!a&>iH V< (b6^,URJyԺHb˧JkulDBS }+dIz2?$lx\e,HnYu_\ح$#j8N!c&H{m lNkP\ᩎQpWMebwrs3- 0UQQ߯ر21Z^FF!)Hl+媸6ݹ .B,@>:3޲jet[M]LI 0> ETr|Q`YoZj#DoZ5t Pi41d́;MEQ)S#yHCQ&]'+#Gm(VIM!d4YWURJűɂ/v`o1NGfwd Cu!NDlBĹK^cqm@(6F>The|lqCX=7~_ ,JMz,6%` ŵDRLTȚ$I n04r&"ZX2ƨ1Xcg(fh8!ksx?<$o9iW T7Þp7bk~dlY>eֻ-&v#BRE!YHZN-~M@*M`#Bi8R$ڲ X gYz3??O: q8Ѣ#dNf3f)RanM**) Ƒʝ"KB C &[MB\/PF#!%;Ͳ}LV3mg`:6fZԃ`ma$b6jL${8$.`MFhLt,Y]6>b~s߰C,wl,JbLZJkc+H!M9@TrN'\2Cotcf) K% _6YKI6#}ͅ<rfR.@jR6LbVȮ gxKl a6p9=F8j2Ozȑրy=@!۹{vPQR*MJ56뜻{#Ǝ{6~c9`@ 4fnwOӺ@i* I0QٜcVAwtR*70s \cNWo9M_;=8B83@w,_cWbࣥ~Ns7q+7޶!$kN[[BBPm_6`ԕm^`ʇ7v]uKVoZnú }?oPӍ֭zj"_YZqW'T57Y[~gN9h)5)zJIz?M+ZQ9y$|q1þvȨoW#G=g>f.lĭsĨon^ě^~7;DXQC(MS梷+,)tѻ}U ৆刑_Q 8)4?i/G {{8@þ1h؈/#>bШ4kUKnژ[AC:|!_oʄf?3tAC2|аF|d/}Oۯ?[Ew2)8C|>)$Q)?HiTTT+/nÏF~ȕ4Ql{}?yܤ&~?n_8b;ЪۓNvȻ_w\\H*U !&Ozv̗߈OQžw~9S[ F=|_BDmsG2|WߎzwN)-֧0v1nj1ۏ޸A͍G IJ)+**8fV>fR f& cfVbHa߬bPH.ʹ ,iPS;?sN !u_ҡBm}mOLnK҆pco 4vhZ@lEQ˱,g-کq**P`R($_Մ6/d$#ɭg9m~m?L/xec^ÔwI=m{w>C Η~/?},[֤LiʤWOn& ӆ e`3saijyʛS&ȟӐ_rHG·'|z.#8(\I)\lpAH.ˀPe;a͈@q>v]bPMeV Ik}g_kd IDAT&o=p9cdrBkCMs_\[RiR\.8M|!_0)U$U|XFIDBA+mm9Yf4|(SvBAْݮ\M=oA[lbGTξT^am F(Uis!_'L1ປ_Yޭ1(iLvfOJ6TaG"!DUTT)BaӦJjE 02a\$SRYQBlٶHi|134al8ABIQ(Z*<ٲIGGÉ] 3C՘MɊcqZd%'+9t@TJ&J!F8">B-ÚE-ؾ,̇8yȀBd1ms~gܵ@ > XM.cLhPijS291׸)_0WloSD{VLcj(ư_ ;}3C(81`^Rj'.r59~3ԡ|棞 LLvh>ǵ]g:zbլG3 6p~*fg*^EPGd4) @@!*}'ysC{GW=c|: DUG(dup\Qeuӡwzd磏q.{~tJgfpp^{{ι O=q;_5H+F-.`o͍ڼyaG6^ut 7k kuhޚ?jM /gnǍڦw];&&n֊dXsPaӣ{˗~G= #A}%UUǮMK֙7puONMeg^7/ *\Mǯ~`Fܼl5`"v\hfn;u|'tj}WVWfiYiQd}WsfD`~FIT7Um8KSj2q.rVi9EO գ ͣIF@tǧL0RJY7ξgWW{ۀ~av6hzB5 o^פ>fh!֚UI)H Ij5l.OBQln86wjPm\EwLD7-^6Y5U~M6dvCcnu\Tknk+~NGvc?UZ~ş,I=G>=J]S&GIf!+Lb m*_Cx6q ҍӻ/bNTR̊7(5ȶ9kJ].ڥex>qBgd6v&HdsH +(R4Mij^;Y]`-Y#q4edZ^xPyVqC"%Ǧ"m#|Sf w>`J0N0#Rq_(wt(G1_ 2& <4"BmqP!_H @UUUuun4Ŭh{[l,S;$TDc5f{{ H(Rh|7lS2P+QR_C~i`#K!LaeZ%eQP:\\s$[b].iDhmtܲK!+0ᮘE[/J}9atkB⩻NRpNeθK{-&kfͷ<3R^rvkZ594}|n߯ö9zڗ/wl"n܀B^/|{g|2Υ[>c`́(m 3b"UGTUk)?Yֱ-^Dqœ1CMŐ:,{㬗FJ_}$IU.`P2iG~8ꊟ'Ny).|^ksEiZSv%95ٜղ['nwȭ7vKwBuzUY_NʼnoO{99EUUrOhIc ,t$nUE#ґG}eqQzŽzI9kϬӨA-5TydwG!{B֚mrk7k\8lPFn1Q f;MzaN7-54Egg_ts0wހ]N8⌽[_/]T;rAE3jדz eຼuҍ:ݴd)̝|8}tY3j7@t+>:&kM?|\8*W Xj:?j 7!swߴv:Tm@.9m@*JΟ5eiSn뗧IB0`EƇ/;9O.y_4ML DSRo%;ϟ;@s>#ڧm-\3!-[SdT6 $324I">,` )@S텿\P )uY3&vfz"u["h_.>:~*@픉e.ma1a$&!m0Wb4MHir?O nr6̟>o->eFDE##l,}Qz谅~g7Y;o/S7TCߊ=n[N}r]p͖K ƶJ0S~ٳqO>Z^Xz=b㮽;mc_kI! {J9U1YԶ;o'@7'^Mt%Re kz7~Vz_z\GSq&Q6;;`fO Χˎ-wz]}_=P3mjG^sb/^xs{?57ѭW^^qǵ%8^4;.V5h2~+#ؚVs)Lh}T ڹҲw?z%@]. lҤ<Mi=3XqP;ΛMǟxM/ ͏=m;ߟt9]l>"i~ z`lk߲ou h肯ɾDYa(6Hы;3MEC[wփfXr& H2T"jvٷiO|N5~jclBn< 63 Pql _3zJ1qYu~Ʉ_64߫sβ]*`])c xF]N}%~wF0oAQ@+'2nҴY)O}eUMzi9rsu?ڹ24i[d_GG~#F| Gćv#F| !ҫ<ކ/=o{{o-To3A|Xj ƻ 3؎ N3bBko yd"22PoZ߫G&9)(Eq.XZw. ( iZ$ъ1lin8bT+&8rE*n(T&e`SiN>983RpRfʹ;IuVnP qadٶ.loV"f)1޾]SX2qexRJܶ{俺!6Ҵ9ħv)y$) _yij뺷MV.)r\i"aiLb@60,, ə閜i՞UZ4"j@@y;A:tI,Q͠?E l^섧^Y~$:FQ Cg]U4вyjܢZ ͭ4|1 ;&oy i} };φߵmwjYZ`8q窯ݯ]vHW>.^y 4}ed}=*w_,P'bŠ>ھn[ $w#\ @Tѽ~xEuWxЌqlw*NqZ+~}~: CRJ 6~5O _TSD@e.Vwd9O!Kp w|䓟?Ӻ1O<9a@F9n̸ȹq6iF "7:0v:)#&;WOĔ4M~4[[~jK|]v`ݘ'<}CΪ?f܈A}:fQp:<6̈E߼g`Gxt‚JDk^S!#(I"0'# (>8--1Ľ@ű} J%Ϝ}vcc@ב||_hÆO|WG];aoE pLPQ`S"2w6QTjsog& X! {S(< :a7.H^ύej32s2 e΂s1~DQHX >?[4ޫm Rʦ;5%qR-cH_YY2N*+gGԺ}e_|ÎkOW*!ޭ'=z@Mrvc~YBEŚHYޙ;4JV/لQn|5un?h⽏ = =Ӿ?QtɄ ӧWlj)s/ơM \ B$u"eY@LMw*!m0XX.:C `n,lfOAF߆6}֤y&% h`H1WF&i"& f"CwҬy8l\ikqNV4J M- :=S^!)v.O.OBQQ^k BLܘ>tFİpd!P`~ֿ{7'^ :K-G\w;8jZ] (@94QNvʖOl` LW9˻ιa#@2nX(_yf!W+,R s€L4J)"Rt "z&怂̫ V.]74ȶUT28ZMBLP t1*]vwS- -]֋bFG71t n: \ ,P{]׵jn"t+s=ͷ;sz53W6o! ѫM?}=?n7PnuY5OCYse(C! 0!-s "&?jvu7WhO0VW@o8~PvC/|O>o̶ׁ+vnXˠ-W 7 =ioK3.LgIrZC+xЛ '͂ݩ'}Gw*)UOYίP7᾿<1r>B@Z[7Rvg`xKd}Fh>*n #z4.>ZGRqBPUWP(Lt[}x>華h[󇗟n?ݺ3f\p:RjlfK()II){,1sIBW-| { 8u^z@@4[~HWVgN+4O9O/n2d$"ơWJ"MST nW=1#׺_]vtUI)e$DtvO?|37鐏IԠ%cن׋~鬵5;شv~vnh %2 "vq|E@s_㣏vӱKRJPo]Šek]ժmIs7("MsFLi] I.*O(jɼ>Me}RWDi} qe(j:[=ff^]-\"AaSU50niG\:ta=iMaN(Db^a f٩fnĒ |U:>& K8dTaPS~8 n|DRJvB)&J4uTA/"زV)`-zhmxOlˈM!xW DDZ&b 9Wcv "r#"(BMv1qxzQ d IDATݠcsQz͈J+] d0m*&:D ̈́`3CGC'QqސD3+.x&1$!"4 C$&284ˆ 7+46T}NAp*Iz&1 &Ӿ 7ffx9lkA'?ާ=޿AGL=s"KG^{~?/5w]Co ,|Tԛ" Ìp0'ue'@2y0sr Ől@K/>2 D 7@Uʵg8@U5a&YB *cq^Kk,@4hXI6[ _uKktxy<Dqj^v /$SVm  ]+w'| X]KP f nѾ{W狯lSv>uVTRe ̰W|t=7u`>rٷY C`M"pԀyhnQtJ<ɪ~<_{{?%GٚHFfRkYz^ņ {:JS*3.]5I!d$r抦罇7uj-\lVEA_enṯ[Ç/8tOF?sڌA)m5g|;[x3_ myNk`'0\۠Sm94u^>ƌ$4- ,erKa qJwݸ岓v|g&$֠P`m?Qkk}V;7_|Kܻj} 4xY[;$""I*Ix n1dcMtfc @aܻFI*}v޴)6a7C\ ר5O-]Ha C6ooMZΞ95?u6Z~NeS.3s't턇O?Ⓝ8Cz^dߞy[ SRC䵇&qE2b~V\Ѫjk-ڳQAK \.> qԙG 8/zs0 pbmaQbY}ܾM+jT 8LGf:M*̃9r$4XƧk-/5{mRuԀaCa2dJ -_ԔҌ_$ĺ"BζRs+ɸb88Qw_c9xS{#5 K@&3 +rq$EE.҉"Li*dJJܹ)DJUdH) M(FQb N*T>̝rn, "do-"-$IbJ)e|Li LL̺hMeJi s9A @Zl-cuAHo.&]Fk†b*iij9> N5BW2fb! ;ǯ=rŗXg.3f4 nޱY mQ5s+_׮-(5u\QaV` T_ BجBHk,HFFQdlK thL|5&'mPej+'@gq;Vea9`@+RXtSݯIXNrAA!9ӄսjY?,RqYӬMiCشYFqdWs&H6Z>`ViP7u;]|;V8} mSkZZ=g%@nqV rdȿx~:+ҧtݻv0]9ǮN(Nq7_@ HVפe]ejZF~l۞K47kt7kwC5Oրʯ <{ v  jgNh愷!!N%Dpyn+,䘄FTSptӆ44YبBm\NЄIRذxzh}UN\gbi;/Mi~깇43Mzs 'h)0 P/a!H$G1-ArfGc7_z=Ԙ@)UHNLB$5)vL-qͭ?\vqNɂyxSkN~)_YfQaQȍ_av:{di"(3g-%iRH@/^oֵ})wm,pEFy+Lu@H)+vkڷ_9{}Jn;$MD*;Q(ҫg/UvNhRT"HT M ζeX5.M=̐<1"'wt=@ ڝ e$A ǙҜYU䢊Xg{Q>yB>gzY9WtwҲbj,UyCdc9!ĥuK5HkEQG28rXBXR&H)= bdڜaKIra"O)98u<[y!5QI8l `AZ40P9M"v@4ZBv"RR:[Bg=25su*_yҊݶez#g9I܆. ;igF֦BB8"@)=gжOPd )$_}׾۶ha'hjzZ;Usa"{61˚COݭ;tڥN尲eǮumߴEn+eL^\4"6s 4G"cHa(BdK%Pn, ?zogxA:o5Of ׁ^3`¤㦌䎌0];,0u3?p^3һ{V?tfdDV4VֵJ(>Xp{sSV.]nO\{%t~{/hs^UVWWU:7Xht PV[cuM];uکKN];k^QDv!S[ AiA$'g`0_vQ½7M8o۷֝tЮ u.>"Z51}V5-ƫJܨI]:wԹcvi׼Pe۞m8;zY>fjptjlv>9dT~8 HԴ]WKie.]7^7inru?r{3 Ö$iRH $) Ӈ"^qc/w3z}iߞWzFc'2mӮs.]tҥSUX7K BWkL n! 2!%ga3ƈ„̮>Ď0 aomvP l\~Mإ.tڹs}*Jvj'okN)mWnKptQe#BGq# 3W:6dJ cD5[vU5m;uܩu0TaQh8뮻]wݵCF#p0P`(dop܎($-6pL|G7AT_>7rq]!IS _n]cC{u^3ciɈs:BP $IcȐ0c-WW5?aA,anX "\3+Rw>Km;׬^S8\"Q\zSݳ#7گN8ۯ$uS?~#VD;p1TfqKP"G,FaËIfgE|=ºZv=jvӀq;)&*֚&HQܨ"Eq>󤩐/|RdZ.ɖF K[W R8\Y_ȗ H4MV*\ш:D GqE1C2a1V6HFQL@$uTY{'v)#"Y X-hwz]LBNJ7nHBTǻ 8 )$&V= 2у`ؕ4qcYj$wgs|^vŭ^;sct~0?DRJ\?;|ic|}_8N{`?|ewPdO tuj pM Hu9ũngs'`s(hF =fH0(&)./Ġtk7ƕb/+Ak&*h veBuW5(vV$".B?MW.k|p絯̭ז)LN}M]-?$϶QZsvD(L{c6kN߿Uaΐ!o6}ϼֲNxm&0$_q+?t?*;Цx:B;"Skovws/z1d߸O/x+T@{,J*Kb7ڏ}n }ސu5GQPX5c7ܐUvn__xu7 8 ~߽_,((5{m׾2ɵi(ц. ӫ,@D:BbeQ r,/* Q)iR8-q-=2}nWm/?P~?qVxN,nFU nۢR%>/NcZ.آ(#)i |G,6X bо5} n=ϐ"sv~xSV¢?W:P+ofNEEeX8òD(h ?vS.읳'o6 R$up}zmaKmц8"FRFDI!!/<6~rW-:2z_ki lp3ɗ3 aVBha 5R`d6!ȤH2Q$eII.4&uv ޹ҤO U7P CG3o m'](j3a1Aڧ J#oJ[m.2@uRJD)1$ b{k,Heͮ0 xw?I ~@E[Cfa9HIR06W-n"8&&ۀEե؂G8q[RK oPki(_b̮ H+۟@Vg?.C JTY3CB);%D-x|y,l g^Ar?S3e<#$ r_.S2c pq1KL7dqӯ|4`F- )@EX90fkM?ӮbP*MSe.% *,cg)2ՊvCwD)7 ʘ0*K&|!DJqr`9 :b|olCJ%>ĀE9)D)e8x&Z'$MM,30Y7Ȭž /̹&L)S"רB#lF݃}mɤu/$QIFBX\߳闵ӥ, #*ϬU.JUJ+}Mb(@(N ,[#H֩RQHYѨB+Uic P. ҊoQL;a/`4K4p-L#ws JD%P=x6 =ԴBb|eX]*#f mT6&41 :<$pc!]^m~wD-0͌]ERn-[QS-PUz FKh߈hDi0htbn ^p,wޡl"ha(73b rX4 .u% b"uq9#c}7g&oؐ:t%xdlOui"dUY0օGw"ljwDfi-p4gMgggWo(kն=xvW,eBIM@Rx:-T_^cfOGUW̛F"l 41I\. (J\ ߂I=FI$I>3oSS_IKN .ރ WNQ«1q#Q{yLd$Ikj2uϯ!mfCyH"k6@d.ATCC KpQځH$ 3 H?G5Ջ{k٫yz^ dX ij25SwB IDATWزj|8|[(QFRJA)&t!IEqIDޣvSU(BmŜ?ĘVY:5+3CJ6u/PA6oi +lA}p-D~*@?"ܘɚ;3Қ$Q*E22R֊}\i.δHHFJVU$_Pu:hk!2;jx7<9OTIZn _¶583HY9N+Ph! urԎ<̊h[lm`" Ζ'JH:!a^)Jf>|`Z8Д.lѲMk V GkM7x6"`3(l kf8Ep2^ə Ӑmg\ ᐽ2,A{ppi1BvrQ{k!ժrvi+W[Q4rC)"lDShEE6KVy9 %vh)?ڮdG'ڻ{"qr* "f,zHp<39g#*zPTbBT$'$0 'uW~Pz=߽xtwծzscڥAfi BJ2)6t8ob 5@YT)ޯu02)أ6%v+DA*ΐ-Ul3XFuqӕ2mT9L1D>LCHG(8RȀcC=ECIDkBH)7q`!ٔ$Afƶf1 BHIqKp e"*PUSeg^eXW`sKDl\Ðhr/>I+Ӗ @?A"¤Ḕڭ1+U|AAiSݶg1.d2$S>&K1Q*˶|)Gu5j(Dxe@Td+v6 s {]3AqA7w~옾'&hDQK+a7".XiYNCП@EGQd(Ѧ/DԊqO't`M] <]=F!S,/hfg*^E1 aH(5|(Tυ=?S-tIYzݙ YKn眙Iy,ϓ2LDga;v:LȬ*fVE̅r:#pNFO Jhc=tZ\V)Q.gvԱes6loYJB!y:65>tJ R9*a9qK{۔3CK(N0sCUޙJ4EE}5!T-h"t|1 Ԧĕi:d1t"B>i^UFUZJrrgۨqbF' -{dksynXdMJQ V%9L:Tg(<4`"i2j=3P4lӲr=]v/D%-:Ċ9Gd""x7# 1M'DwCQ4@`TGLk@BWh6T=[_ѬFu$;Mr^[tDb;"DEPwEbD"lv+ 2sY<th>ց]vMhM"VgXHpd[AeSH\EJ)*XR,PPn]űf1H b(* K"B 3xD`3ƔcυRMe+_m[TB?rQ1bZLMR$IV8heQ#2T D*)URO)N(!H˳YX'ˊ&UߒONδ=)sGrĜX6 1 Pt1"_l5kFcxB`;=LJM-MKnZ׋ٲ SKDld֤K ==4u1'htzϣ8Q3Dh')[!"+)10fr_;ÞT#`HOZ^?*ty4'8Cvf {#C3Y[_;"2"i<dۗ`Vq qBJSP*u/CBdN0I (d(挓xiOdƍk+KŞ9j/i6{B.M'D!eRHΘPjT ȪH gJuܖ37׸/$d.gKK3H9 ѴE?6y3;SC2$s>GR a&#RIX6jHs-r҇E-vnBrw,T a7C8[UF ^ԌJXdΉCv="C&R["v4[s2C03΁]w+k驚d:X&ݎ{zn!8}_  iCP ÂfpU:Z\lOl 8ܤ!$C 0R䌃ĭP;8] kZo?bmm8 #|3d[$"6,",شG"[A9#O Gf=4b櫪ȸ*.UdVÝ@*A(9We=cvcewYi)bbd<5aƥ\N6CTFYd[z!&R4V1f&h庥E~M{XP|yYvYYO34%!B; V( J$g+~MG8ZSo~'rQ)  :!jH%e$ޔ⦵l.u%sCuQ O5l-9{:t8@0R%jPh]W;U0Fَ=mkM#HW;${-vY(DfI1Tv[}4^Gaa{  ;![_3D k1ύMxH PqDn|gXؖ;z״B'pw@GNk0 3C(5z8{*jnlPl b" !U/2 .ۑA\FKL:+O6Q6_WE-u&%o.) aFagpUěW$D*K5Ld2"%3+؁ xYSо]ƄH")HJEEPͱ?t Jv9Z}T5LW&˖]r"s[#[I]\sЃ MVE " "虫ZI:H  !|XMM$Rf:BJFBLZ@rRjqI/PTX-"CCHQm㟌8BU"gcj9j_+麮蟺[|k!&;b! 떚6dםD4lIhWCԆԌ!f zgavIóV9î!&=g>jڰkHv*BfT eRq2zIe9E[X@}0cY,lpDd\[VY4䤊qp=fO]YEW̵sƚ5J D``m#b5EfrVl'r /ʫʦLK Hd$2^+E~xdq3F ~YRZʤwgRLd&Z0f;#i蝿@u4ufq'Ld:<$Sm`EM P̰ͥԎ.a/O| ^%C02В<7U=8V&ǬU:Fh*.w_X$Z]& tjgp,[cNxJN}$lzϯ7n/L"EQlԏ&gZ5qIR.0<IYuԳ խd%asbL}'Ũu~b;g42նq"A(Ƣ+Č,:o6 Bqu\uTu1jL΅9P&VpC0lCu񬨋&mnUf@L%B"{LbC =EFu.b- e(0=YV9PϤ 1ɓ: GT`<`kd]v6fjeΚh NWCb#X2 KayQy ƶ1ʂ 6" B("c׫B"̄"dC*H) b)r;b+#utqH*)xY|pELdK%6!c#IH(R5\݌XԴsCSbSSPSܚCE<Ƥ@Yc '夡յo$/80t-t\7.X7))+ԙ/ 3e12Ŵ*rBZ~"+-912%F(\r"0#DAWəݰ\Ij/FS.0;Q_6g c+ 7* V%e ҜUi6Wq8^ #ct̹3]ݝ+jzC4ﻗ3Ѕ.:&֌m'`5Q9* Y l2y_|/[t< ""j됤ʅ_onͺrP 1~i#4?ϠR'ЬV-75/~ v nRe->mpLU?qomZn>$[ꏜ[{@0z+''3/y]ikF~^-1s_zw^lhtOe^31?~3c3{BwEwv͜<Z$4ɖsg͟cNn6^ΛɸSk7=&0g9~µycM0gy>i0hGAJ)#z3"L!aՊܔV aЛɤ(a3K/pZ`,1*KJ q/FD"$Nf2)zL:,$"!E&2A1 І}XlWvM/|?7ҷv@YЮ5;޹]K;ߵK8b&eM P,PFyi Khq}d%_O goY~SƼ2us>}֓Z'"Jlt­/~FWkQG-}WmmxC/aZ:?aУ׮5i-ũxz}!DD"ɆjGZΙ @T'{_Zolf6~b ~ҀՇpiFy +-d䙆qi"%{a;r1{*DU"CD*˨G!$z\14?|U2f+=l^l2jøGօњ\1K0ExC0DW:ϯ]z_yEq 4ڵ'- h6N+'㜣 ˿89,G+cGv_D_ IDAT:b¦ˆ=pٻ&|4纇~l/ BG]}Ӥcf&Zxo<6a׏yE1|+෹ æ'w4~mhq(C.7{nwx۷y쵍cr|SJ2GӞ[Z_ŨlCe]a(e>cldbLă^i17?u[{yF<_qw[ pdqWu˰{Vca}iE(ܳ. ?ԸkM \=p 0b}B3F#v!`I:*Y{{>cR9m*#Fp: NjD&γ4~u٦C@;D01_uqvlMrb?rJ6?s ! : Bc %U}Z (rh# nԒV&N9ѐ!8퍾ਮ EuB 1:t=PbhWCS"&(ӕmҲE$n;6`~F. ~\|;/۫}ص }?pU=N~#ʞ_64(/9j|G>]ɀV؞хD)B2D :UGgj P^ICٳn.ݷ= 99;%@^mpոwXU.㒛,?f~{^GOnʲ*hX9gϹ2%c=LF"}Wqn;9ǡVvb.'wG=rw^~wŧ7xeY%E ]F SAHHKcz}JZ^IDFW)Тyj{'Ӿ{_L.Yy!@[w >iQ|Xaq}{grhW T ɇ1^g/8nFÿٹ ѤZJ%DPl>h,Y26g~!2mXvo}zW)s@ۊwˆZ7^S{e~?W:M]@rW8lʵ ڗO2ǵr탯sL|foѽ ykv 9yꋯ?,f(־;'ͻ5/?cN ;{oP>XLwOke^3z}_lTxMZPCuѩ47/乱-r1W־[k=d넬ais =7{j=9bQ'?}OVl%G\qn^図)NZ/t0ujV}=ʑg1 .J1!EG&:y~wo ;ǷaYFp`x΂g6;oLp B聗OuRlp'0se=Y^xN O^ KE%%PsGU ]μ];w9k}6<:?kOV[WF)-~[.n DPkdu 3Vaхto5q4a[Q6˔D0k~nÙ緩x7gm`#n?Bq%y{Ϭ+|3 }UyBd%֯yAsv1i脟щgm^}2y?|f}傱Π:~%#o$kV~6lq3M}$}gcN 7cd-Gpvc6~:- E[48іGPu}:!]e(9c:fjUm3;~iGO-i$>A_looZt,KB5sh?t|n<&W3uOjO<`ؓ|R>X5!LSy*!_S{CZ؜wYz_oTY}?8] 7Y)vrs{/AL&JfS ?!̄zo\}a2k&PTz*u.Q5gֱBxT!V9QtekO Ib&~Ű}eϚd"i6ŵ14Q!rKs5=DJgkb:|Nw*ӯ[9:ƉiP"L-#ZERD5Ts[,c%Qqfk}C=O4D鎉փuO ;/%T59/nA/{ Zzo}9_ڏ|C <{{J:!*nxQ4qy>`8 yzgwZσYN!ٴd2B#Բ|5Vȁ}w#"H6ko됏S[mκY4T=v6[E;ezk``f&v )%_腻W }n?;/l.02qb1Θ{ϐifBL[liG( H <DVD,ٕBI<6Ҳ%m.)x# kf Eͷb݁A>aX5YߨzmZ_fzE-J(.~5{.5LՓ|kՆ *jVnT߼$ͺc Vt}Vǡ~tQKGC}GqTTC`ӌOl>6ȦɅE)\<@پ`پ+УIՊk EͶJ\yA[Ə9t֝W>6o3RrjBOV)гi9[k )_. <~vc;3ؾesf }?;c:pؓ*XFH~vc:r^蓚5.sme9=" ݏ>PYm<5]~}wMqBV'F+\x_08ȫ†osŀg}#_;g^ǟ}ǻ+k+9.kC^:~ O9l_xч3&.cm f=TL&Hצ4 1PRaLJwǬe4ch L'- $*RD0z6Y>gK >TC:3Dۡwٴy3@aŢ?R%w È6Ǟw\~K0.EE}2u :lZmP>Obíb$a!9(o3ؽ*}7?ݳٵdw}k_|&RԪ){K|SN3EWs_oұOPc`{۩ud$ÐT>GyV|sϺdNMhW8żb$?!"v ҧ/;3.~|zi=O;)g<8 +B:T^ ?X7>i6UQx``KgxCۑ79!C>Ÿ{\ͅa( ̤3Z )]NhkѲ=<vVHeM:S2gieC7R/C'CE5:+N{d@^Qi"mБ5qlRS۩'F>BFX]~YD(E(d(d(1 V*K&ܳKV+;FG_TCg3vtL@fqe{IQ*PM:L6Vg8C M&qQG(HBP]Ŷ2f[Yؘ:1BhEi`M(,7OCئ^"[ģ6RBF~RlۦsU |{kVO9Azg֨/)6ڲ7*1gY:;:w1_ˮ?șfH= 0f NRi"&qX @D7L(%8&]d !k" Vrܰ2Ӯ]"B{r .-3v nt%s_B̊" (1ʦu|SWvm*,;f2;EPO7ޛK~׊Ѝϰn P^a:PXGt[:~$e5#RMn`@ @vV8Ͽ{1^= Sx7EInH268Y<#x~A^\dp_>1X`54}@oE: SCJA4cJAwY^ltދSnh{xp+!Q@1ڻ =V9}e\5 K~|SЦi1ԴT7ˣ*Rйi=6:{S8&:7SCFh4rĸ])ڬv>|˫O<7@9{7!^w7@z׌bkeM"c@VMu-ӿpӰ-HIYk;Ao~GX'LupRޢh> }p~a2 9]')er-EB_!CZ6dw#_vE-xg^pr=[yiw 8䱅?VF9 9݄́A^bP//}"1@& &| }ɀ7a˼Bp ^Jodu0fEMjEMIqfO {vG hR̡\fՕPԧ^͞x|y 7N) 퍩u_s飋O`7{ו衷j/uTԤՔ9ݑP.LX =jCaqƤ+DR):ƩzmMɏ#pk& ds{:OCY": f{<[I1T)9WFcCݞ.-$idD8oj:WB%1#D|'ѥ>$W?~F1;xtwl4:E_Q7d|ՠ},_oj%"DPxiKB"@DEz A _}Ӌ>ٚL*yUi [}yv3G#It_C0]Ar"[6). '2 M8rԋ Rb٠_v~w/=VܤVwLJ>#4CE %yg?˫ urWfCy= 3P1fM✓" 5G$cסF!"LΙ8Dl"XJps$mì#ծ $wVyDqucgDG["ӣ6cdHIM֖j'J( 'BUE[)kE,da^v* zlΈ.H>Yak'JX`H$ZZ=D1" pF3bnYG5?]~Cc*q2ܶtS-I"Qiiyh?/y?|y.>ұ]'5- BII{6 $ Gؒ[h[2)j*okRRW-C' N v=?dE{d,DWک -ٜ ͿQUUcȰf em3}hTnr~|~8z AC><lNlCH˯@=Zݸ:]5^;ƃ@Iw۶CG/Mo{wvknbD1oK_iݽo'H),l۽dS+X5T1wiQ}_ot6ns#4"ʄ]%ooM]nsM2 R{B_8=iMQ kG$tu|rb#lk_!P3H%OY)iʫJ2rvbІuM@^iwpMQډz~=s<j+-1Ƨ]1iU=ܻk#N)~Ϟ|{N~c'ϾrAUt8RH0R95AXOI*͏0u\P5a*~MI+ӓX6]7Fv웦m zx!SkGI2bHYCιOa DWQ3FbKu99Ң@l@@ C+3IVzU %}; Ku26]?8庣,$b&ZHR!7q(}*VFTP*(OT3a(wv_<:(16sڲ&VX =>\8STÌAnޡ%p?s'6LދBٿRS"$̱#f":R)I=IS y5\Yp׈qSYj[ Ut%KڿR;*%4>vD_W\XoәcG 3O°S4)3dv=oOo̘ܰHM dt:dLDTd1!IrTC ХC`-OBR$H,q#noRd@[ L}LV#*ghC !"M~ *qbwy!-K@ Aк˟_rY;WÇ/]h'Ssy!;v0'dj) x~n_ꢮ]+ 5w/v^gSwL_;%Pp᩟F_pnY}OtSS?ºgT[jF82}&l1q;+|)y;=㼪 uy9DEǨeCJ Rڸi~Oom؟wlLAaih&yN+Զ=agSQl 2g!DcP] BHY'&ň6OxLŵ%:Le:" 0z7snJ}:@"k7\LuI!gIqd㊄F{ H]ha! UfIΘ"\vy̹rxG f:m5Cˊi[ǤEq&j''8J2Q| (XrN 9g 3Tw`Pƴ(J`첈]+f~c7]j:c!APj(iXAz~I>*\ΛW&ill#T{BY*sѶ`'1L^-KߴׁE;Lِ6ie\{eQE兝{5MMV\t^?[H!c(Lr>^QeM={$[\7@ w9yP䟐Hݯ$T(ʭP黌I$8c~]p{A^M%^ &1%|7A@ɪdJ!B!Bmq}OQDwm{7+v 0{V.VI΄=XroT\}7[țIQ^AΙeNQ63hΜp*l&kFL`C2]IHLr)00RH"RARH aӊ~2L&d"L%Ʉ"q1h53ՖGI fL&I3L&ɤ3t:S20ȄAd0Cj+ʡԾOɼ$D^2* 8g:*Eyi>ABXg)P[kFME0H&g5d{Y#5? ^bSuF@O /틐MxVcP|da]qơZ6i3zc[ ;yNi*"ݐn~lf+r CT%_?1qM]еK&IwƦnpe7o矷E/^n:D'0B# AHD1EvܚU-L:3ѐVtOYo߹kvT/U/y3}طDbFLPke2a7AС5hfA~j$5k@]M|ܴsԇwfs L).k'T@}ee; z|20jhII ~,uDzGPp{y^km,L0BU_Uռw[^nqk/m:n1?hW|1[쿧<nDbAv:un]?:uԪOФ[GsbԻw@^^یJp!FoֶcN'0}[3!W|:e]ަ͡xQuS>Zbf'm:GwxQ#MdEuK_Z#{zE;u逎͊}u|ɐFӱnlǟp4<'wiѪGRR>k6!aߑNڢU_wJIk2[g.;kԒY?o΄LRRTNZ,w2t:1 TA'6|ޒW=:횷v̐w)@Yw5=yA-[t 7VjVqAy۾IPjtzz9F0};hϜɿ$N:4kkӭjSO?gTX$Z(4%o֦kk3t$% ~цҁ7 ?]vӰ?|UZlR}m"K*f.ubtm$C4Qwr0V76j;9deֽZ3MƧ_qQ|Ϧ-tEGkGmKڿvT9kspf˪ "Ƨ_M>wCָ-^sa#z}<>o|&Pɫ5N2Vkr9Gg7y%WJ3 T] 5+?E.>c^4?Z^z O6Z]jKiRWRH)@e.2$)e(% b&$"DQ#Ծ[.n~'kM&v5݀[5KT<~9Lmq}MU4r)?/sOm3V~o$ %A{ZuO.ET'}vƶ<83DS;dzŤ1gl׬eף/ip<}&~d.;bisMHUkU4=ᤎ9,댋PVo[f5֬]zހһ7mVEBH ""dyXU]mϹP:hKF X&v((`/ؐ"XF +J ;R}f眽Ǯ[-Z{Dݑo[mJnbI0{]twVvpq5AlΫN'QE"EHb7稣a_ fV2=8Qp^T\\\R\ڠX)*iN2k!V׿Ztf*EU6zɼoddP%iD1 (`+4:CT9OBÐ a"I[&qbm\*[ĉUyu8|G}qYMN鱿.crǏ=u+#D[>4Gy{J'})9vNl{{]v@IJ;X?ۓܵ}UEű$[z`$ Iģ3,xqYOu[æWld`1vXP[`& ǫֿCw֍l·Ȓϙ !(6'\Ƕ/~omcJ)khl <Ǯy#;~u 哞ѷkP><4yƘN!R_)%7+2FBE+wgC> lAA|i̐!!2 ~cbi]Gq8̐ғdH?k@!w=3/lwU5i I~Reuc zo߁ xO>hxaצ/z~l87{o^6⋲5iCX,Uid gc&q珿|#C'Lfm"UJ r{I=բ !<Ǯ} 1k`߼m{6rEdt7W,W;lu $ĀBf<ƚ*Bk pjI䨟,h+u,9D֨dAhJ=ŀ!T5i'!8,sxF:76r.B'IĪPSbKB`<]&]JK^IPzo*2O˩ݕ2{u9sT`Y:0o:6ʘz8qlRN Ɍ@U꼫3 lDg.4i3y (v( 5P|J0R&q='ZR &]x!(3G3wg'I*̣Sk 2H+L𝆮q#?so~gwOh TH)h>Aڦb#l{T|A2hgПPX=L3N$fk)$c!DR_p IDATAqR 4-#(gjv_7zl\w ̑S6(qx[˓(Ivl6:cL!`QS dC YkM@<ƩH(gK,OЏ@&Vr;#ۓb@j*zu;Qz9׺~}zK߿첱Hg#uY`>ܐ'҅?KdZVlT'pE 88dbY,a{[woj&L":Yg:KPFiU: rrI9#Jlm2EYAlSFHa P0zTfxV我8 [ٜ]3!UAY.WBԑI6oV5jjD`*,uO )c(s\gFP=]:Ni@=_vE~O1ڎ$jr[/,]/H""4]TQ}[= Ͱ˔I !M>sr ɹŔ8Q*ēw9,eHJ~ghlsGH%iCE!F)dMCݶFkP G { #T 9=,*$O? s呤̫,F;q0G_fR=b$~@lxbTt/ }t(jwqۼD ۙΙ1GL oDêlCH@ڮSQQ7׀3ERJk'("-d$WUyY2lB(c@AL츟&# S4=[B_)Ebj8 j44 `/ukTeX/>wCܦjNZR:gW#ȬR} :R+M>voS9֪"RܾL옊b]i4Teo3e@AYY|FF)9@}&(+ ΅K$RT'ФIiзlP^[GR)ȩջJӧRcͭ{sB+\ru*Y}Aq-]2W2Tyf= :t#R"7te+c< Pqt9I"XzCQJb|/y{e#ބdv^E$L_ L h2ey@B:q 2Rzd}L"UW39R4c: ܧf/we:hЄQI)i"0AAXQTSSG1p0N:VURU HB8rUX(MƭgC%&DDfJ)!BfdӢQ,!\_yW%B /*8aKbI0D&lM&4DlRVLdrAL 9:iTfks8E^'&/ ˰F(=zcV LmҤb-iMգEݑ33%~P.e:5[ȑL>iFzj!RSeMcJbDLϣgbX< z1#Cd\לQF:ln 23u8 ^NU(y%_+n&@STn}}~QJȯrH=B-){8Л]2kMsO_65% qIĉv=:жpV ang -OK" !!2o~gԬV rd\Dχ!#$Ms68w4k{c϶5?TNY;aƘ׳uy](LIa{BL=mxyXK @z>nH X(P6XDiB7k"X̙]=UKw3A&,;nPRpno-w.42& Ӣ=ACd`dRz$ODB&*鍡kc,Bȝ8z @2vr޴q2;C (:I䒡@ QU9euU !.55b]29zMLa5]@T$)Aȃ0d#g@GqK ,%uIK7_Wz˪:˙n.(-:;XHܻDcD`)hqzw:;oyp7wFHS*T}VYjAI& iFI45V 8SFvGf8qD{Q$rEԣ^'!do)lxHK3\UF!Tջy=V2u( KО;Wmkx ӭ/BF?(V)w4X[aG9ϫ)oS5稵VJpIOaW-x3pOLX'B,L*ݞD.pAk8:SOJ5ZH$ ˤe[lwJ>L?MӐwtU I{+b[ ?7؂GMl\R cBk/}])f*," k[+m`E@_!Dd3);Zԗ)X"5ӤnD<91Ԇz}2iIMdžl 3]&ʃJ{DZUѥEEj t9fPu8SfYV QOHE@j LGm.9xGsL$\aI$ȒD܏g1zY1Zz 2THbGیBU$Y`)\"SfZ7F"jArgCF:\꓿QHeW,c39ӑdrlqvPc(fEӐŭ7 {rҨyqf6I:3W(Ie1dNQoZDikD>3А T`aIVHpK% *AG:S#"(XU8#gwȽ`R#@8uꠝ~YOSU}Ȝ\ iWUj`2 Jzڹ:h^3ꁀIx(/5nLv3Ij5)$D],W0C[xoOBgK \]j:<ҏ`IQ/X[B ˔5OAT,܃m{&ʗ_sH"ǘ$#&UKDMI@.NJȉPH@CD'ƈ ^ QEp(p^`G|i'_RpjzSz ./':8yF%6)@L? H).z:eM)$<<F$RXh-i]l*1Ò:Nm,FsK5?[,푶̓Vp.(AZ^yJ_෯X<(;6e ]*U?G1n^h,\#"UځyNR |;:ƷєB6xɄ1ΤK7Ѓq#MMMkJr>“1K"8!0D*"ӳv#H7yΐIn .,`A:d$%RױeF%7п*3B!#Q={7e#qq>BHLmZk,]:Ö\0}!(Y,qQwd]ov4 ġ9 N!|UOmߐzre2\ˊԁ*R Z$Dbd)ƌK %HXm2$c@dM:s],MeQɪ5 k{FՏ@t[ntRPoO׉!cu=H&z n߆khv!!IJs.ߔf{0 e@䵂R_sXvԔ3 UzP0٦:s "֧"{P *G$uOA#(}ׯQJ|{H>WOZYW9j7Im#hE)}.;g9<'"L {}hR/Rm] _1%OFY5{OBܘ\h퉚#00>)Hhl 31WYqœ*kpҫU1:BB7ް$cO %k6WTvnBJO#s`%OIwo6qp:/Χoo Do:ŭ%D( Hcd{xBYS&H3QֽMAM@ N{%T00T|IaUUq7T=t?Ǡj+"sڒsYX%"^卛RiĴ@  |D^Ց}gP |޲^e],2ĭgPE|TZROke#))I0]tQ]sq\b:Q]yc5qm9BpC`UnKɢϘb&1JthC]Ze3'557)4sz+Ow!H.셉ei%١3C2wnKaߍ3M'D(37&xLsNOROj 1!᳍ ).,JcW[`Fu 327b2[Y+CS3ϐ(#Q3Sim ,b۵ΙY{2IenlMÔ/>تIh#@lRA*/m2IխZmP.OaRmz~m6gnW_t~SGV5}s`iR'LWD*.:t`?qW2)>:>6_ >a2z;'6m 13ozOLtcB׾;W WՔO4X|R@`%Ld/iJM#?;c܏_6y/rts7qO@OVvԍoΚJJL*@ |齏7/_SəZ l;^8}ʷ_ꝧdbpods9Uj:=ro';8}ߜ>S۟Wӧ;-R-|e ќ)3zY!ܽ|GS~\|a\vI9Ún?N47J2IL}>sΘ sYEEEa^e"t}rf&c"1ҹW_38҄pCѻC,퐥}`ɡC|9p+dw0-RY?T}:3y3t̀Zqݠ<)&ɰ>דghs7=~Yg0z`#CJ3}U%4k|]#&LfΘ8(Aof,XqpY."m%(^Fq'q"DB ,D.[$8ŵ8HD c $$R"29  yEEEeeyLJ_] :6* 0,-/t# ͝\-ZOW> @ 3K'C!hO<!6ud;_;2|n/7]/仞zpUWJxKrQnOF7~9o<:z&y\gWF۷]u]W|=}:>0wzXthC]VU?#~Kvnzz3˯xae 8S0Od)$q*Ca%hF<_r=H} MSaFBoV)Ҕ2LY ׮罗<YIݦB,r9.9"IER * :rF[fи*an+s! vCp@'RWNJN;gb迳nΚ)#APYIكm/9J)N}xGO 2+,+yQ-VyjRHfzF6dLcAK$,H1$B/j;z 8&ajKV2$8Q>![!cX>rEW5m!ŽJ=Z4Zi!5 1E:p'pc5rɽza* s#ZЦ#󙙌9J#'@ai )w͕|\N04ɉ7>|OF>}haNٿ;`ضQCR<l?f|[0PՈLd 7;c(9Ch'Hj.B,Jil_Ph)ekO*3$I6};m;t{a~iA7uDrSA!#ꟷ~yQ%1Zq$UқSAb^i*%o2{B_"to31yxl ]:wZdDI.mn;/&P<\qXFMV$;0Z58|׮D‰iƫ7.o[=\toV9}QGJV1KGM?NG5U>ׇKDexq",~輞+qn}񷍃u3{'$r}9pO_:d؄EB fBu7̉mK?o/@TvʈOWo3/PkkdG\s?x%}{rW%1y.4' ,HEbuz@ś|:_w;t:j%&W^wٴ߶?Y[Čgn,-@EW8Vĸ摱xnQ M[m6BR.o|rWͲ.xQ# w޸*II܌KlfƺN?eur7cF X}c=EdMl" Ee+ Snpxڙ6S7DJ~tN]\8ETqۅD4:kHO!P/]T'aЍbkǮ^=cJ?odrﻗ4 Ī^ N2cY7k$='!P͚YX}c/ f:u+1=uaMu3=ǻ=Oh[Z9x-]|ϗ.yqu y~qܞ?42suQuӏÀgqHsLcPS%ɰ'L~?x䋩  [D ͓_~Y_D>h,^r#izbQqq?יwHi8)tyu;* $\Uݚ)L <ǔW R5Ƴ)=c0AHDI,dXZ*G&ZG$}30Nuȣ1&RB,T5G* rdLD4ΘBrE9IR^\PɄk?:qUX,3sA%0p d /ftS*˜€%[;|BTpi :=P:v3t躾W˟58>{rW.}FT񊶡y 'FοecRDVwŬ=]7R"4TMS]i_$I",ߏӏ՜QE@#lh~^&?Nkev9O~8yI?SrOkev9O|̙cu'6vƧʽG;fl`)9{ɫt"I5ˊ$Ͷ'ÝRXin{̍ "@ifGk~cˏ %KDH)&sRN,ʟ"Xѡ 2N P:K2eUDʤ*k\˦lrs̬^ >TAwO iIFW=-50hPҦd]ִݴu#WނTQϜc*`ev=cn:=cq*=v[%!x)hS© PXVI{XGؽd(8s8e?lg/j~ā Ƨ=r;kj2g;4SFV\&7L~stK[WEIRyfGԈ˿fGOlc9̖3#򀃈&%[_)j^| tWۗL] $XԲ_z>n9!2Xu؉?KI$ m=;=K.躧-ww?{wmG4PefX* o wn1m/FbȂκ邝\{vy6?ǯiŀ_ӺV;upՂIGQEI[Z5ggr_)Mgq΋r0J?gmK$5g-lzAB&I"$"{eemT #uہQu1|*6pL˚e370U]ZrCަˋ~4EH@RYQͫ( cg/j~d($ `Yۓ/>m-nYjZ"%ot闞xۜE;`#NF,*4xpX ~Ɛ B4 ABFDqk-v/a` !d땫;\ww.\ 3_V#\Rۦ\?6<E9;|=lbx?`Gqg1y_cak;]'[4Bֺc>LJvlkYiúlyowZ4c+!yv!VؓOfx=ߟ~tϏDRJE]3k)w̅[b)EU͏uմr(|#I"I09XfaŒ`l#Q08yb G$ĉH$@8 KJ H$K)0 r9E"8N8QDHDz(TqK^n!Q^*!?zR<*'& Iq%I>)"A 9F_1@Sda 0 e-6FZ1TiRE)Y*1(ll0Ӏ7M[Y.RUh.$_rl}0V]#i&ufDqưawWUE.;!e#?qS?:_5ra;77cIx+_ރ~t9B{mKH}j'I~ݻd o`d~\7? O y/owq|7=mxM^Mן۱ߥ~M]ox`s=XT~mӱ^r8%ZLUz_1R$tb)Ay?ƀˡzymy7{pP*VB$D,3o]t.?Y_r A((?PqZ*z4O`F4o$JJZ!+nvJt_ @bȈ1JiҤCGUIH ,ݰϣ7|]ay0. A~ 6|x2_wN0*/! H Bmm`a7?|7Jiu3b82ыQjYMN#FeO|iQ4-eľD[*B!`y8+ /LY:S]zJ'~M6+k?'{nY͕^x ?勵=msqsv>y- +qƚCfg=ĵl4oU(b)%pH5E̪Xer~ĺ{J8q$&q67 ?Eη7.٬Sč>3 NEkmJ *qs}/{T ThLQRXqr^ᙏOi(lMWx@>6&w6sN [w{`!~rv! o~mESBZ@piP¶X`܄3F@B -PyM˞1|S%ҢM}چ{ rY+Ri%C"ڂ%CQ"0[@-&ܭ-eE P&"TrxS/PPfez8_S{=}u C@ uK 1mTX!@j=!E%%#6_Gu]'+3GJij<5 axN{˜eWr;NAu=IYB/Gwwe'.Qf[kDTMvn Xh'.**QK\u]?k*ONY /Gz<t[q.?y=:.TU#$2s3n찗&-Z6&E\tB/T-G@$ε;1Ojb(*+ 8cl;Ɏ9NEkvߒ԰00v\ ֪+!Dq|MmxqϧL@aI".Ia/y߰dPGІ[uDJr>7d<̅a. CŻ)e'q'IjTM=[4LH@ĵU6TT& IDs$"GJG6ucfVT0 :!1z +tH8 IDATP(Wc/"a&jvmZnӮXq]U}Ob10i_긾C:TzintWwG&&=f!Q* [k{Mr;)8(L~ٹg=,nW=ytQ7pv򋿌JבLЫM?/|ݡWTX٦v:`gwnc|}ų;y?97$x͑+VT6 ?m8}@U[y]_6i}$<2 {3y f_üiA.BMkڤmRN?{W]wO'{CJ*6ߴ+RIVXQ5h+X򝲪@5.)G$"IBRs(\c(\0L$"!ZQ 6/ ujZiE"dąe/ %$EBHR&I"ABx@2(9RH%$0 1)Q?c4GM0ʆB4QXRfT?ĝA6#̖ QS[[>yB[ypHH9Ou;O;S;\]~[@$(ocx?iE%g0>.2Z˖>Qv2Zk 87$fDB﯀ 1Ch%cJq"S JzW}e*H*WlM vТ][ ٵr֟Ce $l7?^o޳ Ng#DD Sr_TVi%.`J}%;k `ɱCeE:~YA`9 ,9Q8ԝn7@A$7nxڪk$c1IdiL}aɜjv|/J~f J໾6-9!Xj̪Jjme)$UrIUI-]ֿK'K_)SJȵ:="qy yhP_4Nb׺U zU[?}zx L[78 MupTRɪ͕P֬tA= r\)f; 1wˡrXK='Kg64-{Y~aQ5!C[*yYL(:rT)dtd_]gcU#;}:Zm3}N{if{[㣇~puۤo^-bC]qQqq8"DH.@ALuԭA@" Ѵq\HI"HAW͘YIˎ홿逞7~j{_X1#Qu@ВDQ55ZbyMx),(IP{%ځ(ra.rS%5/5cˡZX4$BI Ԫ|SkYǴ:mc&&6 :NTӆ\5 szh"^@Tʚ;;_\krsXL*p'_{I% 1 BFZ_"Ħl ~=[slt]Iv"1oK0yGq1O])u]uBޡ=Q!Pi<ЉA&*RWWGTxS3 1tHIDۿ:idR 8*()%}:ܒ=IsƘ"qUhWn);7$^E*K6IZi3}iܙ wT!Hl\_۷nqղI vnx1,)ȵسU0X\䩛S7^#PwM& ݖl9 ?0M-9sZFGBW,[np!?K+Y˚( p6`Ke_oN!""vn`"? ̨W\vx~H*7!lZ{{[_Æ4=aH]eC-Lס AK޺ƥ%8ɚ?X9[O [64 M?SsJbvHaװ0"7jkw?e Q=+*gBje{ܲ l~О3Tl˚9a㟆^׭ w vÜ=s=ٚlO_[o׃ftnj%83% C'(q=Xog6 ?L_[r&QݬkkXy CDB@6PXEU|`"es646eZ dTly].SB䣈$Zt 9ɼ,Lēa}ѓl 62ǀsn|zDu V)UJ7}gNEQa]vDTn&ъJ)(eq֢EEQBX$ "QJr\.d YݲkʻuaX7MejSg7M嬂E8P%0a@DTU)9g:`fͯr|XѼea1ZZ@.rYU-zsܒ <{?jsŌ1T*ɬBꉚ^s(]LГGϥ6l*sGv*}JF>\d^;tuʹ'Fjڦ՗呀ss.B(qQ޹τCqK%kT4dA)P~گ_.Rn'6ʍmE^go 6/ڤ[߾++m\#lY^t#]wcõqF;y>JҮAY9,kˮo\ӆF?~={ں\O#MV܁s}N9eپ존y J7aYӎYey_eQ=Imd `,w~S$o.UOƗ԰K͵4M{7>n]hòū.xE}ïbsoJrg+/7|{>u҄ \LHm/û^ޠ:?JB3_Xĥ)pyW|Z3{d_Jˢ$qγu`RJ4g΃ ^GF'9W6g\2unC/] b ?u'sW\ܻg zm 3\r($FϞ$yg\[ Vp]Ğ>'G8\+?>V<1o.cвK:-|ڂUt?d_ys?/bOܭJ|qœ/Zl}S~swNh֒]E~sܭTے))),VTynA Zb Hfޙ_ ]8)L:g^_kuD˙ QY%(`=is<{~k//w}g<<|-Y0~ySXe"ڹb -[eI)e<6&[6~qϺuk0G"|vcnsFWmKuώNUxcsq+UG*heR!0XgN}3S; zKȆ:gIiQ 3AHv`of`Jʹnۓ5ISJrVeh\6סJJy(---+/ۺu=yjX{h}þ='HHhCd],)!LϠp{s8L ^ےn6s#?orEw_تSՏ/AV53n]3ÉĞjw=}1dˆ_C"R~㦊o ڙ{V5@>sv@L>)Rl S z]GPd9C2!khă̡DH*}a n򱗮ʯt݄ sbX[|+x 9-~{S~A*dcFʹôitB}Sˆ]Ө a;Km[$w ^}Mx"qθ,֊1&8PJ9wLw2U_oSS֛d@*%W]CFopV8v\Z[=: @EOToܸṥ%Wݺa^G.@5͐Rg07Ayx-9)܉k&Tu?DiU#+^F,^V*^Ss&sa;ϻjtc@GcM7?!ƕ?L1`䗕"h\MuAC6>d~oGvW mz됇_m ?X;[.=ph_1_RgՔ񷇮oMZ/=}l|c+C8Q'93N,s5Mn<__I/yl*y˥ORAۿ]u 1Z3mx*'AC2dsggråO.bKizJH}B𲽮ǻfW,z.^Įzxc'8z{];`P.>Fu ́ʩޭϛk6}vM}/Tm\+czʡe@E6~|5y-~wԸe6}}wt〱@G z5r"%bgSzq@F9hB!pm31M[U˟: W?0HD$릍9IӉk*E3?9}P1,Lq{|l7]9fid9;DZm~_mWY&ś7697{'Q^γG3Xic_OW*d {]k??I,=YR;LB)%f3?ZĴ.lL/sBh3WivG_mW^"퇁Pmvrz0/$8Ҟh?<0 ;srh;5F/Vrǵ'?w5V -[%t/rJpVץ-uCUtirK~ń (rbuͩ ~wg@s63h]e >x]ek;# AKa\so7k><?ouʭAC] ]| _vާ/9/>=!DDP)}ehc%B/~ff}ƙ/]S ߾ /Enǧ Sle隿 ϭ2.eH2h[Ǻ7`y+R"Jd,ȅ T$1OeF$pA 2`tdJ3O9J6h|)0&d*åSEpBJ 8 G,;I>˚ۥ{dAT$C$T2݌bDKFfFj=fA$gs]57{JtBC@)3 ݙhJRϛ 8qK!\_Skb]wtkgOtYp8ΏN'H°ᔾ tjVE҆ڸ7/ IDATS9f}I@Qpva~ȴt^eT=0ַ͗í1璥0 0`)ckiIIb!#yْ\3^ (n㔼x;˦YyWk! 8g֗mhzG{$ g;Qe:2s~JӋ4K wyJBHoϙɜr}/16oDjO_$؎H2Цx C걫~"T6ar]3P:)/wFXyFqp+x˦Dp+^}^8iuAe2B8ah7p; TBET9n>RH'(w&H7c s1a{wb9Be X9(ɖZQE*Tf$+i ۤU8*ԓ=H~vX*\$)]EA @7!$/7]j.5g["%%)闦AH@)ܚ(eG}11Jw{ѲHmMҝx Z?y`BJu-lG5& w6}ƽS{^!R@'Jz-BDA0s(Zd8ْDY)2"-2Z[+BECm1_z9eS/t 2EJJi|)OK=}6ffgh`V̬)n Tf6 㖤V%!a21wB/[0@2)bsIWk3&Θ1&bEy ` ÒR Q,@ HMi}_cGђ_ۡ8cdS*14;fޭn1Sa"Ȯ?|y'tyov ~VFH9h̄dfjpYzss;2vgp&WBg|%)2iSqߚIlk{41 iJS3I-0j4\D:Fł?hMx!,FENCG:yCrr;6mWg#-_@(5^T+R:&A@RWJD,Tӟd ߧCѼPOFRz;`E#y;}?yMכ9j-"%8BVI%tR%$a5]~d@f$PP2EN o;7jmu>|2[[齂I1 N[ mFӌ;M f;@F+۽!deZ* )&R,) 4/M~miV2wG]sd\](0JfHfRoRjO#ݢZ%QH6 Nݗl\a2"gŐ:©-.%>%s!\(J(tmbZyOE>7F~6yoICTF߮O1PPih L9_ك&QLVQ"=""O(ʂTG\_} &,㌤"ތRdK~.X'i1΂0$)D$̅$Z c񏝩3$TwI3 $ ty?R#l ʢe\.x1 $Y yxGǿ7P~/s\-Iʅ:^+J"mЇ(b#CfyN`)x#|[^*"=ll&6ⱷ->&NH)v1 <_5J O!+d̄h>(:db119!\\{cEq]^IuPJ;M_19 48P~mPmG>S k[GHi)g7ȶMƁ92&0D̒fuiQzZ͔,9)Kqh'ׁF<ތ~HD Ab@TLZnQ!ђR"T66FA_Fq4Bzagp&3%{])^0ATxѶ63S'ANfD)fnl_)ƸDIMI(q8Ι_?HPA%p^ | q xkƲWZdz5}8!DBc OhYX$3 {=L;c 簍mVր %p'YW2-GolD*ZJEi[ZnfJ*[4!"^lv<&If#>TjSAjg$r0`}Rq L9"⌅\~_YUSLzlĐi2瀳Mw }8("tL >3i7Ol|ҫ0g8!8&E?1f~mJR3f9dY艣< -vMSyemD)jT QQ=G|'cRgToDXPLJ%`S0LT&ÊP@± OB'jJVEm/~)M YhzMǞ>[x&ICR)P*'YVEޣ<\E-D)"m`f;vP4&pJݱ>6 c&v=ߏ٤L'ƢJzV62^.7l!ou@uKʆ3]J!bDraRd1]ԶExr^ xtsM@J^tg"Rid,u2x")seGcCҞ+$M_N5I)e.=&QQ*vyZ2lQH,`i{;MPqXBwZ[x$d8 8h\]2Y& m.2Ԍ02|7!R SC]{("F0Ll(:aN7O88d/ (RR +Bc)=C;sH "aՅSz"aJHR j  XW.nk8n{Ȅma]@aIu:P pfmLX=+ Re]rN )``="f0t' TW82D&bIi\)%Нqr\Д4@:CiM 4jmqnͮ) Y$ǹ6')0t@q@ /QIglά1M#c HY4n[XX/tLH-e |55eR1 SP8>ʌ(ڧBL*HR r6 6vpfGE@Nd{&;c<"c*# `h3`Р 8ה:K!R))IMєJ;s?v:8ֻ1w[uT%|g*%ąu.K9"]򐳀uyBFuuRH`(d0+7z2(>_(_.ҩiV*aշ8A0f-1d$]\;6fȷ3jѲ!]39*)W/s@qLDa `r?fƑՍw8$}$t 9%s@/GJ~-I:8HX[*P0`)vmد)ڿWk>N93r嵛եRigF3RT6[}s{y""E]Ni:ySD?#$m &XLoT6:RR :4k@bLŗ.1"Zh+=DO5}5 phi_rOjRoLIFHI4uD$S F$-&ږz'sG%PZn|zz-١h[qw)6pi,(P؄ 3 2h)TY:/ [:$ ) fLa>/Q/eLzJ3 lq&EM CmĒE :섣Vlo}s/1{7+MCȼ];kϋTw{Q%ӳgH &PA)iCXJI`J~ `R$la 96F(c Η{&Mm[:/eî Hq%,"*&gCEa׃1kؓ!梤F5]Txo25(RТqɃ_evRzTbb .6YĢ I" ƴ,lx m/Wo񥸖Gh=ݯ7@Kgu򅬘I=zo{g :L )ca;6M)0GO߾uܶu),9SvrA L q@(@()UvNO0gJG(3Hq0!Zb+YClٚ$[UQW!%&^:;x'igm{n^L@+xB1ƸuɆy )1/)S#Rna,=Y np$Ba}cRBj='ZL?-HǷR.THIUBAZ5j B(iȵ1eΙhIمv,󰰗#64R v7 "F% =z14(iXvkvi] ;: ڪOm۬lR^GJ 1ϝݢݚv?mf7R"+=T*Rj0kz!D,.9Mkde~Ќ7h9 .}oY7rJ맶me-=Fqa?}cϤOm+t>F<9>~rϽO>}<2ϻ@1?~sÖw_8I}!  g'_O!Zwg|7c{[(݆8s̙6! @Ю߸ܰ~z]Oӱ|F 9.?vS&UG)l灏|SWђImT8҇_Ͼ _zLu1칷6y769KϹ?ݬ_>CNwd{@|e)BhJ<&91"u`]A T5]xhۧdB0̅ €ba~abl\lwkztSqK=VGЁ1mHt@)S߂aI$'ڨFBIlu.ۛ6:=rUYX$U;E~E_nR ;MHRX aqu?r~է wp,ga""Fr*}Ow:&G^_Ϛ;eִFp|2rnG̚np޿/?悥#nm?Ko`8XcW(?5$xp0raY:"|JJ 0@?dj!&Kllq[oZd1mgqi~MuN(XRgaVG.M؅~^ B?yw CdT )uӧ<*^#۳cfJF.TR2j Z~̌wBF,؊e; IDATFsЖT*άM$M,`5vԂTJ8c)Y^ͻCf3s;ȆԒ De?S}ZyL\fpohQLeRuDo>Nah|E*时9԰.Z_Ѣ%OEkf[yV$λ .K.껿j滳k3ъeus3jzubpô7F0+/wrkG\ԱLXqdvQ#7 ̎5 E4{cQ>v<{=+>/v:]~wO%go{輎#VکO'/0vq]'%m}xE?e3x]K}degzKUtϙ!k~k2=v;~KV弇=fN9EZ{#wv;sr yB ]K8PŻ3312 ɔ2䟷?1 KrE@rLjlJ)B@#^AP;8VKZ'J`(%8&2a ySTq (-)))5`%RH[Q6 @N.;E/֜pCvy1p̮[)hN>Ҥ]i4Bj`<lgs>qz=`u)cwT s/W˃RaWzI|2Xv=d_t56F;P趿 J"CwLb|9=X-EI3WH `#@QuvMI0G~/hݔn9[z2cw^>m#K!v:m}nApYXkLȵEJx΅A.0'8ܲmǮTcSQd4#AM,OؗxA3X HvӬ-Bƀ@a\@nL@Ȣ/ ))A+eٺGX mPudqQ?YuaQ$^fW5=w; 4LO];Fx׉>3:겖jҕjuTѿu:V;83ǸSz:ma/}dݫ.-7V69䈖ߺf咖>o{\1ͫM_=zdlzͥr J:OsG}ѱ5%~oP>?wf!op.;+N#X#w?y ul[|8궻^SE~2Z%%]q9GСaNn?s@@27@iܥ 8\ v9k-zwwsNaa>θƋ߭nY1~Vf̔l:+Z!e+% s9JZ;,pwrOGƦN'iӟh`S{6f쭶tf,2QЦQauY51v_{~~ ֡ŀOZ5_VGeh73yj\O=r6}a?M hӱbYKHcObnŚKگ;5+uNZMmg{}h/xßWJO}s&>#ݞ}Cމw(Y7`.6U0|>"")`{{x)3o>JD'̿OW_4#tW=kϑ{~ډ?  | ~YLMX1dC@JUZͥ,\.QZZ >a:Ѕ1kIBC&&̌K%!CubW!9:i[t4o60ٚt FMm4W`*)$ g _; '3Qp@@(BhtMK cYɤSM)Őq2mn/`牒qicáh 3!#$8 8G#|$B#, CC\3nD^ 9Bp}lHG)kSUYCE[,d(T@A4qMId&ȎzTZWh)QR2Cd揶"[I,| `!@V'#")!I )ת!%kIU[ƠMB/B$ιV [Yl=uq(kfꋒd)]W&D|s iu>4#۴;_,S/XdM?wYpzE }u:7`-zEnUy&_w=_o x@P@X^ 6Rw*2 ۟91矗G>Z4XÇ8 u};&<`R!bU 5 O=rzι\!Xu%7x#ܝ?o )Eq<hD{5bzPqic8: ʅ 5O'$Zb1y^ +:ؼv7+D5vs0 @,neATs-%.t@y߭skoxwݞKD t>yoWEbԹUM\A?nz'QE ܴJU6S>/xCcd} ,iGm)\F.%Rb94~nUϻk9id:*':MtcSSS,xʾQjzh^?E@tn1FKJ W~:fsVm3g(6Myi7ny]V~Gy>ǕifMirڋmwms<СT~:Z>C,nbž'mIv36{'85o:Wߝ2|qt%609wL>\޷v_n28Q>QDRqd\;]"=qB~w˕wr>]7٦!܊]O>bfw*= thm*&CX ( T(է~R)5ɈZ*iLs*z%Y$/eR$d:E 0wR +IڈZ;8r9L_$Jd,X| ̆YY{ϙhCFVV^+8URYpg9N=/cͻ 5569QC=W0Xi~W}gcW~7m9y;?_3ym !R%@YyYI j$2^)$P @UMzNz{{5M,e j!i]D{Y*f#2{zT{0JҊ#uO:溠v{vOʃZi$֎o}pcO}>Z?#U-^}v6MQus+ݦ\tYk*ՇEuMxj0*ԬC5OCmXffA]cF†t]ּ: zfN.zZHꟼ@AǞ^߬*ZTrםW<}k5.~{B/8m?~ )Iv)?oczz1y+gš~Nx}zb:q75sxެaBʫ v#+'͔E' ]S}+qDv}y,"`tiґ6l{_o#_`}GcX LIaM@,٭w}~z;^7Կ>wʡ;"ccYD.gpGL(iwH!(z#u`Tʞ|o9A=G3CUW ֪_|uoż5>8&9"E2ZX馘yPǀ!kN:K!d,m6T9#wjQ4J}d-?#"s:Zr4q'5ΟIǦ1љ-K ,c#{rd < tZ"-pBo2 +=e*)v/`]I\ ൂ~JL&8sǷݟ|}/d$")"6ˇ5Yoi3֑[B^z}eZDi?*Ro|2r_<;&K<>~R#uZJEdǔmՑZYE {J].j@e͗&[[.+R$1""Oذʵ[jU54.oЕ+v=(cE*C&XAsX~3ӫL 6dԖf[*%_Qnқjo]zƣµA2*9ՌoNj=ruuq>"%jZ'⢠n-pEmY>k Bް]۲esVʰ. yQIGBƃ\.YIF.G{IUdTafIA5!b(*k 1 5&LkV"QA A'w[u~T=߼~f龷n9y8}&ɢ.% |BK$%v/^9@վy-ꪥˠ`%=,ǰzu啡 Z')[TL^f=G׭P͟zKji]ԵbOLM2nz}nm?W/ 1s6L()2𖕐3ι/ܞWU׮)7/+2?Վnm1Y6 s<ɐqOȝn0ۗ!@?ohdAfZnnhuix[Yq+_50]8K|[4Ⱦw}[4;D\4iVɂ% f{WS7:iҬuD,oms \pÒ )H/-gJ*!ZPָSؼy ynpa$))},:q̒f6{^Mq,rS7ߙX79.ӽ m'xhD?zv_D UhT $jw@RݶtV&ip΂ 8 I( utZkPR t=$GFOQa[iq4CgsclɣR]3V.ʀA5+eF]@ArCrC%6omLjp P2|ÓOxe'M"+I(xE^=GͺcV*[uX 6?zp/忟ZEOhWDۦ?>g7o+7[mB =\[[[S#ծ@BFQ(1@kj?J!E̙ 7G1(EQIM$@RaQOcT1LD(IR0^DQJtiیq7m?)TOO PLg<Ͼdj+yᶯG=O)MiWn`q"+]PL㻷:ʗ?liGZ*(s{}GdnЍ*nHVo–3{N)*K+VEep_߫wϨED溫Cy̜;<[vTo(UYͿoέ c^x [qE]֑s259Aj|}w:Y=_tkzqZܑ\?!C7FTm }y_O6TةHRY-۰۱E]^mO;dKe={)*1xtoBӶ%(sZzjnwEQn狲ѿ=>š}/Qo9 d_GzVl  bEbaW.z~ͺ񏷙wߞ|Wl%d$!L"Wﳀ]/ml[ BG șOioj}gldߒuG_6/yA8\$E HĘL5_QPCu *T,:#}IӮj'YTMS(If(M4!+hlOPY-_#b]-tzft&26HV"[=?f\jW?Cc1$ CNѓrma,Aɘ]UE*lSc, HpH5)^C!=`CUGҌRozqGςsTr{W !RC9pmL0S=;3v-FݬktX/9zJ{WfacH!$& O@@]HjHts.J_ɼ5Qa($dHUH B%Qi BDB 텣~T gLT*Nņ5ېv/ܒu$}0[6QzGT0{aA`Uk.][=Ol>+MC]LmEi|4{<AL&+|[Z@Ue6un!UBʊҹ :d'vV\Eʲ7سghđ7iw@חtY㦉# iW;K=7^F8qƈO6D~k}2j|Y=5ejҥ^t࿇ 4qMC-:g}ځ7Χl?Xc.^2ohs'/oldvnZةi ZukUVlI"R)H#"ren_ vso~Y םz,>䆞iWj^>gC3< %[jmrT#lƚskk y,*HB7r٧YbLޞVW]=i68WZìatZJR2!k|IVmyjSoƵeオKnxi^KR+`kTۅŽj񯣷f.l9Xbҥ￵Kn8glһd} 6g!].Ƌ>8A|uZxeKڼG]xr՚"^Mi " ڞ~4'W6ڭXLm^^v{? >};A36ŚX*jh*%Ɇaִ137SᄉKn8g4yw[1uאx˚.0ԏ =B k!Ej.xوJu%mM|wq-Vx}TMŒaج[ҺP9T2ƃ;^جr[6O3K_[o5^@o7}O% abBf>0;eOLL@5mny?>taAE(m.U8TuRXԢ&ԖU+WlIq-nx@:afe)k"J6ut-vҵ5WRoa}ϟ<'&"( w'j֏f Ph߁WF)F鷛7yq,H@X5: 5_ᡟ+̮,(L !CBHլ)P1E)ɺI*Y'2(VL~[72e[o"k2cp&+y_$a+#̜ym5Q'$D W2olK4b,!3⮛yReۣo|iE[_pm["?{ʇVrG{:,QϜoږ/9_(,p㝍F]+xz)jx*Fw7pD)eZ\1y?hnmqװG_ܯt.3 CglssH& R.t-njpLi*vb:XEU {P//{惩y^9 *5zb9ѽn "MKI곊< ~πaC+\u1yu/iZ?͇ꧧWY/%y+olCD/{]8|7o8c;6 Ĭe3ReEj^. :_/7RUԫz!?RUwz#gM<@3t 89ԆRos)eu zsUJ@ʆĖ5*Z%lT’4SѸ&^RZy(MSzF[.اor@V}Wj%)P43B:Z]9cQiQ$擨c&[WNJ=CZUL "ni,SHmRkjGd\-"8^ct:(B kgcRObܱS :lʺw*PmSD1¨dFl1Ŧ+7 7΃/?F8uF72H#}}Ǔu)вzA-Z=ܢDL3IJc;d" &C=&c>}:04=I^\Ɉ?$XϬ/aGcȟ վjvt+j =BF-ᵑYPP^kwLq9Q̥tdښPgb^2 tϢ | d y,4nQW Gɋh!Uc7I7;˘0! ;1QoΚvg%"7x~S>5/D.x@Hk"PK )I2."DL ")ҡ$RM$!d6'ӝ䮖Y_gz(6TdymAf;Pmsd@r(ܔQ RsQ(@%DxgOډuRwf/idU1" d2JD$}_x;O!/84W4C&B[[j^c=tb>lC 7$E@L14^PAV bj+0*9[&KˤT̪mM{%;яی#WLoK3ZTg(LߤsD mɧo ~X@LK'6LJ "z,sȀQ|va9ț&1Ƽ,YE8""E1qC]OĵA_OxOFY|dgfU4 ( .ctH2S4t3ϐEB@PSYIj@KU LA/ 1j| !d Qhntyn@14D@ey VnsH3RFKHR" ƸTp36- ޿3؉/θ ?MxFDopa\qx2 z{ ޤUnŁp̢=6PcmL+Ւ-VAy3N'@ 0 ow,a޺I?O6$]O) 1 (OQJc [kS mc vZcK)D b#9[ҸVjzwNPuCass8wQ[kNocToE6y2S;h͊@d\+jV!(8"pMk&b9mfGQC辿Eg'PuȌ,tE8cARL-$P%4*{2A+^h!g> 3zל[=CX U"P5MBzυrݳZzJL״;5D*'#]7pUPi?Lh˼GJ BRn阤JYjzT= /dSohLh 6p Sٛ tfJ>h׶H" t( "k^@鱸GRJ"mD]+޹dڹ&I*d;?AelMYҁT /Fɝ#*%U,o~W]d17ެs%Ɍd<Nx @EJDP ^J)$Y͎Ts}*BHG^=*ex l8,۳ىA#o+s5>u #nZTVb7+Ǯ務Lg+,`ssMocooYʳz,[tCg^9*d0.pLեC;ck' V]qyW)DُL$!ID¡lI,|}db{b M߹L RX_"۟:i% MD9fn:uB :F^$%ӑRETg0+9e|!spgSuJM!lc8SXJ)"aG|Š[ ](|YK;ZajsQ1k&"נwWڹimĠ1Z2q̘Ac5 㹣I}rv|fԺ'/ϣ]I! DA ,YlqRwraxq*O{u7c\)Ԝ$!D -PXZc.d jz[oX mkG: 1Pl71 }>mja$o)Wm ew@zjGT*L2%#%R/OzG a% 1|\tRFa(D -Nȳl(O?bN;;!fEڝoFF eLϙTA` 9$! 1ZΣ3M\ߴkX/)0 O[j*+ !H>CE R`AlqFPoRY]J&A[$I1DQjKXnm 25d3\ڶ,&fyaNIi 1;y09vX~HŒn)ft>}"Ayzɸgn1njams?@DQI*g>ADBi4g_iȠH:x<4$JzEOL*"0-Ck&`%yDDh0-!xh)pZ.vLE۝l=E&)>"#UexՋe=@vr%lJSVAGg8zo4ft'/0r@YW&SX zVk9uR~UdEO:x\GC[겳S1X6F`9Xx|K}Mm6ךGJsCe@񩎽102}GS*HogI*M ~OBr7c~[Cڟ,N,6&C/oD+uIc+T`+uCÚJKHD" CKe֒(5Ha_q oxQDHʑ`4PA朒\UFEd>IvVJ&XE-8Kq7׬{XjZ/Dth䝢+d eV-Ȕ/59fNdc`HJdmCd<彄ܪf3ME@)e;0.Ɯɫ۳X w*YX͈2"Aۜce7Rƥ9;B I(Wx !8cڞ7kaxe z[p K w>Z%UO#cη0]|)R![J9' m:qLMiHDSaRD"OW4fU?6:v]91B]! Bc0\%DQd✟8_Q)Z{-הn3I MmWOzG,w&6UBH&@zq{*fX=[56Yak|" !MCGII MJ&Fn1n6\PzL4@[׺UEt]2<92HʌDa೯6F̄$ŧ2|MwFm>;٣vlSo^,@]d P|2xCݠH:$FPz#f7 TskQpHr3~)s]܌ kJ2;K_42Qr'M h@5Q.&@Bk4 3%a{Q!G:vopΠnlJ>讝$ihhAUяs!$RLIH_J ๐;N3S?m5[vB2S2 7u"(hBC57"qBDBP^RRo%(B4Ii~GQx9Q:Zh gFMwwA,nvgRZlKfbNtjTm?a/r6Kl},G!I1'ޢBDWBĦҐ 'L˦4SaVgβXoKMA(bAMml- dμ/Utqiv3no>8g͍ $=‹F@t7`xg@o" clg!ey#aPx?0gs~ŰtzzMj3O{NFq]*fz:LF]Lͥ$cx$vL!<(T?/bD!R&If[y8w+HIꝇ0JPAZ>1=`b6)r`|)7KںT]QJ?;mπመL$ &LhvH~dr!d:33W4֨w-Rh܉ݟ qåoMo DMm*I( CZ ٞ3N~ϘrIv ;(;b\i2z"J0v]EW!?,2 =ɭ" \l;,+e`" 8WM'v.;Ps2!=_>)]JHD8A(yx?<4 \(wmOv:FKJ*d` &m/p3m0(Q(#؜TKF‚I6mxE1c.w6TmL뻤λ3ɫ Vb9 YUL@HZH"* ˥v?ӎ?hyOsJqGjCf2"ȱ+mlu0NtUf"&_a@6S0=ҜI6ohwΕ Wv,.#l|Nhh2YNq7'6i){||1"l0p(~L+Lɒ֦jjꪫ몫S55U,C[ ҵa]]JE; z]fya}ZF( S0{!TFHsc/H |}lNOꪷ|raˀ1-zocee;%yuk|ʘsy?*]20FwDn :EPy^Çې_ϙpV+ኑ[+:ob'gti 8@3ϝ7%d/%3u)6qo3>7<8vBaG{~N+vqS#1j6PowWs3:C`yi&G K&w3O]p1M1#Jg~򕛞{G!6/:k'L]$kB(J@Ts`WÀ)s8kΏf'.j=&ݏ)_|WM=7SINd/%Nի] (h7p잯~fQ+_/O9j}ӯ?>76yJ?7k޼O^㤶I}#w? 'Їnܻ} 'I*wNdosK}<鶓:@LK^7u4Ϧ" Qx_ZB-Ռa|i3S1ΠGy" gW̥KbGE0%gQEQFZA&T:E!I-ӧ6k̊qHO3~|w-cQ:έeQ9dQ%]x6LYoaJD" 'xY?͚m^Lo zO7?~?aǵQˊ7?Ǧ|ӿ ;S ;>㥁#:1g8 ;MlIR󍥢(9id;A")h[)fx5%v?a3ޛ4I McPQ>y^$ګ׃q;mN/SgG&C]Y(3a&&Lj󹅴=,fB;_\l(^wpA{dL}eEf1 HRJ)!'.:% l S44,&n'G|9Y!͎˂YyQ;~ɷ寳K~Q> RXcWC Hu8!0B*R ۵rp0bC=<C򙢦!7ZOE ;w}2m'v%13E~^alWe#4 HKb &R!$ 0%д עE?'djd]!oZ#И|, g׫V/_K毬 kV/XlF5H*_lk|%09]Ѳi岲eʖ-[ung"O'/?-}ެ[:cF޸5um8!2* x<p9+rt/T4 t+A\:iTGU,%ډ'8cGf hjtCb֣*qzնq| uMӎmD >ܯI,,[n´!aY^tX A=Jwa:3,kᅦA"Jʂv7qnEMUgdxa1A`osvÊBHtI;AC 2L |PRcAC` v?3`  <G^=+"3k5@S ǵRݏgU- O;\  ?/Ϋ}K]魗^2-'M  \~ھ>6K^zg~ri]i@^/ek/z帟 {%N|]>o ˑg9m8oq[LyfNaqqц%*^o߾C^,utgj@Q'j(w=5w4)BJl5!}4(RTZBI cz%_0| S+O롁 6y\zc}F=ymӢxPm0((] Ψsk{^<~?笳s #d9O$hƅ2E)VN3sZ8Ɓ]VU zN؎>ͿX :DA=^K_=džtIB TGl1쥝+} \%#P?%&qM1O![ǔz9牀uDٸ"8Q=Ԍ:TxiSy腗 )q7|Ccϒ_y~KԞvC>3[gV5]}q4be?VcE$P{zRc8GC"IQFi͘b6*KK/Ovr_?5(6{ޘsT4" r6]zs`LY;Re4V*1S)= 3?֫4'lYK} Tnn9ɇ?T&=Jƞ︆X!=QN:U?k; _#H!ݎ= ;1vAjYЧ=uY8=fyd?hN82]kA" ).{S"+%h] iyt {헟ܵ1[ʦ47HۂhÜ7Ǎ|id;"]KHd`jzwVgXpM+$ZpQm :;gcXszc~ : }k?zɃ?YOz_s8)6/l}c*LgjFɀ1mI\iZ_@" MdƻV~toByFn8ݎ=B`MMY0P2 IDATz m]7]|Ɛs;EBDƁ3ƵűL"D"A 8'ދͮ]Zzi5(LeIԼwʢE+~h^Z E/m}qf>`9瞹[ "B`g$+[D SRS&nCjr:_V)e:ǖ)eDdw +޼핟֤Z^]0uy]׿z1N{ӻ"S&ou^3%U1H}ųG׾ZNW_Y8x>vۿץy};vu {cFY [5.gc_nIJ.3;瞾ͯP횜@ÎH&jWTͽk{_GuJc5tov?\ *^J[_V8El&dcm{ :cӧDoqm;"~e(횜{}_FۗxZaA&.I+,ZZ`ȁmT^[-z{?N:]A)ozrٯsI 4o).*TEkLof 2(Ls\f\ʉ _=~mšN|-+.g/|4M}ㅇFoL<'umVl,nD>RVuqCR HP<^3`(my !QD//_%~;R;iWw/:yV诳m%e;]`ZhnJY) +3?&K Cj{c'{2;IG v&cl cE;Cb ~H,S/!6qf20疿<횝oK!DTv t:SjHV,쓲4"D+5q}ۭh^ՈZ'eRO5w<3,1Ɂiv K vFe 5<ÞR=MόW˟\u}@ Zr߸M>_AOVԿC6&~a8Hp&4&Mh1G\Ego~rAQsgt?Sӳn:c儌bދw9=Ckb(,l|n7W$$}eY=+|vim)/~ןްv/B6X]_6aeם>yr7 繧tjLCPDQFXܚ8w5f X"44߽U[\p@q6-:ڦҌ5oЦ1ʫ#y%2t*Hrs@ $8^(;}1MUӦߡ DzijΒT]mmmM*L`i}XUsSy5۷K1RQ[V/> dbU-أXsiXcFpgod[ rVP["O6֣UkC ZеA]oms±]0^ؓmqZY 9. +x+q'׆|;4ЋMaF"#9һ:젳z7THDU.X Ww+ythNשV'x! zb7=vs*sj%a:7LL}y5x~d:( Y6IKp\ed0NC 2Z|9BPN Y,26Mf= "sU4߯k1 !Y>ئf$E %Rp-"oV5fK.l y'u޲zi|B=? 7`@CiكAqU*k_<0Ks0\GQ:s 3\تfu)p-ߣ$&.֕vGgHR*Q iRT HRXMm]{]8sm{4~i+x6)XQkiMr@ vr%?EN7}ovI$X R1凡HH d! zY#C~:.͜\E;7|wr`LC(T: !Ē64vB ?5K$mYpO=H+U"sgaɐ)JȉH}Lc")H)mٸ 0HF2vkt:Ju3扵o욠uS~޴zڥ@=`K`ӫ @}_o|RQE K}BrmRTlivW]d/8DDK([~z~'XC9,ls_.}'O=UmV:V4 U^!"@}=pߙrE<8 gP ҩ2};I\My^1гm|eDk~αu1k,<0(5~/Y\ZobHޚ`Pq"h3WcrĐ^y?Omچ0LGQEbwr1iR9m%,z1ޤQ2 &w}Qxb4nw!HҩT*JG ~*riotmq*LC9~јYPi_ :) RˏQJFa*JSa )dG6(u-nYW^ - zEgNmX ŭ963J6wE>~NU;` ̊"( Q f1!F̘H a`]uTtw_: 7twU'ߧZ e~^3IܦPYg~o_&x׿gu[ޔAw}]ʝߍ4d~>Y8g.9e6O4=7+H$I$.rKﯪuk${ =hL*L kK!?[aݒo<;9{Ot|^Z`mx@jM;?_n/^ܓ=3EJOY'ۭL&c`D4)?pj)*nFRM7E׎'G?S +*y> )!aBvhzޫ^tpUM۲c Z2!DT:5Df zK}}UTBAa>C*rg|ةKšO?3{N^-v;ErUK%@by;[q-8oKo`Պ8d?hB!T^fg_=գYEC!9h K1- " 2:2Ўzg(Aik^"#vwk/1YáOsڷGVlwߵfz/ ^^x(iΚ.,|'Фq<ߵf♋OL`~^OLLETɸ§֝ձO?lXW}}y/xz 6~9ᓪ#;r/=aN}M-+sWf'O&AGtz`jhOȻu-LYgےQ,};)uҢFΰ(\.cdfJHQHB!=/L*[+zJ )gɄA|)$pЖ2`o:K_-aA@*CnV!B79Fy mR9[S1ݵ)>z;"Y,Fbvd#TȢ0a1݊ B9(easkjn/-!RՊJC8n@[ז^xV"h}Db/Njda*z6 ׼5rfF:PG_8Q}xiWvHS𼘮 rPG`i4֘ ʴkkڴǷAB:6= :/s5aQC5ݷ7-P@5l &gD:L a2D a69[Pfd  pLiWpO~_=$U3=aƽBvƈӉv2pAAA~s!|˓_s9l}LRn\ )H$/<# |]T$<9+\mڗp26w׊z dor"Sw>w92M^뫂O}?MOmd@"}Jut)^ot%}xkŇ߾٠/ G>u(-(c,41է|?}1E+*#f[}l*+\6Xϗuǝs?t̰}jʭI@شR ӊVI#:wڰ~_oW<97=yWLv%\6+ffOZ긏g4ۻ㲀,L>PcNHS\Ҿ\7Ү;'\5*EzoSםzôGcœrs}&Z T|;ۉrc=aKNܯ$Uf9Oʼ<h]2-Ju)p@oHzcQݏ>s׼Q > s'Bʬ@ i/[Og" @ 4VV,#,&$I ~C>Jv<H2 au$)Etk g!(רՔ$@ ?0R+>f(;[ZRekkBJh }L&[BzOTWjcVr9qnwECU_\ .w9;fUޡg@ey5I sw|3Rfw=*+d4}Nrݧ4hFݪ5IAϏ>n~O.%f ޣ*+$+> +>`OmkW<=}N'GO+bz}wqa#ر>}Î uDJQW tإ}W;/G)"U]/!Dr s6|@TBWzv(&/WFΞ)6 |GdUE%51kY[% VR\4yJ夏!sJuiVH@B["ϓQڳ*+is>+fdֳ*+&e]pm}r/QAw@1%mo6lwV]Gw{y5Cf*L;DhPq8gL23 Jr}or(*.H"Zê!e v m_L`"*|=7 &1D`@K[xY :;uQ\{~+eb]o}8s J^£jh^\R;ј+WeŞ];ٴ=ha$k7落_F4=1i#gʤ@Nd1;٧A8o;Yqmf@α矓@nA`<{4r<@sʝ`ْb]yyدjxr8M#@ы; #UDNWE˄PND˹D Saycj]),\ S]j" B_ٝӵrXr݀XHY{nN=I%1b W5<34"-DFd E1lKDD== IDAT!c ).Cgu8]1 j+r"]=h4Mm5>\bv] P`7g-NnM$"ڵnNimkI̛zݚ'k˹究I+)65p<׌O99 *wV|71ݚCzv#߸os kb&t& H4ݷ0[jnRfʍĮuMԊMSVi"dIn:{I|owHbM>DnwGx E- 6Cn*߈@5)6dDpyZAP_V\l.jrS؏ݩ)8GGcXWtm5mT&UKk]NyI(qt6h`f7fJ ?yj}6֪o_rJf)s[}U$HR [1>+AdPC5ɼ,n w8 g<Q%_}_H9dAE~.M`뢕RV/ԭyRߺ_`NUBҗow YO^?f=_oz6t:#" ۿ`•U r:q$I!%5̧ <ݾyT.[j* ǘ\1fGIYhkúyβԺw Ym;64:|B&rp7'zD$3qR(/z?RAMTtpd,yl(o|$B&[߰v$IAORB=?̄3-!;F«Ȫi+ۯk$"@顝 ,\YPw*wTxe%5l),ug =:[{tΡ,_ױ[$bR??*7+*jY6Sϳ+vI3c4^lټÐIqXY !]U񡽏_òjQ⮽?FӨ1LI3QQvS3[ƴߡ!+oxx$BYyj~c~ AeX,br> bm|d+Hެ VTJ7Ԏ bvXƷ\% ٭a,3,{fk*ЯaY=gm@".m|{}9rô X6EUڠYv>J޸xUUū˪K-YiMqIIqqj0UknmxXעW+6y 1Ձ-hӪ)US|E. ȌY_]s//6s;Y*SVo\[\x겚y~ JiWG#w>H#ȯX>*Lcm8c:N-c]gfhȐ1`SQr$2G<ƙO2)HCycW @&;']5mG'ÿNF[iI Z!Oh#X 2ٍ 4>lRӋ}VRdܡp+TtSG( QN2CΙKg?k}*et۴Wuث]e;J=yu;TTLQ}+/_oZjR"uޠ /҅ d#-'>3C'(t'ZxaYCihU#3H! gk^Gk;{]tZDx5'l˹+udm_mC]?n+F>5ch3z6h/w\y>Rt= `#`*LaHM>^lB)keo^)8gvK#^􅐈v'=бM|SK j CJ-€liȔTm@Y38{z uhԷQ+22I"mUgr `紊uiqRD0SW6gzR߱BH^t7.>UghߦAލSswn,^^aśww/×Vg%PⱠ#w7(dCH&ܝ|DY^{ӮQvۆIi~5koK}YW⸫/iOW#7L[)z#J]pSrOohٝ7#w.T[_ޛ.fH㾖rE5>(N1Y>7omg52?_[ =WMo#f׫EeCϤϮ!XŮy2DOB\Ef)0BHz}‹7t)s+Nvӯ^|KC]=Kݗj+JV4w.QkU]Wn.ǍaNT@H,x;, kN~{M ]zмA}*R2 < _DhѺ6J>kqܠ~K|>EqHfDo[[VpfSO9s"$ "I)(1/3'!"J>|wu+nl_kQ:y)mkل~M\@}~J7貢״[o6f}7w _VkFv?7Z6VpsZth(gIi֡~ٻV&X8Ek'"TXe& oѪ3H`R Sd)"tqȯ/ꊧv_\զi+Y~RJ.R~sM<&w,,7| ~k/mr'oW=6o}{zډF?חm_!S˔)Ch2bȓS 1U)#Oz'͹-"b<.Aѓz?0/yۛ׳ qÄ!V爜Guy6`5O/9"gu酪8N;cu޿󪇾&H(P+l&LH6'S//R'(~WWJ`냮ۇōyd~}1#e{ jէӶ^MZWzobFuǛwzh-vuI"M%')ŦFܺؑLZ+J;%Gz S@/8ꗭv7Ƽ3!E-%β60rN/2txݷ<BcPP[8" ֫+WKyk5&mCޫ3Wï\e~?uv\~K>GiaY\sϹRdO_7T\$Z'uK`2-> S1c&ŕY'un!O۾7^YD^4$gFD9nai[K&۟}c۾^,NE/0"Z[T6PmV%@--^۞9>Z~7T7w~fAU )&ʾ>?](#aѸԂ%H7eY,J8c k] MsyK`6ݛ_kN"'zĽbo?[t)b斄0'JcfR,7sq 9χ"ThpU]ί3 x Cb1"zP1!L.M%3%ZTn #cKx$I@S^'8HoEf]t5`lE? pWK6n\2rAalUfID]ULjL:\fC2&AJfE9S:\m.u\Yn:uW_m/}<%9潖9-QbQ21z7GD"*F_*!-`,QRe>%Dh(Z,DtrJ%+FSMk0 +% DT403գnsVAVX[+&v뜤&aqI#bLꇅ8W~!L1G|!"҂Hq@ RR9":‡_ǘOHpQ sKVFa|*7.PWC9~ RHh4IMTzQ555M5: 2d@!R8۳:͍'|x(\H_{1J e#x!֐ V{JRǕ ~<';.D$$lMĘٌZꮩCSS\[ikUlgebI]e,DsMzeUgk1Z+:Ud չzD$PZw FZxI7ll[A!2IIƷX1w}ELq ճ9]& G6̖& Q*62Sa'|03CpO!w :<B}qlbsQ@%<ސ Un1dJSCD_-x-Ƀdel!D´dtGI h>b6hVCNF !@2d0)w["a|,4j("P\2T mzE).I25@B# s&DCD6."%g>R7 Iߴ} H&Xmm- [ ]5 4|}+Ș) 0=ﴫ{:+T5:7Ӈ`ȸA{L4C5SS8 Oœ* yPfE A0E9:M%ąJ鏺2T4o3^E#"Fa"#B` NC,nd \!fGQUb:LWcaK3z5b.9f?әEke: y"M4# b- ik\ ᚩ *; St7#]՗N; E@Y=a$P7L6^TZsD&%ק@뙁{\`D"!H:9ݻ # 9LH? )>ƿKdWqd\eX1@V$P<9HM6k +FX%kR-,q B:9 (@88AQIÎMfeqM#t#Ȍվq-3vF3𲳲 X^3884h$fHɰ@愐đ`m$fre"宊Rj-+~hku#:pw{XnvX.m9խBW*&@FCB  s\gNa"][Jފ*@ 7"cJ刱j1W:Ȑ"As\Q:<}-HftēŦ͵ 3mB n6 KHpQKkFfM0-Nu 4*$X{Cظ=$!y9NVDHR ;J  $Bٌ9|_)ބRaeP~t)nŸMr 9WJE֍ %SAi dH ]׋'{"s#OКpB)28&W5/rԺ3,E֜k6rI4 )$)DS,"fQ).$e+go`F{^2i(nEs \X;MEXd&C5)X'>jZ}Bi.tN&C+Wt1M$/:?!8E +ErFGV04D8cj2 ܸ#:V#3GZ)$2We>$Rj!L2L}(3.,ǒuƌ Byr4ᢙHHSbYukgs$1cD5, ƣՀr>du׬!3g6_se;L$l<}SGB(Pka Ƭ(YF0U"J{~x1Sb.K)o<{BuL]BB$I1q'TNb btx/: ʐeHBň2OCU[|fz UʜC$!S):aTzuuùЍ(FO U]0DџHcӼHW0ǡl|JNEqƶ5[A.qBnmd!E6Hq;S$F+lD>@mDBR&0-6f1oziO t`K]#P2П񴸷)uҭZ99(4~{վ#$IB?Da4Y?8r"DR 5pkT ҐP9ݨ= ei$9n9@n#"iVx rК3at*O彾m=ڦ 9(U{euԏ>uxzKEYE7)bkc^iZ59$u=ð^ާ/ezs( %BdiWA1|C3tM5K닕XtE`$Vce-c3 V B;[c<?k1c+'2kX;Y*m/m<9@*}? x /++H$yǂ Ɵ!8:Nr<+$}_Ղj%W^h6Sޒ=4i>!3f}׹~ gNS ֋=H&D"y soBRq4vN8Zԑݒ(Ƈɀh(tJ QDT*a DX"% &X> )w*k<= :dȒ}o[p"'DY sylK,XޠKpv&tL jEC ưSBֺV]7I! PH&99ىDIQ; @cQv$Imq2B1zXMFl,yf+ 'O{R,a"jO?)S$ <{ ٚm6t:Fvx;|YAq҄ƘB $6'PdH7.t'a. RnB4RJƙys72fa> u DiTՆnI+9 Y;&h{?O=93[7^ޚkat C5~m's?5o/?|v1 D2IDxiY-8ƞXnsqu( s'>q ~1dh@F]zu]ױ[vhmoV1e,P+wȢ.K^aK05+mdQ`HiZ_;'Q#+#@P?J׎ <<QUju)1Bmtzo]SXZÂ"'I޾-o(~Xb},G ȔS9^vcvɲw1Dƛ]~ y/y{Iw_լ^d_ 4T+OP2M㯼*լ=V:K,'^QTv\h{\th!l]CC|Zcyz0䪞em^ymQ5ixjT-XNf0́_k |ώ7=|ఁ߶!MK>3_/Xy݈Cƹg%M>Ϻ?b_yw`뒇9oº ҭw|^Gwۧ /~/&^>|pvh‹9k@䤡|a{AƹKjk;xq}]ŒE']wiue?Ȉ?+)#|%V@u©1<Һ~PI7v톍{:ZI fB DA$˄R )LAv 5=ܚ[A(iC׊11tT*O:{P[ĈǾZ[j9orC{Xdg<BIt$[E1ҀHѼvr:xl]|_RO1Ky£_wߏ9e]?SZO@{e_w]n‹{zT4lWosRF{]7~PF76ru]3ހYdHSGϸ QU)g3~ćľ׽=m`Gz_J2&S`^+'sΧPVTs P: "lXZҟ8Y@(J=*2]+c lFw, !-1~~H}q+ sǚ̦gD3\Oi:*Q^_nӝwʱ*hR@a`6 M2ۨ˼0j|x@䠽C5(`Qfe;kM((BF:2c(l?=K/|bRI&:w>˞\n6kɱz %Iy:59cjsN3a&jMw<'J "߿!{:cDČהlUnLHOCۈG/\)/KUW^"u to~VB!Yh\sj؂v:~ Un;l9o[ Sm+%d  "[SVۿpؗm y~>.ߎ^8ug4eY^GɩwOysN95j|{ $hu޸Ú}?o8͒ fE.^"[Dz^ Q 17ssVT-ks~9uE` =}tTWPL[t]"Ā+DIݏ "DP?wC7DVG[YV]J959dEg[ܬv'pꘗm{q<'_dIBLB*ݖU}/;`>x?vc?gV[^8n w?sĒI"BJyHXM!:}gwycc>v+^٘}kʫE/'sZYH[૫vRu/ugZokvϕh`TNs9Ջ?;ۍ7p)olKF[M}r]֖}tys8pGna,A(CcM|%cІ} *HjͫXsQwTnmm"n5k%L0&AU1`UNU(Sc7$j+@J(?C61u+ l+;a]*U\Dos:zj Zt\I|K3qM9w&`VcXe дXbM.$k%t?"kbsЮZzdܜ%SkE%!ljw Q/]u޻zs,~w=M?xDD.кfDb:(R gk}}Ύn-X ^#"gZPƠQV_[gwA5qJKVAԾA$ן' < ٴw/ts0LkmEsBr7nJR妱-Ataru"B0=("3?@9Ps+cG{pxY~M gU26zizBX? "Rb9~dZS31 nQ 8q&.wm`Qҍ9 @!hj"k%\ !o3g~å?DDɶh\in狆Ϟ6BGO9b _!9h+, V>闄i]zrSoۖ}:qԨ7VJssGeWv9nHJ;|eB[ Y R ]3DDM9c矹ϰ ̭5@Yz[B"Ji/XMw,צ5]ߥ>wO^[GR,]2K{^$m-B|l F)m ~\1"yt#\yY.Io~MkH>unS>LL:}z3LrKie:2ZjB)s(odS\y h &i݋:ʓs )qI 1,lF|),qQV[{W99 b@k""sFT,FDń9DA"Hf|Nw~T3w[oֺ.aUoBV 餻lzի(-ӧr|6d񸥵Jm__ ~g\8mfw<>mGsSֲc[CNߒ ~3Ή/J9tjiU#k{;$§/NׇlΛ+ޞB݇[J}Pۿ6U}맜-|QXƣF7)aՠa6V  ;p˳n^o`i}:Yu>pWmO+ITw$/~ϙ,}ԅOuS?_#*bY'=ţ㟮vNXOa֞ kt^V_> x3_ya>/~ Pը.$r?24'}o!W>jXߚ-^я}{"IYvRch*fBnB*Cld5Mw~5?캞zW%QΩ['=+&!郖tLS!@SƷ9_z&?;oKx6=e+Q)WFW.j!Vms7 Fm8Tn-B&-qIlR9X L;M/p*T%"MF? rF6r"BjGlf~o8= ` %BJ88=5<뭏Ӑ?KVLRrP%답?]]Nx}FLYXNjVvSCL⭇>pGS.wȻ^_s( ~duTqJfGY?2d'{g:te bY1?\%Ptb*^7qsVs2)j27lX;bT+%Pb_铙UrЪZ~MoY3,JT 5sx oWUK) +ɯCW*0j7 64*1?TfȌe`NޭTgg/fW܈Q=rr|097HZ|V@qHwY>5{yHV&+!Pq>TUU RD`q)d j,T=,xQ9kެ5'1m3TU˜o3{Jm F"rwW FYeC5*vsΒ˧WW7k2bfo9FZ vQ.Gy,#3_+0Ib1:x y,~'6QNnM+_'@Iy<ΞswV cn -݅> FaLB 49]r=Uz}Ok>nk W{:OCNsS0nwo?}j Dm{ ]Ok }r]XEVUoՙ;dr}ZXݖc6=4M9p=v"V|w1O:ٝI-ҪXaϿvakbM>Ѵ.cǖgF x뎹Ѝ_1<\=mȁ }li# ;zy=Ά*Qq9< Ue=oyjC~/#':հE&%{;0\hFHs:ӤbOI`F]q}kSdihxm'IJi͐lSiX.:EUB=3!ۨ,NLeqY zY^P_*B .xeg=$fϐ ԗn :{w^]Z(ƖC}mZn JI׎8* ZofŰ6EsȔL1,B cΝCg>va) 𸇮٭ڜsM3VW :f@[]poku-&<&$_@"u-y|cq"tkг֏,6_eǾJbVwn1^sژGD)[?rU0ߏ{{ KUvH}k @b[y1Db i+~O vۏ:^_ݲ(dQ]ExV1,Jװ$I"'I `,kSn{OH{ w{ktkl<ۃMCbԪDZVVYl_u٢oB{r+GDuU.\qдAQ^r)_޴d c{]n^R$4޼˕GO۞{OOx姥[7ۊxkg|xuKo:ia 'F&PfB dF'pK3OQ}~{@d",e}?;q+VS V @ۊN5ZY86d1/MS<=Qlgqz#@Yٖ_F s9S*iI 0 i6&u{Yk7탦']tO?[}%vʜ9PQŞ28i65ho/K0m NY^,Kew; 7?v3+˛ }{o|J |.am3Z?1VŰ >bQYͭGݛ䦷ܤivǷI[ f>:ǝ@svr/]_ ^2ܩ0>+zr/Ev>D߳9cFAI2UXk_f"mjyB,qTlj)/߉O| 7fP(j8J?ԲM+X-]!-iT ADR3@ٲK $?(1+ס7go2yA{qӢB_]kcRW6sq @B5꧷=z3+Sn5! a0YiQ0:\yDmœrR9P~~rsȦ9\$Ƣ޷9@Hr1* Bda¥#ͻcF(BFH!Id=|xUO~=I㌅D@צY|}^/vmZn SUZrd՚N™/%|/וzugCrJOۣo}' Ud-9A >贖lQcϒyhNH=-*eOOy0wܸߡ1 z®<1yI͂*8OU}7|Xꔮ?x~hIqmi/kصuS>!7)|nMO_e+tEFYWywD_VE? ym8SuG&[D FKHB)6)PH|u #,MBX+^`˿IHɑ.9O 4' *YA#Y"kB(cT&${D=)g!CBx2 AF;kI@J%LĬR7MKɣΌϹeAtg)4P1?!]s͟|q?p|鏻+b;6Ǽ{| Qcu^!Cy蘻/9J ELؠם^{K@5&{*yˈ^eDf$mlHdYMU:=U028XZLJ[;67u?p: X,9M72{:"jjQN0IUvR|d7Q,㙑[OXRF;ooҘs{i.}Shټf&wwkLx,,Dfn:KPʿDkS1,uH<U,$ŻN08D HsƝZkVdMkh|zhD!fȜs@WmL8k!bb$Ad622|qGAykE3)?V`P[ՀtS޺nҊJTnu$BuUwhoy gqCz~ޙ}y{4I CErOЗ3/V ;$H~6`՚w vOd" CQ2o֭Ӿn{dQ/o  suzڕw5aԆ˞ߤ~lrǼyaI''-;]Ua_u]/0r #g z'֕+v<}eGwl:[`,lgk'I%W&!-3&JM& ̶X^?B;bڶ(i[Pܾ~_CAjs1w_rfFf_ݚz(ׯ-&5gysvUP_nE˷IƱz׆};4XhSn6 zrE!.7Y_//|1!R (<~~B'{Ĕ|%(0bZF)ٳ`#zu%-i'_\n*I'xK ANޛM\ZUg2ƒ^}47bmݺNxկo$5=&?و[MRbtQ cLBoK:MT5pF ¶NDRFI9IDg SoO@"y1JY^s6t^J)Voo=eW|٧?-ׯٛtQ>}}ӂBi/YC{qP~.;'= ;I=?:6(7\M e9U+ )գz-rp/r5 [<xhҚJUu[}*yH=LԸO?bUW.s k?F\t^5oY{S[1&ED@6 U@v60UPuڴ>KػySԵ $HƔ#VLPYvd\Q)l-GL'QK) PdFO:g6!P4#k#6BETU'|q8&ph\{ d+V1hP6SRJ$Ai$: =qp4󋌗bRVL&Wcs4"3(!o=n{߿x]D.D.-++z\cUO ={t)g∳_pլ=H |)BYon,8c FmK{{ UGwo˨U+jYZ7guLNIlus3k">~P+8EAݭS5p]-;[͗*%*!nMowL FNn:xJ ){݋Z9-7YrŇ͟#Rrʷ,U px~8U]& dюM[ *&kht!̅qq `vlIm374"|ȏ|aX[=W])z,%.T,L$~VVdʞŚąPÖs1)e tZ<}C.Z^$xɂf:%mۈ87<$3:_CV "Rj8h~H!58c rͧ-@AV?ʁr'mdb^<9ZS"޸敭xat6Vv~ӡ%ؿsS ]?u3]ZTB-uK16W_ ''l׏1) ݛJw߷1s^eK,n}1nCBu7g TG{n++aBûCH2jP;d1nµ񘒉sJ){^8yB$a37e g*Jpc$Nmq\;5AV/_ ?z?nHk !l[eϜ#':՟>)V3Rn&b4֜1NOxlɎ*(ZJ!%I܉W<%#G<3yp+YX(t|o!bkвVE+ZvJ3. &m7*K-6Z{aR覥2bwⅯl}ureiR!m8gr,C.+[/}Q_BdgxwwL(} s^ @V'"g#e0N%=8c<^V[O<Θ$MMֲKsV[Vn%?㚧Ěv;2p v-^YAb10ZQ0:4:G 얽M BIgřw+!xV;PPXL?D@hLa n7WXvw?) rXfUɢLuC %P_ӭE,NQ] lE!G4Jn?`(7;?׸sN_$)!q<AᦽY逈,eF_UC99Q2w[` վɌb z1+a~ 4D5)gڍڊ5,K\w]U2sak)sg;]1aMe6%?ء<;~<B=AH"{ٍ5oza^4KX\;g|Ž?IsxVF u)ոas!$͹8m3ќK)%o5JB*:SqjֵZxSe9D$)Y㏖h#K(ˆ;|[I24kY;mW'2j쪣uʂ\4H|鰖^4gҚlHˊ3-*1mԈGdG6{mK\Bڤ*4Œ}w4F~o[6=;0r%Išx-H?5o}74)[tTɲWI^co6 FYq*N.F`s"}9{ü#2@lzT>?zrӏxK 9}*;q03u[BUћ.λP-G ?dwj?ors;ɬ$#!42r;bpc^Lk!d2fNzco>aQd綂jIq@VPg{]}%[fЭe~bY`ԩqg,srV~!6Ӻ3΅d8I5ݖ56P@vo]^vޫȈ7pZ$?s?Nr'l1K~b+MOH 2 :CK z]/{ڽԬ%{um/Y9:]n9L,s]yϼv[ڴ2]cN.JH?CYfeonjf82,oˎIb:oӑYey[vhp]7ey{%+%fsAƛ_bo$~v<+xa使dZj&h#7Q+1k/qҘGf/é;*`^KtήV1W#15W&% q`D7 7w<疋Z"5S#pCn<52ޛSp̕7wwRr;ud9 qld%|6{ŗr/O/Nff|:͈@*X:'=_+7)8םߺp֊B[* $WRf!#67ه_a| NH!xO|cox~GNGdU,!fnj&]Qm~@ڜײ.MOwnW))QkrbMy˕m-Yyoe!\|b %ԁhG)~%s(vl! @c[>~o%Wqي߉z봏7UZHY&9d&38Xfmg* /D2if1?XWo025ii]Ɖ#ok~VZKGwv: 4{<++K'}hp`-?&d$"gsAO|oˊ *3Rh,"it64x׀/*z_F# ?Zi1)X6Ǝ^zlYg/x9$`iV1H$} N$I!ҿlkqNZHFX;t]cKЖSq/ ARe&vܢB&Ζ9mݬb"0UnGd@DDFnzC) #ɑHsq2h )@J~;]OQot@d/$"z i4/]H< onfH6:'idɆoMՒ1OEwW寞;oop<yxY~=b@DԷg&A9H zj`> 7^g)dy^,e.oָn^%KilE>~+i!:""Hyj3[Ĕ3֋9PW^MϾ6}+Lnxߜh66B}*)#0#sq}O@ȴAF3>Nx~=M\Hn|ֱuyrwnYn7 no?7~ƠV,S>xCF& m @e:o'\T9e\{O3^Xz={,^̅E$)+18 ڧEއ ,Cz7hU@1-[U IǫeMhqb6 KWw`o Е,홉0WuqɫSP ˤE/Ee9CGsq,D9O^7eQ1z<(+s\,A`WG=mCυ#ƀG]?~907]6?맿?ϧ/G9ciu~2oyc3.KdOf!e@nYG˚5l|7v`7c D/M P 7M;ցNev}[~nOLzۓ'mZ#CJ.[~ɕc/mɠbʏ $Qӱ7 tX1׭X[F 6SAcD0ږLlz/lL0AEUfd0b^ +77ߋe"8$,6ݟ޹Ɵ5X?{w;w[&hz.>[WQ;WA3؝d1^xzȠ?HMR{&yp)#bh^DȜ1ƙ6!g O³HT5E5LJ"bW[ߦLZ="*:GqۣQKKuPmV*r:'=mE7^3qh/*l6М YeDR8S$bjz];&Ϟ΃Իr̤TEƺC}U;5Mi=b4rjcw#¡zp͇Y-!HhVqJYOGTܪ* N-)"%R#Qb "aBB9i?18m!2άݵ$)?y'.I# ú=aGXV(~RJz@ ,%V=S(QxPT`@0ׯgn DhF"도DQ¨JǽBpc-)zpOpODhsբ @Gr/320"E9bLpe@jh^‚CN72ҝk)SU)`լ0BVaq sIZ]ԜhȘ=Pt=԰DrHRDy! =KMK2uƄ#6|0g&i8U9!c$#3S26ljRZ x˅6I/N TU?{3X[!BpR.AiGr1ݟLj5i՟9^Ld=;J$qQ5C,cAH&W''GHY]]Ǻɤ6O;,/J&}0U桘LQT#4~eugZ=q՟Ɉ#^ Dn*"cxZZUUp{UUU>,߹q/WIzդW9"\;ƹ䲘g֚AhW3Rm3C7BFnc"Pp(SaY3*CHgcL ǽ "HBEcI1NP٪l0$?!sKAn' z(Vڗ' g9:8/yi3cBMI_k!2UVp΍t>1)=zKŽbuΚ"(aj ژS7*ZoVJ_a&٢\29Dg*$6Kna2* qֈ2$$'9Dn۟rR=2N)KD3S O vwC2sLd̋ eغ\WrdXw1G.@O!0!+]IRrk)bzE)+4OߊZ:[p"R`"1|r5RMqOPh⦱]nuVu  Zr`'0*pI!x SUR@ZzT~(vvq)8 `q;+I#@@J+9i^ڼ9cK!Ff FF6Oޤ_mSɍP,GK]: ]W9zO[#)8N G(^'Lj1F!!dݑAEu5EB%>POn[BwY=*8LJ^ՉD,B`݌]>Μ}IT]1/R١d .M9ss$Ɣ5|v,Wp8Ĩ f8JQ/})D:)D,)˄59&XI)y99;gN|}2Z: %Q DBcCpPAm+)O?tx IDATH1r\FP-E` +ǹ硉iA)dBI$I?ۿSM n#>tѢ0]v<B{H'LՎ`-/j2ugE4aqh/wQ"AH&71rd\!5Щ@&%wG-y)/5USsʥJёM53gμKslEe ) U.tg ب ;S3`68XN+"Cr4Z*rm g 59cH ɲ87f7kah7WD/ή5 D IS;bR¦L(V5(ܔ[5!dxqLʕ֝2̉")D2Q-$BI 3 =:햩dMxܭ.t!3D6Y9sk֪z`1!qQ33*e809|JkQ!ƙ jmb 3eNR] Oe;5ojZ QyZ ?w%v9߮dhLy4oZ]>aM@qX\8n7E"+A<2G$)Jx0۞t`iP{[a>!/$T2C)%_DrPiOr#L҅ lT;qӦB1Y:X{!SUr|BБ ;#c[+:'KqpkIf,)+|wb~bR)aZK8H:pX2oÔUO͏0^74mDR8#!CN{J^P*=;L,@)4Z(Μ(Zc)S"4\Qr*O0T4hM3o%Rimt)uFш-tɟ Y.l/R  *]63ť+yzvDQ)nfɛ~yc̶ƠŰ>(|(vTFHJʌ٠lT5jlo;B]|DTC0MEh+dQ꩟OOr(aIsG~Ğ6!K"^qP*Ԋ#dq B" t 9ԔG X{9/ehvXa3`eY :D0MBZۦPn<@ f$i@CT*a\>/E,t)Q=4Fѓz$i39c^31xt*:Q\ =5Ommu"3T @(I h>9~ѩ gېK@Y&79C6OzoQɈD$eّ$/QβSjK)HG]Ɍ C8~rCB&gcLRX0aդ5$^ig-!*$cn*4[ƦH%Q)K (1,,k"@$%3rVB̃>`,vkNґZ@vUnv % 4imvŴ2,:dE#FPUqX9 HҲklS̎]62sbZCrmht) x񌌌 ?A"[ekg];hL1EWID=0˔L9 J)ؖ0}!*3|?1Ct"`vlk j̐I"dH)mUمp\HME1IB fwn#r!I@T`p$ED"Йbj'8Ȝ(\Nfwb5}gҏq\[DP`0m(v$avgMa;o$LgK6?EY=Z5CYn٤[PB @CLmc\I;*n3hm%Wy _ !?jsqd왋4 &xdjaA%qtKp…q 9ZmيZYa;|r+۶#nt'`Uo H (8  '-c 'N6Dd)؅@-q$`3'ɘla;cȦ1Y:ZAuUuZZcKSB41Ƥ %vSvZZvzP55D4ì[]HKb-].cLb18#Ng'5sȑ{DxiNѢ:")!֛ RN# #p%Դ w%e hEM:hJ ĪbN}#fTkf5%p 2Dqȋ{S 05hZPdk!8rPc28cXG:T^w,0j) \fH Fr"g Cc4.;c2-D`yD^0l.DTY1koyRRPFQ-վۈB-XL1 )njNXj\mYV@׭oP'A:}s/+S%dWֿ۞2iD-.] F<b6T0 @ !yrl>C֤F"8WJB$2"A;Y1 dž@D,zsn SRַOklJ"BHc9gZ)\>Dbs}D(*"$PJS`)sT (OP ?95~ Hc!thBl2NQ,1lK Qd$Q M jQC> 4P5ܞ¤PWevc!JɌ^QHPYO aC6eHpL?Dr D'Ek#Պi^2^5qjPg 5XD,da::DN0}d}dSD,:`1Di$KJ2wghY5it'A7AX=4TVd$.53գN?l/e_=x\uvW}sr 7ex):ZЊ#"Ӓ; NE(+:gRTⰩR)ENl!zedefff(hP-ƚQs(g)Nr=1zɦ~ Rz$%W0qb脥P;P{]83E/BєEڃ;BkI]C R{ޡ=bV$ܫRjE*Kdž9\/2c&Ϯ޻w<ouʎ;Z;.OSv>xhCߏh]$,E,W Ð&B7]U-4%R˜Δ&(sg~T1(ACRfw;߅>~nÊ [,upIw[URi򹠖;$2nG3{O\J:.a ]MTUxZvvu0 CRps~IaMZRFԗPST4!l yDs2V69P b^RS mQ֨8&{Oۏ6uy1h@DaH?IuJK@rVD sՊB@=8vkF4=!D P).\ = :x41K"qՍ̡E!놡z z u0^$iTc? g!rVDJl p4?Ň]Pl!T*&LaLcK ຮ C`h<7ae_D7:&'a 5?B.1h{k#"bD A)wUq&mGAc*dڈ=urZ}IehuPJBI_v呆Ca>H|Z b#94yrK&v/!w>dDN^fvJDe]u_6ygT\-V5xt6 S cUv-/?{ }Ӄeew*JnZR+=Q_ʧ,A@F]jRF˛&K!*؉)k~;jSq_CG`qY/@ZAp'C[]+Κυf.J-$:ةG x󐁄[Tmı/Xa]_!/?6 X!#ΠL#\_3+V=W䖯$%P2XאWQ Ƒ]@ma}Cp!]1c&׼V[O41.Z9JVY2x۽[K_`SSK V*/Bpnyo3:7t㳽pPަÿkN1lio#&ݞRg?<{tm=FRR!a"(jLǢi}Kc+>oA:Ra+%QQo/ϱ?3Lc j91ͣ GA< z{g>#h3&Z QPi"W=!xFJ%b{VlJYRL?&b^ Q؎NU>`nYTOś[ 5M8HPAx#6դr$*44e`3R*qR@euG3V׫w;QӸ(08F4.ZJ +DQ}c6uk0Q98ƿ]s0@SkE- ]mHщRWT3!f:G [|`4sEJ2r~oXp/}M\9< ;GDY'aD/0y~=ӠsDTE 40_r.nVVXv$ "v{pfEZ+ᬈmW D P$jaObG~4J [8:>db}過O<mJF)5r7F~Y9-敭\E 蜥.DްQB%^nx%PFBq4ئWrV̴ukXM9)07\hx~~%|ӷWzp&$мoG٧Pk-a,={@aNT;Q*qtS' SF//X~b@ Co )r=GI~IS&MNo*_vwN" VvQ&Mx_;n\1m,ao|8?2`VrR;r%XǾ=SM=[^!j[ %N ػ4Z4 ywe$DcԐI7/v8^ktzqs KޟL~$z٨-OS|r[Sf"v3ue-!dRjN]MiZHU(tΈ8q8RfO/$:޴C?Oщ:u&%rV?"}D=٩!٨ :hup3V5:eW2|f\N0M'*^}_{lG~ryذEi_?iF\غ?˨fBO,_~l^}x|м P${PNyM[gQ&ITy%}Mڎ"4wc^(]@{>:~_4fK0mT:Cup=M% (W(¡|[o!0NFM"Ѷj״;x Wr.+1+4̲T8mWAR0ޜHҁ;dLFsǸQn a7zcG7 NȬOl¢:v-Vhqf WvV'$tJ6 ] IDATwҕEpvE#ӡ̠0 a*ځ*  $ll;<'I%:CPY*N44SdWUtL $BE`,j?:̦*'9=À>ydbi+@lFO d86%-(eRSg[SBI|k7{սo`E#2`$bÁ䁭c K7{M:B<͞}'xo|s_5ޜs;=֓ԓx稹k?rl/_^ j[~ȡU4xkc1 ˂#=>X@X[iV^涣:ywHPJۏNuO?}dE/n$X1:Z."#u^I#'h)E3Ϟ9} eWɁϧ~크reȋ6}.w>qiѵ{cL`L! ޤ;MQYnԅTQB"5>ETiM"èuSṏ%/*LT6V V(7 ] ѵQ48(/ء7i}GrAFD߻_+<Fzca֬N)4Mx4Mc"@@;gΞU6y=R ^܊ﶞ>egQ>zƖ$UlܒM#r ]hߔgv;:ߔȄгv|w?rf|ukr6 xIs,Umڵ>cKlܒi(]|>)9_ٓQn)@sK٫g~79Mjf>oݶnMMݷg|oN֏V쿐v]hطU>rGRS%5zf~5SR/Z~|< 7:˂}v߿=k3E{ _kV|::$eZ~WSks_s.h`XR 4oov<{q7=O'F-߷ ),Co=~蟛VMܦFTQBJnڎ8H]Ʉ@꿪ϠN];9yϲ_]jܧWs7sW<|~NQ*.Y."Bu]LJ%£i̱?5ݿiOܙ|~__j#U̢jՎX{ zzQi_p~)K>pU>03gϞ9sLFTVơ ko,; f.߰kMNj;뛉Қ4Swt2 Js#돿~.i75Tgصt\/^&']{#@n=9Q8)x٩ڏ}7jh޹m2Y4}LIe":nSڽvxB_D]m'is\7|eN9vC)1"8 \ Nߵ}_w><ϲ[{7 # DTTTDTuݵg^a!)σzP`|ow2ѱ~`oM9{y,_0S<wkvڿ:b }ސ4с}9Ye_Xط7>Cn˷оMv᎚T?}}oʕO'ݕdĠv^Ɲfi+~g>u}wzg_) bg۷Ϝ4=Ys_Nhon4X~pbnzۜ7H~M^r͸MM/(/EYEb5}Fwi2Fԝ͊UuikM0ھ~-xz%T6o潭K]:~Jvl]!ą 9*5)TuY*}%Bu,f&;Rب ǯ}x'ԎtPHR pɨ0R4@DeJ<-!B`P!~EPFVBzQj>O_AAo39DiWT^qtJAZV˰Zuw :MVػiOwF|M@;.`=8iוzw,wt_g˅Lظvk;` rM-2j ΍`0  (SF:{D4w#' wki} >}ӷlf]6l|t¸ J(BuC7$`1A\BFmM p~΂tiD5E{$U e $Q4MhB5s!4lwjd!޽Nxf\ƨ1F-M 3莼>'0`]M ^Fs|cO{e֫c }Bwӧ4{iєPFªu}OuK@ۓ}:c1i# }s^.ƝwĹ ͣc@!fɣ~u s*Nh<7ADy@}%N XA2*!`lIEA@1ͮ]vf%{tq}=F?[v&C&k=DD >]XxӘn*b1EoլbtҘIY27X t]TcR&}eu(p=-Иf'ڗг(ծy,\ڨ3n/CIU ͡!#_D߾K߾1.8Nvg{sӮt{Ŷ>]u?gz `oʂI]|a`OaW(M?CW)BLʖԂbf;bhCKL CL"Ǒ[6Nڔu N~LYe2&|0ǤaQ9 !T9TM㑪gF-MP䞕&_F蹌 mF5϶Qg.6G T?>(ډ D ?J1pB/#^6Ԃ[J;q8lֳV+Sr`KXGl, ɶZ ok=z+@cyϥ߽dWѺ׈3gx,-ϵ3ߵ\D-ЌkvCwk r`yyxHC W`ɾ_}bGdމ=nq \ %m' Q'K5Q~kq볃iG@R HTfjP\tЭ/9X\4֫ 4\m^ dLJ=wi|^SW,kU7%}WECع=WB>_LLLOcz*& 2SW&!FE(9F0LsY'eo qN2B\t&4i$.23rbB`0hpRh,+=~RM}gQ5-XʅĊC *YMzZKhCB,Bfego\0qG??fiz˧gLRrNw.d$ w}"wܳo^zo{@Gק-iLZhI{ aiW{Wl߲r>|vR'ކZ8F(W(xivې۶f$pD  :]Խ證^&tXK( X{F~{^fsutPa%Z C] ه1 > :>ګ'Yn\sR[֥Z anoPޜǑ3;]y6@ wE=i5~mP.rS!Njsi|)4%9&/ڗQ+.ݸ?/uݠOǩM gl.#@(e$̀nQ\s,-ڙk @-k"!s-}ekRycӜ{kUCLBic!YFw-% \l FC9'r9Bp0rT1z=^ S"]+Js+Y$!V4 [Iwݦ0ZbMU1mX߿jΥL6Ӵ_rB@KuP[ueRW !sK-CIy=3dgJ\?(f<45v4!#hy'mN;j//yDBX|%W(c(BY5 DX*yohCv "],ReOy;6F4JBּͪ7u_mйG)448T$P1ӓo|NuN|Z)w]J)UHF. }zrZGH>/bg^52}׿sN]2 ,*8FuyllãfCT " WIl#j+.\GOfX{FFs{):O߲}<,x25B߯15zGEr I9c.dK%?{luƍϜ>/m蚄FMNЕlmGM E4FDf* U " %i1n3ǂC缁@WneR n,<ޗ,C>v`j03w@$nY5\2gï睯!%_ѐ^V":D_{o_vה !ESR9R?eކQ5^T,Tjm܌9ֳr Q,-S*PN9Jap@AXͮ~z=wӛQ^nPtCp飬  A.mH.N@3Cׄ^ 4o=ҭ@~ǬJxaz!1 GGzM=#ޗxmKU꺋D^5?ؾkڙ^He6\&q 0i6TQz!喚;2;MvO)p081(.{<Iappު|+'u:y3LExK[&M`Y0&n?5AM *vQŜsBæBT1# Ï81Ôg+D/*nܱ{;1[2ZIZ^O\r*)S]}.n P& {?uCw,@soa܇(I8BTa$` 'DGkhӴvf]O!qVv1MkCD7yGNkS6}dè3|QeE\W׎jd"ѽnuTb,GTY%9+S*.Ne&EdkY9vwPS8A}2',`ea,PQsOXB IxM%Hוa/tl6p;SX(YW"^0M0k)rQ;D7NMIqBTpʹ%rʬ'K8Rmښikozen<6>@ΥNs#l"O`]&S MR81R[0󁷇9^.hs=}\CޞRɠv5׮<ںWmk Vv"؞GWuyu.<Н1kϡxn_S#p2I{g>]w(x6er^w뷗p'F\5Z[_d\ C15j+m?X?R0Ggpb(!&@Cr?D^$"u6V^p@^R{qwju-@@`i@uvE-?Sk,z2IIc5fsù\\\,W:XIn1D%Dnfbn`RE-EI}=[";vbaRʹ[5B(5OJd[y#޵:D7 lY4qL4oԤԣ1E.Q|; ˳R&cc@(OdJJ44x5p&l;_Gݽ`˻\ aZG㜾[~I%P|hZ;zG{?FX6ںrTICa:Jfpɦ:paepanW[[i"<@D A)P҉vo51N"͹E*/q-١+(L"gheSzt$\#Yuw+1,(R+2ԏm@hBteI)"jq:Z-X_FɧZD@p KE(&\(Сl׸> {@Rzq[XDHIa Ey=ܲ6!9r ;Wq5fO{0cG*SQ7`Pa3k,*!11!Z]e8tΎbHfom-5zO2 h` hpLP+ .]-Qv$EG0508_+J22rJ#Z}' !jy R~yt~7G~Βuc;=W}u$Bi bڶqzX*[n7jg^,`FھVŷj8R_k0t1i"?Hl@u[d{qJZE5M$_̸Xd7go4,I#;GyZ7"JHݒ#ّWwHIULJ5 ysQPs•bF֌szG.]+3&DGKD]ݡPKh2&bKCNYyj!߮y>2tv%ԩ). oI2<<5s_O R|b 9 = WAӼefsi" mp"X$Ίhqc/Os-NUT)D(N>Ѣ|o{Lp-'K`27bcZ(H\RPg'@[ 9{`RF(̧It D.DTn[@0A=^gZ6mrKR.SU/`EŶ!x yAV1T E$jQ?u_zUemm%#c%d;qp QiLFA14y=Ldؒ!8©6)( e>Hѓ,3<eF$\NaGa.+m4ĸ6(Jkl ١t%:ʩaWȪ= Zǒݢ5eKVX]Yx^K# V곈UAjJv=j3z,ߩ9kmO7ޕc z[_xI|OÓvS6W,9w:Tlq9æO_zwWnlqڣ{{6eHmO?^ܖc8[p%_Nxi1w]=j?HyT3Ɖ+~Пc|& (hH\=(Ysz8v\6 Rtd:꿴FD6j$tt($[ +OhU𭾔s-vp:/ܜ?HD& b{ID|WG_Jx9$v5| yID\㫮(˽O2p{M A=(Ieߛ@E=yg(<^G7@ (9DZ='7Q YZY+ŴFK+%zHzPUBҠ5'V3T&_~yWQL4gS) Nipvx*ZwFo չ1=^38h 4Cl{c5$^Iʣ$$NdH\痟oq]WU;HEnEӂsE@VrRJj}3>מM{z_\3 0b qFJPy#~gj[V`An=4yǡse?6ERm8ol !Xzzct ],uT QJA4d ĦG5%ͯi]z9@j9g#izO!Ҿm/ -9zQ3]9w,؞Nju$S˰gfwȟ!MƨAHBss["?p==qTG5ܽ8[~jՖ#^-#Z_SEڡZ>pʼ‹uL\KikڨakLXiʾx&Dױ+/76?dIɕ?}id/@F^YBg85VA,9@O+{|36N/ sUyK[OVժV.K B E;5tP!'3yV°^~d&uҾ%)@cӰ%EC-NB䵫S?:j9N#Nf]ZE\ۯGܹe/!&o~s?G hYLbޟݬE Я\)"#7/V-anX>|kMJP; Ր0_R! H^"iӯ?z`f's7: KARe.i*zN;D _ H!}Υ*ogkzC0x rM"5_YZ\Xkj~CU O߾Vk?ktl}g̾ׄ(%΃A]JRϧy4 DhWz(603"lZUJi{<-d]}S5ykr_G-GSK͙p0#A qAlcFιԊ7= Y9 (֘!9B~#y,qIap(P.+Juz^%a_Q3 uN\Q:[CfL%yo Lu˃A!N[p0k[{j۩dW "EG vz`aEW^m \yKV^G:|?X#5[#o>#G6y#.JE)->4yqot %E(&}rpZ>u^2e(G>rؗ?'_87㖯v飉VǑ7T?zx^-:zu(p=+ yoPQ)+{rUEo%ULAV֖_ `Ѩ &I<ی h-;K <ѼA/NOfι]sz%C_Xp;!.@B~\7 !Pmcd{Uf I9BT@DDGn\yg~yĢ\8)"qϑ<M@\9qIGQcq \,=sDܻK w_\t2Hk+6͍oG["ՏhJ쭏Hb4`ߦ<1i amcĜ]]t,#yPQƘiQnpnT5/,\C,gc: f^γlp ~ه֌j @51Qi Џo>1msPJsk|-WI2FOv4 đl-~rqXZ.FG9f6G?yuo! }:8(94問z/WBɅ 3^|L"J\ /JĪsѶ0 .y4 ԥUk«3~X%)g)5!1 sa]m~Luw^5\Gn7:+gS>.Ӗ|c؊#&AypI /jg:üy_V09J@@& y׮vyދy%;^K=U@Q,G ؟˚FѪ_S3,µcWywb;{D5GO\a>5ӣ<(6agh1B͢LcӈmE jOI~Y# 8zT\9۴Qs Ěʟ=+L@Tŧ h "7-Bsg g՛j$<@%O\ԊQ ӹFELgo0 9`ϺsG*sifd} ߛ:^%}6SqU]EIJ\ahZ^'֥3uiEJcY}@8= ʴj!' +3ɲeˆ?(Dw'Mf [9lN= V *KΙpŵwƨǯpڃϮULz"UhneU8  u%cЉ J'YLW$dJ`U0 JƘ6I*HX2O?\yE `p.qG[ؼ 43 (x4.x n".t C9 SBcRw;)B)3Cl99b(- Α@!i8T$'Oܺ**#!Hn-<ʹ!g5McXGV:Nv ^\x7!g:e0ZzTJ٧$7yqg9p*[}h۲ )MþʹQTs%~M-:c:fOQIJ DgdՖBΣT !(RHc:U V%@wŦF-|Qit7㿂aL5V[UsE| Fub:XKQ t7=q\Eˁ[h7q XdZW3Jc3t⇂1Q@u) ;?7:h X::p ˒"[Je+ap!eMnj}@R<&Gj3 rJePĭ'8-2S!=m==F8O+5y(0 91}Es,Ǭ'x]HA B^崍hǝrD Wd(L@{H4Әk{!z= nV,HfJ \p66J$}) H4rqXkObܗpw85kwoʭHʤ4#GĂE3U! 1sQ=in' Z;A~;N8%af2F@BA9G[r[!X^@8S\@ Bg9cQs'b%>1& [H*f>XX&Gۭ'Ou$hOM\BD_ tA|H0 3:vE+jj8(G /P01aeㄱ~s:w]ƙAxxg)̬5G*ݔ+A*ꢉ!G1ct sͺJB/㕔]Fe-ص-Ŵd"+@)|Ժyn G[ŝ6GajJ=sON`pHI7Qx+Z$g&v/hq:Ȳ s$!#wIċҍF1_q|2vx5܌ SHP1c\ze8 @BR"S@fU(Te $lr&ǭfNBK?n-Ɣl\eCScR ־5Y IRqƣ&<-rv@ 47x8tu3^!ǠĚ0"?'5үF\סrE |qEY@GqDyd<ϓDse[wnVAg-8&OVQA,Caq6|!;c>)O6I"J1!!w@T Zι뺊Įw5Uf`RIs+2,ԶhI'RV*D49<4bMdO,FMs֘"E|R@π(ɮ&k ʺ:] ImIX#PELf˫6T#v ݧb*;jX'$p#,bcJ)f0[*`sJ8 sڟ}4@LDw~ 1u b}|{B \ZwwaN{FdWi}ȼQJZgLJ1d89jFB$r:QvӔ,"d8p]'J1H/C0 *SS_TgjWbh'KJ71A ITwX{VL"0ؤYZ6J>S9Z!D="@Cl/uk6 i;Lr02S4o} h*ftAEkz&) )t33#Jm@ߗBA㺮87bV/X-&OL9ѪZfQJ |_6D 8\]=-/m-l,!wX!FcyKt<@n'PfO*?9Y8Ob$}e   .$ 0ƁyAI$I~neCȩSՙsh/]GA(GK`-`(OFli-Eܹ3j*`51Cܸqf -$TaqC-j3А-@@ΙnV#(&;ۤ$4B@ںx_3j)"^Al Lv9 jMJi}hⰞ̲w͡)[>BN:0!`kgƛH"36PV X :d:nQ*_dS-~K8wro,Hqm-f%a@#ՏvKU@b,L$~2Ǝ\yԓ R"8놢# >1\̹:ٓaAJPG9敵<Ea׌A 411XB-2F 1j%];n*/A B=(S C9Fߊ\;л !|=Ԧ]SCBmPJPRl٨=JER,(h 1I%a6mMYwNsvU$0.a.0808/$2BA)p%Y@{ZfZf=AjNC9kPn:]3[EF,j#ʼzg]&{$W}Qmrm0ǖIH&@+IzEI0VY05MH5E:qeGsh/b2nibLqNx9GCL9jPeDJb4adzBnb.IdH9vDHvv4Z̞0МF]zSR&&:ZIFeѤ#1mvcrcpjjjHH8H$)H9ùr|RDI18>}7$U]PgF:e1E' 5CĐ+ qEZG4> &\U2XM tIdiZMEVWjh 1#X5 DBB*9grpU4'KJ0˞!2!D` C237AqY`d elӘ㺺EE#~#>Y~]FsL*'#]ệ==` .~yqn#݀INrrbfkZTuhE%eM! 㖬#fQd=d)/tΐ B*pGɞ8iCl'agشCrP |)X>d!P$CƓ)}eqg3?+LP;}қj0c:~u(jv}*8N 3R6Id,4[9!JHq,tFR~Tv*Q+j=oq.#W@HZv_79O72N2YSUYLJ upEcUқPmK n#DuΙM*d6}ơw|af6 wa>k8hNN(ֶ)D\.Dcs6/G>C>cm!o f7>M>2NK>c㊀g3̚F޳mldc*۸ۖ2^҉NYWCF gaW Ax'vL#Ch22=ۋ -D2:SmoLƗ8II"RH 9wBS;9ǐhjyÿ>yF}|IZGorϼMԦ\v{l'+޸I3fNh*65:z _2WDK&^/{_/ѷ%;c FO0uiS'N6q S~"0f $ Y>/s>ww#o٦sv2gg|:꾞#b4'8n[s{ZQǯjyʠΚ7:e~c$rYƈL-TS?ysw)8 8w |D ^4ug|ү!fH K 9yTA[R ꪪʪLUɈ )1p^9nƧv$ABj+5K&|9Z?Z+mwŸ_?7WT(A!@&Um$YV˲ڻ].+[tɸY1-L9z= oBZ:.,KɝRHq2IF넅ehDJ,j | ]YYǙRkzY_+ k%4B|08q"4awW6+טk"ȂQA@tN:yyi U8ʃ gOǔDdxd]='"ƈ2:{1*u6`P0&ۣN+r4 Jfpf`2|m=R#XYQV_JRb[*3 J3x,ChF-a6/xk<4 ͩ`@Hヨ@&+x@i¸@4 L:穷AD*A Fcw6?N^4\hQ8.lyM7`ٛ׀׾07^;N~,\<YUfUI}1r]@Sa_Y-!?&F'$5=o/+zxאe^,j^2tH-?>8斧uy m}L|;{?3Ɠ |T˿u&P$LsBY[cd%Cpd䧫]o&E z'T; :z[}u{%M}L|@ٙO?ٯp- yrȐjm`J 59ƣ%D[/L3֒ԇ~ H!Ҥ$9-b3Z(^M)Hъ`S-[g!JPDR cKU-C=_{O9kˈ~#ö\z%>m'/cu[w9{"=BA2iF5"re4ϋ LPxiD0,5YsYйe-<*O$C0 4!CO, ,F.&zK]0ްzgbEOmUկ?[+ :1h :d )bK:"l)4HRq ;<_"ڂ&8GBA &m{ػˠZLlwa_+'gisa2D?9QzSU cU~hT\'Zhi\l237$Wt1[Z§44Fr۟ѻ=mky>}wp]4WK/w m$ .߼We`8Ie`{J~ϔ5$6}!y7nCiKG.SQ6ehoYPw8Yjd,X;iqr%t rOkz*d@L MDҟ|#<.vpwzΓW/ج%U0-d}maWtT37 ]ڱer :3}4w\+vfՋG9=;7b+yz3_qnģ IDAT (8I|Th[?S}jݜ/^~%AAsS;˾}},djesy=ٻ^JlY[O> 9/llX7{@cus4vߠC 8S[3kN's#g%l\̍D2mcuVo:ĚT3ߞϼs眱ﻯbhre_\= /=mX%Cm<?|S̫r];7M-+6^uD gE/hРTlRDՎ?+:wu V-\|@0ٛE! |Ho ?vI4T*f/>wvi+ ̚L[[i" Y΅&/`#]=5ΪW)Y GN^ ~BO9B5 IQ%oN"$ov{_>>xƏ{Ku`РNlW~ףZRxzlϕw]3DiM?J V=3;o3۟!_rWt'@|ٕ9m>g|GZ>6~i~,(_[J?/[y^Gtʉ O^Wjݥ_ODzSx6~U; o&3~o~}͍ڼsV/֨!=5m37ߚYK$N"JEe_sgč %ФNnB,I]SWiʟ%<4B#oWc-$b9@TjRNn! !8f!(Y@.t[ 7iŔ*n^-갩E\ LUES7hBˁsQ]uaH I9yy6yL:o6E&dvEM'jcYqdss (^H/Ik_G@\=?RFV{7BFXK;Lc#YJ|{Kbqy\Gm^xB[XXxܣ~3 pI E{zΓJE1&ԝ z2VP?a 7g-!827 yW֫L{F L";)7˯[7VHbvC*ppų6xAٜ;w޷.|OۮK;kIy\vMn,V)D|Tx88ALXP 2ĺwkY6ԧ>qo>z1F\u;؆[f/B_3~So~̩翱ы|6>+:-]'T7)݇-yo3/~σx#N[YYX#^p9M>(^ˬ1ړzwcVO hýwǟDu{[]xEh5&%Isu lZ^P !M+!/.oyz,tOH0Eڶ͒#C 4d29 qv[XXurӜSI{ S DigG~^{7>-B Sm}Zn˸ d dŪhyb@Ol}4b]7(54H: XCƾ{EU/)T.G8tA-U^U 68^#8ѧ;fqU@RB@^Z:ݹz;ꍫO?YՂ#TtM~֋%^HyȒ!m;龁Zj=t̻Ta7Zԁ%5أmdx/a5nw5ĝ6?DzM ozJ_k@tAz{^ΰ֍〛>fԾ=Ol7!D?ho=>!Ϸv벟Go]Ynב'hA銵 {Q#;f=O l7?c[Sj[:hk1`tRYaPU)dy[?-cɰW,+oc!!@ e< 5eS`(^uyI*r55Ge6Yuj6_,A]I)%HCNF2}Xy ~C>}tdal*ՕUS)PZZKdxHA@60)V#lJEWdO$KP ÜmcF(0$Y>#$7!hdGx1L!I!"Yu_ocZk"n}$!rUX 4\K`f^Hq%zs9˸rKR&om9cq\qX%)dOdirP2Gk̙!uQ~Vn>Qm[죢""D %&LݥfC/Wlq30"|)%"Sxn1E^BNu}ߏEanX A妚&' a'4ɔCQBnsKXlN6`ʭ!q32c;9 #Bup+wGBeڟ&ҩ]SNW;iI  ~|Y$fqwg>mgk-6w|Dw7Se4޴{ý!a38ҽ&N8:ČdAAQ?r2%?N*R svts_qVkؘ?+vsb_|ڒy_ {nV}.Jl)&y>S<׾`uK&][ "mOQRUӯd#.8i?-]WUEl,YZ8Ze5MNNjTE Jh\^F7列Zg:i&~~Rm.'} \¢jD^Լ~);7<倧;͝MNÛu~'T1P SS3":)IULy΍N=c읅BE[ԯ:ncWKmELRdW3OMjʡYפgCcq鼼4C Aglo. <ߗ$JxgM!@A/n9WepgWyAD7N^ 9[hڿ|g D?=גގտQ&!$t%Jt/’e;ݭ)CA7?]R%kV8oM[ Xmth;_;eg_4p 3u_ .]lW/- ?oCgT I* y/ۧTȟfOb|fК'yу vݡğ~U:.G`mz;~<"wS]sVTR05K6oWMeOD^pǝp@ôz->T-ޣ~{ z@PvAin:ZpS_*c` YԵWE!h%*|C+7o\~홙3Uy};k׮G_셗|~{foY"1H=4#QGö|w8mwD87 X;?)#󻏊UgRh']t_ZSV*Qq H=?{e'\2{sHyW*@lsoW{uQ8.%Q40y$bq`eMPu­ 6T q܂$1 ʲXqWS L5v['o@\uN:Rrފo~(~FbW~|izTZR qtzpXAƯߞ3PY+9&qPa٪ en3n15Z! EUt͇Ol5 `T |!%P z!m&8:^2`86E,{أ)E%Ki29MRY]3š^Sߕ/I9KE !Qiche9a5,1f1 *X6`[7S쓌f.w14>rA}2T( DDB1A%Êe=5ĿTM{| >\¿4G{obD2rDRv$FԊ&:m5tyi= F!˚^[ȫsMaȞ*r2x&~ _gnld)FD @DۦktnvM7\amRJe"-3ĸ t"q6+<<(yBJAJ)|%f'ĩ{/<}^[XaqGD<,+:MMrT=R<OG׭*iaSl]lEYY2`li<7gDp"T.IͫB PxYip7\GWB}1tV1iysXD3!̑JQ,rVa6x[Ko\p=3xC~n;ܶxrMw"Lqw+\zB)cבFG~uJkKWBz22T,g$I@q:Spحn86}6?ؗ!Jȯ4lD+4.&)Ʀ$[!I>P,G[ NI] (_ J0(}H"(/S-tC,_}GǎI)%D93({dxg e%hɢepw^ec3V@ܪzopT:e٪I)$I. uj[h LUc _η?Y|@M2_ !IME:#UYwwJ/ݫ>(ʔ*bN,,4D锏>b-O'C~Q.AB@&I3-y&L2|:_3~!%4L眖?\7 2*q9 A.LD'-m) $1[R0W;ViԒrN~N+wP|(܂Tݦ,\ј_ITRL'^Atjk[Q*+W4Bx$k۩vŶ %IE6`l!a7`n~]amܖF斃TS~U78èBLoL:iT2~tz2߲>Tei"(/+ ԋ !]K)xhjܗ=+,YI:rբNpB5&>ߧuJ`2adibӘ, MaduxΆZu-S IDAT ~YC=TnBA9ˀbqt::S# g9|7xD gr_u*,t);!0}/l9gؿg D)Y槹[ԼUd*jOM)[5$}}284[,Nj_nLtQ7PX͊k XD )kk@aE{ٲ=Ԭ)Aٞ9j~8 _X- V6,q5_zlP/@ vIPy^AM?iXZJNT]peeƙE.`du:⺚ QnҼO_@dYqXQ~i lk":./}nAtjW%K,{AT5 g_wRRwuZZ}^}z6 G/['/MGԷٚ^A V-,)ea֛#A/hi~rl!6 X~+h(OrӪ5۫~ W~ܺy m+y})oۻew̼q K1y~a0˓°B%I0E)wݸO9V9MXqQm Ղ$Pd?nTJIJl֔u^vev)s'6.7cO#lao!D9XDyQ#̊νວs6uvjLJ+_ֳKMC7ϯ~Kf6=yѶ[wcUI?n2lM4?aB @fz=7v 5ofԯpWY@'TS4bJ^6dJlbnxi8VҌ5A/z'o?%w.`fОɒb0fƈMO6]^I=[;_]X }MEv~3"kو^BHwÂ0iNTn\: NkJ$Ș*&c#zu@[yϏ~:>gN}Ot}U~nśvªBLDh8ݣ64SAO?,쪻:Q}ti3u= r~wmqZ|p} IOu'}wäRҎKk,otT_yg4I5ێˤyk+=kѦVf<2PhqOﮟT&&N-}gI^wQۓSv2Lqwt^?jo1MZar#'"m8ۦnqM}\Fn-qߖsB*t&=luKyO{Z#^cv,]:,U??z )Zٟ&m@s*!ހ5(^}qM@*!{_Z|{7KVȒJRdjjG`& rXAB pKQE8QȖd-G>fr*b-k9&,~:Ǯq)fzJt,H5 z0Ρx"f`Hz>#NVG8bX*)_̓ woކWQx ?<{m,%F`-ދ]&`6o5[=ꊇן+4 ױQ ysoqX7𗌺񂻯}j?癁#օ_mjn^{O9آ'z]S};V`Ԃ_> {͓Ԑbow>.Bl-O|qubn~rV9 DZD䮫ߒYй#\1wjgu;6 o%uԷi>u}-ebsWϖI[. e ~|a"zţ|}7>7ZzУ߯1 .${Doz䫽a?{] Qݮ_o˘9̒epW o/55[=G<ۡW<&AnF?KqA,b07|¨oc2&u޸7X'sѵ&)2T' 2d !1&%Jբrو[i/m7\;g̜0U~m?xuR)7s|5KN"!"F4~Zarۢo0"5pmp؆q̩*X77w  i7c量Pܩ^@ns8l̩^+4x:֙X6gf Py ǭ%M7}m1 @j&]"l[ؑYŦjX7OÏ b,+9|}"oF_Щwfm̲e[ sJƮN-ABH]uS$4F,"^*Z#U^# &uG'xD/y+<J"x8gb1VJĸB%"$ _ƝzjPIJ,-`h$bMa4wl|ayi\?NM!X+{gߛF?K3_؍˕B"Bn~8h.O2kRb1Q.dyRہԉY$D5U4-g>&'s ]'jS s|TT"ݲ\96̌s*xxe mq(ߊ#c|.˫$IGGGRCT0Uڬk[4qp|qiƼ"}dTEЉՏRزo<46fK/2J7i(4l LhwO1'X9Xe } s$.+K3̏4ج +~o0kvGRCnD1+wOS2i%=C̝ւK^ӏA'3]D'^vAGk1?my.lloc~]c`SI9 +Z΄7aUgObww>,%fjR9(qN YHCmQg]tW7M33SRoiț2Oa]{,lO:Lͻf]Q'/Exx 2Y-UbHh]YЭ˼gnyntGX,HJDL ` yJl 4{ꦧY.Y}52*+D]>9򉷗V6wV'o};+uؕ`y,r2B?$q2k8Ag봱fJu>ML|&"@dB1ATI f+V`odL9Q[VAΧC^Ѩ5dș*3 d;=Zsn"wxFm2jQֶ nAvxБ\j uQV(QU>R|Q] mY 'Uf\!Nز5 q]q_3'z,kU˯Gd,eWUͪ5ϫ0Vk&ǮKIU#{W=ˆwDԊdݚH>&%d~k~GXFabJ pi52y*'I$8gaAn/*|A(zfl8- ID ,jt::::\wfi7X!X 0LvIըV,ƇyxACβ Hdtv :^J&t0r($DXł'g\% r]X\7M%lZ"1dބ2Ӫ3~xSu U?׶жԇRiʼnd-Y~0{+MdxČ7"))3"RΘ7p\ηns"f3BexMTC7?MHw -Pv!@qFYXw"ljwsW}(d/ 5eRPxVoɏ 8$nlh*4:N')0a+\Q8I+ $2d')C&@J 6]m13lAkPMQIoQTjң`HRu@$\.䁢QXA${][SMPe90|5tMS+k\.W(€K!JRR'/V$.)R{P y*:<;J<㚖Y-Ԑ5?kحMC Daz:!-9U+D!Cw!VjC2'!)_9)s5j-qƐ1δf&RȐ5&ٺYt Lu翜1McL)Ĥi.;@dD$t+O=ݣ i T=) ׳%" yKnEZ Pޮ5lm>O~0T3jjfp+K5RgRȩF &qJÔJwL~Um.[{QEFGwV$e:tk+"!$g+#I(jd i'83 z$c !TLT[#d5P)TIRJ20 A"Gp*:\J,[)sbX5GAIU0ٚZ)''Taij?$*n n"Ha)to:vYw1qRJ!%W'ƾѧUaM+G/^ IDATϐ2*n:رš~iRAHƀt*NRj va&I6A04x߀ u(Kިk M!AXP{j*1DFTH&!e6;+P$Atmcs7AF9v'(+i{ Td[^{P2~l˫/,崴,;!'U:TyCQQr?3o3P;Q3\9 H!(RABkuj  _(B5wï3/Äsq"a+YT$|toP:K *DjDkqABƅ?QɯK03 2@ sƙ2>>JHY)mxqMD݃'6V9Z93uԙakʵi.CS]q$qp=0"1zlլA`dPNTB/-ѿ(gv񱴇'SLʀƻC5ej˜ 佢r YruE\tp ݒLʅ|#7gL Q$$$JBp-P:7 \?ݩ}KTUX}(SJ{M[C>VӖA{iKTE}hzk5fj6j %Q\asNB{OBrX 2 IK%ŠlD̏ 3-5|>6x_uw.Ob UАx+TC>Ppu%DIF$QkʮO?p`*3C U:!eTޑ$ ~+QE9IݶrR ,0i&Yu9 ]Gß/)4,ꚅuUz;*y#V'W $@M! rvEU&H*g*O!"g #嗎n}05!?8K?0z $"\w7zH ǩ"ÊOmsJ%!iL.)K 5sr$C6n\C_zt\+6fl Q-e󯵨(u\p aǬe~ Bz ǯs $o)U#E2 qo1vOxaiCtgkhQQyGn^a\Ln)S‡10?q+JD"R[OhtCF%Qc@c0FIʘq`d/ﶞ I`D5rU:yJi4Ȑ!t*RRd(밐kȆ<䵺RJS/3B"!c@`A'! $ +Ma. 瀂d{{[-)Ӏ߼0{R&My\JҀKtԯ<ыڍ1qS'L7 Cr9NM<@5Y3Yg?yL]}f'G'U;7bzqs;#I GfK-Kbtc*>uxAH yfLX%W>׃o$ci INb̑9ۏ"JW u`R[f CW#HPaQG$ʓ) YSP`\qA8HkjJratRBE*H==.ԯ2@2QV.uf֩$Wufa664tҥk.]6777546a&YMl  4lqj"QY͘go8v@H {<(q-./cQz> _wo ␓y=ID|n8n@?W-w_ _~XuV5lqﷴű3pӜkɂ:Z3Nu7T*Ə6roX/3"/K MGyo"#\YDd<&îQ^Ő&o~ w ^w&2'!^r1[V~[5ƀؼ}'c>ɨџvÎ9>>2Gϱ~'F2j՟d-ӾvVq'Ig}n)I:59Әȵ(O~|^MҜBCF΅:4%mXv']0GXeWG4v]9,E<#{sO>y'op7A.poJ_Ɛ7lsʕ<{$E@\q.d"^Lbܔq<׃ÆAwF?qže5 oN:o< p3|zM.dx-.15?.gK|w)|⯿[GePy_(^1zԟ@7şxsɓ|/ؘK aPlP WTTJےRE& 2k}!))}RWO{WChßMr/>|ϧ~8r4Aï|-}/eցڦo5;?{uR  fUJV >*-CO m D;;Nȟ7L,3Mp8f1=3WԈA &prVP6E˵3Jg_ImArg>h0rtC)T(cMMMM1lOv>qcW~xҝd'MܔzR КEkT gPC89DZJj:*Uy]hmSH=;MZ+"Bn|`gi dv f9IEiLPAoijA2pw=)&"A6]6voDҴmTװ6rx0bK.ݺvڥKccc ]TF5䆆}3BeޤVٰ|esgJ2^g㵯=x͛n _?vSWG<֭4tz[q㛍 6} [滞rK7?g4|1TNlz qo9{XMI1BȬ%/PmV͖&3:#JIIƴ]"}\*d~#ZxMH<*] vBccZW9{܍ O{W]yNzp^rJ]瘔f#PPIJtTUpƉ(8YMN[~ho'ogc䬫􇪦Ce;i.2@F]#s+@Ii/?ebGcqߎE;2Z̑NB"I$F (A5hyMU+R0ցdmXGQhFa :?^1I\.IMs#vV?)f%s 7>]Ѕ'߮u'=mE,6A#nr}>]\޳b'A"7P"mtrAT ikK$BtEϞg]y4t`+fqw]zOX7}73~v?k^9Z"FsN(8Ѝt mI羓N)5pʭ7z{'ۯsթHnv9Qd]9֑/@zY~)^?|=h׋neh,saN1""T*QR)X0D {|Ob(!Zl4lsM9zI;;JRW){W9]{YG;+̣y{K(5 faF!x_M!hy/~G.6?7o <3qS4%u{|!SMgHH#G00T9T3PP3ƝleáwN$e!BX,2*J%INKySV]yA`$$wK_'dw \s\ۺn}+ݨ:OꌧR+:aCLNKINi䦴+KO(Ņ HfCE36yp)eb1rg[ɭMNBhϺ}ܿ偑qZ1Cu Q 3DHgЄ$HDv9"8f\Aݱ]Ha[XsnG:^;xmϟ Ȟ얱OڴrQOKV^:[9W@ bs')HLlHwO||̜o?scqࢥgR$I Vbe93f̘>}- J7sƴ3O1c~-M\&UsgL>}3g,hU2ى*\ҖRvI1b~6ñc_>9lrUẇc?}U3r `[~;|&$"ɯ?2GnǑg~=9zdƮSg,,7}vQT v"vȪT㨯 :M>}>oz~8,mK^&qY;G_vV%B[HHDEQ\)w,F>oKAy3BB1u^10'^ Ǿ/.Cߡ{ιo:q^}yʄNLd޻w/ؖߌ{pvϤz%L5vlFd64M=vCΜ97 TzO$BD2 ' J =zТoS xԈ/<q;p >4O xK~wgSx'X֧Ҹƿy>9qԟ*mׯdo4{eS~5^!}Κ?g73s#1?q5sK.l>}Ɣ> аu~r E֗m7( Jcn?zjNc  bPsAp摁 #T^6X4|)5?JT)+RQ*rRJBXl,64546666444 :H.Z~АD봷lԂjѨq[Xy}o.7w G}h"}te$[ ˅03΀.}2M^`իd$vTF]OsTieU-nFFn]A}UVMg8ryٷA10` G '$i. $_=Y.I)pcWD M8_ݲHҒs95{vQK,ܐqxЫyn[]9 63*g,mT7/d̓>cw@dݷvDq$ "r\Y+EBTʕ80#`ǒDy K3',A(O}ͺ 1|p>94!q!ע_ A}oOz3 RXӎG>~nb:̚v:3Sx'6,I8 ޼Y~W=uYbvrqr?{Nr-y߯={;.خ HQ;i//_Owɞ;\]fs}?1ƃ `R :b=G}Z=Ñu:ͦY%eeJ;kDckh)6w#sX$$T*RTD<92B$N;W~A+1bb@m=7^6m_5n»/g *Fp E)ί_{;RּX55M)hS7nXuvvaU/ֹ(0#qLVT ʦK#o4WWcnj,6[v UZZr<`a@ WmɈ;F56l}秦w6t Q#vONd>`o;.~cMڃ;7ߕ{MUmV*ߌ a\)dvXXSue̬` /s#bZ_i69u3ձ L.ƙ2u7-nT˲UCEF/Z/ |olhljjlnlljlT(0@nXL9:ip:HWeGDqQ˕v::ʥrTE"H2aX(j.?]3#z3/_0TtO.N8b1~~ԂMO;e+r \=#z3_,vS:^=  u,hu߰I+3b+GuoR,|AbOA)%uհ?\ie:TY@$JՌiSҩޔƏJ1ٞ<$ջ׎$ߑ){zU]s$>* r/n^-KLЈN!AU2u.\ƞ Q1I8U٪Ns@ $q$$%k߱3VBޥm$b4I욂Ʒl~9CچAf;`~-UD8Nr{4CR}o{ѳ{615w !(BAl:-9,r,^mB !ڻڗG~qo߾OhY+4hDg5۟(1 H2"@d?neO7o;O>4Ǯl#>|qRImn<^5BDhA&*rnzymq‰/O:wٓ__]VGSx]/M7Wmbov˭] ֩5C >be+4wo(IJq[ ag'T@HWR:j0xn[1{- [Oo/~#7?$KIN|9~x[]?r.~lVgyBx +rn}rvӶhױKi14bnq_u4lS%cI!!X=%=nr}Sq{,;mEbS{-R2Îނ\ ]KEz"[+S}kDn(ĉ͊c$̔`X]ג &pN.JRԑ1X,6AoرwT{ Nf4Cا &1:YKFj/K̶CDqR!)\xI56tҥ9))EB$B,'JNb]) +%H)!$$JRKR (A1Ww/{} _<}@~esg̞匥 :&=7}?cX4_56ȋG]Nx@d8ts^N1WG^wyWBCKְ!nwȄ2$:cRagcùF=uR$ݮggS gҒ}lXP(@A~X|ܗG!yڡf*^oϭZT2I/=rDTmmDH!x be7!H8J7>%ǯ1R29A0A#p<|&fz~P'6~/nђjN@nf*Ep0)_,G]-,|X YKþ 6ݸljK@Ks}v R\ՂJIBRKynlXU.ZMy:tdJR_[p3=鶧hh7d Vɺ2 Cʕ#'$ \9"$d:z̨vvfD_#N%E7yJ߸wawހϦ'p9Ko͉pX׾:EHPy*=ࡗ52N)n[pwc׵W9p9mS1oBHBԺ)A";[K!@Jbw:TEQ-)G@9!Y5i/ ۦN.K߸|7m͟(z :s?F-fxꡧ;awO☃;&v# ~y뛓OM O0ڴ1%X4~j}Ïg>Ci-9W"U3EMV?O^GtQ?׼M-H‘CeZ|]XPjjWdfvʘC'[2"IRZj~4:eTĉHc-<̅aPWTXV{R\2a@@Z*I !uPM ) 7eDn! ^u1BAD e*k Gd#pDYp[$ I*Xdܼ<K(Z*)3u_ͻ>N4qI"HEqEPcڃJ+er%s)SQl))_\8,JCO2ob #9ML?4,#Aq !bdB$ T.eaSB\S56n<KB$qDŕJ\S_to1𨧖AqOlYVf7lo{s YqycNuYtuރX#M0/-4ްسO3@daTԋ5Cn+n! 8YK7z?Ǯ`y.KZyu9aa]dGQv\=$5z^r)ή~pR00 QӲ>(S pelv< lP:s˼FD|lė?8牻KAQJ%gK\ IRX]Q_-O]5XJ0 kؘse3'SPF^l[ =VнZ,Ma@Q#)ƮGQU";tBV\.9X =>W'_7feG3.mj>]d[osn T^bٵOrnF Y˳tdInt!xqfdW?6QlP9*׃'`LJpojc)p '@} ]#j{-2lt'wȇK" +G6V%m} g=:ic dȹZqEJG)T(B|>A '^mwvƴ/6mSOަHuY$ ^Al a2XZv}a\q\p,n6x[c|9'[ޝU jsMH+TNNٰiߗMZH6\1vmϽkUĸ/:rG8h%uVkg׼vإm;;zVJ_3qBB c6m=VߎUn*_rfUMc kn/11qgqu<+A(33s=Ǿ-^JGGKr\EΙ23]NeL*B(I4.!+6xahU@.=HHǛW kue -ktc1Ij8q C))R}uk[[[{TDHe].9 FD~CB[+"e޿;jNj(v+hSMh{bUPV`LЗ>슞jݿ\V_ߓCv[$PQ-բBd>gS]Q[ōݷҼwшeM1 s1: ID\q isrACuōzl?y3Z%htb1:$`-[d+4( ?ǂWqqPwV 5D U3d$)^>k^yu!"ۼ{4*IsU6r@3GȊtYeHU^P)ˠ:l ;ګAH=ë=~]Z D[$!]W4 nOԦԱxjhgqSe05Iy{ur$@r< xQG(ZoJ@'W޽CsC5ճ\6^@uՋ]6ӧWsZq!(nJvGe#=C:УVoNja`BL\TS 9t˦%Sf&͏7Y*`tdaR_XgZ&%犅P,iz@Q$n1iɔ"d!$2)k>$Jo_csmaP9>|AS7vC\gPW.ZҼڕ}YZfj]fQX5e>pO_}ut~߃|W ̅ș y38-?kW?){}OrLU!Qe 5 )jChZ\ι1JI$XF+Ҿ!ûB VhP\w XogEc@MkEIAP(łaB+CvһDDDJ0sCrz Z)3KGNj3LOː10wY, Cg#DbaA_YY)<@.-IuJIU]g=Og( S `Gc5tK\.qqliTͤPj)EŕJTQi% ٿcVKմk<+X4=瑏,5M>Gud~6}3g̘9MxhhELd^:PN%W!σW݆̉m7OW=lv.=igUוul֡]k&7VTkӉjz d2"R=QfYu]MA'خ's+}}?u)< [uͽ!0MNl(xiq'j\D}kqRT$1l~&h8[]f~_\ҲR Ԙ?9u>Ma6_?v~^X<8ZK\4s%w*p͖7=9] NpK,$4@qUg9sG [ii/LC|.BN18漓v0hc.8׷y늷sC u|K~q˳/(W$32 t1P!B*1IM#@nAD< |ʹ <lN3+qZ jP2mWϾӱ?hqʟau?𚳎OnӾW[" >Cw:lzAoO֚f/k4OشY3?q{5}=nj[6{w=˦=XpFOv?~f}}ݳiָo+nY<$Ȥ*]1Kٿ 18ȴ9"QGR54i49t Jv'I$U7G00]vtLi+g}$,J1rUGE=QT$f\.ɂlu^pUQSB9Ƭi.C9cse_&t_2"551H]=F YtHC";i Wk]0pBhVBZ->dr0lҴRW(c)s9s:T㴢:u3Fp{Oh;ّUK77p*;\oWv//x{|3x;+%O{쨭׃_pg{/=ص\!ï>c^nsۼγ#x{hUZ,04vK։RTek(j(õ}Сv\'g$Jh}-f9b-ćf Pzy:6L}AϮ.qcgj`̼f$M6dr$o_Z[f>en\% ^X m!ٸW'Ot32ࠣ؞0!2Waw!O`η'/ȯي^}y1B@BRQLraگ OYa1mlB1s:1@ۜwoMWB2-yGyA~g7ӄklTku Vm:T? #Tq5v|m3j| P3e侵xZ7?|[ՋWȍlѷNo8WҳȠ}g/]GUfIc] Rx=s(R|<϶ŭ~#4w>r<̹cd4L|eθ D3{i׫{x`̓\|iR2xwcE^[FXt9BMy\Ȗ2q< .yb3=YqB#! "gBJk.DBTŤO"`ȃ0,B"s}%.V||tN `R쩟rOgenG >gc?l>:m %Ӈ-z%pGф W|]obu[~^{u_[[.;}~ngywgi∾̪BDBʌ/x7xWk +-υ.ywFLLo4zV;䇜Zzޞr[8yCٝ<~jo痾=RYx£ʌ0=gԚ h-<$f1XWb2 wZm\ƯT@H)5ʹjn+ɵ9 陛q>drJqP( ::7XeRJ"eJeS`:E*WKWXQ%gҪҶ\y] 25xBNS.Lp@D#AXm1Usͷt7H#plK)„:ΪQs}3P=RDUȵݫʝƴ,/"%U;A!0d=X01@AuZLf*<3rO='|rٶRӚO^{??d]{^ǦѺmnsBc˃\G>4,fY~28S`a~/ wMv}ݑ$Ie24R`Y``Ձ hw J?}D)VW'4;R=k?QjsT3i9 [2Fsӈk^U}f$4+?d `KSs攲%eEZYd>&ٛ?!I \dtx@CBU-ˉìPBߕ됄ȤqQ13@?Da(qQ$g3AE,**Qt]W]לu `PÊ F%(Q¤{|{ y%0]]u: UgYlmGmVcİM{D1N5 ^|_vMe%dF0bgd$*#f9c h[Ŀ L}BѮDHjqUN^Ea75;M 1" Br Mk:nU#U ?fiiYIY6 ➉sth7"L[L!7s8|_d,2$H<386ͱ-BI*dUT /B$)qd)j]:f#k^>l5כtmj6\*e:K+S|n۶2t |5tWP([:(|4 %5lXd:0E ĨAbR/U#'AYK?FE)iTc%[נ(!CFB(F7Y* m{4 q`4JjE[d(źuFW( AP{QPb5.1Oi=dg0 M{+8IAMZX3t?!{8C3-*rjLr!~#h !Pv(Ƅ3v^CΕp/;4+ C BvLx)*8Zfpj1C ːY|KN\'AYqB)}' ,fz?)EP%C8CjIa7k2dҶDNN*(_t*yu<#1d!+#F'<($bF> eKӪ =}S EM0y^ꦈ$EAcj0\ذx~W:rB+ CѣNY Bi|0 9e :[PF6k.g,@ @(Śj'`_08]$HDkZV &蓩DC+h.@؎:xB'-UB%xsxKD2ôm#5Vuiv8&en xt)͵ M;cĔPGpa5L "h%0PS 4`r'a&l˲@2t)y@,˲m$DƷHC`Gb̾[ |E#Uט|YnbFFa+QSyc>uwp RH>_/:MK-YhZ4yU 41GT@<DBJ4\Wϖe ƸȌc3tRP!'nfRE0uה>,8 $ >ET-$iYYa2nd?@m~+Z2[/i 7d 3y!7dL )^gr S imٺ+I&DFЀ0"PzՉ 8 s#BeU(֙RH!QG4X3΢HAFzc"PRCگKю8*!Ssj֝m@u}t ^2f!K GOƆhNO¿ ¹?+- M6H3T e] jBb?(@lxfl @c  I=OͭD'8+E2)![*Y0xpEYKÞٻ[yX%Ftn Qhj +~{JbQt0Xf+H4Ÿa@(RA38&)t  ,GL2Wtʠa)T-4@"#cIi*f`tz6"—-C?KC#B)ȴ( "DU4 DT]+U>*յcXe"FhV3A%,#G7a%,4' [ؔMHvt#U:ƐN2Vqs&ߚ7(@&(F$6B1$Dbtz짔\h3c5IRpR݇i(YW'롃NI%u ,Z̜[,<ln!6Yca0 x%TL} Ȳl۲ef2ʋ=5UQ'1e 0h!K۸*Eln.3IX>M,@Hyؖ6n1ݾ+)ˍxŦ.aF#R5kGH!:H)”uKؚ;@&adY` b; U2@nY@* ms9pV AHCOF cI 6|$e1 t 74 r>ɀշ$q}`F#0noe`Y9~d5|,KwU>sjaFA)@$|9P ^2rI9GT& AaeDC>#)0ƥ*)iaWƉ gq&_G+GRSa. Ph Π/ȐRG\ `L0tۖeY,t%eTB'*5(8*[/"[,918zR+~){k5kUl""9|߷8,- 92t6dqP# $i;Sř2nAdda=D'T\wkE~񾆦AR<)VSB'Yb󠕅h:!3YBCD$|j˽@.3;Q U'=*hDFs 1 ]2EнiqA[b׌<[^Z=")^iY^=$L:26+9\o2k 9UPxA.IUދ?bO} Li)=OK ^R\[\b\, *Q|`'73!~"l+<Źeۑj&~BB ej,Àx](}ql˲"{Mi+9s0lit{8GxjaIVfg IBŨϡ[ *qnYjMDʆB9,dH 2mـtG Sb86RR~ 7C$=i$N dYL!Mt |ߋ HHf6SI!O` %GHՋɪ|t780`gOXGO1WB5BudrXhȰIE*煤D2dPJжD"dU rND/u n#GSGJ:A1kYrqІ(}_waI-G8]1` M:&j" -(0dD0\Vw|ϧ0ؼt}zlH\DL$q+JHM!5 <1NgvT}BeYU5aE CI@ T{e9 xv 4f V\r@Jm0 "~ZQ:,K>ӘLҼMM&}:\C!?$!D"/.K%!3'Kߔ)$ oA)E#(BZ0XFCefY l*)@D1fٶ {V(\:Dz34t$;|~9f(zԣ&YIQiG[G@c`84 _1Ƥ1m&i(Ƴ&q7RFm2j_87fk r) ~ Ls.H|efi.B)Ӟ.\M{kq$Bd =#B,DW] K{/Hs] ,QYn Ug&$ ChH`\[PJ:[`L9W *^8"1cD Dgl]%"۶mJgχ;&*場9P//8N²aIv;[;ajqFߎ!rY)6h ) >eث0 )|ɵa22 i#=Z4:CB$IBUϩ g G$fcgw4t4P)ZC#nAp);=SQV EE]r LxL!`\,i-K_PT6bm؎(Lfp.Bb@(]|䴩h}հ&9i/ouʹaJ@-nH"_RQmDV(}D1n; oC5Q?1#! ]#}܆v@ K(( (HHPu,">\--jč8\ODDDNRJl  r蘤:D6sB7I,^mȉH\*ґQURI[-aArbJ26ܕmH"2C #!)F3SGT⑁HGdn&cba\Rο)uwfmPĦ?"RPcg2<`,p((0P_o$E0DɪOٸAԄc1;۔6>B2.mN8%)7 0cT'2:&ʰuMȼ34z-L &c&H :q\?GR<4v)(}Qb}ʈ:#XNg H$3U3c AG/SgA\Hq\WSG3?|A1f]0Ձ"&rN‰|WdBT2ɱ- ,ryTs]Q yBJs۲uSt }7ϰT /.BplFƤk"ﺮ Y3zIU f[300PЪ<Q/ X.!!MhiDczeTl/99#4[y6ݮgek}€,{|Xg:60MۜsT$J[Cnq۲\|sy!Tb9-p]?z)CLU%UnPضc[cjY*DB͚}!sFt텒P!dC`;F5_ ;,Ca#j n$h'sFaбRCjo5 ѤɍMS@K\U/cv^ض*Rɤ @9BC"ϠpMjooiaŖ[xVw|k4@ws$@1}\VkQVQA :n2AT]A$5ː!otݧsؘ!|!o'Uˀ#||qO(г||&9$,-T P {ȜZAHuF*o%ohneJ)J&++****N ֪ѽtC~9}/a';Z3vаY>9͜ IDAT )}FUFY6Nie ɡgޟiK_}Pfno:a>?5'?'VĪzq~u-c-ӹ"oqwZ ': '7 Q"Ln[Z'g}ַwL6M<ȶSQmb8yoEk`ќE,*臅,|T:@pќ/oQŐ. -K K;'F}svn-'`D~_xLF(|J3~% lII ff4#'c)MʅAZ/nv¨m鹞zBD5Be1E ɢdavdm˲ yy)s]Ởﺾzϓ)/rS)7J%Sd2~뺞B}\Ș+Nɮي Ghaٷ>a% |W6vXrŦ]z-nۖeq,8uА'Yt [ZӴKJW/-]t꒕KVx#<(k.,8u MtAͭ]w'*)]={4,ơ°=dU%+}]:357}UKj3j?2O)7 r\Y+~5sՈFAoIw W1eI²D^cێŸ/eeeL* eۈ<&?:v֪eu;b)[Y1?<[nxMlT;ْcY ڀH lvK&| m|($4y-g_Girc*]ZZGO\ZXc@g@ۙ &mNwVhQB _/xTl)@t5jcA$gFbFan"bNn.4INƐ1pfA?󂩀"7He1]纩+Ba,63`PR}$B*4v}sK+{נ_G)HƤ#G0T N w1I"r=0ktjGg-sjZM}R{ %o/)@+7jԱ︽v$x֣cu)_!ܪS.9;jKVzmdgV.vYV>-UuCe[x3,zCNEDPD{ 23!&#"-6ڃs,/==| }Ի񢅔V~or?[mZو엠ᄃAĮo}w=jS XKzSJ|%v?t(얁K2f q?._zm٨)ϾwcR`,H*$,^#YM89 8􄟪r.#pBՠ,>3>{FF< dzh*[Y^8'npͶ='gUWPlV%PN/6WOm7w-M;w"Qm }ߤw+?<0kFL&א:R$mݤ /AS]2B͋)Сb W\ø^L4[g_LH[q,KH(d'4,r$Im' ι.3\c3|Ȗ1$*dTC$ƤZA%DQhPah)I6()`i: BMݾX6E*ew? bMOPCEVsi҈i/jA-]mh XuK#MDho{( BYn)x9$0 ed )$#YB]Cl$/Ru(&v['.)zNW.YQdWS4޷)^t}i;`1?򮛞zyI'CMo!6iF3g纊R#,*VjOɰ c'ZYetLv[uvxdysxD6}yɊg/郿Fϝry/߶wg2(U& Sqdzƶ`BN΀QnrП_u ӆu֯[~mDɄK Kh֜"1&跂}*TL•=]/㇍ռ%VW^b?\/K>U~|1wjzb21:[%V"bҗ|3/_YuAgPݗtRoUi@eYvzeO]toOY4wI41kzss׶)[1xSM+[x^sJoyvg1dܢsR3idFe7!|}O9mvz7W0B W @iT1QI+6ز_ܲg{|Zx{7nX okq͕-'|4 ǬiGL.^SildF˭O0؁@{BHX8?/mty7_v5׭ݒ۩\/rGKk_1v鬻OrX)}:oͲkϝ-'L?s^qc^tͬZر|ٿiz3_+]䇏}qC}l\4jekFd^EӞɏ^Z<+ZxR1 Vϗ{,G9ZeN#mРn~4HSܴxpes |%h53.?.j nw\Rdo?~W|BOjO[t1_Ў9V^ǿ. [s^/wTlϞۿ}֧t9!]~lҒUה '?ןR14yomf!.;N+j_ތoSV}s)%+~5-l!Ԟ|DaM{f}ǻ6D'_G3-*Y:u=3NL}rc'/`W4 W?]xԷ~i+C0FR$IЄn\ǷE#X0ս?=qM.7+J[;GyG̟B׫;t͌zg+8N',-];˗}:oҵEsrI }ŜF7rekg~teM#)Ftt{Iӗ.YC-`vCf Y:Sr:)k|r}=+ XURiwYdSW50`Ұ(#"!7_g8ީ%ຮWx񻋧y[U^ػ#B}Cl z=~Ձo/ܯc&Ÿ<‚ϖUR"Zϗk:c\rivnk>$>ф8 /p˲,VWlXE$v/_wn  ZVb])"wk]ms .j`֜<7* cͳ]e>K{{=q7F j%T U3^жZ1wt«S?ܷMV{";lxv ~:պCê%z|-}F=n?c]Qn0w.p;r.vhg.}RFno7Kݟ^/ޘϺgx}^H8Mk>3 wR -WCNז{XI_rษ3>*h(X.](@#}c[lnrũX矿YW_^t?_|Dd5[~ՠ? k;I x3.h@j_rg1\pydCUw:Ý6ֿU_]{}T۱eE2IRUS4r҇>-煛4A\ #6?5_ӰKM_^9/ kwϟ{n/|^J)` _H*D|WG|ϓB$7Mgf [uѦlԍ=]+o{ky_+.u~gC}]d}{>c^֭1Nș^wU_Y{}#T`g>G˂}d{w\׵Fl712 E +>>[+zPOt Q˻vw䮳hwrv}&Ճ[ٵN~i]ȿ:gC C${=[Yy'utuUm~JH?qヺwE~3򣞉|Q9Ħ~G+*#gv%~h:}ك ivӤi?=׿r#Q i3v2ne<3ù7~3x˟{}57uҾ!Gvl;eC>Ck{K>U% +>~SWZu,@zo;Wرτ=ngѾM}&/xԙ\cOyϊ7muGn~E6x;,^fܰhg^ 1*f1EގVtyVmVEP":ELWbLjpS)k@i HY3ПޫHz_ ro^-Z!,Nmpn{?20"%4>yKdL TP1๞1혥A4|qLrjsyQ_j۶5߼ڏ= mϋrW ] 2DB/弢|ge; Ƕmjڂ$a,|gxo}MwV|e=_YxPMGRzPΕ#f}=ePذkC  [;ESiAn$M_uBBo7cjgpO̒:#1?(.qɄ nGI ΘdفW?vN7x"@A itگ~ [tkrRMw̽ Qq-.S󻻪nQӭ~jO/6c IDATu]n@ JNۖt-WUV..mmB c"_*T^U/ aŪ)t;oj-%Vo߹I_ v}[܊fߐy1u햍 G|贞 $JYy֤sNjW߉t;_lX.Us_ jS=Uu={;U7NCCd;al_1ƼMU?غz{~fS'n~~M7a6 [*+8_ˋ K "}f￸3_|wmf*P7 vm~o?^O䵽%_r歫Ҽ.Nł v9T6ז1}wsNj[8ug3ӶG ! q1_ͳ&sRz\I]&ھ}Ç/ҫmҧh:̤G^ifHQ̂:n`۫ڸz=5>u:CTbp5@'i"' xaEɴpDٺq5F7M+[iMZ\gJY2`m!uMQe(tmqlnq=}`sS~pJPL{ Ծղ<{ 0) UKrX?a+D@Ƒ7o3^]<_{iևQ}6{20m2e)+ ɫطs'd`H^žAG9y au[N1rN %,CX^˘PJ#ݪ*8w8jĤ|>м `x2, #9;}e^fVndPe^GYbd ї:9BD;T1T20~>Sz)^rd8R^(N`?9{kJ!E]~ (!\_K010>YܶY {-b"|rS)ÜǮ{\#9{[HUl][d )bgFvP0 …D^ռY%u{3Xb~,IN%=^Vyu;?j>5/̡S~t=z36~lUj^޾r?W%iW2_h|o^Z6kJpw _fؼY1Fs|~Yr×7%'OiئU^Qt£/`Nr٣Xa?2KzaemZ[s1wO$$pD1VH#{mi IVTa8zt}Ӫ}}:ÏإmslGAQvN/auο+z{`Vu#],W,kΘdඃ$p!0ҽ{miw٫qp|Mߖջz7ӷrˊ~< t='>9 _n}w{i6Y0kU@ ugb>͐-w6z%-tyVH "K  eZSӪ0֘&cU[i& MCxum=F'~?y2i^\T,j:͚MC rϢCuyA:Xqc1w8RXzgKQUeY{@n>XIk("}겝+P)}aP*%!ClAQ v)-;e^ [7-b1[1fs!ѧDm9?|{&ιvH :ͮ>!yd!gN+9q׷O*}ə5IC_<~us:+Xz(Mn`/.jn].z qZB(].I)=w"紮PGx$*~(Lx6j 1xWp-<~'a h/`WoW]) ^i >ySJ#,"3#xF yI 90 &bƕ4;p!dV6ȐnkT{&cxFI4O4>Z'usz,] lWxDSঅ6-ةOyG}SD4Ȩ #Iiv~vsd@_;rk#Yd;]KM?Ed:A玮]hؿ+ysoؿr6ݷu?ذnfNdq#ΧL'_Nݯyg?o`n.PpP`J3#ZMdY65!;Hm1!JU$T- )ƌ{}&tI!.!Qi=#B*Ujs99޹3=otv^z]{V9!#NBFAUZp5˿sI5j9ctd,z gziÿ>1"UBHYB k=6ʿp'"BSj!R#$ϯOno$I*B A2b2pΘe!_$U2GU4{FkVaQ.}'@RF \!%BD4TRPz1b{ekZ_V0 sgp@Ov?JTV>=sȪ]Kfn=N-,.gM^b o,x.Y6#5o˗oϹ} L[>ٮ/o~jKce uM^%ux`ĿM}s9_֕a+*_m+PˌO#!ok aW>b{wV"~wݸ/Up۳D1:O{nj?JWBtm:r!3W׭lCB_[izk%ZWT㼎yOicFyRG>5"GT >Ѷmp j$]z"%! ek^sbi*Aհ]3N4iӐvn]irf';ci8ۿ]وW[RV bpfBJƚޘyV^uܣ' 6w_*9VdўUۃM&,]7YKie~"nr$xJ t ,)iq,@:dvzn9hRYctHլVA 0s} b^ 4I١]>qΜ:Gdn(G4m16Q7˱m@#|Æ\ۇ,ܣZȪSa{Чz2;=6 sբD')0=R! ۷"_orTAIe[BIG!u 6%!9R:(E4`ʵer~]5k C.\X*26i 9!d ∊K1 C=S pPF$C`ȔmQ~_Ys!+AF=;v^[fS*&>@ 4nܠY$zB fr"0oԸ~eDZ<+y˥,۴z7kplm@1MCE&ۉKyZ4f6QJ؟ɲMwةQjᔂ=+7?0)-sg63J,Aň 1b% \(D%ą% 3]uU]]3|ݙ: 4Rr9Z,+7'å 7t"/GT9iޞk ukJREIpr`Q2rwߚY_}<;iW6ʥȬBgv5s$zӪsnd HMJbZ׀}q *W}ίRz|Jy#s͡@=:Px禂׭/rĕRpDvs]qUعfWo@ڹr[feY8Ė(37mIThR7O+sNi\1mA5I1Ӯl skZ2 vl,(ذq{Uٕ6[?n̯]r] ,JB,/f3DV/cRW\2dq*{$FI(bnnd$~[uguޜ+͚/k'ū6gh;e[(@ N^( NX͛1owDݽvڲVk4"wϺbRʩԠSR ѵƒ_:[5[?n8UH%ɋYve-OβcxVNv<;n960`f۸ջecq-͑ ^wFkoݾ3CluJ,v#^ѰV z>yy_Oroܨq1̮ڠqFunj=J1Bڸf3#4 bIV ҹV'XRZ%\WVB}W2Ɉ`8w̦Onjfuo ֌>suKZYj \_o6F; 0C*k }v{Z/vaZ}vhNa]sk3Ou[ТFMkpx΂C] ,uXLjSIᜰyϬr5NMݨk{[~|9ccR[TSjVB=#5xZW @~  W*p.Rn*\%m1lj9#] 7m(,,ذa.%lݼH]7\Yq7%V$do6UȭgR.Ze˔ .dPЬ(! 5|o~LF5lXRzܮPO)5mrJ8] 6[`Æ;eٖ  &Dfe1A`&q|(ɢUV*"J']*C(k}F %3q}[ַG _N^-k*r|Ӧȗ|5w.Oڄ0*[! 4j\B oԤq"嵸I>/nչo{)K XN:oԤcw1{k٫&4W9g6WBέcuժrwȅݾQZ찇Zek=3kvu'O(肎gٷjGB~WG.0jשevAxHtЦmϨ fտ5m\]: IDAT[n͌5߸ջq'n3xZ%'*hS=fS[|#_$3!ټ9Y3: {kuV>gHϪY{D`䫺&hR.K۰xo /EB7fv/@ݍF`/=B"\\ҧ^E9u`9W:W}yT CV{GVb 7lNV?u ޵R#؇rQhW:s!8wTϊf9x<++ʲM(/x-SK|G|+G{~λԺξş?G7y`̘+nt·:<Ѕ0M3Z64LM8 㧌IPEܾ40IFEox0ٷļ 'R }oΏnW=[N;7qB j w|2EF4A?A S7^U>V<2ѺZWPX[⤳k:X=n׏SI^3ƘBDX̠R@+~vV(*l6SD[vcxOȞ^=+ DƘmY̒S:<{Dž1!jmqc۲+%eYm;ຮ+r~qٕڅ̀u=Vh$H/"ږm96c,##Q]znsl=فU߼-I@ԦϞxҋ}~ܓSX̱AVdKw0k>}kի|sǕ{"eѣ/yÐ7@npǹ@9@t{k}xDZwBBGqpeK>>|4 -#C":tX!}?!K xaŒWw!ɤ3!"R(ַ3)>]sIWa>CT»!y cn{Av`~}ToPwIfT8oe_j.c[O~ܐP!޴ر*Nu{lw(|c׏ ]²gtקo y դ1WŻ5|^x{R|=DlSʧz=Z%w-lϡ<\ٗ1Q+}ǟ PR `-޿2 P1,^>OW{_fVL`ێe[m@@YFDI =7JیfbT-T&ѧ*xzĄف{p6ҼNwsB%ڏ_ ^3kծb7R2Yႇ;k^n45޷'~'7qwT/xn_ mMɝ:}焮K ;5׶M~e;>?Cq= R!/QCBa"!OwW3r]}K>]jGo?~Բ6Ê7}pIvrײoHh@+˛?/>|ԳH⏟@$ |?6g; 0-9Lg7fpB>.Gz `7 ?hH}CrߏޝT9` 8rdEX_|S^,8LpѱŃ{<\̣}\qJJ}9y<ռGoCwAlnkfMƽ.!iF^2կ XbSj1pAؕq;`OA):}ĮKtE:U(G y~=b6ax:;;uΉ7/-B 1N" 4uj؁|nkf9e{mfULPbݹ&v]VlG~C^>{?,lpS >7e3ŻMkl*I>w=V;O5E~_{dy~܇;sy]w=۵:!oOC?l? m^pO,';qrm/ (/jjuroDQښa>gRAU8` z)"h$rF?=C9=`=%#_L q9Z%Rp3DZvns xhUm4vXiKIEEEVhy3}g, 5k%V$tmۖªв[w `ضn*R){`6e cZZ0l۶X+he@;&2Ɯm[C$8r3I% \>${72D%P:)E_᭚C۽VV jnd)꿹_͚C[eT}eIјfٍh$moor* w%\N5g"2-"c(h%$Z&E/$9 Nށ!P C_ߨ5}Sp\-9o>i22I&G3HVzaOOMBΰ D0B,)!RÒs1e,A%L*&+;=bT~X Ƙ86i@; !Yl\7ݖ my7(, 0~a L$l˲l ,q,[@F'&\Rho_/pȲ,۲5Au@/Ҳ%';[q]ĪkbO$jZ;2=a=~4d[BL]_jIjiZ̒4T~ HjM馉\`\[Dre61{=cIhr.CFܿrso?d}!ȁ!tjzhUFZhŐqqC[X^ɼ\V~ozŃi eA))e6} ,zJ  !xihFjvoiR,aPQaZnoJӇ)ȶlw=2wz#"XD Xؖ" 25# &\tW/"xv0LC}]5TT%4b*-&LSZsdv[aBFhc2}Z !mIh&82۔"wz4 0be[e~p2L$$8xRzC˲-5UA7[˲1o)ثjs Q"bl*2y҄,m l\cm۶%'Sl.zܲ,Ƕ1m傓 z>~6D:t~p>ę . a7oIHRI):H$I!FS |p;>%[]NcdemFI =\i5J"Ф9@nSʬ/5%3!UMD1["2±2 s`Hm31T&qb$S"{R T[511dc9eْM.OrSe-B. 7SJC cȐsC)s-yAHifή/gJrOsR6Lu+BQ: y*jњ\˜{.?/Ƭ>* uC_Cij* m[e̲|LB2*Lӛ7`ڊh!3)!PͱU!sx>qB' D):5WA5 (,\\)Rك ){ +%̎up=Ԃ(J9FR2Dq sک>o KWehle~H]x`'48"Q#32g?9bе+!; Gԏ?LO u 5 )䁠.K͖j3 y*e0P?8Lʐl I=Ұjic fpkWNOqO%00xނzBdf~ -eq!9)3 PSP RsZ"#HXƠʏ@tX`/"a~Qb=C Fժ-U2=!qǶ=+..Bضm[ Ug̴ N& MH $)hD>j0) z8Ăi:bz{C)&ǓxU]vM'eٶceo\.T9j`+E|-_ѕOt {cHjMB1Q rf޴Oz* _\RxI< iCXֽ!ܦh.tHuII=Q0)p6͈B?4. 1ʀ_0sqqfx} 14Sp_Xᲅ ~O\U|o{&r*`,˶,7妒IAvRR nh!fйܪB 3qЀ- Jo>M2D:Èt,cju]Aa$bcUcX_AD9 ilI  +mASAcUbYq˲d4|)|ԑ$UeYpVg!M~#%ޣeHDH{q˲ė:#!\dcB[ݓ#=ٶ6i( i*=IAJ.b1۱w"B.ůzSBH"Bl۾b*Df=clL纜sE0F|0l.M(:sY e1I`VďKjQtG.< 1Pp.QTI9l&M af,#0z:&@@<0M8Bf 0%-,;C]( :71$ .@˶G|eYZ(S˂'ϴ`:Lϲ265.Ƞus: Ιm[O@ V%0, 0 @i>&uӌ F# %O1 ҲiryZD/`VɭFc#~o=F(jnxѾf04-1N0c߫hT2rsΤ CŢD:e~qo)OC9wȩ/j9UTF}V*7փ6@JYZVfTɱUkʜ2lšҠ^¯O ֘sak]~7~׷ȟ>D$n9k-oj=pc{)7.CAI#4+,9-ա8v2c,s'VK[&7x~et=˶c& z`kjA6kZ>bv Zeٖ?YrOp>VU2-VPa!(-/;v_~5ŘcYx2Y>9l0.nvs}t[MU͝/|մ͜˸w:ͅy3o7?.^~m8:U~6oozp=&Λ7[sdM\^;__s#vEdW:_ f/gnDί3g\XB;Ϛ;3ϟ6yTƉ,Y?_0{/Z8] 5A\/Z7so[m(ij aˤ.mϾⵥn.!D2$RrJqa Ȳd;Ay+`NI#(i v}+aZhύeŢ+~5capjW:;hsg~N߫k8֏&[7h`iqųXe?~e5cRqq3jtןs?WhŪ˗.O0"˩w \rъ%fLʄTYEOUu1$Q8؅cx,+ zzBBH=={=< 'e}GM_?}:Y,;;PҒۀʎ9Y9̶(QTR l灠4W u\?-^ϟ?&ϮcŸS{u3DZۏDb\3,7]Y D/%{mr偹՗0,;SGD SˇSA*X[?;)0B! 0㱜,olKHVe}*"m͝|c*|4|x)yXLIN,Gƚ?1c鈋P8hנA̭m QW%iY r4n&Y쬘cPģLdU }7@,;s,-\Ϗ, trp餒"HB&11 RC-pDhzǂٔCcOyu]-YdkU}_D&)kh}F`)GE@B)25_ v^EYKi#0l N׾}j'?Ǟ4w4|M_(R_tCK,|aUs]9,۶m+%ÒR l̙ cǢmDiwsꆼ5G^?K{R8\\̵ck*Ƿ8pj&OQ޿(`ZWkYB$U2vn9V4>S_7TLfzR ֫/d`H8ݾܱ f~ e!pʡeV^z<۶- MUbR o8)T; Ad⿧}8޽+2, =x`Kd[xdȱl[ʗq_7 :hֿojk0|Ugy{5=Q{n`F hd%V0zW.HF۞[럮ֺso<|m2Egg0l\^<{Λ(:c>[G/$b/Jy+<ΧkwĀwŝ7!lػxO7<5/z׼24SВ\j4+#c6i}.ϋIQxß,F($Po{g,"I`%sXR35Ф=GsryA 3Yp`[eBubp;2=<;7oJ7vqҝϭ-.sr ,k6WKAxH=4}v>]=F< e5:s}·G:;?xi_$ǒ4#o=a}(`V{{Mow]{p+(-85.ŗGWG*vKoٖ8Le !İ+H1'-Ua;޹O5{~+?Ȉ ر,۶@8LJ 6$v^F.W<Uw t{<;勺w}֧gA'P@J]rv[%C'c)INwbDu).W@c2Ğo42LN`]S}5b1')RPiֽ{oLU) $7G}βoDDnֽko~E2`08穔h3vlsxʎY+X2?SH^vݪ,{sj4A>{ umۖx.!aH%6Kщ@LH\a74;?E,DzO~l˒,ƤhohA1 jITr'E= /`^ [ "dPNY1`d *AVd% ^C Yb>2x԰!L9 I݁2nHDd6_G0cfR.4ɫ{9-p"uIdET{{FS|Hw8ym)4Hz8p9İls ܲ,q<!̧3Ab2QxiC%ȑ/۵ TB_a9pPlmܹb zVeAMoڷ'Ū\RJsdI AigB?JWּvځOtGSmUM1ZO/ ]1JSx[_^}5$bBZ\ .n5Þ].j ;cphriTd I5`eB޼ppӴVN$ɤpb1UYm0rҜ?_}M&mZ`]w7 AD^8NhB62Y8rBTrz"?X>,|#.oTxhl!!`Ѻ/?\ m=]kWsF1s{6~:"<$,1˲XvNkQ3(ؐ1sԇR{ʡ{p>7juJp.Dy8@p=/vxBʝf>ǩqe];?l}e=Ϻ轟5A{zYpOx`U/^5znWku@ʟgc3pg7_?}k\e˞~߈w< C_LcFN# Uc>0*yWS~?k_j}n~wmS3۽hq[J? 8rZEv`z+N aM#Y-_qp3Oʅ)veL*è&E!7mb ,߅(pDr 4$bba I{7C4,47jK? "e! S>LP! Cr&Ƙ+[m6!0rЬLjNb~bZˈi~ݾܓslݦ5恛x[/z[9N׷ѣݞUMr\ҺpN4d`e:ށ]G HgE,pU "D,|O *R%CO="=Bu*EiHC '*Ԏ \f &Rc,r0n9NBnr&Hv`O@]?~,IJ1c˄tBO^AoPr[ zML(.Ztڦ?R+ P8*kS\Hcq'&Ɣ\jX xP.8BuT+J*ZqNQE%J`dKXK-f)e )$@!d"8VyrX^vW><NMLߜn,Y@Wgd8w;Y9w`g0'mR>"s w̙EBk-{T*%HضʊmKW"+< ۶d>_j@Vqۚ{iSY]{Λ9oءwΜDVٳ951!rIM^|%!xv۴aĎINּ靏h^7wfUO^ok_=c(^ܓҫSziyY_}/N/_W̱E^Qoz92V}{wwn'Z#Z!aMZn&9؀#;˯׺j2}sw.ZyreX!"uW3^0K;bP4s]92[W-^`[ 8Dɷ~:oc1>o?+wn׶0狅KGdyվ3(M-*]N?npelo&TiBeԩԡ}MR.3"BSdȩuuϖ&[v,|St͛ټsZ9{uýmh;*ۡQ{ٗ=ZoW'}\: țƨYC,Lj ^ 󒩔oM e&ȧ j !R)7rH2iˣ 2r74E"( !1d oP ǻRz|;4"EH! @HU@P3 S1[V}L GLY8_# Ps3րQUH(a2Vr˴əo 7l-\6y{+kw?Żl;sjU->jJARcg^I3Ե 'l/& IDAT@j6"4%124E)Ӵ R]VK(a7=10G7%w)'{WjwsyYAWL8HP/B˲8iD+ysJ";ceȉZyY< E>fIP4PRnPʿd%C8g/S_}R >(Vo\4u$YvAB1@f )׹~m[_z{{1 17]Ξ A^M%2bx,ӊGDn=Qzs*7}2NzW}}e]Ih;j5KY9jO󑾟mo|qr JumzQ-ѐ %7͚9vjJMbyQQ[[l7/߲{9_@ve/{)+n{o.wl[3ӱkc-ΨP 7Im_2s~(Mgh]gykVR̳>{oMYex}qvO!_CI5()Q30"ꑀV^|8#~}Օ{@~|QUFz'gȆa \HW9)hO<]gAfqkU33\r2 wwvN8s*y*Z$Ư66`:57E']"In#B ˲T烙rj/s 0bYY̶M = iRB2~kʷҏֽ{%#'mrrש@[}u d)GRǶ-p/cqD73jw[^~e cġ&-M3d5n^x柢o0/=4Զ%Ң·o(գ>qB ϳ|KUc<#G$݀ BF.j*d7ڭQlIA+&"B2_>vڱh['Vs]_ pbQksUORVݪ/hVO'ܹ-á:WIQ\ N\ד9S%DbӯS VǛܭƢ,LxPX4o嶝[1 kRҨ ԕk1YUA.H&Dsbbr(l,SX;;=;x‚˾:*ۈz -;|Zʰ UZ (>XRPyu]We.,lAa@u(}.6R藲Hn}W,d04!1 Xſ"mBcYvX,8 D̘iaȦЩOY7aѴ%U).,dّ"ڬnN?g6 nأ{YQdTuH$* `Zsd(,  s\ b (*JVrN]uU]0gwۡM2w}4Wog펮ppX|ro_Z=^ml|@r2]E[8@HH|K2_YV] `Lđ 岾lؙrIY rqf[t_?7WE7X都lN:JMX*gA22mp C#ݩFC&MQ6ZT DYyF?e{EGivU_*]'LU&=ײe'L 9.e,D spے9;ICfW޲e"Z-52\A@r"n$lBD ^/u',h^xwG[oXtk/O\lXXE.DUx955s*Ha=ޜʤMq/{Λ DAd2`<٫u}o>s1'oYXVs>W`?RΨ_}2?YK|u|ʀ3qawV#kčb_"@0a^3pGPtт-A\|Si7Ti#kod5P oDZwFk([D R!soun̑TײmAs (j$u4lGJU)nn1AY+@.ǖPACVg?6_TŢ^G8cAh (U9E:[6>?1fάtizSrv^twʱGkxق>= Cmnp{];VVcݾA࡜!r$R N2ޣ56Z%IeWٿ}ؗ:OHGI]cgty9 0& 8*V{'GdYbgލlr6duνb6IUߌ~{Y L;zSJO@mɟ 'l^Z:܃iNbzg<9C0 Yǿlv@aMy~špO;2|U!AmڻOKc`g$0j9{:??8ٔQ̘vm?X=<՗Lh1m*7xlh%xXf:]h6\.-K:%H\@9HU{6(WA^Cyw\|p@S镣nᄏdڬEs&nڦrwZN+TP5VF5GoBT*/qMҒ5,Ro^POΪdoޜ!,acZ`FNamFDH]P)4 +a,59WxՒR7ݲ$P)#bJ_IGE؝0rkC;a"2KicȒ=qGKOdQbN\3k/R3L m? *ēuM"\ lbC\eR(R9X[o4BsrǘZ#gYg'7sEҩA2w)] ^nY&,3"$(정bxu'cVvYO9w}͗̓V y? ]a=s7]kܐ--s.9(rT7VJ o PCxmZAF|ZlʭU`Od #4N\M$ڭ.(! DwZ-YۨY+ "O!H$Լq2|.Bp6K#"}m!i?ra_ӚqGٵq՚eۉ9  Ng?6[gΝ|VJȂM?WLcs}y.8(?URH,<ηk7n('Qy|ȗgAf@>vo M1]q",ٱa-81r_zum^^L,b:D.UT# )ywd<!ෙ >|IsD/,w6jo>W~xDf%jBQF:~4L(cPxEPT$Te~3L(8"s5ޑW^תgV'K.m߫}x-ܳėߺ{>v{6c-SɓXFF@x+a[lF}$sJnI2P 0 x)&TTH!~)Hlz=}DzUG.m_\@eKgTP7k} ڞվãuveAegXc65>vrXHd^=crƠ|w$4_1# ʇ¸QUkjl"[Ak4SKy"w>e߼g#v?uW9cAE@,&u?dMK 7كy "|_MJ̓ Eewuuсoxڟ}f>;Gl5G""319Ct:MWXX,v20\f!b+nbM-{P-%JBWTR&dֲwNZzѺ'0%܉@'lj9ŒF!jMg=RN,}xXɈq H-a0X)/=_ĴlPs R t-th^#U5T Cؗ$`K J:Q@@@,֔II\O%k&mwФ׀JVt,8j !6{e9xh4y"'D  c!FJ9Źu9G?ݪk'o˻뻿LGy.^n TQlHaua !a^MJF.T+߉0̛?tT\p .{֑5 שuއx6']{M4Flh2naBcC# B<®Kac:# S=hYGKת /IM}<, 2gq\L97/P-/>aËA\lsd2 J.acA)s7pa38&, e?p!I%}!2kۣόz@ZwͯgvCf(c$"I1C\c"t6g6O=hiMG4_=J_tsDǏmftbȋѰ~D]⓮=`ԕe +Lq2 x eZ' vYӂq\XzK9a0:cv,^O8MyH(/@s8#IBD5Cku lJ?۫~9, bERO@^#T&ێF >f}`ˀe+s":5sAez۲_ ӳ_E ÙX |C}6mն?QCpi%+f S$$ "a;ƬzdpއnV̎?&}anM.ǚ EB|@ 3A \ Ìn(ykJnC[/+Oq1vaxʑ1$%pVni&KQsY,8 :)^@Mlw,b^.Q?SIQN,zĕ1b j& s1AXThw&Rc;<++Wdܨ%QL"]Q!IP@ME˗sTHHEVa BZ_=?Ks6v?6kIFih߬F!:}/3VU?mUs3cDoY秧y15({ڭs()FF&b<,(k8wJGI09, BNKQ$*pi CpOn_֬gGuYzob; V/↍/l+$s?ewɁJ>0G1bM&lYثIo5Xs€VM_~+׹V#(ɮu{XWT^Iz~~Xk'`mkBitĎ q\UÚ!"p]fW5enow~s ^֍R>dz,)pC XaVG)lY[iwu3zt=ؐ/ &/hТYu<̯tc KKlܵmΔ?nS^i n92~e_]U^=ugXvOZmu78ob6mIKoZT㼦Ԏaʼnؿo;z -"#Puq_(!2FTnz+ μ&LzGwܝS'PZteg5qKFHn;[I@ m{_v~NLJ/1թeE&[tOcR$0)eൺG]S'/ܴKϨsr"H(k?Zfy^TA@Cz@UG/ IDATyCO@Q0O6:on+ *%^.Y ITѷ6UsJE9TUdh%RH5K:!jF$!޿(4`߸2V5j!ri`;5֦_pX*.,OVHHo(}q _J\+/}O5tgE=- !1Db3.(ƃܑLEaM wXiטD?ֿuMC?K_tMAfo>zᥫ?ףz}c.^9i+&J$MAS{k2dwGm պÙyW>ϻ]rDӹACo6=\&l:eI6Ӷ촰\1ds@lvRawk9迟$Z?<3s>)5.FeN!:.뺝uM ,S\ tǏ|gE0yUvNmŔ/Gԋ"o}tK/}{o]?zo}pA1yu쉇^bH\=˪ë۾VA9Q, 2AIdS UH ;[ YWY(6ۘ 5`DY$DZ""Ehh\O UzVu倆ph3=>G_MMPb+0G]Pbvt'i V-RH9w=/y dF]Sƕs %C$2"zprlcZ -' Byosˬ2Hw+6lX.]"v.0SBYT;^w'5q(fY!ecs+. {-XCW3 8WδB90d0sB0 -{CCCQkrJlGV1qTȂ溒^ Z/lK.BL&L.c̐usMA[ǚߞҶ u]qR/1 Q !TI}_!C;!<8ֈm[%pBF5jdKIK39w]q>O+gm0M qeʕYk& !H2t\u\P$zjnaI!D/9CѤkpqB_#XSETG$V:0U ڙPF@B%;#Zl$Pl$#y@X[+j4BT Qbڤ:q H@s@9#) VU2q@~sMbA>РavT5ƛAj}GL˜<&0| Zr+̀ѹUI=RBTsq7\,@i;uc!D %"0952q>wåJd*ud(To"XyM(RiDRyyyy}.!V30! RBF΢]" !(¶ M`fAKIX+[}OɥBTI!'+C)c SsZ);pbC3Pf1@RI -h+&8I[Acy#֗t(\8e&q.teHƔ Y./̃([L 6W:Un+aJ]LVdOx ѥOUg]""hb嬨5lvd;w[>䄪u]_z8(ZʐtdL% ㄧ`y9(Cj,<Zp;5jlgx:| f:^w֬;^"g-Ma;d(%K!$ 6Gird*WlwRۨK2Gq':T,UCGWېO}߿F>]2^z(w%5ڣڰU4HP5"`q:~u Ub$vu`BiՎ!T"8)KgX0J;PT.#V*t;rh3# ;SF%)u4L5a)CzBnJio!fbw*]poar(lɬ5t]y.F6CUQ&O^5mA+BDuaA!6 RG2 7SoQMyi&5$2[ڜXtDD0LAo@d0c?WDGKtDRHyǃ@]Ar2PoUk[CTֆyW(Q%dm1 i yTR'{C*#!]7ǸHl!5?rR!`Nf5f |"cw l&:dBQA;c -w0@Jb&͘<Ȓ9U/MI eMzy'Tʙ/EH()a]@Q<+2՗ GFa:z+XU4h'}dVrq!vf"Sur].9ALs3ƥ߉s""'"B<8-9?Gy a18q-M3n VbC*j1Bw3٢(i***+CӬ ױ'&F}-L ! 3HK,z!^l}RR{bjJOܱ5aylk'D( HRdlCai,me__^vl!k -@DBH4 UgMWN.>H$}eh4qãYܒBG#Ilt!ǤTW)7-Rf/vo[Xǩ~u]y:}?YP,Lj(k"kʇe+وirQK,Ԙ{XYD[__(XUV(i☉UI;gȔz$V _ %Aε96FE@&4ɼq7d|<}!jyxWq6J j.ђ8C \СF)9B׭04Um,KWf1we~&㸮T>qZ˒!{t:mhq?QlNG(-e؂j2RA]M3JUʸz&uMbNQt7f[cmJ"^9u=dL@mLVj_K񪴪(56 21hskG{ lh0[.&dlD9#IZ>J"aAl6a@=2 lj7 }r#0Bu) fZHl8 W1,LU*Jg+P Ad|? 1ɾE먁"h*:+\xeз2[(,d57pd;AB @UjUoe;[hODo=U ; ԓI< p"G$Rc'`)^6[h@('r3;r\=&RP\ R$^㋮cْŠMI:d/ꊕ} !E1$0$iC8] l02 mKj}@0ØP#B$sJ=Bgm(&j4h(ZU8,XIRy*!l (md5`'B WDx8&99"H0- 09#b+Q#)cl5%F Cpקj {BB\7y9[F.#A/8$=O]Ht CQVY_tI͋q($$)U0JeLeSB e9I夌!FBDRwC88˲J&!u lkiՋ^;S?M%/:[5Q㺮+*9%sȀh؈^ |A]dD1 EQ:CôX&$ ԉ֎Bj cQ՜8h;վbM6*kyN[)=?"CE`P H9T:Qyl[M6$$wTLTrdrr%A0ɐkIU3ZlarQǯ׶"J(okD L59iB9|7QجLH_I;X@~ŽWy*/z )YdD$A)&$%#NXZhcج3L W8st:Aû"Y m¼%eG %͜vR%4GKT)˕~1 B}{aǪj@uιԺ#R8sǁ I J!vXy1tuӤ~|JqF_GEUQQcbh*yָ#DQyJ̀YO|+R虺RHW?8&Rc%\r8#_D՞p5B&̈&g19 K $qHȸ㸮9؈9?+,4MB:uBA9D R53s1V ʈ\DA)9z"gȘmH@\QsU^RvEᜳh^JbT"Ĥd,tƗ2#*Xr2M ffF¿< 86lu_BqU*1V[J >ĥzpGc@RwkU/ITVGD@nj)GX1CS60RGR s9"HH tqf]^f\Cު,YZG [k7-F,n# $,4}dG8')ـu[_ia.$)5<8;%~ 7VG,!2jK[I2)d,lzXpby^(12e _j3ӑ3T_DTiB"ѰNeY4+tV>j-^id (Ϋ-@Sy:ȼ&WgJ5=fwŗ4$H{ je"Ÿ́\"D[$+ <Ĭ62ݲ.Y DH@ 꿕UVD*5;뺎SP/2L:D1! ;(ҕa5~";e9}]͜CVGWUUu}g9ws-V^DFD9hcԜ/ύ}Ɇ;KU_25Gtqu5UȪΖ*AU:v޶WO5>>3sDPdT, i!qH3%SV[+YH%+;IJ)g\JE&?)v\A A N3 !up8&2}p5 P#jap:3&"⌻h3E$.s;I~66O.iuIQڊ!dZZ}?_6aNq NbZ4ȈP*¦-YK-Mc i< BE)׳L[q򥔪a%6ld1"+ !(X %& IDATIVCֶo!@ZJ$BNo>r,"m}:F|)Gt:(Ogi$RFMߍ1OX}ԡwX%k3Z=Rn+GjhDȏ4j; BM=5-~I[R8*U$jΙ!ܲW pɜK,Z2k@5Ĭ7v% Q9zzA&z£Z҅ȶd_1a줍@sk]2oCՆ*$N>crf5yt1~e4ܥ\x6:W찯Q~WXљ>6g||Q6ޮo{v-W‹LLd,4ZU.uZyyU'^Ӡ +J:W4G?2N~yq;_ݨX'1%B tm@yy }lP^|g>osPzG6|ECbܫ3&BvI_vnXpBgɘi~>#HV>i3̘%~& D9KRXӻ>7~1yƤ}} 8 : >c;{}1FD3錟R0RR칟um* ue v3~9s룟Hgu᳟&[8kδ/>ؾGm0I3gM9<֨g 7s鯵ׁDpz:1!h *y`YA~EyE&VTy2,;qYI)nS VLLطK,xŖ:O}8aŋL^U@k{;_teO=rOsb_ktNX4w?CT>_FO 3ms36G ^[W;ds/xE˦vVI&,lySms|YZȂ+bMiҋ JxF?pμ>yFz.2#hNR20ݟb '̨ٯ{Uvu1gl$P iuѷ7w=@4WL;iCšMGfFƎ?LSݚs!gn{=CI3 ΁DRjtpy+Ș0> -g PYtFms5 C{5;)E*aꪃ79c7koI]Z)$dPDŽ'oW<O)#hWJ (n鿆ۭe P)^{~1(I/ L@>#G, WN~ gjUQ2aզ+L vfcWͰ̓@PdFn^=jC:[(dE!>$ nHTfԛʱx@%ZM8EQ;"m $_*fd(fe-EKb,+ C $J R@Y"7r繜+e["]V^QN )=-.,Q\ ml98Rº4 P|1i/wiiNߝ;\ #V!}'&qI=iaZZlbOH&jtm>tύm{;8poR8@*q]xAUհzGImߦEyq쏶LqEJŮ[gn85JS3OX@4CN~Ǥ4W݈C-у2&,CWpQ;z_28U8!P+gzmۻP1-%I>]u~ƷqjIsz{H2:B"5kto~7p_Hax|jjrE F%  WtܐsOm4?گWo?-5Ͼg_`A.X럭4^/]&C;}oغRj'(7^ڊm\L[4I$ɐqJ P^ Q~}}&RGT.DÐ"iOb‡n {Mf^}ۗYC.]5fǰ"c(Ibq]nm8Nܬv#&܄C(\ XIAD VEP;"2i#Tp|. 1zMI݁}QYp0U `c֤nzclIxwL "blA'upץ5"L#5f0IUʫj'0s0a9c?z [h\0JX(B##tRi``Bw5jxBL41G`@oB)P6+ALh1 tȩ݅.Z6wїW7ыYsz~4n3#WtO{8eժ߇2dc<:/'w8?"ι10≒3$90j&@ugRA;{<ϫ|/)j~S%֛U-V;F)ȚY/)aɄT%7@g_鸼_?7ԼnBebH_&I=?v\5M\n°";8 WC ;;pE!54\xj\]iQ&IKL=c}.Z+?ckKvάU/,VrR܆pmھio~񕗴c@b״絏܎=C@pw_z 6OE^i|?7 Qu%fa@qusn-߿;j-}{_qqS-/i4l=?|yf}>?5 ]x^9a@Hpu]u\q DfA} 3(j`GZyܯ5NfA;xsMf@4lwFC(:F4}%s yk̞ڧ_l\b˗twqbٻ9.wh\8/t'zoS~xdž\R^3gM5k̏/\RPIdoNu;}ȋLuQp1jD ݔSf/^}|Q'NU}M-Y"->6~u+V,g? Q2I,h-ZnχSVO^ƬB&M~a?L9̱imof̋Jg{0@r 1du}? HG]u[?ukyQW_~tDP(~  7(*P˗%!z?e_^/b2rsud?SW8:~8wǤXa_byϘJE ^|۴d^fb8{c_Yswd?C`n8^i܆So}.sq}6˅.H8쁣wTڷy@Ǿ>kZSl'Vwa8zUyz9A .kZ]\g֞wQms.f:ο#ɻ3t\Ŵ1w5s%1)BD,<榾ç,h)cwo2taOʧ?e z&n];O]ۆ#::>դEfO DE ^t%s>7~5#~n 7s왣ؐH"s^^;,=kޞ9g9~z pg/Z:6%W=/ f.\ӐMk{뷩7v܉oΚ]' 7p \8zܔ;kF6۟g95׻~hFo5 vጙCƴ\8c=Emn| f_W}o8ID92W<>3.M8$(pZn`Ԇ=TciH XOCA~)]v5N(7΄Y֔6ވA@dw -7O3yQ؆D(Ed+d͒D_mK 2[! LȤy6 LR)5ʁ(BA&HUTA 䧼‚|u5quuqƙL81U7<-uխ51p8>E ?6Vy߮j3G+mz N_ٯ. ĻO<l7(gwfw91  *⩘'pg1gQOTP *9č3]~TUwu,w ;S]>}BϿ~=}ɀ\M`-įu']}ᮾ8 "FD\AD/>ڳ8ު#/jͧv ǟu$VYfQۦMXX4>q36B0ƕO]}2w8{pO:<*7De.iXPvWzƖN1 ]_O-D_f^QITYp@YS/XR&=v%q= oUmb&F6 82Պf ,[gz: tMUߧWf.5oG^}hfi㜚bʬY?7VU^>{nOi3h~ A#ܣ%mXn^q zƘMҚ9nm[+saQ:fG۲ċyyO*.^WfksBK^nْS|fG۲9S3Z)`Г[>JpTu [ͺ{ӷ  KaxʳO:Q~ vsWy#?,[vœ\2!w|s*D^#Nao!Iu8A>[߿ yŧ1fzs)cx9qUެ?dއ>%+s3]셃4D.?Pʿ~IYz1KY"ENRMPӉ[qXƸRaVR(FCfogG;-޶A[i'_F흐=}q m%a mCv=Y՘Œo-5F._߆YnzHIOLbe ||/}xAesl.rB%m{B-Q!9+NL8N9QІjj(8+W!ӽ ) [Vᰋk~ZMm u?=̄~ط N=K ;`iѵ%= kcy=|~ϵ/sVㇷ( o?>j֭_YΩF.G IDATޘb:_vњlrKЖ)V^<U5PֶC5S  p ښQJ;Hno~IM\ӥw?[F*+k|MKhs +bɲT1Q{j6 /+E p,K&n oo/TM4sBB[8ņ񄈎ã&+u/+Q"[ 8.9V!֍ЦSܬ RSposu?o;R;d7Ҧ jBuz^|moq]pY8IbEPuΥ~:t`+YϿpOӎP->B@wӯG7oYZ!MzT*UTQ QeH5T̙ciy{Hchng\yXWoY'=뭙3,|'#") |/.8ПѼ:Ău߿ٲ̮*w}Lw2k˷?5~`ԸY{qt^?͚yעc1P57G81OtEV>i;KS% s֚nݜo(tΡG^f%߾2+ē~]ϟxqzA(.])'XH﷕ nKZg7@Y2g5M[zo|o1uy=.Y#0gq{ey}/ - /bQxECu{_úD} ϻ/y(c۹13ԤkLW8O*UB2i{1aԬMm̵O6ZIq *G .D4r^ } ^C4V;޼k *5 k[,YZ|wl oyuǫ]rS~˅ßWwmv6evշ.+ޫgu 꿸pGW/GҦ}{rڰmlzx=[u.Wl5_@ w?6—f\s˗K%-2Ȼw0º[\E߮ܿA{11}_t4O(A E{ q+V{:]XKKvwiA峦Qa͒?{Et2ȱrCX]՗ϝq+aTPn3}3h5(1(}ڸu]+{ۚ+` x!uʸՂ!EB$ ;k|Kw=خWT{şVUj͝8.Nd2M28:Ⱦd5FERk1Dn`/8Q} ?zK}`o\RȆ- TTR!(Ѣ?m}!Wd2awgMُkԈ. kV~ާ䬴6tӊT "Bm{{0imVϯEl-E_[X:UUDJ@~ thMIJ:ղqGl_Jv;w\Wusܶ>_wjPSUXޥ4vwB9_WQrŎGux5wWgV|ǠMޭr* ͘z @PnSG< 6L}]wSmc2"]7rH=:Pw˿߹^ZJVݠoÖwry/=ۃLkb.+@K]ZIb׷פY.^_/- Pܥ^['=AqS+nHJ"ރj8K#|dآ-ϭv:bYN[YP?7tkӪe:ݒϼsw 1K1"RÒ߫ȑv&rўmnM^!`.ӛfU˺~SҌX+1.^%]L [{ 0%kVm(m>Y ]Z@w=~;C]2ꂡ^3"VumhEŪ0|{7A޲QhegڼG_r눑Z4lQgib6-6j͠gP喌y}zmh1A' K z5CtA-?_)5:@ZYM>ax{]a@jK BPqz%i $dBVpF)A%q"&<&sR[5ǫaJ/I!*ZW \5 ` HSܪ]Tl?;wjX;$<䩻ͽիCү_Ƀm?Rcw9U/qX2NRl鋏yEfl[UݾMe} qa?so9^52:D5dR[x>p9Kw;=+Xz 8gNGTM1XD$O>}D,R̟0J\Mg{[1OpxS~*(G_ߩM55P*uNt\TT00|Bt1s7.6nѴqoŃ_<7 ӑ٪)YfJo|yJW5U""$kʗծ_ϥ.m3mkn]KXMo6ʮLKGr筧S:6sj7BPl@o-GR,dK6#Ø.ȴ@D`Ug=Q"jpؖ1hX%2ۦ?l`~'Aͦ:J\!Jv^of%iZĺy]Hv0o35vїDs8/qa旆AY&hi\T޷⃳~kt63)R[9hG,ƊЮ7-Jh4@oE AAH & G98爱pr ȜWLՃK2>c> x "R?:УГ8{!OɯBfH}+ǞZjok!Ӷ wW4s`PAjVBփXЉCǬĉ¯ ٪ P1@Di ZU8 ɬuB@9g_^QޅQ'bIQl^CBF`Dd(YGs&al$ XJXZ]7M8D'6T(-IRHu&Wh@ Hɩ<2EQJ\quT*$e D1E+@ZBJD9gLS @'Rs~.[YQFvjژߚxYi4n}?q=Y8wKK_yFNLX*)W-.4n ~r͚L3,`@5̸s>ws^xO5z5Fk4s'?oRz^.X* g ̘j|_^Sv-~}Pb)mӾC27@>|#gT Ar*3:{糪TAd”k+얊MٲާTbڲcǐ'GQ>~z{ )1UvuqXI3[EK!"Ox\("2"$sγkZkvjY[Wɶ5HPQ=Zyl !aq#Vr}K~޴`mjBpAK0N)7Z^QԊ;쭥TzM^6mV޺[u#7QI}bP3閿,!ӎ㸙}{V_婢:)8*9dhj4-b9 $.[?mSZ5Qu8sJthצk\yYd*)rJ0-kۡC2"YcuVf.K-:5Z'cQi V cK"rg Ag 6%I<[KVZ٣O"@~{ns΁@v, @IaC:ym,s9pKR iֱl7-a#{3P +9lp9}‹N}:eTT}ŕ_^A,6'âGr)hsi[`_WlNMJR"@y~`Fb3@mKroJ cѬIdk&g9}cjLJrd\kֱ *Ӣ>y.]g""Jz a"vNnvaiUvQ)e8 !QD +ys_xq!!s7GA·ӄE*Oڄ2쉃yqC ;9YXjWZhM!sy[]K t۫n6d4R.fM4#, mPKUQnVT8OAX!p Sn/uDtYܺX;ڹT0 쨽HkM,%l&rH ',jhF~5Eqk?6)RӭP|.АJ)Ig2Lq')&,aD$es\.<v 0)a\bķys{?AJQ ˴۵k][0ݡ>h\fsÆ+tƧ5u՗S)8*Yjq%wܴS;euU+lNdon>>InܮFu{s\#iCO_rG-٥{w!6Mb:4!"$ùù2"iK&]0f=H׮_r]xrْÑrI鴇[d=ߺzeUq7 |%ꊺ>lD`KՒw*Mq8Uri6UH 98b帱`~UѮac^kEvoNX1[7Q~ݖjOn[:wۉW `9.3,獝YЭÿ1vy3闆@@T^־:K䦾o~֓|>[ˆ^z˿=9YvEW2U$d7Mk{tc *(E;!%{e]:taGNŝW1~I踂T{{S_ v'z+~un_tk/oo{-t_>u ]vk/6yo|p{mЩ/[~ӵaͲՁn:ٟO|C%?[?,~ۭ]OGgnɖ=F6v{2AUR\ 5븈Rj%g- };]a۟Ioب/:2Ǐ\:lw(  IDATՕW nMm> r]6TcؕGn6eޚO9ɦs1J9ؖ [~|u唪qQ_GR6i;&EZdDp&ućQPW=7Dwk6ޘ!̮核ٰn絬nJhN Ru~irj߶W|UNftk%\}W#P(UO>Y~Ӥnz) Q|NUۣmԒ%^0"Sǰ+2kk|PSTs>STCSy#H_]5ec`R|H#֢#wp)e"nFIe'WW}QYo{RW?}?T<tb/|v^C7DLND2dʣ&٣[WΝwm>\>!Jvu]'/TG5t}c>6[R+ J ,RJ5L˃af@ @F:Yd7[a%ou2IӚ OےLl0kx??UnG?D;a*wSЄ&W_ <)Qj⸎+R^.ȴE;*yUt)bwp:8mce%9u\W?vER&.č/,AQxoX{{w|3eO8Ձn&trs>~bRuڃwﱻMf:ݻ^ģ R$F7~9ڼ~`j#|OgP1oҤ`J߸aDn}kؖyͫCH2MbB(p]Aiq,Y9Wv)]Ntz܀;`CŲy6?;2̏kMz{rK6vLs|:OeYV$,f'76 sY?i1#hs$ùRH"z?)H2)dR"[q5#.m?1yOE{_['`lX^_%0Űx`6Ȏ)g,Næ=x~3C?ʦU}W>3&fjg<"SzT#Aⓟp5e'@DtnWu3Gt&|_[Er͗]{?{_9M_ҖO||n]撳uAR^傯7CDb?f>z 6'Ƒ-:~ A U^7Nx7'ͻ` g^: V*醫uS5}Uoi˿yꚇg1;xK=<s:rї~|I2fҍ[꼃RΎDTIP|O潷BnKG{gO׉ ##7P n_=ʶqd:Rhdnͽ7?p巏8"H6!"S_:4]׼B3g̭F?\O WUkR9_>qrNY"Zjb&54Aɮ[ QQ3.s7O:mv˚[ ڸ>_H冕|9+ zӛ*DnUK9hD#O(ܼ)@2D|y-]qԒd`Χ]gڀ, OAD@ߖ]7}om_R{dI翱|I"OW_gJl걗yq??J}nw,ܦ?Faf>)LT kGeO(Br봇zxK53Ƽ ,R>A9/d7Νeɔ_4IB, B[cID էZkc%'alc|]T __g0!M V27tH|T-i?&jx6fۣ:Cl#-)HQ#T멺uG6^ԸQR!0D%)"k2a=z~Mc'.X o?O.SXKP\WUXƸF$T3\t1{g\>as ZZbd `@U3&eOw~+&lHPsbF3vj6vm>Fz@2=_>/l*FSo痜PyG$N;1]i|zLXU[ hتLjz(P}H1hUl魎{Lz`ŲjLr :wA!Q \1^Ç Y|8I63 ^AZ f$-C3ި 7CF}#aʥeL5!sQ_CjaҌ)/E+HJ!Ydxָ`#mdnOMQY·_>|5ܾ09 cC lQm^{]dZ'B#fl{!-0s&" 6%{RF=dkzE/28N.Ȅ )lB̌1FhC +4 |ϗ$2u9g" Ed*ҶC]88E28WTDRt,0@Ƴs12|?#ڡ=j5p*,Ț?5h\(ZVEkcY![] )IJUHmΉ B;Ěo`).3eJH! ,&Zn$U$(;3!r`hf ӳ\@@i;mFq|K+;o6ʿdaK2SwiRz#:F@@I#  MmzͺӢ%nYZD Jj{^b&Sd|3*Ug!BSVG?v8F&cdck^{MB V63RӤl͘Gve@`@5g LʚHIRXܦ3?1h6;rNBq]R[GFdh#Rڬ\" O& oG ڣDUD9 )W*Q=B7g HkvhtOIXh@cJ 60N!z(S؍4E͍Ň7Al8>Zlpl&lU3dekDc8K d1Xq:㺩l6p5W:nyM-5{88z??%aVnnU?=yMYG;D~N1e a/ǢCܰjlۈ'v™~|:71R3^4j T> v\B^s7g{_CEX#Q v ]nžcsl8/#5ChgAB} Q.R =$#|<͞W!vQva28t9wsf) B]DhB;ùG 3 )"cM[zhLk=:V]vҋQczQƕ2d8w¹缸8-=O)QĄIzPx~6 I.57q7j(CDb;@á>)a ?6v CӘ:[rv7=F)|7~ު9Ȋ^m˖"{VX w<B , 2t8Obhruuu@XELŎy;F-M\u=r9M^4CWVƼiޅazܨɘ=$IAJBT׭ab;^YJ[ 1o\BF C}ÝkTMaUZkK!٭z 5$1u<Ÿ{4 6`vb]FACbfp7SΨXk&*~D[gGkRg2x* oU1#~yd'ukҎ_8wQAUDn׾S9Sʍd޲nTQiH.aY Y $ N6d%"ghADdyq]L|.%~Q,% P1"dqb-Xd<¶B@H\9G1*1"B2S\A D)Ei9B!to M]3TdhnCc3V3[P6<]}_19EFp!@i*KE )8s)yII : )4$I IHo@8s2θ0dzanCHŁRj .8@̨ S@m?ɦXb9V cj_ C=XiTwYb_~UCs21 > q1!˄pl̒xd0Bd :\##IJ"KJ0VY MKL*C,DG7h Q`h),QpRd-xedi1sTCqE tA.5d_Qjږc&=Ҧ#jZr{LBPh'$ ˍ~Yn[U?mjNS(o̧uơG"2@͜B w8>ַV8agOΝuy)c0zhޙhDǏXl`ʿ9ޮͧD@q2]pGPIIRN :bC絒21Ba!hE̩3SMȋqgm]xUjFPrE:;. -$eju)fal #ׂ@yֳf˴ÍB1Τ ȐqΐJ,q%qAQ;FZ{NM(nB+< z'o>WwTa{^MB'),345d1I4. G Fhtf!H:qe*vz151 HkaQ)ƿi#I,f_'ź\EF-'@b~ Xh# Ù|$e$FCZ;6^󐺍Rکy,$+!3dCLW(])9ڊ$ FgB yE+s*.q~BT3SELt9'"_ PB@Vj&#,P|vq IDAT ME8GƘBOnj?WDsƹ뺌gB3[밴v%!]ۮs:M.d䁠jW )\G6/i~.2Lxgج LZtԤ. qƐI!HJa>9"-O%P_ΙR|K_Bi#|4;[TL?Z{OscR#$AVvZ8rUqGcr Dj+r ߖd2R.]&/XOU { mC6OQm96TjݍbZ!*%_A.ڹXh`UXV*6çڐ2!ccȞP5ںE^l!!mBirh^ wP,^m2.Ly;^H,<ĵ=!f4߰c43&"$F'6ͯ$'SD;1F)]WB^ pC!ٗE&2]QTZFCL qe$.BHR$?yQq1w/}?\Ef dSОxz$qWrBLΊeyT`4%QF#ӆ P$3^uw;)`ն䜫Ke#j-_B4\> J2"D:]/tuLmN#x>ڙ떯F Zpal2fzY{t\`TDZG3 ;d:2Hjtf̤Aڭ>(EߎE!@롆-/M2<=2'jKCect˔^uZq8KB Ic|_3R9aIP PV( G oK̵rax%-Ydu m_}ꞈ"JCU YQ@GaT`  X Hu9Yy@00H$ۉJJUh5B8))IgҎ:2)9]CU y>29Ϟ?1 *ȇmYQ!W:pky/߻H' :%j&hQe4g1l2e(4$ <$THb"icrݚ3=cߏw6҃oweҎ]9ݯ?SNFۛ쿑)LpuOj_0Ҏ i.~..NJbq$=%ZX#z^x\s鴡I耑<+ov%!@ 0j4 Ffv?7'4{~#*?0O^Q]R wv9uě_8w^&H3:~xgcӋ0O&Ny)c_nϦM>Wo=/`ziwԕ|)g|5+mCiX(=3&$,X& (T@K+J({R 9Ǚrf{?^dʙST_okjrճ'VLE +zj_?pd+珸h>/痿n߳ws_RÇƀn߽gۮ[O7k꿷{Լ&vv*pD)5MC8-i>%X8jXaܰg=Af (t;e" G0)c QTUeN~iℭ1JFY82TY UE!^RRB(j.)|;:;#Maⵄ~}lnl>OMq5KY#ش{%8*ZحQm̗;|xwcy&A|:|lߡ.ӣn4so\6U~shׁ.zs{ٳo7c﫨Mr&B9w+xbsܭ qkBI8 !B;64A$?wѝ}RslOFr$Wۘ/<߿׭iNf?uh]^"t*> %oxb髵.޻zh]_ܸzc9#'oC jyjd@t,BwfR~*{D.Q芖|! qC7΀(.Pꁂض8`WÜJ,GnEl2v^#\@ DqF)eBߑ8(e1I(WYHbӏF"9 Ɛ p9(hY "Y"jA|\ 7ͫ;ݓ3N.定Ȏcԧ1FElavwۨ?LTw,A}ջO8(懑 LJvAU?K"k!p-iI.1x)ͼ2p9oq;ݎ泌z[VIMTT@)?*Jn1v)3 sحk NL`*1=*~eLQT'~xUa\0{N$꣣I0I)e !Eap !WyNsYS)rFQN4'ߜ#":Zk쏟?7dɒ;]3 )8NcA6p>UJ:gMy$ޫ0ڏx9gM5,zk$peO~zjt|~{^PԌΟ|z%ehᾆ~>k/ޔYK>,/ܳ:`-{?,^>1*%8;Z1ő *q&;%2Kj(l&Vi>wvס ^Φ-xܞԺgNypK7G}:3fѽB~.%pA Yafp[[ۆjk>ŜHiUSPIp3v"c  q(?:-RwO"YQ( + ,' 2`sb[c9nYǶϜ2h12nhaM%miȼ:.s^D=$V$[s\r$E8R/RikIl"%d&$`(J`9@;ppJam7eTrKׇ\cHkPʀI!\9/{ùp%ڰ1iy^%1_Aix3Kڻ^FsN9!&82PUM cp8Q̞ZTuLʋ&p63 z4(;a 5I&,z&I~}1mh3k/F(Nz~Q 4ݿo}i~U=xW*0Dp#+"FɎ oz'[( 5L|H;zs6.QkbTl΀k/$UC~OzŧeKlR5oXybTCw";Wu;7IIVIVtP[9Q-(m# j3[lٻzLzj$ɢxL(^N^ITɅ#򓘘"Fl`@+=V9t,_}R(7qv_0ht#"磵,͎fG,{gE:=_l_1_9G<*H 1–}ҥssm0ۉKxu&O5wa RHqMK詏ni?:Z]8 R/r:AO v[_:%~w￟mܜ@88t1T* iI̽=s@@JIvlWcnJRq-L_g,^|zȰ۪VfO[4x[]a䞏i7;·yz-֟)f`85<5&*V&{=}b1?e1~:Y(i _{oa_Z0s.w[I)k/k(h>(E~49$[Fc9ev6# 3F ,eJ2"*wzaH}hP1H]]:p:8}t7 =( uy8rܟP r>\kc5jq+*1*XANv)B|E,jMⵣJ~m):]o>9*}wSʷ~}e3ɋ>;n&zYB*4l4Ɓ+DQqo9pj9*U(sJ$G$DQ"$+Hz{'^[2mgۊ5rп)4m48{+ϗ3ZˬJylxZ~Z1d〇58V#='ˆ1?G#7e7#F~qB΃yQIy;!>r_>W~z͏7^6 y5/lrcW>s<RVOx29JvHw% \K$Ze`@>s+93LZg^ ֫EX^(uIƒ)y$;Ra?V>~z.c]\0f("IϬKpu˩08u<6xܺ]Q6ѫ'/Cy Пp+cyџh0%Dmb.\p{V?`G9; E;ncj_H~gxHYދhXEVH ƥ0dc9&v<$wׇO^?ץer/?Q3+mΜ.u.sja|]wZn@ǎy &|x!gA֯LL*3ku3w,Tb̭Ǎ}[ry41 OܲuF͖-V^-QOu=4I\r'\28/>ZPI*k( -e@K"x\ZߒCtV6EuN ZjhYG9TMմ5KE2He{4Vhݶy>Y$Z*[Ʌ_.p{9ZBhex‰i:^6T׊T (p!lgY'jė: c64}KNm-FHJz"v[F**,dBl *ha]|Z mIB÷>~gzމCEDJws%n]x;+@ N\^|y߱*MoS*zW͜]'.Ymۚ3-υp7.vߠ['et*HFB/9TinV,؎bJB>UPI*JCs?wW}h:%r1@OOs%JׯnCB w) b-"hnfSܙp]BkwT`זT]bAsצ_"@$N sθx~ƍ*h6ؤL\ "Ş v}w 3i9wZgpO|v9.GP7&oxՙ9Oxǚ5iڶlޮ5uShҢ'%R01(jjd@fP(\497iap(\2MӖ-0p4LΨkWQ7/ clM'O?j蔤Fn])mڶʡt7.4Lu(VJy:ا$u.S5Ƹ[W]h*4xK Jx ZnykԡΕ}&oxsiW $Ea1(qx=xr'1{P/1"8m8.BnXRԟt8(JlЅ2BPIIE9S+EWME0/s)u\s W!Z!|ƐW>YiPUbRa.2{u3bה?}}˟]r zۓ7_2.:._#/YY: P]RלMQ-*dwvN~sm7#c{mYaQ_޼vybPcKFLf+*[JUEUUEX ! /uMc3foia; `),est_J5тUb(R5gPNVU]:9زjJ:kۯf)F$1bTy?6~ >S1q4/ߟv|Vj5pPE^!z皜gJ|=+&e P1)^ױ+nI=3R!R+D!jLX(*[G%bl5oӶaMy`s&y$ @TgqӻW}.mm"/~@/l=%ddZx'_|k~G'6~Ԭ|?Xqo\u9:LD@VQ@j3OU2z;Ț6Cl߮!5x|,@OK&!+~2HnV)s0)TرJ8Ԫ/-{? g !wV}O[?a$O #-ԊBk#_ߝԌsWN}Vjس O}᝗5*H9kفs1mOs&A W+S^?P qF;5 G\:iFɡjeI͸ϟ8ݼMVxjgf?f:~ݪJy̓5D`c;ڂGu7/?k`X̀;l'Y MT 2<~{VӉ̏֠ն+lϩhUu((I]y,XqǛW\*qv2#C<OҮNx %p6o`\&{ם/8ޣraR#eh;o۸[ +aB,Z]q(eTL,?wB#}8(@()*Κ}d<Շ|]<#c"~o$ Q5MQQd~?mK&7lU~ FLRĈ"G.t1Lܮ缇~!A?_-< qObק>] La |>,u uZݣ?X>uyr#g;Bм囗`΀fRKBBqF@[&h9 Omj?X6ug^fK,j^I4|rPިQs)YO+1 \(ZSJCxJ)f×t T}e\RB0|tuZW 1&m rƅad+ +DDr A"HUUP!\ո1.F琉B!9Q Bw@ʘa@SU(BCFh)fs- HP^2ƀ1R AQ}) ̲pQr;mжu|f~y{*#ٜTވѱ s*[wo7/]|ͷ3NCgfwk9f׾` }fȏ:nd(%(0ڟlLXrw3mofm9דogJɬ4ԺrТ֨멐*hPu8|~aRL/ (& pX= A#S۫NR@kV9ɢLWUx0[!uX( 'rjSۗ}Śɿ}ܽsv.degx<61UX(*ܶ4pV E/ɿ'IG?۱ X%ׄ'j)c ~QRfMZxnF>cB0 \1B\W-VlDQQ`csn6=C1K}>TtB$TŒB $]΅8YjrntqCov=1ol=RY&j?\}]sG2q(?kvT}NjSUj=\묟=Rtc="!TdOACϵ\=[ڤ2تk{Ĵ84Td>.SSj.8O1PXneLU{@M;d5Q͆}Jqk5=pM=a'H-+ g,xC1X: Y! p[)m.AQ}z @( |zw+ɼfň,1?V@΃Fx/y<Pڮ>=.t1kբvf鿦X>hI59F\&LE ½׶eK I> yCwѶC7g?mR~4c[BJ]p˥eOu ߙ3(U1Z 1i ≌E8P U:JidU"Ҋi2FV!̳uIF#mnu;qEK^#s+:[Y"^VD4o"eV5}{QM4?-=T:1b_ jTYA)o×wVNFG]x뷬PJ-o>|* OEPUUhre&xJH1;pI;r^=D"Qrƅ=  yi38Bφr( D'v4m<1#GZ~"\Z湴 5Fs%U۾Q5Yۏe𞥇Ks=YGf/,e{hS|@͸:Hc((ecPn %Y1Q+!W*敫1K)W]D-(cB<5b)Zr ks(,μ h?Cc+'WDur@fi7l9TQ4OEgg+j9cUHI@VZf9XJ|r*QC~NUfv^1b ![M)C&lf}QQXv(+XEJF9GN#WbWrv@`aG84;4WvXty‰A äxI%0=1gSR-.opϪWMm]A@U}-n>|3pqqqQqa(ӨiP(kgC/ E%5_<_ՔPFubT$HڷT/^VMHMD#ܑ^V4MӸkR!q uEz4M]Mj:n7 à# M)`\b:>ͭeSK;ELXP.~0m־dMG W,Fř!POz<2#k- 9ҁI#h-nu·sVMHFNު+ Sf[st!WTm} {W{93Wmpm8+H=E)"AB]dc>EgOT.X Dw|gQ(aw-mCΎ׼9Ns(npI!8s*#,l</Ց9uQ_OP׈ƕ[.ڐ5(oƃ$_,-bV@nOf!\Xw3)?5 L'ya&hI@J/ զ\ BtT;|øMU$?:CS/ S/6뿼v}L(..4 T[DDon䜾L+׭(V^eU*8̏_mJSZ݇FT#[c{ȸ0Aی0BgyCn3:V/ͣձ dW.YqVt)-ٳiii%csN.]*A] -1g~zSJ_@s=YzGTyuѫT`s)gSRϦeq*1jL|HŲg-LOUv RԾ~5jdĪ5Mū`!y -M}cCM5 Uw1.#Y/ܩF :Fѭn%S"Kq( 6i -wӫ>CdEu.C$%Z+D7(68s":HW-QIMaC-f Q1߯(D!Q 8"<=,k+5tv~S(&yMA% -ڲD4mmDVFe=3?9lf>}5l|Ϗy4@(j=|X&5o1lx% lXi] =qҳ5JLLnwg,꺄TNY'G>ٮn6G=]쒕Cր4L@$pݫAB[Y{ؘrǍ5EG6Hh~;v'&u}&-ЗB奠ej>jCR@޲sWb vpńrZP IDAT*ٷL< mva.ڮ¹ US5Mt}r貲뫪&vIi>h2r*T pwq;zGh*?tT&wwDEQTM 2 Y6;iZ$Vs7:F^?OQʹUm=`jW>^&H{[oUL0*EQ(pьsUQ4MV"01cbIbE,l])cÆaeEU-f&R(ؼ_Yqͮ"_sa자QsSQTŒࡔ?Ixr׿c;CSYq:SÖ́/&ؽmnߨUW=^#YQroAd%o=վ^vtʹ%+OBZO|oLYRзkMKFfbpʊ%)ԝ5ƹ΄CK`ٚEi(U~wlѮӧug^w:bUF o?վ^F vO;x,)\4 Q,c[M,B*u3ľíHtl-mV]oؠ;;CLMpgܾ~;Lb+΄KN_T`Y&w45}P+{om[hl0j­{-w埌 OT~k%&9tTؽKpO7[. >H*ux0>>G,hԌQMu@BsqMjq~0k)fWXsl7}zi÷q7Ʃ9QvTS 'a6$S_o%Eu /P(Σ(svu{]?.bΞ'oYUa%GQ7_IbhڸP(j$ \&t,F%:n3{rح]TYF"v>pW˪`t`}sgJ9TbcR^KFngsˬrw֫ZRBѱ_6ڃk$59|D?.jw^ yc@0=ۣEUnسMK8@^NRTJ(t,D"n#/QxJ. P giщ͋2&s` ."ضKj=5v:*,iuiC0G|FJl &nf:Vd̤4-ʓ}MQ~!7Ee܆>څ 5 Ҽ G7=R_v]mwhf)NAJZ:Ň3·zen $s|&^{M?qPxf?ؙgIN?r^K ˱rfNQ_??Br.7sTQRܤ¹*Bڄ#FNO=; J26UiXa 8ׅ4iSxpY lA-AUd4UQ)PJ)i(Zw Z0 HUUUaѭzAh 5kx%2r#uuWbddOO20kŒ3?7X..HOB(]Zk }+3#ll44y' PҖ<1~Z>SJU(6P'hdӴuTz[֚Y8*X}o_V˻|ߏSe_?Kr/Wi: @ԂabǾ(zyoTѣX_3Jh'}jz:dF2~Eϐ& :-l[9z!"d YEϭ|cR Qr(6b 0W148㪦:@kn5m7:^{ 8FB2SzsT$/y St*^~q?QC^|jAEv\ᯃs uQYT(L#oO_&Gڗ!]zxsùwTzӟg6D7oϾ]2t`(}I]Gz93M:|bcʽ^W˻50eܚT,(mY2N EP($LJЀ(<)t [nĈn\_ܼír0R ?_%ymTmus-_69}CI?z<䖟W0zmp_R®X;c'7:;#C[^^@iH䏸~߽ ߾l1ك8 %/鑧[f.pؓEz-;vZ:*Ҭ#W#Ět $=k՘WLĒG$3)beAIB@[l jQL- c*+!t&En!0 ƹDA֦tqb9/H2]R&oY <]~$r&2U(נ'MM -"QUE7$=2^[d1l =E" !HLjb[¨;SD$B&䌉J"64fв%(4 FQj7bsV;kiEŌR@@PX(J5M )ܧT5Rek婪]4F23.8b^ǥGaRY1#CwpT0Q%4(gq8}k[^4bAɺ r=TU5*:::*J Cah FbG?**_Xe2Զi0ߋ[D]f*р"(ǯpOuU9_sT{}a&+ܾ|8~\a39nr<9z\(/QUkz70Fm^ϧAUB%%%c&k1:!0{Vq$]v#9l>3բr'@2!#i}Y]nkM9/d%Pʙx)~t凲L` 3BMN)jj4|׷̦\켺bk?>G0مӢeY[QhEeaSe&ɁKH’A^rK"D޼QtÑ&.[E l;Gвr͖SrՊE*0P8 4 ` Z>h5or(KAI=\6{X #)^ZzmOgഭ!:LrֈÅHΠQEQTEx0TTTqF_o8m &Q_k]JJrLp0ahia" kWUU[,$@Ih$~OU=Sd&rd)V7[*wo&AOu#eHi#Bx  ,_'9'B3 8bv>'ѹ@bq$&c[qK%@ QJUUE1nk 1fI)V);R&.ǭl=|D(;tAM8WUE4,E,814 A* 5MS|n|K6Ma7A,乖jj#+-6/HHxgD!<  jh5D(eaڡ2Re}q8;(i&L n4pIژՈ᪪"4OVTzws=ʣ\=t;X1'AP%b!eqD ˪vi 2{ɦ4#x;N\(S( KI#YOH41J *DQfU1(BƙtSMӘ]=5PT4L4Uaŝ|:cUSҵbLId:z"wb q+*"[?j\|MUf"Z&+K%u4ẍjlLOS#?ھ;̊"{f fP̑5YP̮]#*"FP]sY$g$gx|TUw7 37:=o0wYDC*,,aʱwc  l}vE$qD}AT,)"X@(#"}eqʐ!u*[$Js!g?icw e4{uFz{0X܏%D25Ȳ6J ~c 2tWvWΧh_W']~zgn%qL8WԔ0d5Y ØǍ]1:;P1&dsWfl;Ԋ^`a )9`Z j& ֤!ǁl Oa)I)SYf^ʄP(p\HnPc2v%g*pfpNw#`<*OXc32K’I0cU6*L1SRrιQ(& A/T)>ҟ|7a%c\ŭ mI8BE* BH[I!( zNqvl:Rlt1!jv+T6pQ>hO Vx\{1 R)Ƙn]I]-G4_])*dDF!DR)X:kd3Cgu"RJ" Bp.!nI@W7\'D@O4XgKogIX'V&$k1j;PS47R* B]xʴS DTܬ{uRR=tѢW h34ᮤi<1++-|qtn*@ЅCׇ%כr]骜#@`C祤#_AW/hby_ 2tϣێtqi \HaSh>8)<11h]!ca)t豔:ُқY*PDp;og(Q0.Zn~Pա e?:d" O_U H)!|3wBrr/ ukrHF%Lt#:)$r 캕JiM+3]vay ,Qmm.E Zd-sȎMs7|(e\?`%)V`ԲY˖՜55!Ѽ ]aRf0P- 7(UIE%YnKF y%&E_ڌ{bVT9'W~4ԭw~,ڥh;bFʽ#TyΜHPhꭸ5ldڭlGjB!DE SFDqD7}/%g,,| 1,z̵P Җ>K0цzgiAD %Q2/ gS,2ȸ<aJ))dXGkn4v"r \Ll@.wS\ Yj,7^ιya(" O|϶ekEDE|IHab)< mIm"<9yq1ؖdYZAgȱk}NNE/R `*{ubJmEQ#hR3gHTVTYh/wr:LdB,j%7I.;ԛAt:K{>c̀E>?dL(l:I('L8㜛`;DPsq2Q-ch}AA = ЃAթP{@nf%J# rTףZ!(Qr'w"SSP]IKs|B4([3.Cc4Rl'`]@'ԡǙV+[AƵBnInf5(nU A(>k$PR"G1 ư$ kCV蹭O!dS J|;8 [3yg22\%%/!#"}[D7>*)T2_r)ߗR*&m-+-UUeeev1Y=Ÿ=/(J,byFoMfumҗW #E0+C&o~ ZЮ{6!%G ~.(q4H"]8V9Yx(& #god`ۤ'.>Pvn 0:,cGTTr֍$)cO@+A#~.ԕc(`#z(BV(GM'Ѳq|`dXknv_FE*ٍ 墺^FqjeEY}9iO)Dz[g'odKᖡHD$C1TI%!g IDAT~WR)J%{Q; xSq7\LPQDD,d%*~avˎb4i/1RRHIH'j èQzQhIkzgȖ5s3#6XIJ !(p!ӬumRZ-=(A^j ;[#%2sY!rDцa帮-u![H"f qe_w` =]x^v,JX1c+Ne D'"0Hb3M2Y, =)IZͬHdBN"i8T?nӣ5!-`\EIvp|%HnDBOz1 "D!;FR\Duk,| ` ͛ UC? SR._̗w ,/ToaVWW) |b -dQX(Mtom傥y[w$rG:=r'qߒ1ר&r%H.|Y fNp3b^ao,#;](V2@Ih!7O6YY>1ȗeJ,'G[`Q!eBĦhNX- C&ۑhE})1 ɒOLQ\q"MmCMږ*4YF LBFP QI"vgT4^"npgVsE&bP,0N4,Ĺ#}r" @pTHwPH9#"|I R)Oh;|zhF8zB"yzʪ?0 T>yaA> P{d%URjID} >[vsR!Q(=]jFC֌  :2 X B1`fKIx)Rw1dO;nSXDGvu`h;Ya^!pd]5TJ*ť4DDH1(2&L 01y#tQHJ)D@tG@ľ3]v U J{-g]1Dd]Hf ||&[mk60e$(LLW%y6-Vٱ-C#^_CR;R N90TR="e$)2.A9svdZF 3T{"#("@ LP6v&{ZՄL2S4s"RFa@j:x,S *5'm"2QUi۔{S" ]RVț"ALF/ź&Hh"Ώ;WUcAEE=Yӑ=#ęiKmAbx8g2@gAE #*>x{v{YR2G,PW,ԍP"¨߱D7*91rg'亐kҲTR"cD5"i"8Z;CE($Q)1L8L6c4L.KRRʺʚ|Bp2L6***իe3my=/rT}-rvJE~a {q\G8DJJ A@4"KF-tb؟-wF8mqK)_ !>s qSW 0 ]2VQB06:ڵ9q솯)." `T_*JW@qq=xPo/X62)%0B y:N󉔊y(P#K 0CO<QЂ6>fn4J a(aoXdh(9]uɺcX^TTT& C8ݴV0$Co<^-=R[WuuazG=5y_'L޵xOHzvW H6FȘJQق=,/wMDI޺{ NUSҚ-1E{ qZZA }a=FVۧ-;EgD*u{F-aMj!AI;U+ a]j1CS:~-dG̹I#7)%lA(mP>GD`$}{4@CXsӨTۢl9g.x>LZ\vS?gK:D 0jh, "Z$(EB*۞P 6fܺ]6,&s70χ _[[S]-zd um"o*?s>GC'1=3@EJ ~*ދv?cE3΃0YHqKg32ymmmUeeuuU>(EZv Id ׯ_QQ^VNSd3αJL&S+kP~F7jT~L&-$ve1<)R>.ugX&g>v+s7>24Xš>BQk/~{;Slc{́y_ߍȕٔjdMj{|t0qε"9'-M _Taf>Y]絏5lYf"٪΍״o+[C88<m1J0A;8krϾ 4nΗB6l_'L:n'}i}{-FNy„>{-=E߷'LZQ!zͧ͜eR8-N/8i^I[!JU&:ecL* Ouѓ֯5c1!;ǎ5a;Э/ea{!DuMuu0ji>8 PG~yBmxk"J PFxۑG_p)59Ng==0 3KpmRb@ɷ*$xgOj}]G̘:cosbT:rESaî|gL>{_i= AxWcKKe].ztfN1Ll~r^Ћo}7q)_ԖcWuIS޷%Z$59_f䴙˷6v>9y欩4׉~0mSǔG{>P 87 ^W)ei0WR/{o6cҤ_}#!-gڞpǰ'4n?mRa/|}T{~nj0*]͒ .!$dD~8W~1uߺ6iSK/'*ux/{oʗuZoߟe4n=T %cNYck5l}J$S퉟\͇̤393s0>|8F<{\#隓AXS]S]]UW[rPBhnhn>omR F^);neF:=%Jc ESL'lqDHJE'Ѱ#͎ҡ2f.4baf2?GʄJ?:b,tP0;dDd;M:W8d2~*e ,%!ݚ"|u^;Ga$QN$j]g㪪#yy"b+@!B!;O*St|wZxd3x !"+A("Fg֫bNrlgmc^ST.v2W"97JБ:3BQSlfjBJ8^+.G,gFzbcI9"qs+5Iy$Ŷ$XL^.[W/;'((P@1IR t^N,iiL;vt TIE{/3y Ј:Y!#E"s)/<T]]4qioT紿v}A !wY WWt)4학8 Tu7$%*$Rom߫7Fnqf+k?,HۨT bȅaje=X`p6+oZvcsȚեy@8̒zVwM?EK{`f˥]}A曕"BqA@뿹. 6:36z?3 758vߣPH\S?xk+eo(^6S;Z.Dh:[H疳ai4 A]sƼ5am YO?RYGbnq!R.F800"ȱ7 Ҥ:0y=lLL\S$r ;lKǏͦ zWG6g7,whMw?]xKj}s[93}[טڂs=O4b#ZcE!r--*0k?_+񎇞K|rn x/[^7=~ [r׾a+nzsq@\Pw+u%c]T(cAU9G#of?dQ@Πe{GNKlivX#e^xa_lI9.fyގ1u~x%}IrZD.^'?_.LiΘgƝ!7+ CPJS4Ҵ_L*D*s1rR:CH-+te]e>C72h #)Pz`1206O l] Ɏ6-@Hx>4E48DJt:J /4Kq ho"%l C?gs9$Z7GjBt/cHoȘppDU݌H wɈo @rO7F4GkLV*p*$+uX(V;t-ehEܒY%'=#% 8IՋ뵅n$CQ@OQZ"vȃH"N5:wN]Iv)L\/(@PbI+)YlssS3?WI/<9em/{{*[vlyxPe۷ <ߗ^0﹥ϡmbW.$ yͯMжΓ\)9ŪEG PJY:]('"uBx<*)EJ!I;{S~=8b (DDNVR0DA¬G2ccHMbP&r\J|Os4Ո~Z!P =K89cDmUk5h'e]9Bo*zψZOďʎ87 Pىsǫ׌ofXj;SAVT}zqK~ŲGX|`vc?璛t媔TMڋ|w۝ٸ͠j9[Zq/tx0MPJEER%ĺQs=4OC̛ Dߢs;X҇,H_|ލB+ՈQN>$ތEBxmz^qضӅRI"v^M-Kn2W:Ӕn"LS^eq^-z?'|{5d+2qǷ}s)w1rV1%N+׍~uϫrvn_/=1J)P۝wYKyk!L}Ν&ͭWvXg- [EΧyegҵ),j<^~싿<`=xJ Vk;b^I=u{w}W{ܶۗ{9X`R-zpץС~Jnk*17l}mݹ <+nxu+u!M~8ӳz\+}{xoVj J,t.(G*f p#Kzyּq X>}nUZn,^OsG^lFsp֔Ì w4%$4f62`fiT7kVn\+>-.q%աg.~z0}JfKgܺz-_\vyuσG&;i-JI q!rB1 vѺn8I.>"S}ynt\N.ò_?^tzy@([o5?G!3*F;m\4![b"m 43FxwZYGi3v>hVN2X/?}O#?k z,۫]} 0ܼh>ln^E^u5a'>zo,W]n̾~Dy^i{f7MN@ٱC>{=|ZÆ=tWt8/W8xc8}_6YG~bZ$u^]7UccH*ily NiMÎ]X' h~衞TzC˿JE$e'{\_***jkjC{ٮa714 IDATf=3{5YHEؤ؇ZL-6~i {|}fz䧫[_ߤƍoZ>s==g&rwk?k Y8i~+Uzn.tccI qN!6 ȴG-N+zvyj׿n|]^f_M&+O{nEXvo)Wρeםj+W\1lf aٞuU=;5m {?U zgSo |G~Riﳵ"^~EuSzfZ{͝< KN"m4<q4w<^}wْ;zy~~z>/)#v@n^>U:|crް/yf#}pm !GzST+2N7a^ 8׼*FtょrTETʱ2(*~_T4KA "b'@ (ad[t\(~\_2sUI%X%n* '+1bG8qkdNy ǎ_5<V; vMA"!9BT7LM#"ι:'$i-XKoV;&"ƙMhlu"l&f3t:qH !#RHu0D aHRi}R!0 QX5Oo#!xRHaliͥBXWFŇ& :Կ[. QcW Ur޸a|ObbMsضdusT4۞a։Nw}|A#R>ڧHE(B3i drciIF+X]9o)BEE#%5kD^xbB|^\KpKu] DyG٭s6{ z y #^z_!GWYA8:3.xr.=Ͻ{K=n7=k^Xq샃'𗻮d{G<ܽ*ً=fwgjݳ>Om=2aݘs9CWvH  >Cv97+' y~7y53Rb!%%-`=a/P .P&>s.߶}5l""UUu9Wu{ O<<~?<=!w4FV&|nZ}U(>D 4tlc!sswP*.'k%()M= K J]/$E76- ]뀊{/Hc¤ "G;ǰH*vغQ-2ᆕ*!RDu>)ef|zޯ%Ws3]n\(" k_;ca~Ȑ,KOTc\se34prY])8~$ Yd.oVk:dOkZ*Wp7m!&D=9MoKڤԷ{flE]^Ԭ J]k34T*gv^ym]{-?&V6FjR"a̫5K|qf-<=o>[Ygo՚Y;aD0 v.\̉P^Hmq Bk jyVy&1?GOR.ng=k^>7[5-yC'-uc^5jBӊ][Wn].}7.; }$Gq1v> _ܽv%@y{/kr?wK창#l~>c6(8>Z@kd!0 @WjIwwPCay? јYKV]4fKC}}OZrٌϟ{@2qW7ckrm0׹wܴO:1xg[jۈ̯u~|IzMԾ#{v=ʠ._sܜDweg%+|P V #ELpN#*'?{u7s"g3E&˱ăN71 2CRR 1V`JPQ0 t`tkV%GNZFYiu -ԄJgHZ{GBJsιYJ@)˫5̀(b~=6jDv|Jji UI~$KcTT$ƒqKjm|Xi$}}^|k/rlT(+Q\Kl6O&oe#̈́b.0B2'iFxӦ3~NG_zm_xu.~:;WMg>櫎gqV{̂e#~^CvuVeva=2ezN{Ú~ĸLJH 6'ǧW)%cf5PRlF7篐&&ظD%Dbwwٰac/G/ZxիKk4`ɭC)ߡ߃ksuh yӠ7|B2W@'st( '$˘^GWҥIIbf7N]e3n^7ˌS{fwmtߧoZBPJ*!dͼ1R()eIlknkE' xPKfoHѡ>cQPcL Qʿy!K(Zz5l =%:IGO^w;Ï|?C1@*pe/a,GdMA^؄!rag1, )|W#JHmrQxn{7>2fKAx}lnjHw8*isY$ EH'h!cЛc6tKê WCe|lл˝vX&!WJ`9dNںj玓j߁bF7l Ւ1) h]^f@"P~|`?7(4ۭ%Fp[1s]V[Dﷰq1a&GYN= DX'um8mi>\kِ:d8Ֆ[R \Ɉٌ GCD[;} }3'jw\^uzdQ5;s} qþ㲟6;j| \3uD* jaP+u6Jc81t%䈆"t=}$J&S,t!w/KrP&JT?¦]5qH"V'ݙC%ܸY*2(.H+XBc}ޱ%G&0 h(3 NTlj:U D^|Kҧ( )=zR%EXĿ.a'RA }= @sb4}'U FJ M҂%HIcZxA;sbc$])VDvJ*΢hRͿ"PehH<ݱGצiF{U4d3x5oY]kC `T?ju*:(^^v? Jr?#&El@U݊uB vvz9(Ղӧ Q2hl|gKPU_Fl4QkT=GPǵgr}C~%$ܺb0obu} ՎVNl(;e/|18ȓ_߽ńFˁ%Akħ؜B-k@T.8[Vl]s 1!:JEF!ԳXy Pּj&pbT4.('Apݣ+0RONjַUow2ǘٺBpu|F{uxndıq Uy}ؗ|߻0 1I VeC3s2@Q!Hmo‡ټ ݵ[Ftwn~eXӁ)Xyk_|۴.q6[u@iչ\iM+'WyL;b6L*5型_U) BVʚd~A> l7q|oNNyz;#, % 9pqe&q`rQVʚf(=~cWݳgnϫjڠs}u1GvItQϾ©ܬOϨN,(M[]"׼x0a ORNkq$)gT+k[ eq9XtypWȨ?hȯ Yۑe{_^n˞R"ld@nDZDϻ:WϬ m۶mK(n7E0GΩ ."gʒ "Ő!w繽Ajm93 dd*)-Bw]ps7v7LX^Ota7gi9#Q_VQA#QdE9?Da]`T7yC;KE1r]j*لmcoՄ;;mO wcjnqYi p}[xc?cNP3&h0"l"da cY)R;Ã0nqE':U9}rd)u"E!g/fvl&nc26ʸ؝"Q["Bs%(sz M;\|ֵ"Gw1KhF1];a)蚻|>sax#ZjPۖQxl&XMKȒM"k~_>r,N N899B󸎎#1C qvw+c>X :% w|.0CT!rk'6)vhtYv}zݝJ낧F ʞu/%a"9CB#,/&zgzl0ؼC`u 2i?RTòT:I)!$kO͊LZXQG i<@)PZ_;jiE+؜Mw`咭j{RP`N\jD8ezgLESF))@B>_ֱZ8p 7/ C2k.w)2u?;P"{={nH"@u]LkD0  f#**Q$( Q ,"Ar7tWG {{;|]xLNj޲ZNR={G4c O6Js*ZNUSx0wg.sܫԆC_IDJ!j{;#BpS^(rfc 7SnsԦ2X Rf#:ЂD$JoX6*m"rΔJݫWUnX#)y5==f7`閥TPRZft$F`eUNhPVP5eh2K"PT(9/7ABn2+uUO(M? pĴ@Fu0*ޱy,پqmf~WnnR$3sT>O2>+4AhLj3zW*eX5*0a֡E#!c@ZMLB6 V`p{h Hw%4/PFHeJ:&NbX܀[6zԨO#(3C@32W0ht%=_p^ }qg]`7C 8ǻ.WM{>KJ3۶c-)MίٸAFUW 'ھvT:2<a("O$&Y8hZ\: SҨJc F>JO邫XWEkSch\b "镳$qYavD*|\4d8+8vN~bmֹq^o<ҭ_!q7T Ԥ!(+IӚGJ>۽IsNQ6n}(+]09+8,YK/'3j؍AJgju[~i'9MAxEZJwADDsZ { -_Y?''5h,Yz70{܆po31?J+~[aU>~|UA.eK:{Կd]Re's TQ`6kp_rۃq_=]njrݨC͖w5mߒsO9T뾘[/~gqvn5IobQ4N7k#wǪ_@F,_3S.4 D@ȫ^^żWWN޸eO kúy;U{ kZR{7^BR6 [ " LU2ΙRzafe k|AxUrդJGwU[Fϗz_Ew.ݿupMɮ[VukԮ5 LD( Gy5 k]ww#ЩFُw-?|,$evP r#Hln~gk0|QyOa?[P^ӶP{DŽ g16\,iX~F+7j?1Ю B#Fq_),fzk4n,xMJoXm`@=6l=!Qf; yu:2oiOqӦL۴~RTԶoqפNj^W'Y2' kW2ak+״""7^VIǢW/*Y.=pE<| ;*DnS8#qc̘̉ WsEyɵS&~{ Lg?xkuc\]vDJrn3cWYn\tի ֩#>%_TrW;gҨ8]mv}Wv+Z¬lsj걈W}W_Ct[g[Zr^.(},T\04lڄXtMjS^n )9fe\ش`]8tY& U[uSwW}?U56z{ꚰr3\ViS×RlCӸB)ab7=ի§_u88? o*L%"0"TNVX)\:6<Qs.O)9Ebhd%"Ǵuקx); p4wEsj4];aUĈ'4:VlVDjuIH"ZVXh]O9b̠E1Rn:LV"ufڌUj$’$=O,~m~ஷ;WbL{gZ@?w O=y)^G0"/үd}Ч{z0[g>oIw^[†W^?j}I_Dh$EL|0T&>zʋ;'s:[iO)"J&/Ɉvѷ24w%i@${k 3ȡ%‹Nk؇_p2R3ܸiO[v%ϮS9Kw]-ԏ(bZ4? U@qFW?u*ks]^%nefI"Fm:68-۷&;؃Ė~R~ێXӭ$qu  F9hWͩ:&@p =mH)w?ֽfB6s&mjS!Xw z`,A޽Gn}n9ڵg^b54t"]ŋ$Ppg5c}_N>*QAj\j"I–ן[q?{Km>ʸlߊOކi#6ElHS`jtQ}K_y/p;Ϙїa #;Ik:z,jrzfQ-$1oU+* |AMfMǪ ӆ dƃngv0 Fvr?8fܘ\;u Mj_};H`2;[hw f {ヌ?ؾ{̺T`-sV|j0(fPP<Α"B~Ӷ\(~zs1u9a?nGBL 2Tu i' PJ$}1 Bp ']zfUsnKR߻j<~N}oC #f?E{pGf2b)4T$<2Jk1qCLrG\uc_}oO[6ᱻGM|MV'\8k Ѽv1?}?(z^a}j2ϩ/ƪ$ ~kni}B%v[Р4S#<.w?0}| XƵ=f3vBJmoXR"Y89G:沪\T @ib_`ޯ'+z?3§wxzK*x׶ՎA(K_UԲ2xPOkƃL5   \^ڻr*C;&/y6ԺArf5Z)<-_Y)>yW>W?m 9mgޕuۇ1u:8* 8cB@iڊZ;}fC>yÇm3~3+.Y4{J{ )wo !MdxߐG{ob8Wza!jEH?߉~52?ڗ6fS^Ti:VԮ'[dɒa-}w{ArSܒW!|".#g9A=s]8;fz>{S P9ɆMP2ʥ^ *S(A3"L$bͨѸFi<3C;t=$1Si!3PBBd,gNgGq|NCZPhf0Eߦհ/]}{[;ri?F3D:Ў sny,\=J$AaX.O$ JJJR;@.ʈ-j%npjmـcc<ΐa(The*ȐsB 2h*yQ2Rފs/s)C!YXTYh%kGd-L[PdҴІDY\8 XNHq5gܤ2@EK 7vłiZ&6n&{|m#QXj)FvLϕ%/p*FS)2%ypĉiqe %e-<"mLJsyBXJ(d/Ao#=Œ~*T>$a '7tLsT2/!DZ[LN[Z'Z<͇u=Wk02a*\$X*C)%j2J< US'Bf}ԥ@ A=*K}"eD1_gGvA+a}o #)g>1WED=?86 %Mje4a< v/\PY+;|mwgSwHg6W I$ ;< ^iO3aA6iQ#%1~BZF]r,#X I2J0oZb 6}cc6 $H>ҝKYچaȤTmU{uJc,C!#bL%ٸ:jWA&xZ]'!vr2jeAI&$㌤*#ل9"r&wJe& <] cTĘ ղkjm`,!@g,Pp,'(SB_ŰyL }/~v4;DذȚ3&}< {gAA,sz9< Hƹ~BHy+Reh)+9VQ@ٞ3L(]#2>t(v9Jr`[}UHǂh!f`"5['a֚ oH =֮l[wD8Gt(HGr1ogӣ0DbLaoR@b*d e|Z2;[gEY#MUخ9n߯۫Suw$58C(%aXźZCCqU0w֪$ι'aԔb`hafÊ0 \ IDATVڬx֖_vCB]st-nhӨ0$Y{vǔf(S!~W3xWLBW{[:uIg8 !R"Rnlḣ,SD2n)DDlF1AQBO'|g*lr}᧪@߿ѩ:[]kv ehym!:f̢1llMNmmfd,ɮD(@3ڈxMlg*,EI'K#)G q36tu) U**6 "hH[@H<S@P6!D‚(M VkYK_3qRt֓kB7ʾ4nyۺ_4M /qنֶDRBbͥ!Ȁ#7cK9Wd4J(F<9Q;3`7ťz!:gL09C8qՌ;Nm<̝z %"1k v 3K@'TPAJBEQL\$b T,Tu(0E?wXqf\M9YeP6 & 0(oZ<:kT#xl9r}6*v3YĒ+;TUWS4EAB0\18` RצnaB UJf#}AcئycVlk\ 4.x#)sjB=aE %7P@t#c\'SYq-W-YI tpt)h Tss"\Ph@T~i1;CgYjmJn҇ʙ cCL`t_z Ү2&&Jz =k?u9.J'SQ M0R\GL {(0cȁYjs RUĘgsOa!J}F ei.F1+Hg4$Ոqf7ic Y|QAB;>mKmTŒY3]Pj5|DQ3Tt#3 '"r8BcubZ~N #!41ATn"yPRR L]/v2PH$Q&՚9ܑ48).qb\`3&9 扪"0 Qr7<MgS`B!<9C*jD$H4-IB=`ӏb$B!F w28g0!Bҫ^WcX}˜J*i2c2˜d V+N fOdy "b]58T/Wo@e&IN2HW6.Yc2%͆&r ҳ #]QN`?rZAbFh92>HcXdc6R0)X.v1Sr PAa(<8bnNB0 ;5P7 @0HY1Ƨ rL;҆3614t,'l1[De#g1PXU%jC7ꛔ,zeɺfJ>u#W)I%0Tu(VxKθ44XÑVsr$;r?bZ\pȹK=6 s:ظnh.I*Xip`\M{@G(cul{r(lOL\,]O1)J,⠋e )sHD^AA$сhbze78sfŒ&O˔!.;WȃZaU3U*) Y+(,#NZdxeTc$ gPgiL0֍J]C1lu"RO5^& X{D>sƃTJJvԙhqVOh"*K18'~U'_NO1٨ArSN6fRq$,"o\ !RG PI%Um`~Ku25=̐3E#tJCa '|s(:{YfϜۇw62 E2%˒A*kxǔE\S78^_&A(2^٬=c}XJTVfսeW/BG j#m}]aL$_- Ƹ9+/)H$ QȔk:9b~ay-_X*$AOWnnJw1T, wI{iTV]l'XqK?!B9AgzfF?W6am;@!#ؠ4"rQUe)̬E1 J@CGX4pVW'4!!:DKhL2H{IVmhl1ٲELLRt(kLXPFnB#h,*"h$쏬LKgg  b}: H4`kjV^le+.[۴iQ렜\<₢rjB'6iOi B@LJ# S!RsECtQSmh[&#sb|?Kd١ÇrSX~lvi3`ԊmŴDS*0N˔Ҷ-=}p'ַ~ê?sNڴ7ޯݢ>foe13FRƂ]+թQ=xFH*k'>GDiщiC"FݬE̞6j Eo淙s^``ڿz>5o̟5oέAPn/}Ի=9o4=j{OԂ=/߭6_X|W>ޮqԾ~]2gߌwImSnW‹+ @{35E|E+Y;\92ssKfԈye]Έy?1b VzFkPQjk`r@N[{4]{r{ H kG[Q8⾓|!cݜ_>7BFn(6J%9i:uOx ؎iQ@@hpƤUd;h呎1AԎ-3P6}W^~S Ҿ6DQa/\-&Ox[OșBd DL&MީzS-]_Y0b)sLGZk;>.i̫=&W:n&n`*36Q&Ry`F7 |-M^KzGno/3y|C`tP+;8s\MPm0%<1,ͻwL:sn.gւ`j`1JT-$rxѩnՇs0r1Oty/u/sgvzU5y})^4Y)+W}nu 0_zkVc uP<úPuTkS$Lo>Dn PW|J9əqdEv 4wC#{<$2sG In]9HpU ^кވM)­3^XpEǟ=zECݳxWL4y+UU@ܷ yG*ρo??yGewm빨ႋӷ=vPR28sk%$1cHxաھʰ`}ƨw_{No^-l^W_;7?xұIC-j[CnKH iոWoco]׮eu\}v byo<?7;˼E{u1~_̛wJMm4<n~xw3L^+ߎyى ˇ:EUo[|)|fjeyoIkm  u~;8Jjפ}F;>2vZ2Wk2IYU =%*%vyú^aV~z+Wx =xL&jkޚ0sƏ_u'JL*xߝ.Mk|+Q73rAK)E #* ` " 562-׳$@NSrux.cf pcr]ƾ]O\艐fttq9B:Wun\ύNW5RzoYom˦nBD^ڏ?.W>$v,++'\S_~1[;{܃+#?{%S'n T)xz@JB MV6ƬWOCX1Sv8]_)7\,o⏟.[[ڲiwG{MJcuڅ7| CunQ|;m~On꽩cyzCWbN/;WeާѪ Sl m-8媳qAD7I!*WE" "&>:ŵqO]'2;)肞!999@Ҳ0 G2o S3[d`5!T?9~TA;.U#bԩ}N~bvF҅vm- V ]ұ?5hHa ^or-9[E% *}fV˯} $T?+ujt͟נQt3;.821ɁժHЦ= vڈP_* 5xD0-, _207Aa*jRJ'Sg×=;Y8WF@ch)E*Ö3?0!,='v ]|>ss;rBteA5] qj_: ]yN[pӰ36Q9GGڂWg 0ο;Sqׂ;BQc˯wUk{%c?E6C=}M2qAA2$SBܼ|{ZmZysKײJf9 -]u: }goݥuw5#YG'=䡖F˛]Ms$ xgzfHeXXY,xu~avo|++qA@rZϫuyMi5JVےv뱸ҳEM"c#$RP ~qo&S9bQgKOY-P}Y We: b(p+j|Zҕsz':nse%;KBBDD^<}ը;p#ֶ _c.=?+.EqmxE{&MX?H%TJB jℳ:)+gxnKJF{>a wY},+־V_?qWjA3[8U%'uWKhUVXY,Mڷ}?q7]Ү74FBH(:^<;^6=ᡛ.|<ɳ{l{Yg'Nq^[N3e%bہY@u`=8ˢ~_Y<=)T[{WJY? ܺ}ި֤?xNa $ULW_ksrZ>MpSygV4n )VZ޶/,B^f^_7(;ԒT>5"O>`֝4_g$WPłsXsv.KW sOr͸c J^6_]sJC)!&<1n!&]mYA)~xpWOx9g59 r#xhn7# 2һ2@ D]Q,\@`L[,8( tW.Ă]_2ڍrVAFS*k){lVWK/D{pps8ئ<3CdY@hc~ )!gݮ[26{%O$$W*[ƌ|gI3_+k_>E0erqq P;&?֯C~OK&(:ڳh# PHm$B!|[@B Mٲ.'/X<֙ k2~UPw(07j|0+ tj/O(9$D gзXW|_Ӽ`2sjsa_ZoֱVpuV& cm -q m~U%j?]v ?ӥ yyҽ ms3Oy~ެCGf,g4q>-_ڳd8}^:5pЅ?t`˯}_?g̩ۦYN}E?hcAd6o^CФz&Dh1c8C]q[ݦ'ٖ6RЈ)"@8F1qC\mJ_,zgú_=_'By(=P)Gw|Ch)2dD(._XA"(oφCpBB;e4I3,Ъ-I )xֽV/?J^9lXvj9S y׮u1~ÃgM]9=ZW 0nx/;$@3{g?ڤeAvR kOZNqCF \2ckZ bk<ꑽTТEo~rY&xH4 n=#s% 4iӴѱq}℻+l~揷F'CF9"hTnjWTևwo?(nBmɶ`7~UgwG^zb㝿VFo-Ql o!HCf}ƽ^fsƷ+鵡^q')Ԑ8gx~a@۷[)A`[7`(Bѡչyzb~$7dv0 b{ԟ͛iPc.HJ?Dp^")Seaa[u??wq&zaY=hUi_>W_~bCAF˴ECDΑ O" C.Li)Hc3  Ҥr/qؠ(w 5T*f ]jlGR++=p77dxߖlsa۾XK@5휿R PU?wndnO\.>!;ȯ]8CQ鼟le0U]g}ПN>{ WMʑv:* 7U wmRH"ΙVQcVc׽vI9XG|}ЌNǼW<2joKJ 1R<7?eKO}pg>w}Y/ػcVnRHRjaԙ0 * 9} A 4?9qׄ6Hݾu c XmY%祽0$16NJ$@穇D_n;2J>fxԮ71i~~PC`bYjv76$ 2TnMk1W}a6(]o6ˁ-<ؚ֔{/~gIjXX#/z/XЩ{݋m=7<dڝia]N!3RwA Nə~׏ȐIDcp4ظ ZE:†e9zSu}H 9]@Nd@GLnܽfVii @ؼM :vЯze:H2HSp x>:qN@T2pߊ6iM`7j1L)+g'?ca6Vbwܽ6sn:֔$v+l-9dnkʎM۩N[ׇ_JjA\qd9Zkt<BkO5sIN5Cq;5us!H+l FbH dU˳:$ɉwGIm}Š8Fdh3oD01*BJƈVU7]W*i^Oc=Wn"]pګ3n"u8/?hjNte3_~;?ܶ:~pDXޘqDsB' DC?@'9L2G;Ӿ%2*LfTޭ<~XcL91 Qjx<((vB_Z=AX4K]3[Ѷ KGxo&V(cB'|RVunv?2] |wdS>}ƒ(#|]%qYkҦ"@Ι(& !/2:j? b/u>IHoέ lAR|fj<sˏp5cWa>Y;Z7_R꼟@cc‘݄ IDATsEkiQGrCi< fr{(cdƥCv^*p2>Ung{r)/]KG}3o W޴j&X| ̓Ozp~^{{|Q-Qy7͇~{kge5"F&̀3m͜io^qnFGfGW\e`X Zy=z7dM@n7=i33O8}Wܽiͺ/gy|Ce "A@$cEk ɂJqh;}rJ(hUXcgJs tO1N@"d"?e垧"pBW> 8TSW)D #{F,*lDNb"ˮcWE R&$:^pqe]ZelE^}ybtw}8< Z (A}o8˖V_tM p"52 t _ޥKĴ1V>P1ww+\W.Vp$O"H-zi>|ku yw+ !srQk)]MQrsv >zAW#c :3z]qKa'v鳚ɉOO* o'ͿxvLV= a$"I ^գbLOf@>J6fP{ޏ08{PhBFY!DljuN JX͎; ࠃJF]g #n<_vq)Fri;] ,:DC6˖M f9mf(h 1K8d[ )3^tׯ?۝ &k‘nlLs"h)$&ʾX8J,<@E\QIv9p:=$(& Tyxh:[ ]qhPR/뤀SqA"k}cƚ luX$np2%2b>b?Ge=m]q=U늾~ۊXo>G٣!u8P>!yA EH2 )5gq:PƐ1Ʃ /MBDq#؈.'+2YvMқ@4-j\,a̅ ]Z_rkklֿi3N H(p{)ޜb+wTovne,zS\ {ݴ9T^BT1{BE1&wlٍ5lt*dFasH-yeGqH*)R&~$BH:<5m7+OV[ر!:L4ilN9Rq0ە/d˨AO]0';N(i_& uFܹ^ވנePYVVDYgw̝!"4֮3|ƔJQ!J!"-P&!g,B+-YÉ% 8H,aNH#4WJƝ4.\8U{,_E/M1.;XTy-^杉kčTUtgie?|ˌiOk2X\|mޣ!6;(''{ɼ>ڠ, Pr-E/ڟAiW6O}:NsRZsF7R0Snz988O~լʶMIĝJ}:ZʙƓKCt ./ %)gJh0]5gTyYk״JFq60(-{1-d^FGcs J7} 4]Ïi"wOeuK!NBu"uC1D$ɩ#DŽrӅfq!w •6 Jb֚ZYN7!@Wpіd>s¸cDD D}R*#}'g\ `8ziBrhDi` Efva!74F(bNv)/WwoH٣7m+۹2vY'uR><;gaA%7~J'F^/jAǟsvK bǔ,E餲wNl" "KxHWÓ <1ι0dAK)9'+3c.tD:-MH!%qKm~mm@4fVV\ܥF2־ـO[6ؓ.&]rz@\UJ?s!iǒKI*WUԊd5Fu?UUO!¯E&m0VXw5-AM鄲u}k=:ߤ:H1f4w7%8p<%VZCP{UA͎7v)=C1YDa-OF Lx12Pi^q=Wݮ+s?dΝwlļ޽quirjѨG^Ynߵq" dO@WL} X^wjļV]_YZoեRxcOM~}&NB~9Ғ- }VR/DD 􂙛p3h5u~0{K V]:5)8yvhޭkK()j $~ $O@ s HfGVW.p^?OMuGNLpYOw}MZ\}Qn[+j-.sj]{vJ]%Rm{[}1F*vla7|uv}nK>lQW 7_@G]q޺dzRd4X\r_Vɼ&@^}F/&9n\7sBYh#L-?=y;voˋ&!4`$S# ct)I%5qZ;mJkK3D;nOפwOt7oڪ4.-)֣dR;o#JKlۧԎ%[u3p%c`$^SW =is H5gϣ=ܾOVPRXY&\8o'~-lԸ9Ykˉ5&M:y!C-5Ctuֽ~ls潆6,z/;[rcV^p€ƞrpc?~놪Ǟ|JSJWN}~ u'pMMJlWoXX¾'}cԞ])I*o'~KﲷV5` <3k$ּאs᫛؞uZώsou,mM[/*U!@j;Z熕=ۓ]N9WYKǾ}4ʟ'Ny ^X<ϧZgCι|Üw'!%K~n<9uDl`#vYx;ɷoik~A48XX0yva~*]p$Z2 1=O#r!$IL i"gzum9ZiFV"x"L$W.fl|owƉtْi/[Jo8!]KK' _'xyFeRa羧LIYb}G_/&~Pr gq;S5_xy{]3YSH' רYVM? 2#+6mPPSYo|7!f7-w #mϠjoD Ɨ @A 1ko}xo/5U,]JҮ0Mq3)NiRG3=O@D5+H^#YfI mNU,`]J|mkjVII֥AueR# D:sK]" &5ac޻U,y^[ƊHot:Yx@ݪ:Ȝv`Ļ9lXŒ6amAN.|\ٿ,K9u8xxwnU3*-jk2k7/Zq1$D"B)?@[Ɏ_ۣT@J2  &x٩)=_=zCӗ=M~stDKm勫_?<5eK='Ү|O@e9OW [ϚyE0=!8ܨo>x?ꥣo[xXI~荀d2 ~D^-}ڥ 2-~8ePso:`wϹg`% 騗Jy{p8Atz{*ҀsQ-~.k~;^|ǫ=.<ĞOw)ͬ 4hhۈ0(sФȼCSJ1={+~jbzIgtkbOjg嫶Ūj1 ! <#@>)Ψ12T+vEKL9W‡1j 1G k.E5mn cM6h3|{tȸ.mjz-b!.-R\CBERhQjG9`$C%eqWi7ihajQ4!#aO[r0b(}X(迼;W&m.{{ʵ ]}_Q|:9YH)@-&Ƹ1FԼyKrŮdM}a]3fyJ qiQQ= 4uNf1֡l0øpXZpDgq_;rfjK2Vʕ"V11|ÙU03R!FSeT-(据uf+psU:k@a=" ʧJ7aK P2AncZA `'Xp]Ifa"H,Mah.!d7DʸVIHtΗ<6iNf:C[k@e⌲e8H8//t*JI!2*׀T:Tsl-i 2 Zܬ^o3{04Έ$'E=C1BmQwp+k4k]P_GaT|bɆM;ra&?.> $H])IRUy9x -|^2u2a}ZFRTmʪLg ]gv(dk5s`CW II!gL#\J$cirR붳5&}KI8UM8(ecejVa֬9g繯Aunj8BX PPc"ū+ my uKp9'/LmTKƴlXh'i W: Z*Xh$Dm=Fa&ҩmԣ6t IDATz1զ@Ie@@ (_J3~$^"`A TA_:SRlDžQKvS=8 &8v$.?M0K FЙU<$bع$ҮQ 8YNW"+i)6~ҕN č9v7^&s)5QgA*N1Lr#)Bh6Ad4KH4kЇ! Q%tS3":3q|Ū] +47#M d*C t{4P[bm# 0>Z%0c[T 6[gNr1ƵcahL3DPFq)[~@T?jaȤ2k3 +Tti '6/-~ +-Y_='ZĶy5R|tH0jy;9cGƐq@`@O$#Cu]6xc,*v^u̜H?L_Ьjk'4a η'vΞ4.}J$:@@UM2pDGw%9;;~Z\3X0jj.C݇)x,2fl fΘ ݤMd 1/%d"Dzo]BǞ/p>U3 #NŸN,z#I `}YHdR Лf"i(3tNu`kc} ;T i- E1ZDܲ#]aA d%j&cbė*E1^pC^ORJ)]sݓ2# 7F4J+%gdoON߳DMx3* +h0C+Ұ :<0rm.yRT*DW]e!w=WmbEھo€a 3q g MD*1ld )u&iMd&<%:-K 3\sO# Hʎ.L %`0~PQ^ƚ9 k PH=/aѵJކ}Sd!"KeʡD$qQȚPf#Jy]<=YeR DEeq6!rA20&B`Ì'43sE'Mkh+?BTDJX#Cd[cTB0d*hԴ2 l*X4Zb Q^:8q"+̶H# \Y)2q΄F#4 GBq i!v4-D:%^J1֡ +$/$-U]ZuEHE;LD$YDBIRU3[ xaMj^ϼ wA4D! 1[>nME %J2HuRJ?cc /1m̐Ѻ78f>YEPU]!P팱Hi*H"-əB2Dr5FΘTlOrp^ًʁQ,Do{d[tnPBصӇ۠ӗ8UW1R҈Q)eRsΉ\l<4jJ_-Cz>Ѿ:t[ܯ"3۲^)2$d3@~tqE.%RLj~ !B )e:Fggm#, =Α10#7YG gQI,ɍO5 mi}BHs'@H!DfZD #J)"nNW k?)qڜ8gd3ԾZGWQVJ5fQC Bg -,|P fSĪ; t_A+u ,alB~QV:L")ڛyjw4yjV! t C6DUh^ Ui1D;6ز!H la3}Q? Yp $3x.^,ƫ \\nc xΜ "V8""0S8l(RV:\cH<ӵ6?fcc1jB_ʁ{aqZ0IKi_PHPDi]X#KCߢN?uN 15[́HS,+= 0AƙUXA 9##RHL~_}iwVE͡4z&yB4>9 'ɐΐ "U0Da71k?c,g#E.E5r {@W+cHQ炏k&^K1<'Lj]66R8؇-:+Qȍ- o!r\7:i M,9bk`qϐw/:=u"Jpa93Qy]L<+c38(X li#{k<1Z&XC Y:(@ *=(|2Gvm̉2gY'-F6ټ mF=2ňYgD$$0m * IVj!ЛI9IMnez|7A2ܶ%fcfT f-ϲIM) @'_ BHDƹ8=BOl z@1j)+Uo-m$fוJۦ*H&J-KN hx"Ja$ څJhA¾VRB@JUgsAxD.> 1gb`1fYvꓩnܸ.mAQ<+{@C{a`<qa@QW+E$p dN!Mgig#8h,&}_HD2 ZT*Eĸdj8\LGuv "DŊ#jaa1phfja@Ҥ0Q;59uu_ g%0,źy\~~8p9G@wT )1f$/r,3'TKi2ι!P ehH$A'(KkdEn11UOQ4ڐl3THNz|>ȸv^e*Vi8Ԗ̭hl͊a[?"`Rk?dT"C$KKn)Mll sXN2NRɴDY#+yd\䐜T<iWFdKׂҽD$  Ghh;)&uCC1뀈#}CvoMDx9hc4xheW8O!CʒC'E ͜&}VzQ"g )kM@eR] VDQ'IƉ j5; blL8s{3&exQǑqϳ"j@bH 8g^h㊖a&ކ[Ҽ@iZ4%D0;U!ӭvf?qQ O8T @$ 0}uT?dfw`c;[ų A{^"j ͏Y )zI2<:$᳑+)@%<)Se'-Hy,1cGn%>$o,f#A2C1Yzݞtw1&f:9lG3C*^f;0L{2CធmFsuy}؅d:hbf4SCw 2Q׫=Am3ƸA %!c$A "ʌ))Ra>U@aE|2[FaqOx8Ea5B<1!VѤ/lW H RX@AF'^pʅKW~|AɌurԅ\Ҋxp{䎌r>:Gv.[14}Ye9wxc:}@ƃW-r$7VJ-kU=v2wӲEXqgaJƘb"z۟hD|gJv&SC+xmow#uj%Ӱ戧Ժ#联y^2Sk;?ta)ctY\M[ $Ŝύױ1MԤFqxkJY* q_ktLejAI6}ț`t2u156hfSSKjbܒEq>" C*f$U%ȹǤۭ:S[!t@sS+ٲeu{IasZMp!LJB/ "P*'Y[S*Y}v"k(S%9W&Lv%ـ\t5L1,#WbUCteGkqS)ꂎvȐaxjT'"qMJpq=nË{*9ίՉc;x/GcT{YҭϪr5UD"`l*07ǻ[q+ƭT^H5'"wS݆eY2W[UKaǞ$ bTňisM?ի(lwc>3sޜ&wjQR3{s1pޒew Xo_0kڐI",=eP;c5ZbBW?_Λ5W%t5!~7nCz/t`Og_8&>tJc^_|gvMy]ohwH:QrxPǹ穒EBJ?59鞿O~xG}Z1N[WVlwu0\ Ihv-0Q4e`(=/]˼kQaeߌ8*WMQ7t [1#ǚr~?Z)o.\>("63RުTmOKrui)mSp(9JtނO {=8I?g|Z^C|*M|zMI}t23[FVF|{އ:siM7#K+[(| !^Flh.CUzHݠ5QJ9T)ʝ3D'^t}'ȫ/Gq ?38g}|mWKRK&>~qr'D$v|5g4*!j\!(Ly+>0[nn%g2Y"?}Yi#?tWmԸ}rV~yӳaҬZ@u)ӪrS0ߨ '?m{_n8pe5Qt}όW^ڜ_OOXMt}Qŕ?[]8O^yz^%{A1d$)EPCJ@WF|)9c^h} "yᮆ/ Dh"F:9@qg0gv]U(82e矺h;NF\\q5❑CF^ӨÑ={kh0њ+v`zu8Ј$ympݣ}|mqSY'r>nNnkADk.i[=s5D!!tu|޲wGM4\uKkyF==.yo5g3۴U !_FX#IV+%!L+!nfǗl3[Ew=K^\%8~/M(][kk\QL {į΃^xʱ68龗xyǚ+ƮKi׊ /IRΑO6Դ EҪ]#2~?fJ 1@>p@M+Dw/.5r܆!ۊ@O])Kvs3&k{M"5k?rܱO͡m=&1Ns}cפ~ F鴿otNwTl2ƙ=Α;^;ADT-u-W-x||\3&rb+Kj>qdūq맞fʒ7i9ik9=fw[O/rԱ?pg <+48:밦^S^z`A+~ӹ5=#WJdnw]$E/_K3oFzʾw\~DsVFO7?uǷ]s]r[/>f{7sF(Cx933XN v-{֥a3Οrw@lrYW?]?URQ7>[XyExJh7_yM]:Ë;`?Vv^ЬYݹ7]sƎT^Oi[=.N SGO;ޝBT[j>SNloX#:Wqvd}wՠ{k[k5YԬ E豬ǹ$B) SHj=9x6aZ3&rbѼ6Yt7h=cVv"%P+5Ttu3WOso#KW )$4;s8D'W Θݿ 8}zW߆M-'j+h*=uMom =_þ^^ʱG~R^Dُ|prO~&a:3TD9~ny}J`Lhз.S69GL7so;lZav@|9;!G>H}O]WtK7W᫙ ]1a?oZYXuw7FޮљO=Df}բJ>P>aMx^g3{~7m(/:EO ;֒/HJWمJ愎5_j:CoLKMcWp'6&qU~ʪo-r$DִG۞|F2 *m-pW?KneXn4mQUS6/=ԢZܸmy{Wl].\?mNJ]3;򪟆mr(" -;`>Omj'{_QFo>o4PEE,r%0INtnQ !(둜579,+K5rf *)Iw <:K$ai;}-Qi#~aFqv+$Rf;g$ȸ!'pH"mYx&'s<fp`y,uHPwh/gbdK $hn%!퐴r#c;tiOyQ>>{keV?V6ʿ}>[˟mR'ԶAU!׿=Qc;qGwν8]zcz} wfhrD5v1WNQ]Y ÈLs>A v:{ezu9NVuO`š4}4$h_c!(_gwz{yk zm0a8ܙ½_sb?ķkci/E{#7)_m;d b>,mf:Inu֫G#@ў76GK֦5!d??.[ɰ*3gwm|赿Qg_MX?qTzHTP=׸%i>vk_of49hW2R3_5hD~OAN|kVI|L5}pfԆPGb(HE|%2Jhrb[7p$Ή&DtZ[J#Nxd`1SD8YFf 3*?(?Seq{v:##LChjj @1 dKa$!"@OuR%;-wQvY$e3 v:Rv@w+`+[\(i`'C9RJ).e >/6^NݳE ꥁ<6!PY3 K3=犰xijl%^!4P'blD^Zjf6a,1ǵ|kJf/ާv+J:AXU e]d[h:&rXq?Y.ڬ"mQ\wAEm 9l_|yO~Օ_-8s[P ie a5Ņw9i3~̺=񲁍_0nδq'6~1bzek<3cFhTfB |6ZM@n7Rnُ/.zY+AQCBx[r_ϧ,\lO?Μ&O>tң}4m?>}KSi f?G`ŲY߿̢]=w`6WbWSwײߍx۟wɒ>bԀkWmg*?nuv,=V޴:r 6/oxNнJ\#@Sbo %YNUEL]OSC=橃˛kSO D_5yʆGwE!/)g(Xj?|FCd}Ot@#m@Y|ɻMJ޸1(B榦Fܗk=fʬ[}f~]ny¥zqZ3{𾓺f<1tQ0%Rf!D*9^֩ 4??d},ˋSx)A= >b˟.5>и$֦G[Z9i+*W[Q>~-3*/hL??W-[K?[gt:%~ctftd+>]}>"N;bʈt (nlՇ7?1f&)=~ܯB(mvh'u@ϭ%9|a^<.3t%ϜsۛCW-UnmĶhkO_8lǬZaRu/u"qӤy5?RNBlaS>{ҷΟ[4'ϢW,ygʹ!M9lss@piׄ4& XGhwl⹟"}6!e 4ǔə2Ovnf&R!Y A) EdJiGX&I :s(2N"x6-! N{xz,'P)&02XKTyb Z0+EeR@x2dY~h3KԴ"L]MԌm I,yWo/-kK4_Z&R*>r<cR^?Rm)5sAT_`mv=ߝYdEj6UyQXN$7L?zSmuA)zAH)u6TE>hYeM$ƚF"/cOlS]#$t섫?D!W1fܿQ/[/&._h#9 L&I+E¶A78M-?:gjnOz6OB`۽{%Z&Eq~i;uD"?@DO*c(KlXA2 >dHH!"d*{m~)tUuEk'.@Px޽k+.pjjSoAw(PalBE_3*tܪ vY 4suWJwTh֚޽ڰ_jeO(B$6À#Buk*WAm71hZUw}}3޿oQLaڮ = GIW~UP>onca#(G ޏ>P+_/! m3_::yExgacorwF5&l)5`籜{knnBr'I("GQRհ{bhK_yx^J!B̏%['STqLK61`Tf눡N6Qs)x!i-  )dj7ْ7n~0cҘ?eYcx3*}W(ʿrs.k ܪY0oyV>)1THԯSM~yy 9 v=bL㞪)MZtcyD~nOa["ͳQ|ȧ;nWkf*.н{`b%e]{87}8Qlk!!Isak7V6X^3{I@DZAmL&SRe\#*<˯^C`^ݥ ۦ^'-Q{ZA~cYX3H"]߸| VO `/ަ;gHL*j XqoȔ0LCD.Fpf]5^WW01_/S1R Y'R,&9yC|@amZ2ىA &Nɸ4OXO$Жk 'Rc= 4%DF:T3ku,r#m!F՘U)yhs;[LhSro\)LjIPCfEymq=1QbARV]@@8sB<ng5"bsSf'4F|Ns^<B2.VX-c Xy(Ǻlbqj!3N ώP5@)_3r[@nF 冟V9NUfD oۥ#0_CLcݏ8_՗ Q9y^F5 2}"!9<ƥvr="%{ Z>Wr cn~Cnc(c4à :!7 Jʋ7|-=8hsxϣ^ٽ_>=~p5Y;42GU@ &gDoz6|א RU"r7`N\ @nyҡKfevw~sʺxEh!2)t3w;_g=;@J:Pۡ~1ټ׆\[+B&$e 9u;Y\3ux7C}N:v,:sE"O'j̬b{i~Z.m^R} 𺫱qɹBFwEH*HJ 1[Rx?yߥ*xvC{ℕu/Ub_H 9~y_-h"dL&dB-dADʾs; dH@P5%3}c*k,kjm26{$Vk7 }\@ljw(֫cNvTއhT]%٩{[+ n@YT/N޶CnŢ BlV@c9_8muu)Ȯ۹52$MأGNr4^Q[.5jRc[nɷ&S, /jO[]|p qm4Fj `˨6lc98cW76}%^`#S2Z]Gxɶ~Ϻʜpli"T;Ih_qr9 D3d(!5rZ"6@@(zSb{~/Wo{oW}FH$TL}QL:C-vp6) *RHY`jeѠ:g!۹H\lR9"W}x3N6 ߗRsXPV!ښNk5gw糑m]-V;}Z)Z`M^lm;C*}yax5ٮבfȔdצ5w_;Qs~w~}Gn&@*n)SWRI\Vqg[ą2} K ^oWP*Xa\Q6m*/Xۀfs[UōPʯ5U9DKQz! ӭZ(mkYVz@ACCȊin9o7B_U9 Lע R@sgj+,+?*h*vإ!rRZmU墙پį; yQC-Mzymx} I>U GNl)aZY cEeT좧"9^2-B>`.;[Ũ7ɌL  !%z)OJ$5]Dǎz mt k9ƪ:fcZmR1p$ j},68l4˙Zc̸m-۠`y1C68oQ(qӾ-\*Z6^3K%軞YRҧVk,ş}x9b6ν{.&EMI}բUcE_]#mYQ=ZlŢ[nMIE֩,lS^x"ҩ'8/g${VvoŢ[nmqm¥s ?tiî28N{h>` 1=@E8gtlV8soUO~ʓ#.ͭ-h6d +3NzbGɅ%F-lJ;^b/u:rAΗ%x BRp$`oǩ?|CoL.='=}W?+]6r|7~:4-Z3cCSEKӿWy} ʌH~ۿzx]\qJ@w#DGM.2JCy'>!S#򬮋_t^S(wMJq#G n,kNzbI(eZʳэ_EnZ4L}|LϕguYgqqo_^:hXq-z).EfU ysTӖ: 8黫F .u7/b/ry9DDw}KGDuW6Vp{>[qW?^ M 1;bIB;OWDvbyNx;דZ r,\'=q{^An]-2% MfQIc # a4ӂ irgO~hLϵv_GLըeiGay)r!k\4}]y|R/`/o?N[V[ˑ{ZʦO*a#`c0=vN^]~IZdžur ^~ɡUoM~jf}י(/~ԵggUu <;fڲڲ]ܣM*ջ*G_2: @T\Um X'TS޾m*SA}?4-ŝ-;n:hu/}4̛,hq3]ߵ7[v+쾵wԜ/ǧyFD_kg0W ?)[Ӿq*pM֡/x[\Xqt54MGnUVZ\EYf;tۊF7 vZ?vWeNh8r 5 fvJ6JKuykח>ú[ MWOmiN ٽEUcA}jR-h֭ufOU͝Y=nfCzG ll׾jGv;J$i)Hq= `Rl1AA)Df\mܮm)‰r;[caM:Ɔ$XJQǹjeA9m9:ủaZ*FZCvU ٙ7JÎtMr`vI+ c C+7e#'Μ!A̓M辞iB$)m')dfiIPVZl(_9J wB`Ipϣ ) ,yhň MvS4`)u[( x}? ŨL|Q3#AW)I* 5"<گb}u%mY>?@TNS?:l+_kKI6Ô=:^xle=?- *?^C M9{O.ժۡeA'}Q(/n :壄z*= }1Çeo^s=ƅlQ_eőG^<?9_xI"D-eh䈃<yW/B~eޮw.)aeFt \ف/y n_];=]_75/0a۹A 2셿U.yodS#s?2t?}_u7w_9+_]C׬>~w 䕗U'_=?y//%,uU.nͫ|v(r­ݫ{_ Aqŷ_t;g@jڧ_f.K'% IG&{ֵQVx\NZ7>9noucPP@|E ȥ@wrY]X !ͦ/|;{ó\x_ZkƵJ9F܀PGNT$Bb07ǟV5gB$/R&7գW?='9y9+=ejCHʵ{n뷾1{)7zr+_.z˾ky_VJCWw쯠_!:#[vʛEWxUsƾ_~ sy7t?;ejtbJQgwwڷh,Xf V]|: hrWϕzkVXE-Vwg noXS?rM?@e%[Wi^ź!.>dM [.+)fʖVIؾ=@Sv4"k&~n!%*@4rDdžcvٍ1y}Юpm4gXΜ?kAaYZ[MZb@V9' .w\@׫m{y[lѕdm%I5іPG Yk[m[/h/$lk; iި1CyZ6͆Η5MVkhieCX/pOд\͏P!g&;f$AՀ4>: 16 ]80*DŽKp(Pʱ֮"87"_8瞲B/25p;pcp(Ǖ^Rc`Ȕ&"0FRf42[lCƕT_-zk%InJrQԶ暏^C~=E98znr[S tȯ1 CZ .]juD5 (P(ߪ*&܀p[(=vjE.z~.X|ܾ_(Z/Sۑ1ôk)6ۏPPP9ojns~&)))rMMMf !b Z bpc#ؼ#AcJD~.V?٧(uN/G4C)0mxC=J@zt?VbMk!0ĘPhdۿ~C t`EVrS&%9%[!cU2e#psΕO r맏t{a%LL }5pѦޢ))SG" ]*Ls~.CL[OnZc][վۼk#1d3B RAx3UA)EQ/(Bڍ)#@ܫMd2WæN [VVIsGHNlA$m50#N՜R(Gu"&BZՂQdYPbܔOy NRĈ-Ebvh%!_w:iss$f Ո0t4*);kF !I)Q WPr┛<Z7rlBGnϓ=gl$>\4>9Q?HQbtY *R)*bT+Z_!alTB=|&Nΐq%Q& X@pD4V,ml M)9D~91!{2B [RUAhll((f3Rs/t7X6܎8pT[j>*KCBt7PBG$e>Yx^FWV)@Jѫu!.'b&%J $\52Xǎ ").<Ş:T+EIigP#_BjMG/.T9ա37ZcM Bay8)+xSgQ &tLm D *dͬ bϕC%J;P/Znb^Xo%1,oBCLIgl'nCB(c/~b$*Kȸ*VIꇩP"w{-~3؂YbxcW )Q+XiId1f^S RlTq"_r]=?l'Wh91r&9GDIRy3 v2~ʏ:BeWrj7MSJ-)F{0&QyC ʝ- l8 VDj~^&J)Y&1ƅ? '$ )ݐ 1r~ΰP9۷4"[ι.Ƌ=R(QL}jmbۜp׍w@qp˗ҁsq,#6b%ֺ <;#;*{h Ԅf B!,H&pom0(s^Dx!A4N| -' ]*.! gk! /g )x' !15:)M|#HS甑Ա,d,ٯT)<*Bz IDAT;FM 0Jz,0vP)tbc<㩿#IA߿.א1nK`mPl'9'YG9<7Q(D3t!`ŏpIR@f5[?@i͗DV(Q59!(bCLREh4H}xRp;2'뭷WMɴTiM7g7c*&VxQ f;AM4Qpޞ9|ߗR0;0w.rۖS"(4Azw:8 y+EE1(2k,dU/CT'1s=ϓIL,bl F26N%LYD $)ǻ86'9HeLA,O#⸮T(u7鰺wL\Н z /2yjg, Sl1`ܣDh+N#/Iӝ+ʙ1ٓ,.*.**lte h e88gIy&K)mX"@ ;cl6=u [@1"#;sI|aT4IW wj83RQ,>IRB<٭#cePA+?Qf 2,((\sNH]SBm yڮOZ9z757rl6[T\d3lV0mDYE2sC4CLVq$Hrv*^=n4<{LkB _9fg-P~p.MySf6uN$ps5r3H[  "Rm_:չ,*DJtqaؗ'F%lA C1b¨ l6[PQcSSSSy=D ^25@l6[TP\l6$!8 bO? +h gCF>M~8Q_kDФ䞰XU^J "#Nmf u0ZcdCT.}s{&% l1M)ع" _uH-77 Ci# wk\(WN5 ;TSh6lfK75Ҥe-'ƾ 2M^ C!$IHn(H=V=Nnk&BgbNɅcG1^,>Q-?!W:!;Ԑ~̢6z !%RQ29ikM8wQG,cca:iIP'Xuv!t|@$SBbO4.,.C[[G1 S!gLHc@LGhZF㌫Ζi||7El`9ƞeYi?$I<[/p٪IFf)Ecdh="iOJ!qθ@a]i!`tfP)L3H577 )lA&SRXklnR02uYa\&_2/WB* !D /(BLE:;DTrh<#sdh*r<%pV)TM {lJhQi~fL; MFORLoXYiTS"+KsF7$rVx,gDuLP?HjG$H"a$il2h4Ϲȕ'h)$a\qn="o?7EXn`o6]4V !ThD"3wx`7&S$=m3Q|eL&N>l4b*0܈y˸F0׽arŰp/4Zv\Qrwf b VJ5]sUTl0h1`: ܚ3}8:29 QpRJr[tFOO{@fYdR\p#W asf#IAcSS}S/D6).**,, q.flU6`&DblcLt;j-bZoWtÐĆ2ŴII@Θ o=%im/6Y;q&=}ݯ;3~xu/Df;0S4u_s@EN1iʯd3~xhw+"`󔙌YE>?ugtճq#>}֔?fu͐e'&L9y^E\T2̞)3fN؇(R7mDY&<|*Hye1_Z[e;{ܦvͤ :6Pc"v&|!>F XfaOk7X4T""/';ui?7YQގon)3]?뉿q]x>y9y_.@7q6Gppό6#f@U ϾwLm7t%e qIMū7ؕ )VeD1#"2=sc+sdL"u XbC0nxIM Y8 r~sԖf4iO)dt]pli$yCo}?&O (AnR?H!PM jn]y7fv6×z5ަ3׏{ki3(@)jlR@-P;ܨ5L&=rƐq8R'"us|>vI#Z *\Jd ."0PcQh|˞HHI+8bɠM MygU[.\9=Bl:Vyb |8֤"RHfl&#D (^FC!`sؚ@85KDւQL,J+ƙB P-h@DDRqyS LiQP6uPɦ#mrV`1Yk)N8폴2Z'GQqGѵϱp`d]hft2|$KymWqbsn(-HpBX\ܔ[gY^i7cʒNgƫ7`]s)EzmUjV9V>ȱ=Df]{CϿ}<ޮH+<<}tjzSIy^q.I~ a`ȝlRP5;Q&(L?1 +20Cc9?ø(%"M @D^࣫rY2v^Rfd돸뉡t;{x+٣ۜz1`s.vw;r" ƹLqNh^⢆Y_|>e{\~ pݏUF%Y1DVsRrka4ZS{AKu?r~ʥq)bL!P!gX2 ?keV5ُ=x'_Aw>yV A. -SLB>i!Q3I&_cƨze5N\ɍ˾cULS?&SB0gjkx;DK Q5۟QRtQWo>\/cMQV(c!2FZh oWhNn0E@IPy~}cCCSS eA&SZRRXPh/:Ĕۓ:hIBێƴݐ~ M 8ìq*,d,#e:144hɱaVUǹMcRjy8,u-R`cPX&x|LAcv``xg~ 4 kBRg UKO:y~;I.HH^(N_+ΎpӍĐreZ 賅-0O.Q޽MKr | AYr=xD-Ѧ&*$5ѸHk eqh¤>aْE;@QSo駸d >9{8uk#Z>{ʇ ЫOb0H+bBa7)Pqɞ'z _pCǶxx:e$BrWo??'Xnh-|MD"'&n_1AEpɐb'<܋;J=q _-w z.ُW]/d5#OM0g1 I& 6Io4tKy  6EU%bƝ|y=>1{aΈZeꇌi;L*{' f uUQ15`F19iQfE,aHㆺzfP}V s~9 Jnq^~=0 ʯ|ˑ]_NG!&}Y!!0]~o=ec͏ ߻[>]/Nqu{zu__X ߻]#s."B|CJowozv|6Pꀈ)0Qg6Z>`}ҫY=퍇nt3nvi-&ΫPTx^oߞ;M >x'ή@@X'?^qޭiwфa._S{ ?SO}aEXۙz1rUd آ1h B\daKzxZu/엕YX>pN?2.PtlN2e'Am|6=b[-}oJ@ |-wT`7LA͆ mQ!Ko:eu3_{#muG+6NF]}j >Ojq},ԥ!ț)0oQg6$d^S_zOswod{?:{nҏ9gJ+f{~-Y#GMჭFxL{#Om#Ap h#"͊P LI{uʿICDkMrBl5VI"h BA(|`<1iDt ɖ<:P! X˄t\i3P| [LN19d|% Q]G΀\yɒ&c U&*P:9Ĵ ͣA43 7⒅\e"d^-tj*n`ga4ˆˍ@ƿE]Knna߿P#'GZf_YXaGu9i՟M^VF3дJg)kCЪ9`%e~iMUҟФ+2+%z5>rdGL)H\ #Cw;>7[|4>ӑp1M4gj]=Ϙ!gkuoΘ5G.='D=ԠXTcz/ԃ~7\ٷj&m=:ѕ932'x?϶k lqʇzY-}oܿXxEgF=g=叏ܿ"3G^z¶rAG_:[y}xĀ?/gvUl,nؿsN9č(~И"[":΢D1;*vӮdk_f@麤$Wm Zo V!&s2EFN臋R?jla6LO}OvRZ :即g ̜q [7MK%I\ T`o{xnn2dz73hԩ9-Gxվ刀e}ǘ#=w_U~lPOZ1usvưkג,O슩N}:E׽{x^Mb,㴃8-G]}9궻`i>Y}}׬uܰߒz-}7_^LgZx=wά"k\8dwB2Yl~(Ysnc QgDt*0r2׶qs0*F O1AtK>Y2GLF1im ;cDTho Hl_I{s#CB1J@S8R,oBRA&>1cvhadf1͍%[q?)+FA:Hԙ8 ъz,n;z7[7N^aK N2N{20Arkurl6!y22:S ݨZa#_0N-&O{zfZxȖHe#!rme;THۊT O3fX Es%g̈ MZfuNekWEɷhV`lk V@L"nqӓ!ެ*8feIێ~A6auas9E}ghP-%4SjwK_|9 זM)Cv 6-"3>㵫v~{W&)Rs6hi^S.c{OM,+!s0Θ' Kyoܔ.ʭ;dXtҪhZFT(iijngr7yshG_zx7f̘5k_7 ֶ?ssMyoqYu?+:_XG~~1#" [':Qӷw۳VA{Lj{n//(~3xVN+;j`rHd @o.]jό)x3X]O~*WIS:8'?^ӢO=]J<_xs֊ ]nZƶ_EF≅XY Pߺm}kte3O")>mgs9u+e`(1=bY Y_G?cԯv@(8~S/9qS(]6o7}św>0rɲFF?HLky<'/ǝVfrf ALa7Be3tGvW˴uOxrWNӶ C p `,mdLt{)oޡj6f:eZu<(8BP@VɗxՋe;@,bmGU~/Xُm*zt(zswߨ-ݺ~Mh[_v7 1l:u{xyO< 7zMՉIo/+m϶>a?\pj?7yUfywTo׵ۭ S=9i(.tW/;0쑷O[M8ʬ( 칷SOY.7c}?z}r7wy͒i[Zg5{ u߷͆ P?FCd -\TtM e 7t8q֚|`mwIֈ d{ּK˪,[!թܢYh[y9V֠FrzÚ_m˅T0*πN Oκ{hɬ 7pvB}kM}Tɯ@5u>y=_o{];ycwVQ^JjbE  70eO>}7hQg[49 fY0cքcZF/js̜`pO[D ]fj׫Gi&|5{ fꎾ%;4kf̯ڷsyIgѥَ}?N9}|["̜_u;~Ɖ'~D _r6 C敛rC,[k"kֹsfe:٣.};w8N:.tXՁX X 7AB, VUsʎUvl]}}}>%%%#2Bmײ-ⴾauɔ@AˤR:&] jϢKt<"$5 `.=,vdqrnjԍƪXuIf˝tƗ䗈f;7GcX$|1`UcȌQA{^VJp܇تH!#-aK4E9+zE/5&cc 5&p=$A970 Mm*'!g( ;"A9aPZ F#CHf  ˮ޸چ鹏A730 <ƈ8Nw$HH_@94~D'@J0%*\6_Ilb?ػ{{\^Tu$:Ё_bX2aWS Fzo2U}9-Uީ7I*fkdfH`M%ݶաCb̋X9W'? (_"+DBLB:cqQƵ೘ SUkuf}P Z_m" 8A߁b\/wq3YmC榉7 U6[5 ~GW@պ*;3 q~#}lN pfUl[ T>\?h NQG:i<% Hٻ*@*(kSQ>,ݷ_T%Wz.=ΐa UYyuicEn bDT u~Nyd%_ q&U^1pn%/RGL= *(k][}!Pcodz.-/:_.-Jc6f?lQ?>:'4O{]T4fjl L;Rn ~#V 7Xԟ*N߽_(mmޮ?0˾ݻ/߷ۚ-WBQ.N1W!Bwt엄?RoW[Efߘ(m]~zVLND3"h1+eX|> ENS)e9D3AY}6ƪ2W VbgO\6Bg/qAp(D1:.vTXaJ{EidacTg8c<|;4cV2ySW~CDuSx}"Fs ( $AZy#OgIBxi]gL용ey@DJu=/fJA IDATb0nQ^X,ӾGn;0Ӷ箻V]rӺ_dþEԳGZ7P?q &^1榚&\~8v Q4@xOK[}p++znC9錇#ln͈DnkgYOtրuhCK{3m^^J'Ζa  ed9@(R=myn\lM5A0UW;bw{ |܈Zyr].y?,YS!핟zjr_^Z=ӛͻ%Xw'bXfw' }5t8A;jbB {+d@@XcmPzsz%Pjn:?jW(8n P.iL憡Ѧ W y|R3;gP گnҥhgK+%ƟTk@\ b3< qBt FTP $ gXrHRTOܫe(34ݢdHb,mHncDv+c!D9b:91HT L 1Bsc3QʟEA>>L`::Zf Pee!2i/"tmDGhJ8_M|Wɠ/\/t" Wtkn 3B<Plvh{L+ .ydJo}jGK Qф 0P .>aZȣR !d$gP`58Ո `TgX UмnRȿ I<9CB4-3 -+C|YKw`/o}9Dc󈀄s7z|ֿ A|F !Xj16cytk;;dϙljDCf%{j@>>u1k)n &KvqGV?e3+b.R?q' ~fŢ/ o4zKE`ī/ .zGyG?8 㟒]>[:Y}ަ7=Y%?)_8|Hq\AjҀ tc.epr[ R&Iz/G8"مOudm~ehrk SG޼!6}9ܺ9{ׅÜq/G[Oz;_P:Xg?7T(!Iv;*g>u@~ne_Kcp3kOvelK>|;f2W9g7̻ȳ\嫻Fw7jʩ/?=5&fLldge+;(ɪ/gԨ_~K~m# tyQ+!@" h5s` Wk}by^62 P⫒OۨԬK/q@@R2s_6_ȋs_g"u[V|.|Vϸ]yKCG܏ Mp(e?_>g?ٰzzYn3W^zelWF^Ҝ6d蝤}t&eJ bqsܠH"z~W^|2y\3aULD1BLǑ%Jm|Zi̐:8lW^elWol|eV\ Vˋcg\'+~i] ~wh[_>m;XW?m;o=)k`m ܰ,{XNm[٪@]zӧo!@_^{䴡 Hoz~ٙTIU5U΀m~o9R)t~MW@r5ߍ=k%ݸd;P׋/~ tRY;-z%~ҢS;~wh=`M8U*O%XT`݇#oeMo}scݺٓ& vw]~ϭ\zvٔ&-雥3bZD& LܺH6h7 :*6eX}.+u I2xm 'X%#1 #b*"x~ B њY• Gc1M3D!+#~8F4V$E0ۂv 6L0Bn$Hkݢ2nM'D>dڱ¶ڿKCN$ WrTAKT>/Ǣ1ብYE 2I*5L.#6 |(̧hB(4T`]GPs HJt+nFI%=QĢ9SS,BRsOSi?%°6|l')rE;2W<::[B"p)zcGj\4E @Ks\W8 8C֞?]DDEkH@_LAfV&a(@_bX2/HUJFw}eH[KG.9鉒uH:Ɣ0GYn7fQ, A Apι1ƅ MqFfTIdQ74эH)4 W}Mܹ$Vg3.!c:.GG_E3(!|Py%0>1#$,YHHrj[s~挧)X6 `Je,od9d 4ڌCvOdIЃqòibb5Y L 4'B ?*bуM/ӂ_1^\ehN>PuL%VZOGwFEJGƘcHrz/v(;yoAM{g,y7:!*62 obekrl#=CQW;jdMUHDHSn5.shb ̴mwji阬ƌXg&L]_F9ۄ-jpJ q.D4X&]hjENo\1.PujcЊnf$kgf_ N(RoHƀ] C&DЀ2BDl'zl{y=˔AD. ZHh# BDS0 Y2 c74bqX&5dƫUjE |8O18 i ١4vN h!"5 ]DHL.3= (tu38kMM+-"4ل8"mss祲Fu#fHDQEw:A,Ye m#V0%TÀA>>pLү 5 P1 PfDd{\E6:;-VMp70) S>jπ.(xiZ:Dٷ=V4"Դ],bdUC]5/ H390aS)KKrl}6ԕ ZcYXH'#l.o\0HT\GG 逺F]DE$>'&Aw Hz%i{lNQ~R"$kBcG1E ȟ7BH}>}_@& h$Dprz[M+B Jl1!L]|RW, "DnsF~Si/f'(((8 EhТZd V A~sDAD_gJfknѽ4B%VCo/(D7 .$ae+k1!H"ZI&b^.#a( k02kSGCWD cR LI]mQBq$7(}tuYqp2+xݠǹ{fb d)K`#r d A qrXkFm5_D5{a( L\)2)ƀ}pcɌyFi+T."C#(EȨ';9c\ҳW<<.BoS$rKsrj_ꠀ G[ R,ۦ=Oce<ƮciץC-x; stsqȎƖhmlx_e.l2"3"L% rfG|/%6Hvh6 9#R)9 T貦C"2BL L/ʭ/ Ð,$BH @羟$0nDcb!f:@Fe0f1&(\0./s(aZ E\6 _UTq:2tKl45LHQr!"JFsY4aR{: brgcj6t`){E Yy:ۮBu`Rb1(Z۱XOeLG o$Y,K4i;4T1b9 A!2Ejl,:]*tμ1O65٩|R?6Yngj ߕ=^MMMPP"Eaoeg5$cD.uiBNBsm-cND(٬#9̊G(hy7éK0dĔLBK|ƹB-S[&C߹S(^ M$l*2#4"Ra+67:UpEljv9m_ @+HɀPys@3 Q㞯Bff{sI $[Zac+8{x=6aAI(Q- A0q.Īb"q%M6m@WR$*I5RrI̕vQWL69pҵE[ĥ&\D6,oDy{ Ḅ%y%7+M Jy+@43SzLNWga. C9c!60FeK`8,BX A 8Hu>0)1&gsc05me L"bGaL&d( lVh 9B6xMy@,0] GTawQ! Pjde0AđHDGfz&edRD5>[K CЦnR1/R|=6l4tX,EO"ȇQ*8/d<ϫSb%Tk, j*^McQa> <>er`Mt7!7%:-Bމ ~.| l&FdRF ̠Tʗrƙ\QHrjJDfknK[C,D,XIrCr.Zӫ 3)n Rٽ_0.HY^ێmt/e}XPGpc:dpiQd|$SZ>}l"fBfKge.UۋR#5`b(V:-d A $^ ),Z, I(aL&z!Hh=dY \֡"'$ Ysej*I2T̳A4mħɅpZ GC_w֢6Po{6ޥb  1dfF3i@*WO֙[)kfD)`jqP,z`HF99<Fa+ve;|9L vq : :A mj J 4SrU <(-5AO#!zâWƊ$r(ڦ;L~r*c6K4Xo؆]=7>tRߺid5eyЭ IDATҊO$<@ kI{6岪hܡД=9{, F,U@d<2*ՎqDsysP:qƤ1U ";؅v3g,*-hU(c8]S7r,G.$dc:, ɪ1$=Yz3B5՞"%:v'.L?&[̼s.%#]\CuuԂ% OZNDVS]E9 ̾"M` Hx˕()G`w@}{c!!' ,Z((>.:P@(0%!SYȽCv7x/8v^8\tIGh՞DX$[Frԕq1|ΕOxSN͹3MZJ)C cg0` eV(!6avnDjjҪ/6lH154t@cq!_;CgTX.ht=BWQX$H \͚N_0NUEw#FoZ p}СRSh kct)$i 8(ȁ:eM-ZM!0 5q)_wŠA/}Qz$ AXj' YĤ!01yA~cvyIy}v,*3m|cop]FzN?\OWV~J zO"gJU/NFX9 !Lj96wn&*ƓH)玞#qۼ].yR뎉Xl\ۣKsR}q^8|lw<Ӿ1!xt}o~;8iӿz) N0ry1dr/|gΙRqΖ=QoM=m/?x~;3g_MGuM DqY'T~׏`73g Gt`C|?gws|7gf+J4Qd΀܉C:1ܫΚ܉ú #<q:+[RٲW!k~疎X緗:,@17?főGwJ[ g\g2$[e ( <d{c @+z4W6=AHwxѝ|dD ߷-+]\kʽO߿ꈰ.siρ:7*G`+]c[ [g>#H ]ZNq;V"^xUH(;kjF6Bj(:A˔ ɚɷ0dQ]XFB' ,EWMFQ:tYA}}.Yi&SxHV&dbhg=TTbR DX*J)^ԁێ)TIɹ߹Ɇy CKϹ6A2:@AaX_@H{ B6,") YV ^G{]cE=eX\yz82e٨uC4pl[5`X:@};9#jeW "UkM6-')ZrGI,ȿ$P/QCDRRcMIo @?vP9GvJ=`~Mf+ "x9D%DKULX3; <#S^Xu83)tTιǹv<0Uͯ_T8vxL<ΘW _;qwJŽ d~>kK=¯l]p)e{튩]w)iB蠿¶E0S:}ǒbW^:J M\qL:T4˷VD3Ls:[KdJRtMr mR'$ \v5܋iI%X&y8s4Muul(D&*//|u9*E2ÊXkm:Iε9 B~szjQbCQ 8WDh1/fG(Tۈ0dB",Ax{c*,/?@{'VN6'rr.\YhsG^M@Ժ/r)[S: Q\s?AҲN5cmz>zYWtl7˅2|JOu9eTV?;ޮj{ϹRnz%@T(%(UCST "@ABBBIB !v{f}L3[{O{gZzM2 5p׍^z8=P#} =Qd-熝橩J?SNG7ū-sGw]=QEQ죘o>g|3[KdfD˼\‡:ea>37VÇnJzY=qFLy[q?/#L^3RPE`s:vSUѦ=맗 €8^zikq˹3t5mAGM8_"jy_lS/;}l'jv;ڱ}wn}?{ _4J@ H}wzm$be֚^Av%5#lYP:.yvg=ʏf2@Bʍ8鴝9i0斐$ nrg9v;7@pSMjJ=:UB v /*ɥM8aNĸ/l zׯ߮*!I ox'_*:{v.-o_eڃS~xGbHYm~O7UfQj:>޽|I/k\,Ddq )0RDil! WSߘ~;}?\&|oNy¸9E?(mvW^KCBDn(73v^O n⫧4qs(}<0Q[~j&~__5K6l3]o@lpP>o%7E7m- ku#FUUhgëkX Ŕ7}R!cjbu krz_f!A~ @# }HUqC5:STjsj7%s>!\S۵שg8ذl߾Rs'/֣ι3{oM(Jͭܥ,%kQ p jXK1B&4$:7 ʷ"OO;&$!bθs\_RLԴJ᫧$bUe$\R8+\*|d&+*{{( D(%"%WQa.'EI X"]F[1ѩ2&$&Aτ6[-yal $3C3m7fz4$ PhBCagx^Y#J#NXJV&"Apx ӗd֦ig1L-9\O,gu_wNYASWrwRS@1SZ6b\PFB~g[zdJM_z=fNn;`&Wm|ɊFTiu-t$L BBoDм`B]uvc@XT.FQ@>tӼav(LYtSscҋ/驯gX44_PW=9aU;73_h^ΞlǼ$D$ágppk;#v2ַ, 9^#0h zԷY".gt:).OXPE:-QZ· C?v'/.At PУU&#:VE )Gn KbnT8 )$XEq"BKJ2njx8Uaҙu??~tܕ-hX{Uμg~P}:xc'yg>#0m0z֓6A,V&nؾ-)0 k.8Zu ]ya_?ަrAu$jI-2*! }R@Ō$+wB#fc= La.9r>>^!Din7,f6$ñyF RuH҈~G& SSM{]:8ROm)k._9Ǐgn=\zӞ8+5>znӬYbom[+V뛯 e]ݪ+]0WyufMN*QMY.oHX'z{bͤr=&:ռר/oV6G (Jԭv :~u;cE~top脝U:{r^>$J_?&:c.rΐa|&Ȏkpd=pTkh|CC\̏tZ'"E e}t:un\\JR |mmMMw" MQ%3آB8RX^/;?^%s=bAP!̮FWЩ$žs@f62YZ)b",[*+D H)CY*,T1V8 ϩ0d@)tdjS97{w'?plj?q 5jsn&AsJus(Rf + X{τ&d?cUڠz6|֐?Ԫ|=ܽa_,9 :;}@,U+|[Zo|u-q×TwR8{V]~}upo}`uÃGy1_ ~{Z5_ {/V/X8߱}{>dxeaТgxlݫߝЫnx_K/[ʕkb,: IDAT .~ݽʼ=f:kH3{{z|}KAL WF<2)jRLBVbl޳K >H? 4eTr%Nvcn:2“ Vb6POٚqb12ymPUUVi9#)݉==y莟a %Eq bזMf9JjZ[杜DCoCķ) r½pd}GLT2zr̯i؊5=y?O*csJR61d"]ɶ17 7Ov0Ѯh,MvhDǐ_xD)EHFu$gL,(QıOʮ5uGs?ZWکa=r$C,o{N(ҴZ$X!S>캶#EA\>-8~A9)KRE-O/PuN;ʫF7/ke4W6Pu*i;UES!)Q徒>yI(A$  m5. wR( lx+߱Մ3o8''f&>B.7ojX MOCWM~;x"z[ԿS#)pa7&ŷM@یPIߟ"~﮾^VCLZD&ƫ&"z%teh(bd L/U-ȸ!!(j(6RJq.4z S˄̂^Q|4ֺ(렁MӖ4J3\6wc!]T}:vmiPb`^AEp? 1{ 0,:HI+4Vhe%1NDB ~ԼqZhϧ$)DE`6-+?ꥃ (]h.Ž`g m88rHnP_rUeLg`_-۾Geb8>졧]Rř[ڻHV* Ag;>l[ by @^r!}J}KUkɐ1 #kzB#USbrfPHcAQ-{ ?ʒM+^n2ECk-C:C[ᡍ۳)&͕TIA0 X\"*Y_=gu A*, !8x\rT&MIo*YMFYycD<&9͔Ҕ&i2N 9:\*>U8-P46GpV@@BǨSn+Ub䡒dz?2al䐘O.$6A=)E pVjn+Il}Bۏ:f)}tjo9ceiGIΩnV[Vc7@V$+I2q\?䐞sȺCD߭=f2&5PRR;%Ntv&'H$QG0"԰-VHՇ@QuJc0\.#|>lhNk\]Q JIRh΁sX.5uYL]O-ꗨ`u=MZ :[j׿ɕ7)Petã`Uvs7y/_{N[E6oh5ۦrDMRҲE--llڡUgP׎v_yв^:|sFhSϭ&6{tъn&f~ M @$@QL })- !IdOC}/~C_; PCBZmGR\$l;ARE_V*ڏB^uL/&J#[J1 mӆFYƼP:hl۬it`26}k ?|'yk~r' ‘'WALS.ȦPӫz۔?Phu= s^.L{; U bs!'˺7.,$"HC>2SL+D<8V۩ А3QJ$5 TG)T*F5BM}m'`jGn):RG'ID1pƸ8Tz.ٮmr?(;we4§@һ~μJY? bA3z>Ι^qD+]p8AFQE2gvMl+S)DPdigtZ2'f$ԺOP.M̭S+ rXg)4X*ʅaU>AX,GRU7=ҋjgnQ(sArAGD@Jl܎6 mn#<BpBRBaIv^5BwL&PstQGW mAȆSO:HNqJ9%9L8ftRT]jcHnrh tF߼%WdLSj8 k擝~.v v(ڞpcr5xZvJ\ćRYXHnت@ \vB@*M^_ ! qjL _ѻ-1UFoZ'jvLزvTW kzBiW4Buu 6!S@c!ı $ϩ8e(X 푺=7]4`8u_RJ_Gŵ 4R2y蠑pĹ9z?qFGDwl_Фx"ё UqHƹ!l{2Z 1j+d&-"g& M% ؚJ rDy Sgmu>xUiɪ靍+=vVmCwY^lR,k L.%! gly_GX'ƣ'`FkP) )Ne޿O^?$$r:TZׯt39:[[gu6-P}}é"o |H37n~;vԅۥrve]0\*TEDO}lڸ)֕]|oJ̥ޗXcQ$C+ \.Aͣ8gB\RR)G 4fR[Kg+s@8~^aF"*׉S+C)%jmt2(6&a#;Mj G}_n2Q/K9b|ˇt uQ__WҘ"W6oÎ]q4Q]@i*r͛7i^!v;W, Z޻yEj1;{[h`q)?܀h+wokz\%y-B_ nhm.75ՌKKڿ!f*MWI9Ly|61M*3u#N ޢTR 'JbЇra. 5҈mtWn@$Џ$B!Z[[cs\55-RYS*PjxCʱY0+mERFQ*V9(& b9#,0Ii;r̂)JxOg PEZ_ RXT;Ҋ@%iFDZt؆}fCҟYK?"w(60c|T|"=z<ӎbB3md`jMy&eZJA=JCT[ר}"xuةi"vӲt;cLzd0jhz2O$t+ teořҸg$N-&=yedb̄Swr~B(=<>1ꆫ%#5)%2_W}ĝNMm^ф<5UYml_M2gn{yzz&XW\IH72 1 s*`]Y"Clmdc-+ ju޲D>ռ+[{<^H[/@4]D6\ Z=wYӴ~٪-_Y:+K/o.*aw)(") Pr xND.kYun]eu /dO=/qôV]> ޻r؉W~wu/}@sVg.:6v,sɬ&D~u]Dg{^[q)&4`v֓?Vr.9)-fnebxhoW_Z<ǿ>gw!<߲'_]""Bׯ[=iڂ {ɩ?g?PB ֙L0}oΝ~$qȯ-Pimr#/zѣ഻; =rG+rս.`[rO/oY!rl#IpTq N婓oʹY1+J ٵ.sP^?/|d^17;==!,y0nUC݆Ic\yф~L8=p[" #/zϺɳ`'(*]G\`OcnHi]^.д/Fi]vOK}ףGW>` GumQ :K. m~mgNft+Ԧ+*ѣbRj]6-{׿uӕ=sŋc/y|QHz<"-՟/s46q% JLCJW(hɓWW=׋ٖY/\{c9AIO]qU~ -_'Dze3ŸwVz'DtjKzj~n{LXg=,~O{&?D R& 6ip?-2\j>yUo^*tHhlO54!IbcGs2.#U-˫zۇmifw/,%ض)c?lT Vi:=Oּj {b76W}wẄ&]ݼ>mU3&v㦨R ,L, zZmzjc1]}nGg-o0P5D?\ͳ7Xɪcښ>kD\2fa}fHX5Vmcp&E? 3pRDx*jb/Fb2Ccn5#b\DQ$zplDj51R@(R\rR\* 2Ill;~7El[bt*E\`$BHp^g;{䐳ںoc\rL}islVj$9gUE,bqf" QEDxiLP(I1-t|H;"0J>83rWP}t69֐Q{ܻndP c:=]&KJd&)=g}nWɹm;*vTpZTbS߀,tQ9{ZZ" $eY)whZ*\ycWjN܏pK-XMfYN^\)]`jL'!@5ՖA H"iranIpUeV9ԕs\JG8tc[t5% sə HñIrR)cű1HΪzRy 6ɷFex0eei")c!V1,(R`(LscV1΃0@ HBH& m i&Vgٍ+6 ̥Nю,R;pY|FYPzCUd3g&]i7[/qW D,D#९S aܨ}y_60e+\.ű(K%U|:&V ؚZѩ1!"FqsD+T8b1sƙUd4UN쭖؜m -_)J" 0I O0D, q'2ghYIVɓV}fY ]nmgg2$}B sIA^$3ݸ*u9~_;#q |>Ң?.Y$ebh,+intI2jTUƄq,2H6ÞUaVw'*o 2LRZ ;A]P;n%alA>χ!bT IDATvmO*nj  R֖V郀T1|՜;jQgpJC@&)5sq+&$ Ds(mr`9ibLns_dQQ)7v^l~1NoV]bYv h\mk{cyt;J :dmј2̢NləfJ%a^ѭW!d-ڿ0KPs;zk=RX@\螖qm\  P/ YWdGGf< R2IHWBf,RT2XE0CΣ(.H{l/Z@+)8[f 4 Ԟ$6eJE|H|G-Eѭ1O0ipՇ#KIpBTҽRu]CSEP )(HJޯ9io#`'r8cse43}CD@YOʞC#F1v B;P9-NXi'z9tZNNlEI% lod',- 3%ieRJ,d'@Ɣ;#HEV4 .01 NLRfb9)4\xYB|FW!6Uv^Bh2҃lL$cƳ*C\.yMOLQ!S"w걆[\P[V3ɑaKpQn!~(VK٠8{Ҫ1eX7mWWW.ĚBZր:;[gjr+< ŗ驈hHYu&ӏ0 2ԳM e~m 1`Cg0͛-﭅FƥVHE$rW,T%̷' w|RwP؍=UVvRFQ,r$)d jޫ'~nUQ $A) $M1#4o܌l h~-jCqShG9%,9MBOΙ3R3v/g?-vG퀺L\FזNDEce6uT3!*Ri6F&ǽSӒU "czku7ȘU. ,IS׹b\Z 58Hcs0=WGA #C/ ɃZ[縮?DrQ&4Zvt Hhsmr?Z6H]H!8.6 ^1ur!I$T( `N2s55d`BA_rL#1[B(P>m̻H7!h& U]05HHJZ,WO~:"9jՙi촱<~5J0D+*e.-ך#='6У$y[RV{J:(E䵔9HXSnjb%n_BVS\1t>#IW v2!imPLOv64`m/mCv#k3ϛ\A9-M߮qS6[71(Q).Re7NT )݂ckY'R:؄^aWJQPǖRK"Pl#x ѻisU@R7*/` #-WـwHQ(UUU0AXQLmL}'e2cqx,C  ӫxFWɆɩH7@^-4Bƭ-\NqFŢ2 ιX6"BsTaO6{*d&mz)'0aNJVkө nx4HUB9) 3|»u:܀\wZg>M˨JC)cFRHjH)e9㜒/D#Ę'{Y#6~:gξ0c!JR {;is)=ifq,09j^t7lC\>Wlm8A4j4o$ȈN߈aR9RX2Wb|X]~I!`W?~} RJ( q"E̊litOWh޻ Q$cb2 Q#$3)Pj SC~n_ruC TnI;${Ct0\)Y#4u#$5a\ܱ{IU2mQ똨4{’FDu4+P* cޙ Q!1D (VՀs|Dl& ;e0ojǎHwԸ[m$#뭬]iV+ pWC wCWw1d\Mؐ2s h(ZGᲴXvKEܡ+ LjuILN$=Gvd@T]]yKɖ ?l );U='gJ"EgPA?ozRD"axı 'Q:F'oqm@rYaX[(UIHtD^YX*zypEQE2CC*Tf?Xfc6u**IT5dRBTx9Q92SޔNIpX^X] Em=HtPnF3T=m`Q_[(>u¨O.A  rP6̹4'jb\ ł2 ֱdd1h3*k`1 tLrXh8@K$mzȘ2yp*XuXж* ENW1,i'r[v ~RAk|At ҎORI @ӿ5쓨 y4J#.ghJ^MnTp*\LQD ~HFdgIJ~,eh-7dZs}]o4ЦbS~>BB <iA0XLy{C-D{4X9'M#)11@ZR8h-e$|~t0< cI-R4)@+\wMŒO)JYS?< rlwA=VL ݩL~Mm|,҅kHK[I1;56F& +6F)Ii m]31!+l1Of x@@ bQq\UUUR9*Ԓ~2 Ko&Ք^hG B0]Ov+gP%$Bnb\y q,Jr.1 $FV%A~Ո*2CPlR$9sol/(o̅;4\#)I,,Q1q`׺ '݋M2ױUCZo2lL1cImk ~&A{bW6O*" cS`@Kkv߬b$EcI)㼱2SdsN$or ypDZ%<gp\XK 2.Utwz_n1yWtM=KGNtn؅gtJ=78 sAA3L7dWFɹXCTx0p91I8itAΜ1{sv9@ f"bn؅g8'TFnbJ\"';&/˝=ڿ't<xQ9B7(a복3"]Ϻ̚?RrRIð:a~p[T0S0iNH]$I'C޷.Eei"WϞ~9d)1P&MCaaahL88JN+DqDZcuca(IƱvK^+ng7hҞNԅiI4tc?w)Jt`6#dV;Ro:DF;YS@ "@'(*ZJҭ:,QƘJ㯼0TPd 'C3xf7ۺn?$l~:i/n!<1'_D]bM~:}\~]TS-Nx>=Y?pd7R8BDݎ#sg̚ƄkF `й/~6g !\&7K #cB Z@ӼWqygϙ1k5`\~?ϧ[9}7 N[3o^5;|=cٴ`қSV(,@xLNg b9)Vdv!jjP{P)R668]I! 趆i9{㲡qWOx3?ӿ?j@-kh:qM>uIz+G \-z݈3 w?|#2AN&3uU]5ثǿ?矯>?H5O͜=g[88T<ރjɿ~4e[]}x7灔B͇ua>F01Yͅ: vD9=]rOu[Vxԕ> {\uu'u1d@ZZ:Ս)J;xf? 1=3XN!˜#秿q}z[>yB/QhZ0w w$D!|_vА7G>_1ơ1{|sdS~Ԥ͘_S T|zg3fGDBeD|V?қ}wJ^G$KroɚzfxY쪬O??U  :c[O2,RrS!NYS r//'Cuf3$Zl-O?SZ"1Coѽ0M]U~]ף&^O޶w먫,(X勌sE T2'"qk HHnrap.`3Dw;w[\sHij+e#Q\MN*Xrs*,`9 wtKK@*¶BĸJg[&e)=4{Tf2#Y.yQΛ<2Dis(s`- @Rڢ(i=3ZD$Z 6TG()UyR%)XO@0֡82s9'Iw()%79A!?CSi9nʞU$^<{PX0N83Zț bB?SOvjn?{˛d~cZ5*Q+$p!bi\,vYw޼1vQM"1F?Wǯe7_F6~H(|oO%55ȟ=4^x; 䮛۲!26w;ȁOL8򘮛#m?9g@ 0of=ss׊!j평U'5_YUAJƜV"I!Nsse^c[#E{Ԡ/Az9D"!gA*7ű*-1g6~ݍҊn¡)wC7.:%?{pwr]7޿e-.wٟ=v4!y[rǛ`&L1=47:1rL8VVOh'?BH>qe?$՝7޻i,\=KNij]sطu.j u|ΒˏO)a))p_w IDATZ,Q.r?%g|ս7߷q.*>'qyug9;xyiQf@CϼZ_*L~̇o|R&HqAegtė;w1ؿCIOlRtć\uo\t {}vwmYYזExsQtuvT1fڲ2Tvgztϩ}'=7Wrw1n՜^\-X=wO5@AE8'ocdz>~$I--55W ?Zj)H&1Lk6E5L^6;pK5k{[qx8R3iUDQGQDA1$Bʦi7;{>{nycۀ#E[-7wrm݁{OQbD1؉(cşdr}|<W7:``h8)^Ul&(NQ1`Q0S  ㉊f,9 ’9tWU]]=3;>wtwU}߰k/t9ls~?*2D]=%@* p;|܅W-Qؽ~|29ო^ua>6{yuM-:^qɡ=M_Q[^ł'?.\dᔧ/n[{+,Yf .Xp SYrw!#5KW>se!6mw[N_fʕS'-0r{/}i._ڻؤo}t_?}۰}{C 9w}͋\hيi_wTnPxsN(5" ` SIzyM~tG;],Ve]`c/:#n[u { 6p1cNK<5uᲕ ;eyom3LYQF^ 3+~my&#wUDf-ߗ}jEKV?[^?.^tOi2i} HJj%S>*XS>܎hSg5a'hšw__=y_,C\O|>2&5"-0[;@DwxG׌rOb6yDަ.]6gwے1Dž,__}LPN1sgVyOLZpe#:-|e9kZ Yy@i7^S_VXU\6C9-L՚׵?3l~/y]]uc樦2m [ݷߌ Cw{!-wgf3lf׵yZç=SEkw.G>46W2#]7cY禷9N'<;da>szacOv~,K9D 9qJ%-dDC$89*K#4Ǧ$gN|S]ט!K쟺fZd[-U8E~FnPBF!$)(R=Zp,o;DBI[w뾾9Q.}g<儫ǔ}=rjmsHD Lnk_#Vz}n5+޲!7׾{E#MĪre}{^~B^X±FoCde,m#?k;ŜW<}O}y~ Ϳ+mweu-1z5ez3u>ƾ>D?+E( qkRݶ+Oq՘ G !diCu;\==DE`M}zĐӆ]sՠ X ozi SvdӁYUՆ6s+yKv_Ԇm"V}+Quߏ@n~Q[u9>krf/d;];ݦ4Jf&߲SO~Fg>ѨRڢbIԜ24:<\")|gLeGuI{̈0M)$t mRsiI>25 ֱbl<-&+׆z>ÍLKQȗPR& zLsdxc(9$HD5E" L->0N(Wڙ Ya3dfAz+J1Dt]7rTT"%pU["p}a-+?S7Lض_D*Uթ#9~u/!<=R~}MងRL;$ c9Ê&9Ǒ$}C Ucr"Xm,boxJR4 Ajjac%ެ4p@$tdlo``$,[kLv7z6$=6p)֘سtYi>NiBFn ,!"Ď_fEo~N = α.WuF/9S$I8m@̯VTRE,Hk3kų>{Kj8# 3nf+$V\`L tr M+,g{vKXn5n՛vX7wtn{ea!cGm2!Dx[Y Dۊ+[ZB!@۷m9P?LsvDQͤBtc*%fڌ= 6r֌ ? i ly1& ~]#єLXo7 N|+]˧/d}`L y9?oߕ{i-YV-{mԲ|ѫNnmdٜ'zϹKV.w>>D:Gu/qM/-l?їu?? yya! )?8`# DǮ5Jr9gb'SI,o6VS6gyL zmof" Yp죓>F'G+A@1xSG3yefɊLXK~-㈣;dK%&Zf6K?g*|׭.`ԏeޫ9?Ɣ7#=K[xž WZ'}hzXi$:ځm3q tebŐ_Y O8m_7gYJtwۀᅻr;pWEGx pjrd-{Ɲa5[[?wWZ0kfkӺ,>n7o~S&8!@힟pGOϖdtnҫ oWߚ"_Ⱦ,e7Έ}kqLjIr]Z2+!iЙ6-8(TVh$1ƹÍ $|սgq ={&*4d۳DIdY?R"o18d|7?7h > B?=51&o}ǒcFQ,eʪM\Fv BR iЫՠ^0~ޞU/HZb ͂a{>֌>~}i}]zBwg]Uo^sL{VGƌz%݇&)v:ݹ|mftK*D!6>׆8co:!6 V2m*l)/U$0DYð~5>! { 7Y m[|uuNqGp8eY,H\ި7 ]x5+^qѣ~ f~C$"Y4j?>4~wLWQ@DU2r2M0cf˗"{kء}VSumQN t#a Ƞiq7BBQ~^?;ffw""k>0@D֠C[$Uo]W٩![!1QDoMUKuLPvR )/{£4(f_2O;gpݤ{{~qMU'mlyGbʢ=r"CViϒ+t G l.tm_תaء5k 6)$B|w־e[_8ۗlW=0<ɶCl#+KO~- LGDJSݫ*.(*O~Ok31p2xI2(9 ޔW`Q\5={'tnm<1sZSCHDUQ7iJmُׯﴮA߻fG5$v^gł 6={~-d*}bʔwrodNs{sv#t=g;?x}e=N0}}Ͽ=ck^}\ֳsyw@Pf2|-{¡3 Aŭ[zUQ,@.ABOoDZSS&uIQ޴Q' e;x~ս޵ KwŅ~Kp7!UDDEE ]9Guа4طվM^G@ ?Q+HZncاFkz-ORW\Hlo g-:g:uk\M!x']hfTί(CbSҦM):o7Ue6f7: [^F: GH~. @bi Tq1!֡vf"rUd2' |e IDAT!ZvBW #Ju]<ԾBpcLc!I&GELJ-d:d ,-:c²sȪ2V  $GRS1(3328c qO E3)HesEVFc"p(UFK.S_L)֛RDH:wWy*liuN7J8 ُA("hhBΙrTXضN,Cu1n5 8K)gOX,HALIz5EVT'ƃtjkc^'}*s>RdÐr]W7[n%[H!|9VϟIJʯrXG;GKAӉBH|l޾_=SKغٶN"!MyJk6'Du+ƶcT]g<|^AO+nSs}ύJ*}Hzw-s52 H,Ƙr4HAAuHӲ ׾f.xE:oTUQU% :["S\JFͥ{^fex^xRXH ?rudrNԳz|5g lgD*sqZq306ݏiGMlAyC.r ZW;x~UW_Hw8kn@TW_Px֡gtkrl?/x%T_1/DQwbjjjPv&8i}E(g2rшXe@y7sxb#W_PTRRE &"藄I0}9||VPIb(:wuuw\>Ca0 e i/儽[]E\k85}=^s{vxvl{wۓ+C${ { 2l~slkńߎmj}r{\p/|cit_St9dj a1Z#E ]p]q_U\IK%J‹=vÃ4R b׍ my(jfQa9 !Qt)PrNWQ]W2]\`@TUVBqs|f}PJN]44d~sJA0I(ZI- =iHS9e# рZ8sVvWI$ir%Ohd)#o z3uٯ=R{93DAz$\V-ښD됆0$e4m +UɤԥGBɩuj09*`Vl^QݻGݦoP<}cEdv1 TE @"F^i[u{ߘX7O/Hv dw<ͲWju2Q7'Fmp2xgM0k_Ns>Um뇋^$ :pevٸ VP0YnͲ1_o<d6x-M?_y\[Q_ʢͿ;5vfUn깪VkڮVy]7bQ;/n~ե m.v<ϓRfegb8ׁR'֕4Q' @$յH@i e[|u_yqkZSSY]mS SWG>=5m6wZ`a?9i&wd=_'nD _p* pVP0e4?[NT" b-zOHpZ}̠k.3yj{xGܴ:bߦ6#ժ*7=pױV٠[VO&ӯg򿫫cM)6TRtd6X5hΚV9 ˉز|`X<&i ld 2b1 >@K2XRG{7ŃmI%Jpp 4 %&"ԢSZIg~u^_z%l}/~z{/b:Εp5;m~U~{MYm,ݲ=ަ-]tk[o9RVho W[Z_uP ~5{tKoC;>>UUJ NkЁbSP1_L@@RqU Lɯ {vN.?uƢ?vg~ ',*6ipg&Ð /%[#D`ޖ&n-9K~m~4ec<9m콫[WM8薇/}W!|M~ y{ynХ?/n9; C{W! 6muGFnG[ q^{~ujQ+8'g˿R S <@M!lcJraY]2\1co'nl< &11+Ixn?@@ܑ!O>&M8և/9Szph_[ǤTMϸ_V6//jy9]9~%w+WӳA=q`'RK6^W+J U8`s$/ Pfסpҭc.~ss{ųw{g?|>M ˇImxezI+<7sK &QOaW_ЩþȂ=!Eڕ1jg =^ٞ5;b} }䂸ۆ5-κ˞WL2wx^=Z|k/r[_s u"grMk>i(e2Ξp{ܶ%T/\VAFãܛwkyz;65 Onu%+so.K5ekxt. _uE6}T~n2g?B,|h[*onN6`2E \l)F8* )qLP%5;-4䒑Kh—f(!/`% Nr$ W8r ӊi2b; t@AV|-)mpg饡/L+ma͟}xwU_<~{r;\4xɏ kD>iVf̧8#1M/vٝ7Ï^&N|r wx?*7[4p/&.Ngms,!_UiNĦ 1/Ms_;f>mpM..vL~8,x#- [riܲ "X5/;f|z˦ :nM-׽qc /ݿ}#w:JCߚpO^~KlY!gR2)Cd?{^I{#aiT^p5 шO{nŔ eY y쯇VW|?~vHe/O`ē/O_o?$!dFg>[pm_~To.|BW rWitgx9\kz^W<0YFm~qu6nbƙd@ieicnop޿+Y-GGL;:YC*-roqf6įn֢[S omgcܫokpޫy KVocLJ"dunJ#Ue.lD uDMdǪ7ؓ4WkYk 8\.9bU=MvL=$H tݘbVkqB!OLՙBH4ٺc+ XO~P).Aԯ9r2g`3DYR]u1RB;S^ƀ3DƔHu3&`q"~XU{1V5Oh{$ 'РXc`UX_#D!a$i((Zt$llEsQ bc+P|idc815ʊL"y*J3y*ܼ# *$G]vމ*5P:@i}9Tu MP|35eQ/+v({I{uX;BPE0ֆL@;X $aDh@uy3dsɆ<IFE2F>PIBe`X">i<Ѽ%C[ +XRBkws|) O"%ȗRVI!DPaTәUٻ֢lJ֔ٮTo!TP"*-e᪶ f " `* 6D A o DIvzƆB>1!bYޠ $.hAxE~¨C{xIHl%s=; ½Lgg-_$ o#O+VZoLC;[@G:۰:HͺFkj&{4˟O/^ʶ UzKN7 "V0 {5J00!1 d6O$XLm |_O neWuq Sav@"J!`#vF~FX2<N%憲ۀ }gO00สՂ%Ē/@1U;z G/ԑT[S05D!ˢfZRo%5M: ڑJ~V%םZ$|!ʌ1DE77, O":%C溎놟+F.Qs) zhNr*'u P3$:0S?w;1 lfF1] J@sDm>NJ]* XTϟNZX0!"w@B_*6vL3hbtnz~c QJd:+Emmna9T3@}DeeykO5D>֤ϫz1ڕ Ǐؚp`RčFʶP I׃0s) *1B&I9g*7$9::dIv7K+v8~Bm $ "]Ԩ!Q<8Sr& TB~NLzArD,*I z:[LɄ6"{~nS$ _'uv"/Ȥк8J; .@XHnԤ`8cJfR[R1͑ Z~fbEA ]nF_i-jsE,qx<`[Zg=6(c)duŁ1tݘcO$P7|kn#p/|!Oaс7/hbBfhmBUfĝ{꜑r9[źꨭ+Q3U u]Sź13yT{$/:wJŠ 'VMTWMEQ@eXX=:96RC_ FMIlncnq9M__ZOO5BWv0b.eN4jAJ901dWBI^R\hB@kn>JqI{ 9<߆`FONRH1q BzIOPU KADPKj`6jG"Q FM4="jG>i gy.MqPC~ .>%=LD6aئEPȖԇi0uc:/0d49B96άE.IrG}5.!kj?xjY8jFiP?*[ŁMuVDk* vH:`Q& ш)&f`'iឈZ9DkȞ+S j ; )811ekn " 'UʃMĒ`#P3{A`Z1Jc$Gt]Wv}@m*5I [\<5܍ *`> l:% UE0IDfEFIv *R9jo) aZbRI zm:YJ6cl$I"a!( pD 5y”)v6hR4JgZ{krK8M 6&5x!Z:gߚ8mSЪou8g}(sϴoMִSO|koM|VƑ;}֤GvVC+9 4R\]a&yV㚧>3_kMϥBr{CI19|4rڅC:'&6Gn9샩k?U~^qC£ eq5 !L0K3@C:''<鱿jngyך;֧_zki-WlDD 6iڴ8{a΁I!yo?{ۡUXLI3+pPD&X.xʻ`Ϡ]pb#fY~t̡*;|y'46:{%ceŊf¿A4ib@T.x@^Ji*#]QwwpĂ &)AgD#(D$Dm_FWL¹fRJ<ⱻ껏k<-1#(3z=G<׺z&=<aï犃GVP6*RK\"~w )ۂ7|^yԙ˾ l`֙RjC¥@.ފ,~=cs.;pjL2}R^ѻ{< _UncPybu_sv߱~]۟Wc4—6ߤyc;#M\(~%cwo~W]q*U!Ek0,@{9Ï<ީhB7sQ?y㟮?a7y-B4%n .g'":\ʰ}ƞcS9G xΩ( nОr$d+h@7֛xݿkyWJԒ$?@86 Oyk^sOS4oҝxȾr9ןFS1kxmb4b IDATecJ! T|-,;s6iRJu`Z垱JI G H)D8/Be _ԡ9gHa7eCƂft5laKxoJ(QJh㭙SgPa:!g&zǘ ŅZR6zA̴$ϻeS?Ũ`p[:Kv|K %LZk%,^Q? ۋ>"]M! !˞BjZTiL`GTfD$-:H()Dt賤yÑ[ˏŦS?Wrzʸh>T]śzJc$?'̃(rPڔQwAI7X@:KS!u3JZO-K3A96Yj؇W9|9Pjs`2A߯Q.Q 6Ϯ_?Xf\2w]~ вCVYڒ61#$H{)5Sxw\qH44QҲN{ o=b_ޚĐ<$PUx"FJ .Md 3x֠4  TF*_:?_iF6;fQsۏߛ;λ3>mp = 5$6|>d}_=s]_Zѹeӫ^yq̶;qsoM:@{]xK&5{/k6;ͫu/O4d5H@LFؽuK_{ͩ޺}J- )Ɣ;VQ(`[.J[ﱨ(%v&YhM Y5a_fy?ؿ>|WitT)i wmV<2'>{%g_^%"V7-Fe&[@*cw?|.F58&|sŅ)o}S^]0dM&F*sno͚5α|>|G5;']Yq#~ǝ~35ޙn'5y;{=2v2-OAZ11>#XE^numyCvfdҒ1:KkJ3{Z2TtE%OȝZ勿?x17~6rF5 ([mz8}.۴{_m ز;xKI[~~k/n3o~~iwg]TN||tpt!I$ = b !nkw(QHSgRDvbcF嗑IIɋ>A à 16rQ>@kCFH&۶"̵rQ4hjAD fǍ"y3gN((LPt?K1&Q2[^L8p3"sgِ:B;0IЧyeT*fxO,_E2]4RRFFR,-KL%rEu]2}.Yx)Ddꗇi) J9  26@J;i1ϫRxW*ƆjCZM SiN @޲տ R.x ԿeȲ^їDs;yȀ@}2dF5 !dÎxbϯ0"~k7z?G:Z9)P_D4x? >4:2}7)dH!$87zҹsEi*$,+t7b")_kT2HGP4a2'EM2Lݖ)fT*FXo`׌kY8`Q}ĒO^bo4:֕`M9zׄE"A2SYW&5 {b-q nӟn{wnpo8/wqfsUoІкi=cÙ{]6c>c>٬s~:km%{61.D>2(oI)-Hɺ *B,ϡ<EuW|w5ڗg_ke$R:T-ͲL[gQl6*}x7(-Rrg6r:ߝE (rҌk҆ZiNV}OyFpQ@ Ԝd"Yfzޟ8'5To]CMn?/?gٶC1lӝܼI竼B9(4Gӊ|Ʋ,V֑`җ5l[w-܄.(YǙ~kz[مm#Ιv}p>{1ǽ4gVVYwkMk>iu=/IWa֠muԎ n8`M6;T?_{unͿ}j_>zW\&osʝwj$a;WwVG.܉e?̝.FS '*jiTAtHn_'TJRAb塶l+IX+5 IgdYl")< v p*xbct]LToyAR ĮnpǥHĴjC վjR )V;5? ,׽)!c"q3E)pN bBR0(wm C{"eU^U'pn1d{{QƜ! X MFQ̷# ^sÙ6 .Ĭ0BHD5Y3T/ S*-m>Mi-U֖jC[: p$3cn#EbMOVd6?T4<4w^K_9Jv_@-7t,8^ J+ntCfΆAIBDk)Һ$ I2")ժL"y&PmljJnb>'7?'ps:,50mFQW`'>m~}JT/{}G)bTF\Y4.}Z1vgY ڪ +_ӮN-͚6v L4M$I4uơxDi) ~m1x+3 Ӧ&IRIs (XB2L#@kI帚&mHcdm_ (eZAXMD$ZAܮ~;^ؿgn;&j#m6zڳLi'"J4;ɠ*$}7ZȼJr/sk:>섹Y{n:KxO=|o4oڭ@?s7|o}t6 5a"X+QQ Tø$7xhDQ2FN5.V we ,OpW?_35RZS:m_zلgnf1{o:Y&.lP=ҼM)D"CWQZ[A^ۀ6o>5;i\YKK=xy[D2h^~y3;]̱- ;9+8+4QJcw,d+Zŏu&Puȧk;>;F׹7e..d@ ܂ՑG4@ wkM_|2?_4en$οOk'?;a*}}\ݭc0k'SyUo/WLLvXv|> 2W$4ϾC\w')ksǴEscVt$1 (LU^^BΚjϲP@M`PC( ',Ld"mbXfgT zɖZ{1j6v!66,P=KPŤb]`T3cچjCil,D)MvC)rOA>B$*&0z*n;4'EtK7`~ѹLua**nŪ" E0/>,L10TuѦjrHuզ(}XD/Kc Gkz m#j!-M M 4p8Ύ3Hz;Dȧ@Rn%~o~?;Bk Rؠ .j()dӡ)`e: 6a);M0#Q) rk1&D.P&V@lh446txb=)xGA!ȈEAɟn''==[{l^@!ZͻnY7e~>pe]FiC Q\*g`ZS1MPf=[#"8 RJL0(Ӵ2u`T =cޜ/`aJD6sGS4- eMc (|*C%pFd ҅}*-=-]'0NuĮ0|js#Zl;uNM̰QΏg̫n2e#AKݩ_}ՒۊǏ{a.FS_=zʮ]~_viWeSy6_e.ۛ(o4!B)ac :Xp_dNvk3G)H//) ZD-K-K!_jZK)QkcJ-Rڡ鵋nː/AB­HAJqQ̾:꠰NĆvyK)L==5ۙqy"rJ&N@<^.G'tp2 4D& c_a7oT-Ue86ދe :ܼLΧ=6i9|S*FوXR y>J#5@Z @ Ѐ]=ڦ'*xxE$KW+_ENO<"֡NN "L)e]Cۢ%)PJe !$ReAIiE83Žaיe5\֩ QTh05Fv ʲLQVՊ:KSžs7 s(L$%((t{Z>S5rgP ht&C0.W:nk<૏?v^;p0TXHD=~{T&j`SO6۞Ԃv >*B\2 8C:j~M߾|/4u]mKl8]p Xj]"!C6Wh2I5&*ڡe@w/ l_b+hH]uv_uΣgѷ_\e=Ծ|@$y1AYghM,2"TPI7 yIzƇ,&Q9}yنOD/S87dⴶ3[RE p~-}_p>jռ/shCqmsJڃm7>v×LxK]h=6(0y혟O:^hA:и6yFWB:f7Dxo`ĀfFj/o΄un=sB$_t1WdZy@mmV)"H(:@/]a:}g'afƜ_]ghQPZI@ )DsS# tuB/y>B8yen'C _1{qT7,^Q+>T;D2I"E>zr!nJ!3һ(= M8]yb?Je)IdKKs>}[ZJ")M.70R ,2J `r[2Eo9[}1m}Z6={J_aB\:deCԧq!wx$bޝow~Ґ^q ;gu?LF,gNG~pwH[-Ͼ&HMP1 LRk2tes)'nͫ?JTM{ +".|٤=ucJ)2Id8_HϜ2iW*qܩGdFiI#w܏6.C>=U7_~uO:l+u֫NMz'uVִf|#"h~};D(*IrLhO.*|$1X{uAZ=g=W\yV[iό[bB`!a 5sc}^?G7뫖Q $˯j֘#!}fX}U dQP M~Z]w1masl۶j^}Odb<vҶ+%VL /MHHsn HBA(ځ@@k.eYf[J$*y*Ed3IDpEي'i& IDATTd"R6_͝IT*yN69 ogEe/;p%X BHD&3RSR"gJZgdygl`ݝZEcMގS(0?G*D<slS(XP(-}CvU,*n9+"2D_y܁ٍEo&\gMR3xB LQ"EV84Oֆ [H^Ɯ%EY @X.(ʤqzM,:/T)彙!|]0l&H$F0r,JLe< {zWp8jRYF@ܵڠ!({::;:.TT*2"TRZC?aZfx*vj*x\"`Gk<0YchiZ2'9>O7V=Q'2lӾy+ll7bIztvNx@4oyc0 `C?>k^n n5f*::uO yW;Ai(myq0֤3e*9D ϾQJ)͔5Xep7k}N#Fn) ?* nj3ga"l3y=3yGrFx^q={i^ cԺ>K+Wwzm/=}3ȧ:Th:޾癎 N8nV\qNJ+i6Tž='TW@Tذ>{1c;E@<[#ҤGK4c6"0}*Ͳ,J,˲=p?V[mѧ=abwZokWYu_yƞCׄԒ<͐P6{g6>rO=h>hCM+O:zCذn\}L'/>VяW_}@>'ȑ) >Ie^ { 3Go,lh5z䁏y~q>f?݌ܫZT®F.<,:૰{f>pׇ?MGdYqݹ}|G߼?=c&7kپ#g/ޛ~8=otdž'Æ'o̽S.KS|A?iZ07;~ڰWYw}p16C,foO^\tˁۜq{nk.G^xZ=:3PF'o DQ?^G#Vi6`QP eݞk#7?P$sDV,鐶< )2RX'1 䟑سBb(#ohhhnnT a7 BÂ-BI9?ɠ'mn5^[~;DRB^kz5e]@ĖƦj" eeX-.c\e3.BtER*NzDPlդA(E"eX- gHX Sk(7!jfbIZ!ʲjrQZ毀f J%C5c,Ɩb 'Y&P}V~DsQgZ`i5}ڋ-kmw@~v^)™O]zԘ7҂>s {_8xl YVS.&-1YENGLڵ93E<+lsEd^0~yokT~NxW({>Y5rSIk_x:xf?q݌r0aͱ21i=n>Ծv?LoS-"Rjڤ aso~7~9~'~R"=i{޻}w#k_M37mw[ԾŇ{nrx!$3^M~vg x=3!YyWiZm.:Ltǟ:`iuf]g}Ço_s3Y~ }nһj!4/?_PϩP @͋C\p{e>~dGobAt*+ܵ甈pL_gC=<Sw4[][^7~2_  /'‚ =)Ak5OJـ!baIHjff%2a9U49&?B2%45^m.bQ7I6iV*¯I @4)I!!D?%_F#R%83έ@Rw ABJRI -XMYQٺqz DL%8}x`.z,?H X3J$B0E]jhqRwhC^#{r ,oN۫lhT1hx zc[nF@YST*.QJSK 3Q[f,wqG#F˜OM.3_\*΢{r׺HD4KU|!6ؿ MD1 PɭݤҒ죁Ruc\@V xLI@I]*>zFu *:Ė0V08)8h؝ .a,-y9 u$vKuRȖVL%,*_7l㢁ֈRH haha5WKk J03/-buMVe5ڼXC>G,s K[ؤd@y@ dymU 4+pڶ BV-C'oKvׁb$d vĆfc 7c,:E"i43yʙ_)+RffDHQ)S$,"2ՉH1򧻝X1jiCMZih\L/YLt`H PCF*^qu~ߝَ@؄0~<x~PͭaFy(s9ɣ7Zl֤~|SQquk?mY@X<9?p.mʈ@Jk Vz/am:,f9u^F#+(&+i#ȡ$w@AF"DXdzAe6Mr!\EE%Oߥ˲BQ( F# <g62s8]inl1ݲNDdVQ1o3>s.*֚" */9*$9P,",Ԍ. qOS;[ W@+L-2}ӦEw4&kbHRIN{v¿dFDr!&'>oV̀a>9T8&-F{sO( +3B^"ݲM^og{L ຮ:Á7l$t[XY7QK~\im&ҍ3"E:Z->=y!фE@Jdbg͎ <: cl%A$Tr"1 Q(j:+Ͻ)WP (c됑%O5d@>-weT `Xg8Gc5tޡP>!fà+3 Mh% A.ؖ䎽fiT3^K}[#,}J|3E?s%Dg_t߷ٺKPFF6B)zؤ׷NZJ$9QE R )t~g@-A_t `VkhlVZ M$0TKsJ֫eӅJ S6Znh+)!Іhhg8|r&)ogO9ŵ @ ~ɨ=5h!K˜ ?&0vq @4 ZQiťB@v;U,z,=r 1y m둯*o*솅2[*͈H%3oAR|.9e9*c&a T8kKl1(E)?sժմ$Yz?Pkķ0}NcdbX/hB b|sm7><,(t+q!V酬&PojNYxn`tR4fd K ld_XpfPd P.n&m (yJ9٩ \+Gg7h!XK;`&֌LQ8GE@ Nzr,5d= fvEnd8N_Gp„/wn`Ea]pq CQLf`  yO7M61A5(!^=0.qdof}2 Ik'R*{hɑ:yu#D`Bu-_YqBȽռEЅc+ؼ#jM_`ҹE-P,.l`wG7Qh4XH}q#\໌W0 -]%*iKk8Sā儃hu2 i|i2qi)I!)%H#~134|>CIcC߮k\!vZߛq%Nhҫ0|)rCAWAجg=0"PAYe@d9|(Xֲӡ4 !0Si9-sֆAwͰW+]n>@=!WGBG#vQb1Jɜu!$Yk˵56?&^ !$P0cLe$mo|To#kl@/&R_w ĤTԈ?hQE_`"p$/v&G1M֐U|GL$%аD,E HDcDfUchFF! SE0i0z)4HVDlTb Uye_n瞇===#:r9z]!?IkBA#"Z]%ƍS-)h3Ҥ@9dmaL93`N32%$K‘GXۺ}[f;/؃R`FM'*%#iIQ66JbfY@)CF N4y,V.@dJ)s , xjl'IfIbMwFqBc!@Hk#Q"k?$z'1=\bNd@= PDB $0!G.|\ViS,zlƹ{ ޛO)7eȼcuEuD"@^VdV} ϻSZQǿ IDATրH|!Cx}'ˌ ,)~­4KTJIPT" H1p:? vonkC,A/`z/k䬬`$mgp^BNdFX&ODt>a$ yqz_]vc$p_]mygL4!k.m+_[`e@T*Yiyw]X$0HɴQ0־xz яU>^y9z5Q4sFNTfأ 8c|G#$c\8،IME<K"!WkNۉ\/hqk׬6OEWw^!Ƶ :'D9A!K z0?*(*zzj@ZҚRZ lp4gݔrm (M.IȘ 63~[2v g|R[`qsH=A䨜~ZIR&V"ՙPX{Sl=ژ sjK].~Mm{nK%njG m sw(BD7l+8F$n/eB@!eRI_23uh @(UU@9{d- 9 ʦ<$Ovr( 830|ql='8ߤᡨ,45UG[[ LdRIQe|M+3S!ʔiNxyB,SY":6_;tn_T+BJ35lDGJ3Z z nXŸ1yzfW;_&3gT ˁ{}`~Cn >eFGMD:Sr][(ZTê3lfccD9Q J,ZaS T=+jYi>jX/z y|=o8{e iOF`"݊BϬqi=y۹ae`D#ϴ`T--@EW?Y+2fz+ )d%)z n~) ^ݼy;؏W]__e]@V1V*6bSV2g? sR:ut:O M|ۥ(ӑ༪)gaC`,rUnznڤS[PEv;\%R !۞ys'OgoyPr(I"B(v8;VB ?{\۔xh(i2E:(b}hp)&֯#l Ƹ֛/k Z3u6LH+8-D"HZ5xҽfZi-0gj\=1UH^%v6'„o}`0[^~m۳\~\1ym07Wa;q69(b1 Knhj&q9#`xdbV@4s&  G5:{jRjSYwKDua*/A>x?bH@n8oj$JkScKSTLbd)ćNwiKRDJ!I)tɀgj^⬶wIzTﶶI͛TJ#bRIn..PDxz"jmm <ŢFة-6KkiL<ȥBYEG\r3f,GgskW݆trK9R.3> ysswm];{^a|8F!DJ22]QYa[EZifrn>9$hHB&RJo7>{;mk{̅rЯ;wϞr}pCBJdn-:lS _//I +mr_o#_M5+V9 ($ef0q|MZ!TՑ;~.luUs޻~g׎]qj|WFmu/^M4 |橷=Cw~y;vsoVxV{W};/>GCXQclM$qեS'1JT"Ƨn] _GQ7q\R !"nqLVC:?o 4ϷH/\p ?p-3$S^qq++ (j+}ڗJT| ɤ+%B0=־!JNeJN(աk}kwD4zv`b>ˑ(o^AB(l=&ÒL^<4gv5y6㞧HU1iFٓ"حddUzr2zV@̑  a ˬl$s((O4=$9x)35pɃ[V0Kͫr-2#M2eڎ^ R<λ@`&_RJtԕ< I$ĶB"dj(G?!n#א:[D%qP`"Pi2DsVUW3 ܎~*009G+( g\*HcA"iE`R"JR)=h˄J7U^;6ǎ??P *N9&:9.)(/"-܉/*aM<3CǤm5BC'[sLbT1Z80NlGXe|'e8b4Oםc,hC@xM`nN-SFD\2u.7]тZ!uh{wiY;K߻W/h!2 7|c3>w~Ժ{ -e&@\4s7[szg__!{Tnʢ&䛞~hk+ ZlI22&pS;Owk2pŤO'ءч:bX"Fs [ gs"Y@}a8`8>ukǟ2d3>>eAo}7?ϳB#o~۾vmY7OoG{gb6X Xb?[@&o=zg^XYh=m.=7D$7yvf7}.-T/Z03Pq[B5۩E{;+?\=aG}ל}Ad>qm/},AOS~sá^+G^x/}"CM 8,Orl)p:)Sd7vPó=I}KoWN+1ݓP2&#_Wivбc5>{SKOIyWw^ ׵Eؓ7ԧ.|OҘc> o?w> #~|Q}_8trjqŢ5Af8k'sM[sD0k~a DM; I.q3rUa82B2¬q-|)C֨qtgU-CreȐ|v>!>ǎy>o1lw”'ň5ͭ[Ԉ{}Ϯa+ KFk`~"x'2HHѐ{S5]`o*&7~kV̚OhR}0'Jx6nt>7|NvUUkoID>o|g~G m:?m/Gsil..zqՋm$w}Sч媘~bg޾TX:ƥg"~v{o\GB nV}-Nm@WL| ?:@X Zae'#1MT+=2vb tQͪrS#j1F"MP 4V;3OfxxB9uˡ6;j*!2ac:#D7~՝K6q@ky@XSS0i+ eVEGwaT )o >h/l&<_Z CIFUe@}!Ddg)*gX]C^$j&& +t0~dHe֐]R 9+¶Z2W5a"c繼yڊ6Aq4e7Ŋ_"rCi1t-Ш1AX-5MUkZh#_2G*"#w͋.ba$;iu[W@:sd6pR)vLeI#yKjtd|X*s F11O,`ڦ!}pߖ˰u6?da>-3&/*YeF2nAi՝rq w;u-p!zAe*D\EpTx"yg~H*pX(*#WцA?ƿ7mOV;x䶅3VQìZ{:XW>v݈ל} *hCC@cCoԡv-{IhV;x^f Æ߷eh-sh"ycu=VDgypآ 8b.%![. kNLxSzq2X~:DTUK]Ԧ2YpdRO~6>}勂cyʋ64z3DuYL҉A Q"^ "V3h䶅羚 7wyhEzS)I@j_֓zXO:~?}DpCn@6G:Eˊ{ hl/oo6&ޣ\߭тX_9`[2{]F'tW,[w֏Hl[/{=wNyz㒶܀ahk,R)sOߔkLIX2RD!):M!$0( d  YB'ί]]9grY1\'"$E˘' cinS1r1kZ4Tw/coĕǹPrJΐv 5 >X{V qVW3~F8Ā-#rY.gL&žVf[v&5N}FW;+7~%$`D 繱WCp*goA"p!̧AX*JE!uɚg@~ki-}r_>tUn2ܓRFķ;7ѐ0\'!fqd:@Tj~>]֦}j(7iЧ1%],(f0G-kv}o\4M-0|U|@Y m =]olj9|/m{ r|an#BuPZgi$%X٤ /c%Y>yZ`5\I+̵V197K:cPxs<+ !1\п`w~OS Wf[IYmݰ]rq`V62g{EZY}{exލ,r#ER""8]ElħRQJAY/j|'QJґ0WB(^"zdʰ6%8RqՈ.Jvd%VM&1ʗY} #$4߸ 1-l жfj۔uVVs JUb)\b*GA)`QY}yC]jHmJ6-3P &DxXS+ 1"Dă D>gecB1BW撓#!+׊\Q(J<{P,A;io D XO[rŤa2:PTZ9o6e:PBʡ$5e tҤ3HI*~DfQtA\m}+yƵmsTxB*JF!)o("H,1rӗ 5R(3/r6jmzHM)]Lw?ʙ17ɉ=O_s㋹3{eU7&FV.~a/ " sM%TK<2>z+& X},ԥO$AmRڴzUCs}Gꣶee[p$޳.çͲs;s^5})w潷ړ[4y cƟsœG]ys.ꎴ)l}nd]MN9ؓ_wļ˖0`5}8cmyV,3P7Mc:m`4O>{ΌYs|u|(h]uC!0/?Iwd6rU|uMM.WUө7_}3?l6y$IeMt;"&/`& dF"Yfk׬jj @qy587B )r$ə9\Ƨiꆖ0a@.z=G0uEm֬nl %$D>=!+n,dI{]6~f!t: 3>EM:*g<3bm_ 17)̍ ey$8)`Zg6VJY R&r樒QVakӚUzmE aظ mqO3@ahwiuc6%0Uz']ҰC8]ʦͺOo~)sP5Gd)hJg Twxʨ"Zn7U|_b!3f *0Q& \rISuQ6-]2q k02 1^.6r$Hx˾Ѐ &Q&2}C!JQDB0\&S]]f]0};1t֤[H DsL6#V2D?H?`*jkS7oY.Vj_D/&']s^d%JlƐI *)eת0MfpcezΌ$P: ʝ8RmSO{[s%(@ _Ahn1X-6a,,TҦ|k쮵{%y<$ko8Lt!"3}`"j P6>(;h)ck7<Qc@N `Ѯc3e/x9(wm{yCهx9тGgWJyCytvטoz{ӎk#}+7SQf2<ʬp]]_$"לrR YhЋ0RJ]޽_}R!:CfL)8cq}brƠG>=cBP&II(TA{fj縲USn0 ?Zhiji; \?ӏy˿9?{Q\MIk)) F3LJB6n*P3OR (ߏB{S( hkNjσk1qp1r[=Oz-e(N&B ;v4fm^FvY׶Df] oC눅fX@417Z-??imhvEO0mH`2:^6t GO1F;Jy*V6n ecBoqh_H"QfutawEa?o ܱ{y;W0㜍䔐OYǻ,MKk0c-&R;QX7JWuy0"8 $κO&v(44X!4/I֏iL+ǭ $xt91 3>j# D1 0׮M*oYNh1Z^TB( 0E)b Gr\; {]v&$7J2"HS<8S&]$P{BGc) \n/8;S"LDʎae@=2>c@Ft|t63!{7 J?lݑ4mef=s%zDEUǖ:_Q{ .Kh@+&%ܸQvG2nyp@AʩU ߏٴh+7]Od=koҾH:׌}].Uuqv} @r9*Ou5B*Iȵ6!MR-kG 9p `&u$~ Ak&$U9HFRa&ɫs& Bf36}ίѻW<" jzqǎ=s)W|˞:7Ʃich/Y9+e$lg P2fg0I{1ǎsS=ӯph&3~ϑ;4}5Ys'yvW]sXw~ikXn$-[k5M_-h&s$a6RS?i<߆9m$j?s}?z[oNt7vf[oٟD$V/_xu0څkDr"`,}H;\'/JܱwƑQ  ٩fUrz۝f"9`lkU~8%b@ꍭa{l@{Cگ7SSVio\ U2Xq׉Ќ"&k!ફں苆6mǚ_o}z-Uu:~@cj~v]cVqSݻggps)e;7Y2!jqu~7PC撅S#7WlCX(1e9k~v]=2[ *;P,o_y*|n9@l 1!W,Cȃ3HJd=ΩXVqʷ0kVr?ZM+dFvꞥ0XկW^˾iz1}v*U9QZquھQ}jQJj!B@⧎!\.gWʙA4$6(e dBBXqdsznRGN0Dq0&$;!9!5Z%"߱ÉU(։t%j t$%l/Ka,y>wi~+-uxk&0r2<-wt7hr睂lJD(RXM>2qZlBͷF?( (0>bM>U%9c]Җm;'SV/²/R^Ǐm -[)aOEN&ҍpgL|t"H!IčD9RLݠ=PJ #k923'.^{RJ*DT0v v-咁G!*M}1ܪc~զeĚB qQ_#3r޴qbq+bUGkP @뗷ivY4c,j9e.o,bCn /~ e47u^2D`D <o@ i\Jk.^eԊ;_y^IDȹ<% ݃_uw{Qa;t`Ekk/6[I} f9IsxmA1L}uu5% EWdzdQCGbB0܏ozm> >yq}h셫ۍ>]iW-883g9m?]01S_^QBϞ}voW(Zj2@3d>e[/y/./e! %WuW~QgR%J}k.:7*!hodW) DX dq޲uac/:7 DDR21܈a!:>"iR h;xPˋǝuɄw$hB%sAl{l՞u̺w?|MGԾ h f:l|N2]W; Qo7͉ԝsN9_~ٿ7½/>__X~Yi!ܰ]q}|)ceV{dϾPO~,4tx' 6,]PPLc0%6(ݥ.?y>G3$~K~}^YC1YqJLDR!d2Aۀ!c[D5,տ|;>\vN]-(@t$BD*3\n jCI}iY}xC.B#M_޻.#n?4K_\0಻jw}}hCr6ִn#[[N7кڏg3֬Uu@i>/ u92q%o__oS?f2/_j Bo#̑6x5F1$\T 0y8m` jiۣ.;m=fz7?q`a|^Of3޼0Z} Rs{<:|"Z} bk4cS3P(&mjRfR"[*\HZׇ7ßTؠPbLlF*11OU;7"`ꅱr9ҪSOb6G5 H`MeU]' ^)Wh[1 9Pf8N)!#V %e2e F Q2ͽ{EMnjHkG`XnjP|2t 3!1cNTH3S$)qDD@$(c/$`|{ w%D3FP 0*vtmLg[-(S[mڪcsǁeĤO'pE۱q&y"FQ 1R>J I7H0cQj!TpWt)ȸ5ks܌9 Lz>05k !k 5 Vۂդ]u+jzU1ueI#Zsc=6ҍXukyRU~u wU2t0=OaGr=K^s .,Zh/Jn+ SG2FRF>p޵ys4} |2Z;Oq_w%m~EB@H  O-Hr~bfbmy{\&e$nBP5ȟT1scE1?y=o.dz_?V$J[fsssM"f /1OxnKOT@(}om/LB0k~7EE} IDAT~r΍a4~Νg~SiaK4ez};Paɴ/n(,YR>+x~D1@"wb;}铫_њh8 m߹\޲a<ǃB"lxtM>MSo?^‡lZ O}S2@i"rrptŎ}*j3^yl7/_ѓMLssλ^U Vx_<47wЭnieB"~-UQKy>{͋#Ivzxm.zbq Î;pMjëgyE,&=O?wwOj  mU}9/J = E3Qmθ#/heW%l2Ky<:?׷fvV$%Q)(%MROuk&A_+|B篽ұ} \ݽvVU3q#jFLϼA~ PȬTj`#)kjiܻ7?R HeC`rmhplk|ʶ E4 xDu^imd1+ Dha/ǜ?O@^w#jv_&)dP2(L4NLu]\ 4; Cf3RPs962L]Eݎ]j Ϸn };5R o_) bՇm'vmOƀھkÄrs|Dͼw´A? ,AHrdbX֌Υ@PlsAXVurZlp.P:tSВ3Α5r; wapGԧ[Iu !1vl5 =I`>f;G]ٲ a1) ] ULAE4! $NЅ%"b)$|&>cչ\;03ޮl4 IM)Sh2t/$A#02@GP:'9 $TH $rф)DռbAq?  %%I! #ADB*ώ?U)*nluZdmDu,* DÍ)ԖŴS/t2-HfVꦼmE4E,2}1&Hj< RXw2־=r-+;vOO6 bgM'J=WrK&c 8ѫnc* A0dL uA8#kdV\ !%݃3cwNq0$9rS [F5snzERa!$iAI`c\'HH<*BHo;3_]2+9W,0)ᖕJ{ʴi׵v#< B>ɰ?LޏB 0z(|6-AB#.edJ'UARUu9eJ=DdqΣ(B2Fh9saA`20f9A47Gh-v $`JԵUj!>Oܞ XoE/T}hKM,nhMLfsW@&JzALAc@e|RIyX"Gf s1:a׮8V(0l"xh"Y,ն' ռ# mz˜{R0 -,^1*Ջr*fajb|MKa 6I4.M.ysIȶmH)+G\wy=r!c3X,Ŕ[qRtGΥ\)݊(A(H_BMMv ;|Eϖ2]Mǖ$P}T2nH (1LS͹] 1~jd,CŒxN7I`S0WEQhQF7eCU:"0,x3= E\L9rc2Ivq*p,c~x< R)8K/#.'uX!o~O-mST^RN=mf7rI.Z6sGQ$6OVW]9$+VAr"RDaQ{RH %HA'qdBE2*NN;cba-e/c}c2g 1|P^ײJ3e8!Y6nY *r2Y)2]B؃,\o\A# 1$t͏Êн ImL i#0jz^-=5-Vuq3$ @[4G,YneWWoc,޽DF9%1qdB,lFNF_5E ]a9qBd0r@]>+@?A]@tCYUøsdΖA9B8!`$"3̢T+ -bHxŹ0|j*]F"R襞@)sQhM)NLdu@7A $ !9*Κڈ5'IK3߯ԩ5 8#&FF, 8LAFHS 'q,WL{l& yy*8,c}%D.l~O?gXrl-L 53J>n^&Q4a )L>3, ('}'t@=+g fۂ$AL̤RϦZ\~W1iV^ b+Y-Ҁy朇ah cWA=^6Tddtߐc*V;Sݚ E:hP)[ůL5tTkUQغy$%Q 44B"!- Rhɪ,< C8äGRJgvE,PGDTaM 1# ]vfŒRbLt5^I7 "d2 ԒRTa"ӉC%BBQ,jTv /8lɷWIR[35>RcH.?e!Jenֵ։ M6( J1 3W7H^܍¢ȀSJ+kp֭3!iN *R!k*;aLqEB%@CJԬ Už[cyzCa$1slඅ,YOThnncj8㌫YdRx\MԐs:;Q4tW{ ^R|Nڐ|qR1ēur*l,>PNQ^$!R^@ !8=Zy"(`Im0)hv|!%pdC)")$ !( Cz"f}([*(f_8Òdb`B!vK;S6#(*!8KLVs\SzpأRͥI6=Mͻ}>Iđc "!e2͹RySJۼt|cgAlnJ)V WZ ?;T墘N2d2jT mTb0ԔS_oI (L,5]\HBqXq%2:[Wu/l*u9ڧh.dfH=- p&c.a~' "@)%\Y łkLJ b%lѶxլ'~4HΙq*\&,z2U JHD{H*KImi^ujWsl1UQBA!?F)xYOWs8nYR5l`cC\;1Iڜ9R!cȘ"2BŊ/ ={EZPgQFQFٌjo2*<*FCw 4 \Xi3e*+udF|]R‡: lUuaL35,!@5Ib`Q("EQ5q#U_h8&m@e\=c?iICjD"% h=lL7KBp9O>CG=%QK)Qͺ`u^c&v8gK0CgSBLf@YYe)k8"r!Mկb v2tֺxՇ2 ɮfq>-@̦HBJe]NEK;Sq3R:~J$^0:sɜA<٩ҝ1!jv):JHӛ!"5d= hkmsƙ^(B>}dQBGMC53@;f`6gゟdh'!DRAlbC$imf`ڵ[_0HRXB Cƴ4q%ɘ@Oqm]Y)z ^SCm=xˌbJB[zթ lFfS|W S$rcNl.˸NԔRZlEB  @EB!I2[ eTm  }i7s"Vyȴ3fmgiN.wqmav^R,bgZqZ.9^ P^1"EoT烺DI@1qqHZmuI建jQ$(T_ܑT!xY+@`3m(%,2ιa9 i_*z <-~02;hɮ SW#K\(dՐ( 2qAԘbރq Z"k]*9J  PǴ[;s-u;9Q眒Q]+|p dET܄PH"bwG L&rHF?FeHʔ.AvȜbL=q |sfESy[2e3eՂIl.!S]g|k.gnB9E]`xpKY:y+%*D@di2 B+M?I`Șuʎ1 k&.ngvG*dK~SRLFcj' ÔPop1n<Q0D8Ai"Qfh:"J} V E72J*0 9lRAg>=r1so|T*ǹqX9QI!m;)L! BHyS^WT+21β{m ccXRa6Hs( ^OB Q@JEE@QPA)ҥ"Hz(!@:Hnwg?fworA/7;S!NC+ye T!#M[뎠ю; g! d^b0!>0։UgI* ]f8=jwߨ*_OOE@&Xa,Ƕ")j9!GIb0JZVYH$JC 6+{d3򱝵Sց\ TQEȼ}@TtTj!9c63Mw򊓘˾ʆTvvLua1bRىkʆ:rrJ /Sd&db9HѯA ;g1EA HD}JhkXhtlhtʲT IDAT__41h^:Ri@%L*m.1}2:OI PEM(KI1D9syД0BGu`;K8ԶLNΈ߅groM&g 1>FS54|0flic%(?"5?Oj-y"d&vlA#];JaòjhESUD@ń lKDB찭>]jJi$j4$75k+6v®bL($QZa Hfj1<Xr6fFL" E ?VTH#"=,QpPwWƄHZ̞6DFX5Eړչ80%06uNzIK"Usn1oJD+4]Fi! Ül6LR'cd R""ƈ78sJSPAgĘfDH8Q5҄R7rM*' gH Rv);`ܩSI lYl~R-gUצ{ JNx虽߾`UQvtQo^>7*#I!AlRzt~72^Ds u&8jk9qCEXSyMTfV377'q߷EDP'rߙ;Wl6$Ib%2N ˚S[aRB0SAZn(^u~FZ@ $ \Uf5ȢjJCDQJ$>RS8QNA(%|m~/&{@1XO+˫I..Ml6nR%C'5JCf٦e RDJ⯜̮UDʌ6bJ-@?Q d ,d!3۴me~CЀOaNGwIL먦(bpZ7{9|K7O UDL1 Huq?&6~p7͘{ӎW"FFXWͱD]zFyJL"p3^|$4~H )PkG42"̀n]ARJ\KSmN{Jc77t0 MqO5RArO'YwEnU ۗ+HsN˄TX5G@ϷoMhve'[0V%ޖ)|G#,ledRKק~z`_Pm&D̃ABfd4B$,5zJᥔS< q+!ATHuy_qNݟKmƓWoFED;^ -J0`#]zF]]DB8-Fj1 rm!FPπ}!"#oGF޸~l]jMuvfZ%^"A*䚿t㥀q ӄe5y~?4z huU,49F$+;& by/C apexَdfeL=EĢ(rIXB*T:VW^%%ugWC5Zi48qse{.1 |RB³^'ž̵ +]EIEUX >F<c!*ucK7$9 9mfwd>Rg10[b_u%w:EͲ V?E)腻!hڕC{E\dw9{pn;*'|YCTub.Y8rs]9D&Z^0nĪO*}k \/)+x2\e)WF9"8*F@ߟ*2)9jc c6__U[m[=MoPlP7sj )Ly%IE@%eEqgPT I"(T*xk$v][J+:n*M7؍Ip88q'FcWN}P}OMQUA %g{콤C,6Zy9e1L$1&\y&` lk.}ih3ۀ%w:\KgF>_ iiDWD4U{]vڟ(MQMVR?~ڙ4t@#i\ܣGq=~ur;9m>mًߎzreG:E"eg{[G~]v(~ Ξ(&-^;n>oۅQw/wD!c ϯ^"N._y.dUy*޴twkD@ow<ݤOŽڔ`hF&ٛ]<#KAΒ77\G/ ?u':}vذ苇~ҋS5ƀ?0ڟ_gC@|@߅GFDݹwֻeۻãEDߋ80ouC}mW߸u7r>l^ ޺7hщLmecγń_OD޽{zŧ5Uyi9ZNU'ն}tE3sÃ}+1{Ĥ+Ÿ_th\|V/L`g~UgǏ?|r|)p6ھ6!S1?usLs w6/u{/ʩډ1ـ@n'BR˩fۢ>N/l Ouޛ!~3DNn\qzi͉m7o۩K1"Z1uR;pȹE;w/69f;E= {rg ;5>E*';{1w.+@3IY}¢y%*4&1SGcl>$4|\F|FLh̃'LnjmJ áꏰ=7=|L(* ]˅ɿyڽyQN5S#2eĐ+vh8t@c#Q.QCQ %m`"(^oO/l-*Hޯ=gCî{ma92ntC=Эs?LZ̽\ "ANWQFZt/;m~Hl"yn,0+SXbz~i8ˢ|?-eW7fHPަ/{u` MG7{ҨuTԸтC}cee:<XS17!MѰ?c|͆5l3>s\o, k'2anc,rhBzejK^W~\ A2!6p_71v+smsW5@|9E:-~V@ab !f6֨ѿth=lmAog`@&׺ՐA7wUತ Nmu@l{s֕3w}>S7?tFFyvt@I]:kށrGam:{4:v-_orl (G/.n=Lz{d&!ȚL"_kĶGݖ׵{vEwQeFk=.ud>,iSnpS-yݙq`Ưn扚\&\Z;U‚1 `^{]򃺘R %lioX ߻UڎX[٭=4>2R(BL6;dtԻI,|pU5|jSß=-I*؁b5_- M2훷L%4 @RVpLj0Bⶁ0D#tVmZw0J.`\˃ 5OPnt@|*#֝27fn3.utМ$g!u>>z>F&PyNK/ IDAT\z.HmrP*۱ڍ 0[46/D`YM$QRQylO%//ϡXLܷvw= ޵Jo<9d/ [ +ǭ.?O ٹLa!|( \;F^ wcދ.u'Z޷̃g 7v:ԈjN-uAZ@%Ot-*m>P]^φ Tv]nkԞV۵ˢ,$I6P89G-˿5/ūSmh4u0VScl%8OPσ*?4'Ky粳S΃R R%3wpӏܹq\۾ "ۉ%DN16NdajKdV?93,sd"VÔɩͭj YS]&rLJ9#kc"{*hywYߛĦe&;c-U^ϊ//˖THr1c"}*:'5hCyxkEo $+vë#W)C|^Jꓨ7۽AY2-ti,-"84`qԸS{5O$H}ty7ff'I˧^5_ѝ˷\|<\-ǪW)C ONط{=^abu8J/T3Лyxq 㓺xw!$]ܼlfߋ柮mbeJ"W/ 9v>Y|c,\@ , UֲQcvL58nmgvrՐN>sQvzRty H Y _3&3/lghuL׆?Z^y_?(ޖynɋsŝ1J=8/'f?=ZוB5TE ludF@@Z4a,vjJ4^ϛ lpw6 [PZ9 %G{S,h9}~Z2<@L}G@1""Cd"b0$y^MrNT,yv5,OD.seV0y wnڣOR\=6{A!YQH1P*1_> \Lѵ[I72SK}lrJ}mp}soa!e*H!8$NYVh@$fN&Ro^  JRB%82sDTW|ֈ\%ܠ1yv6hTS7z;Nyd2qG(SB8a $C"- y&|.O9"I 'N/rZ9k:lK6d8I:TvqQ'PvLt6 H~xQ"$B.1Є!g [ť*XUċnjU(v ?C C w%,ك=_}RJ6;3'.IT8w$~ϴ$b%a"^E)~ .`6Ȳ% z`ƈl˩iAoJKӹѕE:oo5+;ϥ5j@ A|Xut5ldJ^(>Δ0Vj9r7 gM4nbVr@#!Qtmc|!!ati\tՙhP\ V8e%]yկg }Z,QBEtCl>@_Ru笠کiq @*dgCPIi(bO??Mw}C.6tC aļ_k\r ؑphW 㻇}ocHگ })_9{u(i9?=we(#-6cQGݹf\bT k꼉'հ>GgT+gL샽Z{PdĂ"눕d3!63.>g bMw㌐羛ô!)B@c$!qaJJ= {ѡWO}y,\\K" ߿х"v$%S153_9|H[ҽ $GqvZ ,aZup e[G_̥Bؙ+: \띏{q Β  Y/QJiYSTPDa$`2ݹZ]?ɝy9Slj$1͸V Z>8iOl ADHXE B~IQuDZ烙&esa]&~v*pVeSs13Rq`BAM Pj@#w|%Ҳ|Դ%lo=Y`fIw J2W k`{nD8mɐ7q2@ X 6PP ']S-FZ6w!sOe٪@$ F! IHhAl=a!2Y̸.Q֙jd J}ZO6j~V':{D@$ܷ"lmܹ?| %i?Y0/J P[-~~D.B Hkӭ^|;I$ {:q Jn4pJh*'NƮ4AlOO2[RBn܊£a)hK册~f5 es<#86lp w&㟕 gA~P}Au`<傅bj:ӷ.`""7^xTp9uEA$i`eο`u řEgn8xD̳?& RhKMHdQN4R{BSB+UF~yr)-8)Wɍi]ON+Ǘ-ρO1-w>+u^7굪L͟.O/"][x½]OrOFWE݇0MR X|y(s B{N*+USUbϝ~WXaDvHcs*դۤ;^ Ѧ%`e)xuKPUBtD['oػ?\'@$¥V-ATFg~yŊM_Pki-_\ spy*z0y$p8iaմmG>'/~l+:|ku >kHI0=}MPhAMUXL3c-ø[Zbi[hj.BZ id4aHIv1|,W jmsߣLC<84y58JrcNom8lʁ:˄ʓP';=)lKKHr[ r"ʎ&Rm#{t\T#M+ɼɡMZO';lݷ\]=bQ%!5ĨbJ5a -=`6!&7&1aA"*O,KuPZvxu|K9^:|4PIw#8b1r_N4",J{M *M)e9?x`[P]F"j#ҨK 7Z\#sN_>G(B84A FAEgyKf<]:E+[&80A)PK<hrRQ:`V{i Oan[ =])һ]_W:^+ҪO*: )0S2e,s~ߏbcRY@H 9ovdKwdӒWQKAœ_mVC]9oH=\$$IRbZcF"D3 ^Rg<^P]|=ˋU-"0!!fh4HAR" l4@y]荭@[9`tY (n`+FhEv<:ndl<3"|JĢĢ4o\vl?+* W)X&$[ߍbfU R긽uYłssڋ`M-B xL$)BN>oH+rFZ*Q3ѧ.=^Z zY?h_EEwSAPn&DNѭg%nw@*ޕʡ 0*q$J b@AՇ4wi#&+X ]Յ.t~ҐD-Qu|2Ge/y`/=k=fcn kT3p=!T{<$ H)yØѥ*YVAR-O+Q#;d~>Ⲕ4ABW48l{^j$/c@ !#(f_a}(DQ6qeIxx@>PQT!(҂ %R9l cIBwoKrmMX9n5'i_:(n^ %Y28%6 oPV&jT"uQqUTnLϫt[TZK[YHlz+hs!'"z [W oFT!>[ѓB @,R}[QJ!Fu ,E\J$Q DkdTd@5Pѿe]b@/:цӪnبFTVMCjRiٶN >os3,U(uAe(b݀$I$X Hu|G pEP6qAH@(a-뉊srZÈ6 Im# dj|#(W^f$N)t03zX8@3#"IVPťd"hFTu4Ĉ RyU[EaP}8YTTF.&KEmn%9ݺGBG=Tp>(f|ujDrvХovEˎEkcWUAQ5v}AZ8)P Zxd'Rj{zL0Sj jA aΥ̉F.!B)te Bnq׎M=!-xH) yxFcEEk%Hʙ[w %uMھ^8+DDC)(t'I@m_ȹ_"c)}2j;ccd9%mBRUEjSGUV*PRiړ$x3M& #$?O(cR\CR($ A w]R5l9V[ECQXOUqde]=BF8" D9k(ESJMki 1" @L'Y$B5Gv=j@NZ3R !xmgT@>Օ?=K֌>PēF JJo:]@o-=y)8{jE,xg1cnI$q3Dٍũ8I"=AZO<Ԏk <Bl-?1!z˫X8 1[ qH"$IEr#oQ_<4}!,>cLRް>CC@HH9q(aԹEJ:aݧJr0>vKK2W C7m>՚J~9p?ϫcVj;3Cu[T{Y5iySE$I>F|=F*`Cog/V$86y]<99 *ޫ( _mFʫ^QNjPְY6y8#iv3!:6@Č'%͞a/WN_M{^抸Vשi5/49"5g0~D}gj6wn\|VѺ_+qn\je *R2}x4AaEQA>e`4u1W~fAASzI_˖[!ANj,Y1lݤ}>gl,wSa>w:Sh//K~uy:dq @%qq͖-~巟3a3Y!eeMsO(}"03``Ŵ{kg؊Ե%mݎ:U λ'}/yN58{^inoD(n+Izfր)e`w8E.ԥZI ai9?gMGeEDGM%K6䓰ƍ Jb]2^GeeP(*2Z4QA"O?RKٟƛnx1!`G;-!#11&(.6,?sz.8-!LEF!Z4 ݷKITRJ ev0BfIt~o!r.l;Dj6n׻gsDU(~H2[)i _'#"ť}[y~$ߎJ(77W w?.G &<2a :/eϩ 6%DQ7d2R!(y&9s̅ +e9=ΨjDȮ#Zc牬LX&hǔFIOa̾L/Reӆ+]꨹/'}e1g29 QFQ{?Hv(D*(%p:aoeEN}إΫ* Jpܡql6f"\1U XtZí5v"ت +)ypҢfcD1Bޥ9$#<#Q"'sOCz?hDqD[+__?spWLq;'=>v9/o?.p [zC8".^dr<bRaԟ^ +ur!ey˾x`Ώ9`$ #`oJgVLLquTu{8G^0$uGIm2(u~~ف{c>'Ȭ5j{wsL [37(UU^Y:AJڑo691^c}yzĺ=@Қczgs# 2t6vw/VٛѺ\ap8{`/|0I^穃hh]|ڮ=znhxߟO~M~? ad;Uacl&LUr >jyxtT9F%Dc)s?!27'HZiqF!8hb##ܜ9g~l[_=J*MH$ vc{5"{ڙL 21̫zϢ1,ojwr)#PՔD* lc _-"oVA3G-LE4wTXADj$ځ M.{SfbPE@A)Eɷ_@+ ci@@HJ~q@(Iz@=6-߸d5 6ZDuVPd9siӾ?,:xk)@̏=>'({2Ba7 6boFe',"Т+ÈG<GQY0A zY0TT-Sg%?V x4Mz=M b#1Eq2$RZzNo~l)#"SRHohٕlwwnhV矨GSu*bٚZ6Ӌ !gSx4[Ee]^Қ$5@(G[}[]C&9/ˤXYAt GyG:d@<6:?n|ǽy a5eQ `,q$H1\jn§r?}zT|AL{QʭϏ5o12m f<30fD3)BqdX# $%,TT#n*7y#WЃjXΨ>ĂUs<61NdqǟS7oxGbN 33v%c,MS!l#f'$8 HP%RRf%j84VXT! pIR$lNBl4:Si8yl}81)׉P 30'nq,תzR5z0AZ|2)˘wLz͛t*/,f$3iB标1 me9ok׃WOza tJV-8рH$Bn>)2MpӢq,{_e:'n~D=xդ/E,+&$u%iIJ%v|vxxҌ.IB!-hz3o鯁8nj-i^eQ4z=˹ -˂>xFu25ʖx[~m,?;jP`E$հpi,@#Mk2 j4c^xݞHEr$KYdιF)D!QTs fX>%)NԷo48p8n5~JtN Z 1"ĭC]kIRO#<y+]Xse5jk4?&Qk!G8]Rl/L|,CqG`'(F+q ELD̼ "y9ghf71j0Dd\T33lÜ-U^u""+T+R4!GD$09_HʺeC q%d#T4ʶ`+K-OM}dɄcC5Fdx9$m9'T4eḮ AT| "=0a"qysPMH@z0c6Ҋz48µo9Wp@d\[A=vlxR`JԺ,O!`jCuVL N%y-׽s5 ӯ^IY[_rϭ*p.<&H&dB! CLz6Ґ=zH9oT1άuwo9oK%ՉeR[37@ʳZ(1U'+z#3# 9ٗZږ12)|s= ҆d!.u~M&0XjLr#vo }Ju}0v o ty~FJ /3%֚7i4\1nFQsI(vA;(sgS!VMJ͈ZRR1G`Q @ QHYKGP"%Bj3#Y+nddM_JBVCkr M~G{ k&!$Q*%GUJ(TTR$$MmLq2c b(IMQI=Fg˨)b7 6*v_K<{8пvȐsf?TE$M뉛שHfcr3.R igaC K݂t sSI4ŪEjKĹQMQJ$Tj}2E&(c8]7=:ur)D()6 /LƄlNN"7DU62 m8-RijX)5D~k-,[/R.m,Jb(f3ƅ$LʤPcMiP)N+iAx"猋4B0 ]"tVŀv.0$ƍMERL<G iCHKԊrH0x@>=.MtUe?k5BG҄P݁KHH4 ?+0yH %*{+ ъ+ge-ѝs9BJ)LiȢх]LiOQa$ d gb74Ȑ )R FOxVd;2UG+k9JIRfڼ0'*j7[W ˹yu[B=REZ-Jϸ-\`P|*~G9\Q0 KT#%8U_qNXTx!MRcJR!;:rSYH!ƕ}Cy{ cheg(BrTCT,*8{_9eKڇ;Kk8kfefޓ RTG4L6haWFD3uBH!,@vHάbM| r.=r =z*6>)13^d,x$o_k*Lj~3/C(Q3S"ѨN,^ ]%JDQRJ ' THǚ^x&VzE\!$R*2)f&کsߏ98&@n Wn%AXE ЈPRah`B.ey]@k ,ӂHJP^5ة3z~OѤFe R⼾_$ 6|x؏ ^2^ >bQekƶAfФ@FW#G/yDdΜBBĈqhQ('IqBU5yR 4MSIMWLޤ$@Vvt4WJq #6BfMqA AnYNlw _navI;ݶ@i膼co צ `TK$@X+=~]♒PW-#EQJ@z]%r1뚰OHN(dmΌQRRf9i*Ra̝trD"MSP-c3GD&"7#wXSf.fy=K˰u#rۚۧίGy =Se@<N_F1EqqKTu"r`T/FL3-~RII#ήПGBB !H1Gat@,|0MÞOUюk$b$su 6#YPyɮ_}r~Vc%bv=o\0Hq!rS\j[a@xI5=EiQRXnjmIpn;&[ؓ6 ^_ TB( IB"ToEMe`.G'h44/K="q 4̜!{Ba fVj ߋXE)pq$jCϩlW U̬TF0Z IDATNjqrhyD pOvܗżEnCvaGRm-{[GՐ݈q%01epRM~8#3LX"Re1,3#NDI )-SwlS&AB*?H=50ۥ)6@밬=.IDR1ƀy\jEBD]m)+ TpHw IJSV* YIoۨ1EH整VI iH3IRHA$%9$iI6e6>TP8Iӎj q @qě+j*ZQ'6RoYU:P6jb 8c>@fT.k Lh#BJTBBGZWEZ5tFL沐GXNxwp[Clw31o[ ZKz(S%4HP.BA 91C!Tⲧe9< h?0Q#P*OM sQuNkȜ6c$@#<42˵U4cIdl/8祸^(1}5JƵ 0Swp'6\0=} X~8aB Yub2+?l E1l7ۇf4 g(bE$]UU ӤCŻ$* mM^'fzC䌋$dZfOWIHMGW qa>Z舠$(P[@`[W*-e}!ho%iL'"C !E*t V+H=q^:ސX7g n8I,B,3zA qw;wjD^t.*Q 4t* <GIHP1,%x@ bW*-h@Q#D& jzgGU8:4 P%CBΘYKjPZx[m흛5(ſb .4y)PH#=l#) F'a6-U%05FUZYArKK3!)|qf3 7+LJAQEq9׸Pj:זd pl]o{6P՛)ݧDF5F@#aC RQV5<Ֆ _\vKf!d lCUJBQ8bai)1BFƀ刢ҖWۛ\:.|3'z"(*%Xz=MzxY)ܼ|E85׮5N,6x9O7:*8cq+! vnPYcF%m͔4zf!.jci>TbcH?{Sgx,u6ز'>Ҍi3>zhܐ޿GӦvgRXvf|#T XINuy *# Bo~7񙗦x7 *wvcDAҦg??hǩ,Wv:)\0C t,|ڊcyw ogE\vޝOg5()7>oOg٣!=H"WLхS۹w>7Sy},Z#jQiԷNs4aM_6)>@SZ)G+GgyS?:<L{ЪHy[?/yw=;w{{ *Y4|>jYeGψ- i(b*e1 1mh_1&VT3q\)˩7C}iggk t)Fm;fx“A![X5k] S7PũiK!$% b +Iͥt&Q9N SťRĹ)XB$Cx'gq!  obROJ[R&I$uH[-Js _tqHk`d(a6Sdړ;Eᰍ-z*C9# }zTn-[ =_65v22MJ;U>XeCqNJ^/}6 oJMY̒$s1;f*7@;&w9%DKqLjJ $IT[(7ƴj0q9GЦz︌dNzsKnt/; {n؄X]@> 6 l^BpAk0i T5d%2h#z/FTv@N)W@\>Z<:{cŔ 9kN8갣ξMZUGU(_A qO{x^0ng~ܖO =rţgqiǭKBJ>*ŭMGx=8m̘'߷xoB6yT-s4gKef߯&%I!ԇ)QVu*"RpU $EH!RSMlם{ CjjSr9XteJB"Z6YyfA hc!=  $$Mt%,e*D=IH-MRI䙭ԕ[.cܽ'c,I5g&C'n6nǬYl4^Tl)$Vkz-MTDI$D !2tt =s։-K6N=HN7sMAK9fn[*FJvc"gu^5RI^Wɝ޻pk~4o[n1#q)eR'IJZieGsTG7 Mu,Ƙ)KC%-ϖ@65m{@^y8ߐV]hT$ !Rځ ~HҰ ъ Dණ>d}_ ?pM2.w7*Sskz߸k&>֗$(ϩ;-sxMyFC<{2..zƇ^0wcn=d^ˀ.? ?|?>p!?A7%{s]M}kg;(Q_zߚ]ywZ e!{S}\um '<ޔ?_i M3 ݰBVXKƐ務Ida3(ە*H{&:~NV=p=>8h#=q쏧M~ nggNCAT(YG}c_iؾ [4{^9IWq1!`-}з%6;xIWO|}o>pϰX|͗Nɷwr PQ8LueOs̛صJvspko~o1VySO֣i-MNn<|#Of?f4qcd3iH/ƃgPEcB\?^7T'~;_~f{ko^fQ]k/?va9|7^bοg3>|#>GOi-7m?|? ;˗xfb.ۯUxϔQ|S,3)QV]ّOн &\sK<ʢp sTB=^O[Qϋ\K^1!/^i )HʎWdֈ"7kB5q):cm:Nשab8wFDĮ?)koROIH'G8.Rx%Xks2M*qvN1%I!igGg:ᬥ)67N3(hb)6c&_9ޭB~92g@jL$K"͕r37ڹNh4ĉ38A#VD\M3HY锭kmR@-rB,>VLz/^PHTյBԪU:VjBi!Flkݰ--n3,y0 =YRaQC2yH۴.EX\Fu: ^'JZ^K |m߼5dXsڥc\iVB0E<^X8W\Gmu >gd_ BJлi_`i'sښ^WkU!*%!}Wf)wR .yq&6|@,ϕ7`t575,ϕ7۰;#=٩ר/޾DŽ2m'n}5[^znzct!GD=2LM32*q|Q%Ʀ5~x+:;o_N[uù[ϼi񟛝u9[!nfM}čٲ !}ͶGԧmb-V> @",GzjQ0DP9ZWn6@چmv'xϽϝMDT_M{mo効 X~$~se3C 'm-E?nÇS|f=L/R6nC0HC9igl:UoCh߅{@³2oE#Ȍ{Zu:INheF9@Ag#uA9Iu:?2N,ź^[qۄθ`UΟ֬h-)ߨ/ޜSkܛ>fCxn=58kz>+q΃u8N1nf/>WI{muWhSknrK~İș+9{;sùDC=i*㏡()ȢJk._.f.w}Op˦Q+-q|QhFۆXm )%Eq0tQTId> DOVxn²6PT0 ;F'RqV|{gdXs^&ǓPh,v㉳*N,=P6't܈~dDp2}'MS8"+b cQR.y<|OU@PlR"cQ2FQD<9 T1@ Q+1T8F0m@"f|`J4,87IIC ƏlJZ'vmXIVI]qZ˥2ƶىhd{8H˴:؛f+.|;B.B Dh]dR;@JImwH)tȱ@"y\R6]ag9!cxuX[ ;`6:2v"okS# !$ĐE}*k.U"0I=A*2Dd!1fE_:&\E޲5aVq|[5 Vцl~m{j+!VjOQ1U5K[T$Zw^z}ՖCm'm5vS P~EG,_K/<% Ofݽan}#Zr\SwZozF.yNLTsЮ^3_;7kEh][_ϛ_0끛vdH+We0-1}iH \z~44n$9`6Wnٳz;V߼quS>W_O=dAF9*c]kN:ۊEگ V-M/|O:(wZkUV^u~ۡm^3U^()*Ӆӧ;pö['ƨև9_KPZ .IFGNZԏb>fQsЄ_Qҩ~@ zV^]"˓*b~o2ۻ/~:U`1"Z69ƛwQ{~Z[m~ G/Cm-鷕M٣uxww;h5-G/yU RcwN.w3kzMly_οg}_sGC*.]ϻY*0 be8G։Tfd4ӿ;nF+s(opzr:qQC^jwV.`~cVyJ$Q(ਁ*H}0Ga43QӣA@Dmvrl)WpĈ'A=.Ɩ|z[Lg &S^1o,R Bѩ^e]*褔d]{F( q~6fɢ-2Ռ̭i)TZܾIIjT+J\ǕKB'X8p BYHc蝗bð˺'W#)kLԠbg`!bȐY r:5\"LSnjAT4,` 3? pDYD\rԞt4#$!ci!utn ZWתU!dZq IDATeW| \6yi:k1X&3:fEim ΘH9-s使??d5JNǶ l#S[* D$zz V.30 A(VΊmB`dtÈGBS(4 m XIV.jHd8wopYŖzVn3D/'^vRϝ}ϓOvѝ}~&_Wνok<F:2Y]lqX錅#\cʲsڕ%m܏;tMT|/>^Zv5k+$f-ܒX+-I ƑYc] ٢d z^Bm¼P0)YОP|!=_vzxGN?wo}MYX3Aܢd咅_yףF2q}7/+hT@yG'/HmyuT#tzO܂a#l!=/èx䑴 !Sn%K;İ?|5>U_ u{v6q=iX2d4W@}̥HNgk[ܷ ]ceon@r՜.-0wOf,L8ITJLa}w ]XɌ55=g8䍓NSxcI"ͼuϭo.DBι97=7V\*Jxd@lIzI)Dg S(ґb/$DRuԵr)qhw b5/dD׃㆙Q誈H _k6XbBDq딫TdԳ,+@`lse 0/4$@{Dysten- }x{ ˃B8[? 1&48/J=g!\4V% ѳn7!$2`H&D*ߕ>:7`G3f8N4MeGTr1zTe#s̎W@oh{>vKh #[21&DOpZ-{1B6H)$gGUX(Q^#D)!v"KT: 캌͚Qn'XXbw'!#f'|oh!(t( ML턮.ϯl32Rz^*RITDa6,(328+%0Ď ?~ha/߮IsӇc,beZ/gc8]Z?j-` g "@4IUl@-eo+;U ]lz@2@ [zלITe߬ mK)j\Dĸ9;7|;I^IүۗǏ} yڠ}J)OC^y^O2V\3*gèm2|MlsS.0go1߿s;kⷋ__/ڶ8wq~2 nEIIGs|!RH)k }-b)#ب2Wf59LE[+߾r/T=Xzgk 2|9=:.~gQN$`K1gI;k*@e۠}Jn*:j.i[V#^Chf6h_Rވo榔 ]QnD͛?f;&[%|Nb禌7y^m>>LxA'G֠ȉb; M xEMA{Q3 |W/:rrV޵ ڿ@*^\<@uGax邱/4okTiWF^~N)j;xmW}r뭆-ڼOͪ!gd PQ/(Ӯ9Q\vS~O|zG<:eT{+me?Q4d^AԊm[ve;N236{olǩ㏸iat sDJd 4jzn$j5(:艿k.Yj]S4EQ\2" y^h=# K$S0 ӬNC@Fg%@0jt%!xF,)fm P@QVgƔoPMEk|YD5GOQ U Jz(jЩ8޵Z\.W+=:/eW2'f39IB鍐.j9q)%xX*D=I: #x)niDWk5Eh㡭05F;19Zr K QXixaiifLAR(Rq Զ(5hxAJA@̰p¶I7=uNž[h?dODLKHkB=xl "rV!ǣI$~. `FNe3T3@{ǂ%zʶ_g} rioZ/>QC;/EurK)7(S*S*rsewVFmhf[mܺdg+$zE=[{tgz"Jh10tރքW`~1|蹓a='qRm1QfѢ^n˜?捎c_u¥/.gA +Z1_> meDPYos>OlXJBsXS)OvdV>YYdE6Q7B+g>ܸuɌϾՀ:<UQ~毀5,TgzV5![lܺmK"oeRw.j2g2E^`#`ujfSQ־]xymi+ev=v7#7BG]ˀӰ=KDrסTzoQ[mwZ~0sUOLB (♿==kuzF{yW~/=a&+>}g:?swMA_Oh+ga ̚nԷ>oeކ_+铯 kp7I! fN5X* ^Re#YwݏI,t-7{utZǥr˚eaADM#1_^yo_^fPsP^~!{(RG7yG~mJ8l[YJ3Z_=@F]7K <(Or#) 5g2dOx@+Ak}!]Ik Xd-v2@Vɂ(U%IܩR9Y-%2x5ĮBΦ×hx I$wBBT*E0$C'IVc7U*3({9(1"$3%ԏj,@$RigY]Y蔩oUhs%ccW  l6{k=?1O ;ZK$DT S GM2#4f~YcEq 0hYV-k!$BĚߛ"aBRla]ovzfE~3]kώ=]ʁ}5kD`,M$M(-L [ B+G65Z:xq мO']a(Mۘf>yӋ_G[z]f/'JRWFꘟ8) 潟g XVj{^j*mvtm3butHм9!CVy9t-ro\ƔIvZpVvm֓^{Yv`mǞ=nݹ>yռOin;[W {θs}Vl0jQCR;ߧ4CA?حm$qa-Ϯ'Y(֗ΝŬYg͞ҹ_|U"* N gHpSoڨڇy7ny S,.ȓDX@F۞DmQgiۏ=z*N|Y.uE>c PΧ>Y3_l;Μ:^XYِ!}毶茕BCo^p󽏽Hڿ%p!l+t Eމ{sTj@#dߖ :uG)}VCd ~m _5:jΣ("4I~8W[x@:ox5Bo's&{˟Ncg<4gwϪe(?c2 R{M?YocVoy&68{/nл}|__):hږN3= V~Ӯ%,~ڻ~xŏr-PuD aPj+Ti1l a支*3 H{y~wMNa?x7av=oK o|qտ`՗S?>ba9%!c{C\/;/ - Ϙ8f>&gTgo|Dsotwa7s|qA>.b,/jӟ8^]'h᳨-FRjΒjf(")1+cE 3q\vc<9֧wk"by"MԤ C͛AdTy*W7/`!ī\.3ƪj*RWYEι)' 9 !˙R%)΢JDs 2fvfYe];pcøTB$I^RA^0 -녹.892Y,ɥr!r%IjM A0lj6܀яhsNbC3 Ϙ|9 Psތnnr>{$ أW}Տ4tNJu%=-8 Dm,]i-{ $&6ZSJ}]"RgٰׅUtRƘMiZ[gT[lKL3.j ޠNkȰm9O)VJdQ_m X&%sGٓFveN8cZS``aȐ+90KyHJu3dVJL7͖-~6m6 !aHRkFRg+6Zo_XtpB!Ey0Ga!.(> (%TlSc̄=[~ 46'`=V=hJF[. `Mt J 8bRh+GGrՅwcmBt1ֿn3y+Qv/."`?ovQ#6M#NuſJ !CH޹Y{TJCmƹnA*U)M]7"t/6 v'cbŘI(YU=)Eu= fmn6a{hڒ]k RI !#j6J}g{[@TSyD D+oaߒBbO%scƫ {`9$$nԏE|"ǨzёB8ڱ-R8i!`-UO .')6c%ZkÇEUa;pg*iڎ$H5)H¶#M6ړPζs:p˖U-Y1Ӂ,(.x@(V!Gc;!!SXqLŝ81!a+t"!|OVxQwHX=.A[dVXJ?\rI6ՇW[CAzD2"D)R4njc6mZ pm~aZc{hoJEGҍ 0DS844).]:>=C|dZ D6k+U1aOQ' E6l "[d"SC)PjmټŇpfZda^1KhnGC(bhL !CP G(j kr( .#lhr,]~-(]y5a"D؎ݦ'BI!Ժ y-(`)TOfv"NZc/D'p|@`ۢ S0[´@˒ زr#C2J!,'QcLKX,&Bz".5U1MSNJ|l #wWBU u4M؍h!( ߀/k5@AJVU;ۡ&RRJq~n,MJ!4.ǺA?)i"M(e$:S+#DDN3Ro1e.:j ڧ`ŽMHjcimm$?77&Cy.,f| {ZmSl|D-E Lv-/bfBΒH,*69c*TJ`pѫx U% ߡٽ+ R;\UD<䷭# )F#uvAFZ/lK6c^#n;CWWn ƻe(9ż7If΁,,/rrBt?rL"[NF ,4U*[ F3!bb 7]04rM!1 Av^_cnRi4=+ձ'  ʝRѺ6 r3 @ F;O)tY  +RJ)$4M4!2 KS^maH%2R1(ymX Za#mZ8qc}̌< YQ:D aWP;<`bj)ߴcNMm.a0HnjD/E^a$ޓ1›P['A5biX0PqFX82Z,$ <- b)u$$(4nLa)ƠKhTx'zݑ \˒Qڌvy x@we#b%.$4딸=>0's5g3+*q™u:(Np'+C+O m::J@S P!k))YtAHt.,pJo D! MJJcDzѮ*4ٸn684ܞvC)%D7DPIh;k%`"j@4D.c_mK2vG34uCdڔ+}&``,d:ۮd[;_3ӛrn"m}$`'䎒Gtռ6q98+#SRaj-XMV:ry [,܌^*zGĶ}%0MBXvC :7(,i ^nSC|&Nی1^)Fx,_ CҌҊ̴ |PP˗ *W!%]"ssRc:iC'{4o"(6ZIaB`nJ!JÙ" 3ۤhnV4 H) dkS ь)3Du ./u]"|cJ0e<^h{ΉlZnH)%t6L24nTu,~ǖK#Iq M04.Y\{m^Q;%AY8 \'DqYj5XZ_Qm*b(QbG̕ѱa=e#du Hu9=5%<!84ƐINKLX^Q0h`a}$m_a+  ,p7Pߌ)h_Sw[3o]>0z9K')3<˽椉"vF!m%< ")4u:EI7: MRMN5ԺPe谋"04-vPIoj &Mj)[so"S7!vm]6oo!!I+ B42 Yb̡T[Fw@TJ`Zۓk9o|u[,Y?F==k!!ºzwD:^.%x$ႡLIਲ਼h\_@)! 5Mi"uYQ oY'BzMҦ8AٖdU,ׅ#FK%/Û]Ƌm"ϝBGb?~>#m3.g*yk~ y<9Ϸ5E^Zō1 CPokmxQ?߈_Ϙvb mٲ RJhlJTJP$9T-!h8>$ad)@1- \B &)΢-qq L0]ciT1!tJQ \l'*;r 2p$E رi)ـm,3ak3A+)E Q.]׵p8ebrfXZ N `nB eqn[ [x~齱ܷ7 Vf,1 sPf7΅y1 R-|}|l2W*R 3O:pgtByuQS Ll_caHN#x'1fZk-R`dS-e; ;&ٻPYU~f됱@aBb2XjW##|Ysg/YI%G˒e侑ii+_|ʽϙFޘKU^B6Mc?R*5uԍ;kϏ?n7o=o֩^ Q@0D#=kV^pj=3Z_mtx-n5zͿcŊ\~kT~0lN0qf4Po}?.*^,]%̻*l+xǭw.2\t5~qׯZӛ.OJ5@dOFEwo,`SBBˉҿI:{+3LC;o6@+DGDaDJk- FngdG1\DK2?z|[0$ yG;[LSbWeJ`g/;JiQ 1( {h(S^U"Mި䬘MܻYOVY70E!e(LJhWRAwdC,YZ$D~ -Uy3&u5@b㺄j 3k]c +]c+0.RLR{PL0/u&4>;)%!|I ٮ/lh_)~(d\*8  ozX0K%]XZ@D.Bڙ6\|ěGgl\i܊ep!*h:(J;8j1 ȅ-7,8C޺CI,\byCw<=iR* !,mH`D-K1#!Yd[!ӡ>.&eE>{S*xƈ˔XpaX~:|9gAGomZ{ۢ*qOEDMI|Y?8o9=6Ujm3.3 Ug\ei^|~>Ow.=g&tc-X5P->3מxYqm.o<ӢܼE'y w;9j8m~eW<ơZtܹg\ޣ6= } TV[K[90섣/Wm>=^H؜,$3cMg+tMgKVހ'e^W (%J }{/qU DFG6|W'JmCq1lC!]sh$ü!MmBXN`Rޕ@vtH!a&VȂj\1EB}+Χrw QUR --g&Xv&dZ1o2L vO=WȘCƐ&B-cbȂ)ozsSC:[DgK FΞn ZcTJ bxp8$ׯibyRbj|i[ZP8PrC6Rf$``xJ,#\I00&* It[éMDF Jaǧ(PH)+?SDaw%')񹁝N )TUJI%R)!sXf4%Y-ddvSse~)UW~[%9Ca98&0fyfJIj\qZPQl t>VOReS2..Vo N=M7-C<0p"6ϥGytEÈ֢R"z8U,븮v{9ϏlsجRƱPg#wm>?dPxuS{[|蛖<ͳ.nK]t!iJc`s^~%.>ݦ"r`~CO+ =":Cj^;,k<˫u?yeYq#2z_OO^û~_x¾bG~V~r9G`t_jG|/xg| ?_oٽ}?wwso\:KP(p '}NpEˈ:e|:&FዧIz *jDEx埽3.7'Es^ݟ/}7qKZcl3il{>bњ+ξr+ξU\fǥ]3-V$c 0vt['4 7o\zzy'h}`f\ IDAT~֟uww?[v )Qmg]޵77^|?UdĜ×k9;n~ߞ} y翻sr9o~XȪjWkv)%@9Uo?@Ÿ'DḒ_9_L,u6M옆o ,#߱S^ymMݳرJNgvMD-Z** n9W3@BGk%]cfJ)TDP61 #(:اsnOEl`$ԉ51 HgtvC@0SH]O0iP. }w0-@bZcgSG»T$h8wt[g.p8$2^_J & L  ֙ccOiQ7Xrd{/TeSpsmQhQZ ~U%4ANlMqYV;+TRJ)ÃG)b)! \Şgt! XAUUիVC"J#g^IѭnBMS}kȈq1ݕIfYR2$"#U0jյ5)$ߎRB I;2FvǞ altgC#;n kLij|`lt\ Z1:z+f&U֬m;쥟=j_Om m­B͛a?u4x?iDC0@-~Cz͝0煻e30C8cmm s^dL`ˈ$+Smy%00|Ƿ>=vшv~ o-ISɟnb<7z[ xI矺󆃏/~3gϝ߃?C^xO~L k}ͺ|~~{u:0:cbuW"Q=['jcF~hN){e裼%xhRTn^ZphzF6N4YVT0=&@&g/ҜJS0 ¢A?/p9ؔKK=LJ`mJURH$㺪H=/ |D#?<~#|sy{OO}ʞ&̈v1̚?yILv.(1/&1g 6|_m3+)1vsB̜k`_g8͙!p{'/Ӄ *Sd-.kɿ&yG<:k 64렯g_zq=)eKdf~P$a/(opK"Xs_#ÍkMGE_w=أ7νꏛ}s|?iō qurљ7>a/V7McG`E=x`$|`nT[cgO5R1ҥ]%Bj?) (yG0O#5׫@ @d3#A)e)iC8!u]رMWJ&6=ѳsUFW|,=p/mO-bbń߶(WSv7+m1Qz+`, K4.Zx PdL=I!S vc\G`&vι[iLv?]Ñɥ%"kbI{66`w/(Ғ#m( J ,pM ?Z sF 0޹K\"_RIz^Ua4!#y'4;Ny;: bjr O]l6RL9SD;6G,t!8!HŔ8@Y*?\Rr):F[ N6/T]&\^ wHLڊyn`Ri~'pFI*%꺩92z ]fl#dF*7 {Ãw7BpN2kBqʟIToXkmhR3N* ݰ`NO,H$ic|ނ]DTݣ bVÜų]LjZ},e $E> < )EWui|':'n11A y[58!"jcM,LJ Jlk<$VT4^/u]pc5vMbӢ^OWEex{b a)@ trq(G8PՒS/Tȗ.~ѶͥرlVe'@@DMmW,E3c[dLWUJRȯV2g%’c JwXe}eGmbL*4 ]CK^"3-y-Q#ђ"YVm0SIk8YZ`~gLdVIg~N1Sk9 J83Wf*w"<IB2{~+po 3c J䴣 0c0YM`~'#o{򽻶ss׏z=9aﬞL͵@g)G6d*e0! 8s} % I\]c*E-uRMWy[~RD<~_\/7qw_5]Q:Q$,Ppkan[0`|z'k'9>ka P`|F+"#Ta_g3u֍2au(Qأe!L, (tF@׍ӟǏ1ьǟD`80{jQЋ*5fuka `d׌q/ (e֚LiC!#Q ;2 bz..s5W /ܤ vSF'E(Uqw뢄j>ؐB1d WU[1FA'vEXc?p8 *<](=kԵcTE9-u&T:Ҡ#Ă3cZ6w[ĵa jKCȖfbw! 6yQ:Rgo[Pj2$Qc+N4άwt`RF,}/ch8z׃n?uh’[;I=Цn9r[!DҎIiP sqB(#R bWY]D]pR`!4(w<8H| ԭH8۩VJYY`Z7b 9uNTǟA?c٠|7?rq۱.}b.Z͏= .f+?Ht(zUUuc+)kՐ!Pz^OHA@zǞX0sJ}Mnv>1gsPXu{iDZ]g5Ԓe7-_=~;Xg9/~ތu+&H9h#KՑ+%;ϣ۴'|E(.%c{q!c# 3Vyp8hãny$"c?chGlE3yY~qGք ݍS?H8L,!ߍ##!&=s u_%_GdCB.p׌uHVxq,( c Oݼgat *GvT-}bӪ׌՜95~+Vcsϟ3S{sg/zތ+}F @͝1RakFakFwom aJx mVak ?ADoV!̆y*wV?5x^d&pAlz*Vh\g/١P͵3c=o];0U^h%/" =A]fOn~GD1}>ӶUs_p@vx::::bēt%`RVJ)kX3l_ԚR߭`B#BS̽KQ\^"/-Fuyt" #LY,`:8:N/ktHkLm,r7RAVRd)mL]׈XzR C6#*St B">ѼdCI6gI'~[Jk)J. DD;j{"N+) "<a;TIwsE}~h8/(c h_l9Ce Ġ]ϟ DA|eǙ!oɵBXCK0&LlTɳ m;R]&R)6Bq#l嶔=9=. xa@FzX1u^eRJVʲaӦۮa3{'g_im' b޺6iӭ F};uBTJUUO*eZzRk]HB(RJU lqKo73׭}t9}>gc7JnP ]OiN\Gap{`S W^lcO>KS߾knx`0Ulz iX(]Ǟ|+v[cD)5k^ Rv!-n{ȼ%{^{-m}/_z@;Vr6{͛{N{/{6n÷{-i~[~KO>V,~|+OyۂeX <}}O8_N;j5Ʃ9DlmI M5d뛴ͪ\ܣ>֗/^ң>|p[_ovMW|yGֿ^G}΃wIǾ|Ѯ锷-Xuݍ+ꀰ1KYCqѽ·%K^z_ul?/yQ'?O념F3f pƠF7"{+sz+cN}‡pf2JX"~W>4kMmY[>|+/~ѧ}Cnx`UM6"H2gm+bwu,qxIG?wmxhKc5ewmm?x;}?替bP==c]_q/^:fh >o{v=˒=Ӷ}ԴVmFz=5~ 9lDa=U'V:J}kmbdddڴiև%G< °:BU)l[k|5T Fpux;yExlTN zqG'B < ,t4Q ;9Hn.Rx&o'hFEɍG !*s  ѴsE0тHF~`x2 QC2 }-&Ymha065S/scc6(9IDp_)0:ܽ%k!LH0rdR)~D ;:F6F׍-+Z &)͚/ڱ;~wT# !Q^%ܘh4P IDAT;Ӷ=쳛Zi $=vkf,9>K:A+ V|7;S\s.3?s- O֙t?ѷ~\MMXZ` 9x9CXJLoR?2U'Yvډuh+_um/ylm]_wy-p*;wCO<ٟ<-u%0<\N/O۟x%U8_}\Ԋe}X馱D͖}u.}KI\~~٪aiN]`#>jqml&էkV1 ={&:>~s; 5v@tՉN9=~g;5Xs׵&qK>smGx_}]Qn?3a{ϧo{ƭ<ȓw]SoZkZx?7-(P ?K/yಣaKa7)~,cQFkRJAbX8BW̉N]h3\LY- "[KJI"GzuFQh+C 4>Z&Mb?J*5Lg wiD^年IT`T8đVV(DgRrbi ub/j WϷ3Thb`BY4,ХNEOvf"Ug9dMbׯz@&)DL#?&-RIV-CVD6#1QץLhDtKݯOFd t;I @+R!֚9:d&Q%G;YvSqT7@Q  ,x/ k|LJ9\U~Փҹ pR) &CDY"LPSKAIJ+l1)/-GlnGF' &b`=Y9 K_M0u#.8}tTy` Jэ/1r%J)mn-5u45TUegDMSd+WURH) i/MDRJꔌ8 1h!M*BE6zpkߏ  "x#X+()6L<˅ٟGK?̚0@D"Z:`J65YTBmy8;!G%zR`4簹() ǀLD%ӊ6!>Er.qNc('/llHMÈӡҧ'=;c:-~ I+ޠ Y1[Z>N4r8Q!Vf1-*M|%R;"~<0 'D:sZu5W\|?[xu#aCT;ޘ!zs>i+k,͛6_}Cj[{AAND}xtx"!+UUj0UeSp17oCcLZ5w#hUD4lj~ v!Rˡ '$퐻;,mL:Qx%^Cf6w $f,0L(;7?uqQ:ޒ:gnGKboB&K;U +U+|e(zM4ul/┏/ JbV )un5 [xB aTug,[eԻH!-V)%({5vXHd1Ƣ׽Ȃ&;*ĠttE( ,G h6W_d?9J.zv}v*,Og..SUUeg7o61m9#LpJ4i1:?E 3O;ִB X{y`tx>\ˆ6$'5"c[wZoڴ*"B"ZIX&lvYH΄+㶀PpcZ!e]vG [%bڿ3Ѐc 79ԔH΍gkQ!?Q_ : 0L01ٷ?VèHailr}+{SnЍа@S7XDcv6{&2d z;Fj[}0m{ - ;8_qcb 7Bh}bM>lM:c!mc MJ9`9o? +3`L1;/V 0 qQэYi,$Q1;᳛HCf @h! 1w/·)v8"*"6WURH0l 꺮jZ_)d+8.gB5!bO܂^DfWf1ZJF J"q: gvS.FA*>Xd=ad6F 0 2uJKJLp LxV)6b/q~k͛R9vD3Cw0˱'#pFs; Mp ~SlxmL\x۫WUe[/c@Yfw~x?$6R*|סeń8f) Ij.Uʌt bB.Y̜t-5i5uZIk`C4 uRZDǿvjfDVJZ7Mر[pi>!,66Z R_JSmQ0?[4g^%L@UDAHH Oa-pQ_CV&LքKh1xP-,:Ǻ0Rj˙U,HHXR3&/YTnmy/% M͈Nq!ݒK}p e|rXģ@D4ܸ6 TO6%-R &cZ 0铚xAGfhMnÅ|x8,pN-wSIQ P p"f;T0 pHvDhB$X:UU&C\PZw܅!b WpYmunyG $@!!p6Jd"LYnP dlSTjD8B`vPRΩܓJJ°3gߒSA}u!;u@Jc 68$Ø2 {ڇ6Yp+ZBg CޏCe9b5hup$:>3܌K|E![[OjoLz2*ʠKH }a"Ry rj.1kCnxG P`K1Q4R[wP8' i`cSهp ?i 9KkypFhSdliLIe+Q[*yk %(jHQK'`8Ժz%F7jƒ7YO'[]̛2e `gn'5@eGv&}(AagvdRim8WL iBcitc*T cLSMXkNCn:-"[m( wc, Ύǔ'8;[!2asi [+N.Zmc\7ɀ^i`{A7'{l 3lӓRs҉Q]A>s~\/ay}|xy$܍v1 DYژ,՘#_ca}ďz-!.G!8f~PYd1 !-LHK u"hGHկ/`qU:I>;3h|a+IdkV|CZ<IͰ$v%AeUƘ`%pT*C{PQRy̕3ŽTX =·mmRaЍ DrVL4D B a]3]ID(Da=ljΞ!뺶?kH: G8@T׍6ڳ@R{@e`hrȀ{J*"IJe%^;2 Փ=*DV J+#-90Vv)x<2RR?9S~φEDY25IV} "7qM|n=KL.} 5X]jc 3I]Ozln"7c,MlYAnKIJCȞG Eo֓1>;ro%PkKFT,mjD?ƈ$Al`/E[ 2Zֺ2u@ABMm=}"hQcBȪ L3c=/C!𾅖m]B%%jnus \R)/ D 9*=|3A>ਆ熈k`,[UR MXH_UBH!ii0DƘJJ4(e2De$b`!Z*)Rd]ޭ5h[t:[Hm''k#[vdrSzU>gzKan51"e|5w%^dhbG\xo9C>$!ϋiE~z"2Z(pD-msiZ/O.\Ji scDW*LK)5d23^YA#!RJ"k=O6YEL :|`M-'O"DR*)kwAF 3$MR7Q)e'A)U iaQ ϙ@rdi C aXCxa=1.a/PU:2Y(HiPpIq# QN5Y4& q֬ MnKSU6Z7Zi4PGh:ĈؒmFkm?pz ӈ=M`] ªʏ &^Qc%WhFϙBaQ*AlR㠿UHLة5s. %k>C[Svq(PhQpcTe"PQ'fT3馑JЏ! _,M6&2+|SE*man՞<#F9`bѓїD@ RR Fzk(e{up@6dgz9ч1 d <#@dXFژa]#J PoĂJգВNjUr ) vu]C/3hkZ(t"ur&K@#BȾrGAF$vrr)}{ 2,RV.7,M;I6$@R>(v(RAJ`E( @t;jqܙݠ|~l63{ʷpnn#tLQ񱱱b B-LUl@뚮SpnX6A&MMkʷLHzwtcy $㬜xPT#gԊei%#YI"qF aҞW:CRbp[^ؿƟ6h֟:TPdu,7OJqw~ekP縱[ȜYBumGil jP@C[ 0{ހ|#)i1ۅΤ0]o- U޳5vr& ՐQrE1CAdOQۚZ]asc!S߸e:)z c>OQdQi[Dhł}!c~? y'xGUUUU{ޣN:>0If;Z w-R 0C}G92-4@-s wDŽ;۱wkJ%ڳw.蔤ZNcѦ%RTwҘ#tqlMp EL^msUUU=HD]rڞvpX=9T"ѺumsWWn=WhI*SEU[C7fL-I3ag&YȫEz=KreEp]]&0l7O jV쨋e_L FNkH?D]EGۡʽ(Z"x펧$n2ʋ6HqWDux2\Im1&tpQOKQ"uH"8zl1ܡ[#VڸLԬJk4idLbi`==N0Xd&̔ueruF-9ىDy$.ر#]Vڔ;TtCW}x纮[U>zZ-6< Z}U2eX:,OH!0SX\UTlRύLG\ȊFj́\7Qjhv C" q؆紐_C_[r Dh%~޻U^?`C%V mk\W9@ &6Vx,K.)LU}P1X1(IȫJü{ '9ՠk3rlzwصgfh]z=|Ue b;3gŮ;2wfT;/sߎ_?$sߎ%RUÂ{ؑ IDATvd_J3wdf=y=E56o\33s嬷})gU,>ZV+{ﰩ?ٰs禝/zjB5׾Xf]wnymƈ }O+o޹kV9{ږ]vy55 }@#~lyLtІ;רͯ6owv3K}**x -rc*jT75HrL'yc=;25M8DB093Zg?_a={7^2yUsYqL3:׀_Ոo~ݼa떥߿PeʚG[f-;񍇒}.b1ڿovfl_%v<'XrϹbl.H%Eglޕׯ_lU -FZa״S =y!II Q3WgسYoN;UDAEJi0 npkܻwQmR訢Op8ُ!cK{jގ_7vӟP+cR;JꥸB=5oDz~C7ip[ Y3ERΤF7iOݶj;BvDz"Z%ܹ4I7#4Duw-wp 0jRgJZ7M#hbGBN58F]$y7"VW|- Ή,&r6a\ް['? "s 'YZ9;pQ*"[eXdE&G(J*n;2R1J?`"ݬop"WY [#F1[>΅v!|->h#FФ3Tl1Vr}>tXoDŽm0.D̀+(I<>{?vM/]%iӍb[i >S"5q뚮Q2Iy * 9ldAI )z٭lj0lOQ@ט>ROZTD>ACFm="a @3tБ1U5-q2d@mCTbl!Vq>t} G. rU VQUA)hk)+kosbjvs:=DBtN kD\ "{>S|QJ/bl ~?(Z8!kЕ<#2 uOogh*B"CMU 20Dα iW 8N+@5Yj_3Sn;: .HKСSn;Y]-4@MiզUrQ_\l߾)U?_B΃boSϟNm]-ݦep1sjP3?\m{!ubEs?9hyw\'}q1ؿ]CNGM5e“T.=^x9e r{noc?^j/.IOV A~L_4O?'1F9َ;=7LwԿ7_}D{ݻώ\u_'%]DOƴKVܱcd)J%(2`D! =ZG+g' ^ٹ>< =FoR͍ɡ:¢aJV?~Lg>)l| !xX֨[)e4WX[tLOMYW'*f)%abl[Sޝ:6>(%~YvJˆ%-G;:DB0gL+F즅53H"1T7>&ɣ7H{#{ݔw̸nnnJo(σ eݷF8ݨ/!4]  \: c}bߤ /!Hmn#>.aVӏ 71/d O_&5{p/}hwlhv$ KIwnzzFt²0 P}>2 /@0.p9q1QD,~-<;i0,v݃RB(#LlPU纮 !  ;]؜i {9MxAimI@6.BFFQ%vs STۊ4*lIьri)IEVX9UE(sNETE"Ή1f[y'ӊ\The~7žkс1Ss'mJROL2 dZs8/%@&OIY9 G'`'t>߱LJ-:)@(yLl~Nu 2ɱY(@@4(B(٪&n&ute+ri%y;^s*^WxϟڱpcU:K/8kɶ|<:~\V_qB5}ݴ{n[I';3ڽ%cNLVg%=gŮ;n[6}ăI>YkvmٵcM`S [2ڱ|n-J=[LYGL_}ΝMYe?/wmڸ`Ԡo]3Mjwhֺ[dZ8{xFC_.lw얞5o7=y?\L}j>öDYQip+?lۡÙV٨M6>9R5F:t3gw;y'ߝڹC;Ve+T(TZO}رͳ?|.kƀZ*f-vc[fݹ;8o["m`f-: @ / Gm=zj]:Va\$樔=Oe+^{Qy_3R-?qNk{wٷyjϴM}co\#sߟIf,ާ۲_1ܶNm ~gߎ=Xyŕfɏh}澭fP.+sπl5W m{o\Dy0[2mXF`lg{|<{}̽}ֽ^<ǵy㌙+4mS.۽c_Wc[VZ~@$"h`c~ڰw-T@V4o?9_ٺQm+ 2 MF@e{12#s=[PYE y~ٲgoumݴWTLxV_ra_/s{3W{ JF}>=[voZ4}}}b+%;vooݛ`v~\y t-(I~ڰl`LJN?mXvQ-ۜi뢷}P \i돏7צM{~|8Qjwڝgd_5}q RrhV~`Bk빢õ|qeч_JTC>\)e1kޕF3jY3,E~|֠q ]yuFZl yD7%7b u>ٟg^{wžzT<"3ƨuG2"BlæT}tT7x{Z;%m:QKưn\u EBry%akB- v?%EnyG H)"P ĉ^$綹K%<-r WYU7AehѐtÔQTE fqe-F[͜|pZ,Xb@.8b@m3F`9تQjda458O57.<*N3E@7 $WRRHtdQӵBs1DZu;>vל;囇^w,nLOD\ P :~YL% Nb@aLQ,!!,lbR1J`sO\2çc˗BF梢n\ |lyO!$U,ˉ27ω~;IxVXid`bI˺yBB\r9iF"*fy>RAx׋(#uέZ-[WAZ1G8 a-k灼(K8a~UвMzB8P/XpY0힎wk,*iwwdήZBeLۼg۞M ?;[^3Fbۏ}صEn9Q>۸ݏq.LSf<_sߤ;th?`_R*76f>ץc4|mʈ ܑD%;OwԡgRߜ>iܣ}OJ\z޼keM|}t=`צ$*͓l>&Xz 3wM$xPuLfU3'Hm e؋UPDnKHoTά@^5K0z\wZ 3Ƨ7PphۅvI"]H7/PcIƣKݷ-Uyy;r9O|҃Tevo-뎇K{A@:w=i`+eRfF!bBF m/#Eo?^MŁ581d':5`a_ޤ ų#O8鞹cz^jC}[Gz>" o67اcOL#$u=mn?a{Lj䐆񦖁]( SM6jp_ ۃԦѬ^Q<b+_yw/thRtٽn&/c9m{ْ>d[M /ӟuj %_j) ;u8PRI zc/%`b)Wj؇Zk#F-?8;{lԨE'v{gxv~f:osi6ʙ7gwhEU8bUhfM|a̅sg|Y2QLlS2X|m.rq3QL0Lzy/Vl\'>\|N)jUy8ᄆw,JKވmZ|x*Cy봵ibl:F%U:=鲥;Gjps~חhQؕSwz &qo *UUu>K06u Orw\ǶdQ6D'|{ P1}[0p8 .e#l3 5[HєٸF Īf iL6XzTL/ YO[,`ښI@_Jh3Pu:>,)]jtcz1ʈ=DERqSU7􂢐DZ9Gr=H(=nNTȂEqΥ:tsA`oJ6$2@$0߯CɡUK,*oE @  2EQCgQUX@ SɷUR"PaG0p8diTSE,뚮Z:6 ޞ'Dr,oA/uR-*їجOZeĦ}O 2.e>a.:AsRO5i@%\g&> ڕ+΅ '#"Ɨo _s#0ZҵSn?عfh)fSc?;+ b}k=im,) ]vʪ_XBճvܾwŗجG @p{z7,֍M8wlix!}e(*wKZ"WܻLz-C`M]}K܊JEY9!bc=S~? Zl/l֮\\HP”/v6)B ]9cE{#_:,]رX͜h!Y>jәp]pkջr7nk(LMqB'Ocf|;UzW39j޳/uԘy[O;gg_Ok2E2' a%[xom"ٻ} gC޽g_Gɋgn5y"Z8yq3~8~WCo_͵.=VD3k~=U>JN-wn9pҹc;~fU zJ9}9^M:眷eiFpNMpjiĆ~rء۝]hwf IO"V{n'ug86c6k!J_t޽z eiFxv'hriĆaߟ__:P+3I4%/&d)D3H­8Z2%ϼӓ;#'tKg6Jv #BLlr9atIRԙ4E.!z*`ksg P< ':( xn-l [OAl&tYeFiXY ؃bMbbI898WFD܉hZ Z6֥>m⣸pX3+*u N>azd^pX%q@AdS.<S BB1w:NsR!$y&/ 6ysDg IDATǢS(-.zDUMa e)"npnIMs0|)LK{xo.-DSTeMxnfqa!~mWa%zwil.*agtL/S˜ZxίyD Zނ.?,~*=aUǏ[ Bzm"뢚Vz%Ըa?dG  2#sg"bmGa쭚1"]O `yeh\Zw]ԄڊBf%SRb:'pW)6qF ,A#h^;z5F&WFElC\Ӂ0!%%NYww DڲG*E9Gɺ4+ʶ"n-?fE{w}XR\ѡ`>ؘrDYKJy8/E=N~Ꭿ]dunV{~6N?.T!YzZS(ZmCfS}oˏAFNzL/`Up9q7{6θ`6r.@FP,tn8~! d0 n0ˁVsP\˻|\v",e{ u9 .FDEGrǷgn5@_˗n8s#63D#PŰ8+{Cesw]DŽwD@\ hd5}boPu׬ȲV+ йvEm8wCp~ACt+Oq@?u0Gje"^d !-TV/HW-.7vq鵓%^dWkw@W YԔ+Nr"F̡@`\?wC` AQ1fEE @9}g'67t"C / ,%[縦|כ]yomUϊWUꖽ'#K(+{cOF +{eSlH:rN3((t=Fi(:M8F#ځl6^ aaaQLl 'An6/8-w+Hʲ"iQl,]E-z"GW0ctyh9DT;<.U ђSS< % fL@sE:L"#x k%ާP眬>`8z H:">SfU7LJv*IT|G-/fj|5n*|FP[jd.bg 4܊ ^sizISh,H}DվIؕ-ص+ *'0:n~&ٔ]wJ0 ~JPesby7if8FyZ+9ߜɈiB%@`WĐ*p{(LE6 "RUn P<˞~r10nʛsn7M{״JFWuеM5TRzvG+\xMur%:@΁ ; .B|܍uo^״U^e.B\ƺQסYW`)-m蕭nC?F?msns%n=D{mR*fm^K& ȩбWmpa1E6ye+״\=JNI+;Ǧ%ljU)r|"ѺnIjےbG-;L=B01wmZְs*1 npb='4n9Dd\{b{UH.˻z?z^Gjε.-\Hl͠iw}1YZ&(QMS*N "c<_ߛ ing([\=\'U")i$i3 &=R.X;Zff)C5˽yvB6c w>?68 P;^uo~"?hDD]u_z3lƽ[&FI¬YJ $[-S8#}\c=cq x-n5@ 4eRuȘ"pH%{Cpȍ0~ ǚ/ݰNFTPlTU}qqpETe;f p9U^z>Yd1v%C.$n ak,b`A~(s:-"4"zm[(\NsXi$gEӢbP/&,Y1 4rHL)6;Ɗd^ɲvj Y0ŁLM0ӝ$3XUDӎ`2 ctN(n]MIqHdPs *Te85,8KܵR=Cr\#I: Ne#!/_k aIKL2sl~?=$m4M Dbyp qLPrE- ;S 7hs5ۣl##g{f 0CC˼WV3;.EӴ7yhԤv gS%^qU$ϟEkE:#X~&n,yCiG.DDt[9Dȝ>[T WNb<-Eu2s[+Pb/{{̣bP.M߄R&Yr Q7BRO٤=* R*QTg_4d#sssrr kwr{I+U,:Eܱ%ˏ,@?>VVn,)'ғFNGtS})V$?BsI3&jCȶv }>cj1HNIēU "ԍ$oK2 mIu LΘE) Ӳ^IWa }j|zIj$6+ ذ5вRZV)[TjŦN ?uP8?PKUJP8[9!)R +G6,W>^&2XO|pڻrb+L5~*@l @lL; |Avqk;/,mʹeo:F<P( &VV:rYXsak;@SodA3ogFi#~*@Lq`:Sلut*Xa{*s0tMtM3L-(k2DvbTUSޞtɑ=5c<%Z(\*\e\#Fj(l) 8VPd2c,'osk,*8YSP8`􀬵h3[\ N`Hk ],SQ̐U c 2@']@QT5]ܜY9F~$<|qc!)W'i\h;\n# ffclJY@H'acr˄zلZ1TY\< ah [LJL&r'"CdjqyTܥWNY0++MyA zW\s&4M7 PhE1Eqm)뺮PSpM;B|3 6ؼJ3PM3Z=BuFUGk# kK+q^7_Mg??п4ϤjXlR:kW+ؤunVƇ:xJO wWwz}@ʉKATZ~YvkkSO.\z;FUFv!rਔo=A][5oTA~mRw֪yُݦo[~@K^v*e[!vZT=]M[=@ n$ې3;/{KK?\Z)0ф?o!`>ӖVL[m ]6gzkT{)ED,8`uA/ulZ+qӲ4[9>`ԔF-{9ņq{g*f yAJjC6]] s,:]ǚW+_L bEb.塓uިe7ǽ0"xjƩ3Jw5CSО::A{aZ-zܽV,Ο<4R!V^/w`ᚢC^Xrzڸhϙr _=;zwNa.5 ]=un-P!5Y\R{_•CÌ!Cx?o67 )-i´gOJ U*?pY˪iOcY(XcsP5lB,Z$3tDv;hb(BzLmA7B6]QDk6Gwn7 ݑ;6E՜˓71!$Ц!I-لU*rWLԥ&sIZ 8IXN E-Ĥ2 u]`E1%=nB,~Hjf-+qUUy=,m-nidT10@Ou,pZr }HEՖN,L'hd?є2׷Ex8?GƕfWāTE| 9qG痨j0hf!@"$4]3 C1xѴ xTs/QE|F[MO)c1W@R|@'(3/ -BY1`z^1_zk#|zkB5/P{D]o85]'߽:#}]˜?'·7vW8㸆>of9ڨ  |yqƮ6]/u y~V{u0;ܾǷWxG<> 8v g<2 |=G Ib=~vK_fi5tikt cF K@^dMK~c?mqcvMKQB?C @$ᵑoPF,&-BYl*έsn"4,U!ٿCQTUPш/<Ϯ 3H^] /'d﹧Q1|Dڑo?هs|:S(T=+' h16~цIּ lYod؟U%Z:E7&m{wV',|i=$k~|`EEEqqq ]sZ٢-=_%vqƼYDy79xޮ1t tضfdބSnOO?c+&4fg>chAG}2Mo#c,72Cܟ>ߞHׇ~u3hjn+ƾpm# 9KJKOZg4G ťХK&(wǧ/y͗_9Ov(t~jά =nQ$#0pq(*{scW 2~Њ~u,OЯ>(sKM,Wf\_9'o F쥣n\\3upVnny&qPp/C%)S]I9{obew}Dnly:q j O7~8X; ];z[9Y©*:.?1 mX0.JQq@> GIrA$d-96r֭um IDATl5]Qoĝ{  :)0eZXCf,4/(,b>iZ8[ XgRh~QZ CblOU>传Hh*"\m:l/Z q)ːOTLY$VY-G"mYCP nfyG@6@ Јj\0 Kw(bE*v64H u|x1("DQ-ނLei?rWQ[b)j-sEQa'E^L$f8@(DJiź:gѼOL4d3Tubp+`2S~L{bKnJD]2D4‰{dc ڀHG#Kϒ6 Ɛ?uW *.nk:!{RKwO ä|¯ۺPHu뜕9"~ιi|ZPX`0%J#&S?i2B$o3'|@~LԤvsN"W Ι~UUt]MHuEE@aQi@(܃ `BOLiWS&,_ؔ)in/i +_prO`rQ=9|bq?DT}> tMV^Qbj ]}Z\wA8G渇Yv;1JŞYjE B1` Z4KT4-6 pbzZ<tZk,v`þ;?VkJ+ZlұimTԒnpKt^ҸDw_ H;5wc% wPo[#؞rqH@@Q yyyYGcFj.ۙ{2Xl*Tfyg\RA+'"h?)x,̫"bJ0*@ŝDSUEeB"$#Qɘ;G(a&*UM!td"5\"V!drTĞa¤ a8˼Ix (]$a;nrZִp8,U&C1ňBAylFX$4U,YL56!]!N[cOTAݖC=v")zu,mðKhbQ(a."X3jY2H3 ]t*2z-+ȫ"<"7&gyU)KZt:}ѫbKeOLjj{pW#׺p^^W؛Rh N9E'^Y<`^0ɻ\V<֢.F @W ʀ`rgZ>wƅPrw{Í Hn="**$(S }ꑃ/fD1x;м%( ]3*֙0E5[edE*P0^MMCB2>,̒=$P ߡH @_ə[`} .b2 8; ' @$[8,8۞NsZ"ht.DV -G@TtZ"̜W]r< @DM%y}%Ӫ+"\y0 ׾uwS~Cp秙9mf5uf" ='D K,kHnġapJ3HLf>&[dR8:HB&К0rX1b[ꁈ| @T$ d icOTj8b`95MHhH,\&gC,CrуW.Bu<߮{@w)DٓCr*;X;j\7 MRM)@0bR;[ju踇6k10՚/dyߡ»cX،":eB*Y΍;dH]>t1Z';5XArmzא?EIT)++ "cs=mI6) [/|\jU0 RR,DqF)7_!?Ue&-E[rl+0fmSpS=OTGUHom\_On 0ŀBfY&'. > !3Jyζ.lןZY' e`;[eBfkV6֌vȖ@pD@وa f:[3b2v]PQ׳l !!#$ ",Sw'D#wE'%r:x1P.1k%#|8H #9Ṙp_d05oS-~Y}0Iw1\ڮɣ(kуEJa7|M$ Rh!E9Ş5E̴Z1R.%:N#|seq8哧6s 86~aT"K:D'Q>p"RXVJf@PiU^W=t?@ c2JB8K #ړ1 (D_Ǩ^P ]x3D]"^?6E4q%oͥi deܤ"&GwHiKdKDҤJ)AҘ'A)~XWXmcÊ _QsFDD5{*36 & %)ԶCNDZ@ \y+LCBPBH3;md*! X'Ʉv ֌P#2F#4RVQZ '1]+Go\ʘx(@ G%2aT9η+Q2xuC fD Y!0aG6""Aõ)`)6pK!'pe`wle<#˜RRI]UWcc07 |`im辨ɭ5D)mֺ(Kȳt5J+)@ۨX7AdI&j,oJ`` AטY1,YGɑ}쓰I?5Ȃ@hfd\=~gyF!D) H+%s7* AFEVΧiɐ%"7 @4CU"b !|ҷP̔e [$e0Y!>ǸcA֩3T_*:)abJ{Ƥg%jږ iEMRk a{1Jmv!D 5*G!%BՌRRJ> ˎŰPXp;PU5V§|IReLnq4`-i>n\j$͢"e *;᫨fcmp?kBa#9]ߟ[3 gڟKUh*PMڐA2tиԋ<YH" bJrL.sjӂ_3©hVdQM{0Lvh=NՂ G,&ٗ`[)1T7(ɵ,AR 峞\6Elܘo7^;eiOӭ23_1r}5FG4֕GXJbZTr ]=Lc< RԄ*L'6.]RQ0Fʏ?ƫW)P0cn(5nCN(c Dn` C I0x:&F.È Nx v\: t|`5Ѝ2@@ u&bO'cRo`S"Ii]HssYIlΜ uY$mEQ+wVK0pO֟g0mHա-5? 0 ;of988Je7RBd| Oͳn66|@9B S ycS :+bNH/o4)GJ?0  9+]}m=>끽5|R8L,Νʲ,2&`mU`SYq^^w!@&3)3m+RrbX m-5`$%L\~/YtQbcÊD&o[wY !VڈRfh.Ct.vEO`C2ӈz PZkRff-fYVD7I8*duuuw4$SAgǖgl|K;|k4qh>@ުs37=ŏM8c=q.EY@!efrVd;bgn[`Y{l7{vNl?mNav@OzƸNf͛w5?q|c0I`dGQ<_oǓιSv߈$R),Gӯ<23.>5}9Ϟ9̙Ȝ|`O_g}d^q O~y8^Og'_~׿|z_{~aDwt~߿$x)>|ݳ.\ěDT".&*(!$aHǐߦį+!p: P7.wެyOuwFZf=Cvv!V|4RMF_[6pe>x#?~|Ndbtt;;Nhq_%|'է0N+dƸO=? 󔭷 5ѹs&4@q5S0W V"vG"{(I{cO̹l?.' I)L܅)̵wE¸kZ[*}[|/rŽO~\{N+ɥ__ekQ؊ A!C&AtOyOϚէ~q-C4Ag\y}OΚ M̠շZD$#RZ)| =,"}}}y0?WK<;::԰T@tFDX{(]V<1ϻٲ <=ozh}i.⤞XO{VtRڐQsQB| IDAT0m{`ceFinT 6(yFZ CVkOST+#}~*XIE)0?Z@9@QEY4ԯ֜BD@(iF(TP̲,τ / 4A.KdC?j򸈉Uk@w' e~{m~/g3Rʾ6mX:@kN1YD*R6MYd;9TOmgLT"4z{-<;1eק}YK/=r/xsذmK4qg}Ttw>Ω{=e񵿼/?zݙW5髻mImg}sYO>|gmŸm^Pڋ?=otof-S$nu墛f.x97{邉_eJ8Dل]}1y3y5 V ë _;'l@n3əs禳H_{>6o:{ @gͺ~эtS̞wݮcDݳVܠ_UD{L{K#tخPDO{W_zkqSNH86@ŗ6y3/c֋/=3k9燂9, Tjb*tLcpޕÛ}.JQڣ՝o1Ŭ?+Nu!vNu ]sݿ_)4wk~캳zkWw+oS޾+҂Ǯ?ʅNU R ?ƿlʀd}?zݙW.uv7X,384\s Nҹ! Aǔiߘg_vF1'!@/~YO=3_#8gKYL;Λ5߄@m~zv^;>Xs"q}h'vv~s|o{}{⟞s-9H Q[L_?pףO=|~ӷ7Fƺ_<;|S}ձ;k׷5X'iSދ/w'޻|u&|춇j}y^ur]g Vg*PfRvt4:::y#ϲL\F4 i^si߆rF$P$H\ЬT7sD8R$ǵZC{=Q3maiYbcc 1b SUeéAvyP$jJUz X%fSȳYl]tqU+_B j0!)FI!0sy#I5(َ漯&D!NL *|mOϒp Fp3Rj΄4R)Db#yWCI!&jp< ,퇙"t(7'Ζ(NIHal)Aa,J)}qa^B7(TYY'/tȈ1n5LfpX`VQҺX3 ,f֨qk|bx c+m;i:㱽Ne B_h|L!+40;1uAxc_z^YBzcZRσ^/qI>7e˱|P,̊1p51 S"yBɾ]QDMbg@,yzڀ]=zwq+J׷nPdTQګ.K1vI=l!0Kz7nw:f-~ӣ$U|XG!};x [x[Ͽ} Oܲ'椭_p^{s;'n Кm}g,m:jۭ>'>ߝKpϖ$@J ہ̔c^ ׈?2n=;[f?bG7ObZo=GD^oÕ+%H(Xa x'7eu^d,E]1.@]W0a ۽GϮkdocV>X<7߰OE-xa-"[ozSz{'o9vB(~S"k'(r ռV̂t)@xs+|tՍUF(~e9ʅRƋ.-ٗ$̒6hZi `r[|Z׆KN*s[_[ȧ]F !@On ׿8w&N+_IqS6qo}|>v²9;g筿֧זm)[" Z(ty :lg7> g.; Kw??;`}tOM{4`9ߍwg=뷶>k\_7vڞe}|捛N:dڞG]?;Sv|[5328WFGhdYf}DFaBځt<5qQPFw&5g787V"*ʲT%YaטBmLC=4DQH3B\l&Im brfD{(5d05q>f .JUl-td15QEοh T/|!UR8bVF O]Rh&YcpF݌E#,u\e~*BQL#|WqJN)b X ptVH`hR, @2qJVYW, Pv/1qE ۹l6M"BkVA苸Ddmi༟I314 !|)9LD)!wۿAHJUeQ͕ E,(,P)03[^?Һ*HQRj5V/*E=p}.sȥ̲\H!`6=NzMg["9G5Y92U )A Dz= Wk;be5Yw`Q^r:jhi?'Vl;[8+ƷAuw+ »F7C:1 N1D){w%Go7}ޛ`.ffko5}zG$1g5;[}yg}y]1/_@ KK~mys>l{g׷BY*c>xٮ:p'*{lc?݂"2 lAeYru/i.퇾uWEY*{{oy]{${_\evCؾ,[ml\E..u|/01ԯ T 2yǓe9JJU,T;$G+LyRp;5qg1N I-KlRHmJpZY{@Z*_ tPr|݇)ᔢUp MD#.gZ ͍F !2)IҚ"OUj&QD 8lDi46!L`YM)EgG#2IJDȒOf{Q8,w2혽K_W6ؑgL tQ@*$>x;r0|!k#mU@b\mNjrn/TJcls({*!FJeYi G~KXhi]."~ 4-xC`PI!2.G890izl Zac$Eio)BJ`ШFor`J,Q,3)A970_6L77sQGJl`D'W/)RƦ? ά;?N{s53#J9-"8EŊoˋ\n)GKY:[P,KIQ+-z nt@'9bOk{#qnwq+U x4!`FJIg;A'ZM%A#ah 6(Ƥ]imR-ŭaq7f(dI }dאa$X3hNȅD5𭆐a@>,G/RtwueR ijPSi!J 3^[;ԆG.qT,̒ߥOwzhթt UpˆȥDG0ytڝL:%QM\ d@.1+'zCS&b.h,gA)sr6L:6xEY,7~UYer^YR5Dk YeYY,?JؙWk"1?7d.\6BkW-"F0 < YtW2( cCMB'ٴfrKUR~Y*lZʘ`*Ȳ̌Y ,#(i"ˌFE)PMeBM^w ]Ob4:&ӊw|FnW _L9 i> +ȕ^;zi>b_W]O#?-k۔1LavZzFwpе}п_sj TP9Q6c(\b_?>_][KU1 3O=gCV "4&ƋK-7ݚW4? P@ba V 57߃ Xu5ҦN6$i"Z@iuVb*đfw_Bqyk|祇n}[Ο3oYLѹ/81ga$s;гvǻ:~Į y z8m:?c~E gv=P싸Ck"*_=kwwߩ@z>_Z=>xjG^B4HnRA 1I#xrbq?~s{=:D*2m[Yd9{%JKU*PрRk& ķ`:>M[KLVyAEQVF2wVoocP^i~;o퓸n %-褽u#`sutfְJQ/׿M8#S}4:;[CMUJdUZkU5.jjEY_k Ra= IDAT]L ~JN=kEMV3)LMHIE,ĺ6ov٠V?PB3q*': <*B]3FN.oo)ߣ6+ȵrBCܰP4eO%|~:CX2Rc.c}_v7:qh#qQv|_A@Xϳ:/&-_1@^X-.bR7F@f3.NLSC݌% 8#ĶCc @ 2%JN> (r\4@r0ݧJ=uq` 7$j3ZKiǶT] !w=O3yM#A~sum |-?ܻtދuR|N-:r$NaLVV@@lbeOZiצW?2΍c7ns~3k|=/g-@٘-?Ի쩗WxWϬo]/K'woպ9/eKswo |]ԋ}A޷κcG/]Ե6u c-?Ի?Pz潰5ayMBJ_MUbj"*x;kˇ=j_sQeQy BCaEnL#Yu8ec[eR,tHh;3{".k-\3<1!a<(@Ыeq"5(eȶDEB\ff3"*ܢPAEq;QBdt2M`s*ZA&vet˖`ID"Y MP5yca|C)*UIژyRy}_ !1;+C*4EY# 29C4#ge @\@7/1j_sV[U Yt)>v"@m5de (`8ges]'|pWx]AkwMH>*oZ5r?L}O>t4TbgO1BDP!,_{܁2e}N8pXv#_:VpM?&St +|]Ftpடbmv;Ys?@klk5k̔7xZ(Zo}o߶'nÎyw\F\x5d8{>l|}|ޛXgsV;f|cۺyOkW1eOZg!>ET0s_ow] o}w০y;eknصΆlkDhSe944XEDo~wˊ&L|(n }AfK&MJ+!!Ѝ>SFOqGn5ɗllT_o0najb#'4t0[{UظDRrUCR鯫HuCF$orJñ N 0a:z.d*˫4^42o ջx\TOʢlJ{),#d!axњVvګN: 1`)nZ-~0f=N^ .i(8PlzGôTuܮΖл ˒;! V@@ZZ2+.tY6YъlÄJbXbpt#Qbf:h\-MBeXjUm_X>60Bf #,/o3\䚙+Mޏ9 8eB, LN<ѹFcB )Q+]f\r~ BLڶ6ۛd2S=tC,WMi/4m4ֶv܅ͿiI;ٹ(ݶsJ)9 vE:w]2y&A_5 p7}6^k[޺ְ7ϝj0۶j+=qNOͻG߽|~=uj ȩ5Bu dVPvO~s⽧o>+_-꜑vd´^>In9d"շgWuh;}Gso7ϻ}wW\7^`}xxwhӎuG3?J)@Av1Ư/=|%7#[o=v?mFБW]gtx7s+e] mh_v#ˏycc栱;r^ӯ|O(W"^%eS9℡~R3bYP )`TJ)r,jѤt IiMq?=҉fEJ=C*̼v:Ϯr*\Vƿ ũ@wE OǑ%ir'D7["M(hk"pT:W1-ld=pDUFTI{Ζ;4$ i9pya 'Gil{J50y#q@laE"@x 0$*IZV\qb?⬬vgeA ?RB&Jz2xaX rLFGC)U,#HFQ&oohSge`||0_c6iڑ)aLu4YEl6=t@mc4+|RRC0}6|OÓs]zW}l]1Mte !'b* F%ʄkKXlH! 6ɭZIgweiz*)MͭfG0o-n9 XM@DO̰ͭR9d(mBNPQm+{U^FL2Ax`3Rڴ3*]i?IV6Pb+:d֢90yI:[Mpњ b:@W@AVQ N#+alJ9|5ھMqZeBfua~% "AŌ+e~L_NY>@dWұR;ߤb'zϚ|FMmT%8/Sy9zQ@Nn3~aux5;[ٰͩ?J/$."]bbO?cX=6Fm-Yj!օ&JyH_f59\މ6m /xCf#c!L0B<{mp9o$f즥j(id|_Q ϭL*]Ws %#e"YV* {"PPzwlp!C(A-Nj{j42EI:eo~MP*n7V{{0ЛƁe 82I -\Հscxw!tEHp\s)BJE Kd5jbm!βe :A@/jp62 3eSRqC#cN?TrX.KsH8 sE`!Jꝩ]c%\V;oz./EQDM eYfYfؑEQJ!mW&굔9dGj/3jNkОU(~cA~ R0h6ZisM!(L-]~feEUd^ Ѣ#R֚ѓ(MD?Y(Q{DHÊeBLN:;ٶ?uՇٻ YDŽ,$m2?!&&)bHqO6ILqSOȘD$GSMMMq4i}Wi"VEWʝ4ԏG$6 Rl/Jk-XV4" 3ûeWp^G*Ԑq7eY4E6x$nb1D|$fo4Phe{DTE̜<-!)~G0v/A-ę{;9`B A>'+m/y%`ZZX>.@J+pY]D5X&1&BM$ -|*,*~lkjx.TbЙn@@*>Ae]]]+8O'#'@+p2*sQBs(!B J5[ ,܄iȃ-leF;W4͙VQ^V}eʳ ֛U(Tnd')!-zb>* &^U/ݪj-OǫwWVS5;MM,I2eʱWq윦h fl{ I gC:O2D9KPQ, S*R%"JK ߮q0 +`leR3 5ATQʲ4FV*ViJmHl>]u~򪐕q  I  D6K{Cı<^-]f 'OD9hI.iIO| fxFb(jYa,t;M8:)$&TiéV KN6,( Ҿ.BEY8Jٰ8oKμ3)m79=4Y JΘ)k]kjIh^gBޅیƕެ`胫{%O`nH08Az .bBf"Fد ZK(0[)Bw ),I kFb FW' {wb0v(h2!Т^:*ZX b|-Q˯) RζcsJXISQЫ^<T DueE)Zt,_PŪ~lw#fKJe@d6m LgtC#DIUǚ+Eb Q qN&Y9 IDATE"3fuWqoŌ~ry¶gT׉ekj.kNPe@Ͳy|P 42YYau"Cu Q1◢ٮ{I6#jb2qpUyf.{iBE*xP[R6#jHْbH}+eY?.ණ9gSHs,  S-!\oiQ ؆'wFyoRuH^?QWDA2>u&Ƒ(#6*nfkV hRD!kE"@4&#uYQL ӃC52tʸVo(m RDAQJEJ%e&Q DSA&$1oQk_EIf,k,y)ViM"-PL !@Ad <wmo#2N9tXba_Rz*q#/Xqfzr[`|BPBEJ6`xzmK""h.n}/T= M&2 tuk8Iz!K'`aL+($+)evtwaA 0 YZoƤqqBQMmӒY<zRCcA5/;( (q$ lk;9 'BH }ke`Zq{/ !fc3տ1b[37K7(R$3D_H7(4h=JVe4Vy.δҙ2K79s~>;:;l*]DTnOH$! (JH.My`Q RA"(E4( -B%I@ 枳gff>7sef^FDe#,'N5,lkP4MV/?GE)J)'uY.!ӆ8ls[DF+gB 1xBc}c$rNJNJ]ՄX"}(aׄV2京%b N`Xw܂LIODB&DԞ0':C~ԂseU3 690stO1+l8m!76HFk2Y6f8 Pl-P4IFm&lvzrzG;=,-^,0y}"6zeZ6JfEːimkjBS$aF`BQ)EfM5՛Hx EXFɌLذ¶Y|KG2>gLGHf FfAª,1=R9ȹeLˢe!F~ƦmյϮ]ӊPֶVȢ]Һ WpXVig($0ERʍPymeȎ}VQ G.u=~e&XBʢ(,!~[Pz;9`m]w܀)k(ZAmꀌS.4M]f_Q4zu-Q Y)6JimՙxQmbܻe} ;nI̠ 3T92rZtAjArY av{N4d)z9Wǖle!w; x|=J@A &gIٖuD5*e!-w+(p3K) )`cok% ,\J1@vװ67rIGtmA@)30~e#Z,RHi&hGӅ,VwmՅ(R%U($F)&TVꍩ-n)pF&}Ozm{PzeRzm5H@jA cE!eic9b%Z"YEYM$Y*\[0m^iHo.X1FVK1dŴ4xvI'<%x[3C5mXa50`l!e7h,V6b)M&LmϘB"cSuZ^@6r0ES/F;}MnV" 6"1J4AcBOF$@CjfexzsVgɵ1N58PBYW4 [1EQ3k7OB8rOۏ1hcʪ  1RfxyREUeY M25TIcUMѶ<D-eV{#&[Mo[HB6 ;"cZ9111.h/j넥,lNc7(Pku뺶 Q`^3^Om.+ : pᏮ{k' YVJ R DkOm#Tqp`ss' /ffmγkxǟjǜ۬gͺo5lgdhm890G%QNJ S'&n~όݑ ȐLy!ҧw;gofmEpp^|=u)Uop@`#k0D9RkXC@}K_a384l )vԀ0V ~^M@>C-:ãϿg=r%rJؠ0E%@~֕wϚȬngGnJmj *-‚NVM2~l2Zʷd r-8|ҍ:ϜqElZŒ1y#<2끙3~a"&ouony|fJŸ(j\ù_mΉ!]k "&o}onࣳnحW+mL)?E""̠ 2 c| rqjg9GϚun5jidd bq0+#}>~C'Ong?r")3 gn_ EÂӊƠ跃ap%Mn5K"'<;y鳦_#\s`vȀ/Ä,4Ā L)h #1'CA&Բd!e#=*45Y ,.H֖UY-tx+&\ERr"`%~P#bOAVZ!( )_mȖOqD `nYleѲ|ڄ۸Q !(Q:Ѱ"Ĵ o@zK.Z,y{%d !{݀Rӱ,G jWK͛ (!?pB+=˲ao6(9.CtJ:, C&_yU{~,'Kkwİ.nݹ9Yb|^D? 6D5sɐ?l\YCTQ), b6&]_gDDgC.,LLb~GğfVu%(̹xgwZEd浆B.'_q@ni0!Z~eAp(|f c.jNBB 0!T -8:oJz=% Ie&*]j5}twc&"IX}]:Ko.*&8yC+F"Zulp!k}W/Q[7@5ĔÇ*h^Lku|0(vkR7({Ʃ;+Nav'iR?RO̦L"S2lֆw>K~"*fDp?V2[7W:V:佃PsYloӎ_4obe|aXf!bA)Y..ìNk\V3ռePXauڃm~ǥďZ'Y:/ 5} ƣy]9u<`/}qM^NPsIH#gi8եOO}t 9O$KBD$;%۝xW DQM'A]GZ4y7{Ϟ%4k1St)_W}k]vOkViIࠆ_t "n 7O {;NE^G$yvklfAqvF#k"[mx/pQȟ\|#wsf,i7i&}6ӿ7,?AxK-Wy/CWYsΰV`[W'`jI JնN@HL)_7V75,&tČ}̭bIIhw=ٶaY:$ bǥT$e u1RNUI!| hX&h}Qk 6S*xD& >V2 ,D ,;J~ d4:ֶ8utOՄ08,2sŒi)e|^X;@-[0/Rr"]V ā!Nѵ:I])5>AJEX+QÍQJlخ'>Bظl`RdY6zj|\sZ+mVJս^W )3s-!Y6QW@T+Elݒ^@e78!1BBY|>ˇ#5֩3p: a1l ǕؕR+4\D%scdW͢@YVF'&2Խ^Z !;ZյV*\qTE5)+rhph$_0;{`2d=VNkb0r6OK/ՇSm3͚bȽcoǞhU9;x9J) δv]k%矟~)ۯ=X4q+.:}\ʚ BN{is^zʅL}/L ;/<O>ēO?&0MЙnkͽ ~{/9WZJ#V"7^A>Ah2X -mSq^'sk:Su.uɎLG.6 PMa׵^'sulpM>rpV޻Opc>Ľw錯[{8[硇o/ʻ\У9lu R~ &qÏ ylǦ?zŎ+8,%9wpϜȬ~%?fӧԯ~Xqo_י?'*'xG9q/zͥ7ϼ>3 Mʚsw3*s<F76Wd<취oK9|1jW1`o׎EG7o;SSSC&-`Zk"EQ05:>#8倁 L5c"k S?%,'PڇE700448nh.k- Cr;;!,PJ6,:et@8FsFH.&0h1Exa.ц6vZx>rT6mC}ө$ 'y0JG\ԳH;{o2TH)'Djx[ыSCSXȆy-1"$DzbsȥD(8c/yD5v?b3ݴ1J)2x_aD]!y =D&. , )%>(@j !3-Jpn4~Zq0Q\FMyچYJ R0C?WEQ+V0JdLMRuq&),˲tr_3.O摞>@@h ՁĄ+y`-zyCMLc{k_'50ߟOVk}8ϱm/6^ ԯ?g9E!S,g><10gΰ5?Sxj ^N#T(ϕ,qqc_ ǭ?3C!Brj_s8& Eo7|Q=3jpx~Ԧw'?ݳ0Mhk/o7و>So]d8͈i IsVƑg] 9~FF~u%RK^E6xr=` w{[:m-OhҒ¼>E6X{}>_YNdc*U IDAT6̎^/ƦcP՛h呧P?Ģ 5^@j Nǥ8j0dHH!<7\KsWD\؍_sI#O>ja\7Z ~c-=a5zݷr/}3~x#:z?k'?sd<WtznqG}dݯ{O}t{y&Xt~9@o7}[lse,18gCn'=پ!I?y]5v8hy]S?Gc"fJN誚̧-'c:E7.3DāABܪO@U70o2FR7]L`?Ǭ\N4<ֵHYR iۓ>񒫖S7dSbpf&>%42 s}[VUYU5<0044XqA_)DjcF.Y=e{ mZ 6 dz4๹#5h\ZmDFBiFuBUvDuN]fz[bmeqtvڰ:+5g sRJ+F, }7l~r2p;N{ƻ° 4ZcJY ctpob kRJ)XճnS,s?c]m: 3+ )4VYaSxjj8&( EE\[~3wSG"$%F+Qm!ke!c /Ҳ}.[^6Ne:6e XVCKp1#ƙ=A_KRG4r,ęs6/7q|9!}=WG@{u\)a%+}oOO/3 MU80lS4?nJۜugomgϳKM2.b03@,W҇gs׵'~c#3f3y=6_rM=  ɥ O>ޗ#ͼ7~fCgG^|?>C߿Vkgc>?ˆÜOBHH_߲!ZY%Y!DmB)K&|W8*qM:oGWyɠL&J8" CF˸Nn٧W !_(b7F'l{έ?w 1<>_?gVN^n79ys*!¶yFӒ`C4Ub_7~ynH(0(XDu7 W oXǶ;~ejU\/œM) ¼kՇ}_z=y#/ g-p+d78Ԑ~>Wn>_o =pyW֗wmMw/=um|0{M?X z{t'8N4nwvb- DUbag<걕["6ؒޞ 6G cݵfQ@K)/ר|EM?L6Z{!7eõV0/&Tj 0פvp[:\h4 Р%q#5Fz=Rj*L#Qf[qj !>mҋySQiʡ n4Tʲ.H֣DCMMُuOĨ E?8i*@Y-`~*ؓ0$'ؾGIQG#5"1`O%BQtdD6ʘnkʂL@R,YRD)!3_aJ5mr0ȑ@Gwer| J+ PJ)lAg|֛K)˲^2 (\w, #&Zg/oRZdOp]q0iҕy(B+`Osg ,;@Bou|1f,xvFGA@j^W֌vͣŬefIa!E41@͹]"n19lV8),Ys(ݎ}6Hj mm Z5|ڨa%:<r&yTOF;+"#bc ^@A??=\npםsq)_}7Pe}7)SW! Zs_йMVT#"G^W;V[m_Os1 ^@?JY⬹?GbŏVF#w_9舓]cS|tN+BeE?rƘm-In⍒=A +3 RGN1& c`)U(yvIjz<DU]1gK& w`1I;NMwE$~a1P*Nk_B slg#(eQu:`?Ynx8QvO-wnBʶQ\ADSfⰒ',\~&*gR 1j@UeiE"IWePwQ"\o,S)Ͱ-7(C?."@+y $f3 %ļhַͻ# 8A&R̒jv&wVJٙ r 'B1('6ы#M d F(p#,+R iu{Dd[eMؠ#rϱw$cj,^@i6~Vb[Xa1۾a˲f OCkclnˇRUe)ȍzAw.xJY`<,G`X`?m_p,w>)3]:Kgv$`!k17|g)1m[&c`h-y u9X*:jWt"6rL|s'[f@) XWXs /?e|{D}Y+<=߸[.l#PHMm$>!&Ys)и,$u> iw"LM)tcFHxPm!`v,;MtͳQ`zo>s5ߟrց]7;VNhBxm#6xX8w2^am¥w;?Kxp";EZfQZc]3<۳/kf ""TYj#IJ[h0Rʢ(e8=ABN  Թ+2" Kpe(V)%k@XJNQ說{u0y(Vnf,P R(@"EmyoFmx3Qq-t2j3a!S+T~~E"Dݙ*ժB씋&A ]Rg `fUYX&mnF^KI.3mzp$vAl xpPQP,ise,EƽgYEYGFbJc ?+lϟ็ ]buafǟ~?)|$v)X"7 +{ԵRZMTL;4$~,4\]di;,k)iNfVӑZG֊-d#,=vVҲPcblaYEUUvQO62] WI !rcXp81_rR{DJe~( )iiأ@hdFz3Bv:UY6Bү9wm\{it| y۸5 aQJfa`Yz&bQ-<0C|DRNQT Hgbͦ?Ct e0Ffu3Ӡ#,9Ɔ4rϟU^>oQ{x]͝ڛyԗWsv[Zπ,Ĝ-]|UouW͙an1mf{ߪvSF.p+:ܿ^Jdk(kJN떛o[lՓ_'G}7h9'շs=RZկ%_mza.Y#[;?eo{Y\+Zyb^}`Sq&F&1j2t27wJ)3Y̐gp<)_uݳvhqC?8_znoyNP>s VU"ޜ?] צkG0eΕ>;꽄޽½eY""tg_{U[5m= Q뮜=iZkmǑO~?7꟔r={ f&pMx܋l#v/G/u1 @Eqs yawW󇷬S_o;{AmW^{WG`+n]a꫾s>t8kQsFdӶb=T9Ī2)wMכ2mWNR=poWA5_ϐ+ouԏVmk}v}cf!١J+ ~3ulU #5vI 7LMF&{?!D؜9 6TjuqXJm"V7[ 9N5q&sȃ;)\$ 2=l_W+7N׾y4Ԑ4-q>F0ȍ'ikjc@!ŸRJ] %Aɻjm,O@(TR'#QfxChZCXQڤ_YDeJoLaι 6AYAk5 QU%"tdl߰wiAQ*h'$ہnE?0ٽOc8ܱGհ71 ^ND6hБ"-ɥ0{ڲ_]6K)R]NUaEdD<&,Ojm{'h # w2q _##d2q66tik DD'K(\QBj <[< !VD6 9jQ ^",ˢ,4J gl3ֈ %=ū_uK׮ySwXnm8_Bzͫ:ҋ{bM|s-߷u0sũ#1X _?9~爉'yeoͺo?yLmv+cS5~5⯊߾^+XF$A=+ыDb#}qLЛ?1_Qg?7鷿i21;[{,|orUnPN=c9W.oЂ]r:GWuc?rdP/4tAϊ28%3.%į')goKL;ȕO<˾!ޚuű^)d-Q}O4NdB 3x%@7"Wx /=?8쏧B@~Îpg_u֣W!wؑN'Pw5O)_vlѶ1hصBRJzu*2eeBo̵ƈ-kV"P `l"B cu饗p{67Id,m mKI{j ZH^].m YKY k8@czy%>0vAzG #Cc0 ~kKO{m&r'PU@Q׵Ru BFNdc sn^:AzɩJħ_aa ^ ݳ䕪> M)LpAn0&ж]F,V |b ;#hN&h>-L˰޵lEď #q _5ٽϑC:xT:{,6~`j~f6v-/hj.E;T} /dBxP^R,؁&^kØYRk0v9hYe%!JQ ]VX*VUEDnE<ĔCY }J1$.e%ړ\hcQzCa9YqPiFC}щxt ʈc$2Py #m- @m v:D{R*NpyeYjU)U]!2 b`hpt4B "EQeښaxx~GJìҠ=EQK DC]O/.Vxem003Dk(˲*,3Z3'BY6VL mtܟϘrN_Z X{YZæN-Fh׳NJ.^LX::}e`cĞtC$t:Rʑ[rE=g)Gd[mlkQ:?M[m 4TUUu*To qG6H:55D " dVZH,*BJ69F##rl(4Fb*;U5Xv[2%0̕ 62lg@2YLeT\0tiB@:E!ZwK.k|"2),/71<c.CƐ bӼp,PUpX /M}v˂@a^.26P~i|'hm )5uct{=)e!@ƠHwskKa}~Vօ] Zս(ʁNUUn7g+tG1AJjDn+}lF\-FYCؤJ\aGDDREAa2et0[Bd"躮6dfZKLqH&gbNnM,Ec6:IjYw?D,c6l~SJQF>e@sft̊37 =p|7a(FӦ=V&1Y]ǻTrv?0L !csL oIZ:J,cqŲrã^s1&[wsl$"6E2*"hNim0#lN` l|EV4ԩ)a`FgZJɀQl>+D$`&1Iy >_;ql8eIZ` 22F 1aD8BDł X|zQ)dCLA&\X4TlxUQK~Ӷa((ʲ(_* )Qf2((f񲕠}ږ\?s?so}޳G1K6{풚*tMVPLF=Hu,oDD6ȪA%hh!Y !Z;锅tAgt+*2^]'bA#<6 $!NJg!1C]h(GyYu]׽^YUY.Ydܸq]2EzB(.8yRJz`h^g۩03&d}!g5\x*gd@BML2B@h7hI,\Йc;Gv)K):"!nѳSٲ(˪HAk,RvRtl3eD0WfBOg4Zq̩W=R#ǥ̀ۍ/}6)Aͬz̭e%0G:R1xBvyw}z8Eb?_kwR252iPKi[ ު4(FMD%v}?7'?l oiͮ#jha@YH&s#"hÒ:%Q \T܊Vϱ3 `у3#Z8f#4Op)mxLT1DE0\s?gU`1(P Bmhf I(4.Pޅ3Q#o)R:T6ZL 0& 5 bq&--.Ԡ^Ci2WϸJ)S4NJ",Y wF,~x.<'|* αb(삯Ѧ( r`at^#H:DZACmRBH!l8]VHYU,*  <5 ă6,b* &ޓ.rDO$(74PeS) #:HdM$1օ:eikmǝx|2Ɗ:Y'ðk$>"-вHQP7a䟂0eҘ ,yf#HfO76dӭ,AZ'-;t;Tg5xWe(R-]퓙X) *Hp7sOsQ1$|00@!5w(hOp50p3o K<˓ZT˾R.kdт)FZ>ǡ!K.:/QJI 66Qŧ гTg> 1`K 1 ,(lH]K* R_bɇ^r/&S` do I1d^R -S?% Msl4BE7ҧvB"Bh2 D5X,n7CP;Rץ, т|Nz{(Rԫ zA@ɵwybhM~gt]KuU/T;#%jK˫F*V@icZ.;z6=R @hJ)@4dRJ,bOZ"x!qn){DN[06<ߋaReVJPgySXԺѶa*ZbY^,,ҒQ$ڨg/]@>( x(B #(D 7O3-}s~1% CĕtYgnY"K.Ʀ5207h;Ke1 ˒'ˤ.qq:1Sǃn\5Z)LIwOmxjP#XCRAzNBn7L`-[lPK50c>,$V[hm1ΔcȆmmGr^x~(X\QH0dH2ƻO9=ح$=!.\Tf=o!:[@ԇ)Cf}߈~ԪTLM I+·jgL/eR#΀ay چ2HzW"\^18)h["Ι/V08"RAۉ9NO$C {,=pǁ)FC)QhÕƔڶ`6-iOD ?m#t&n3 Ҥ4sEll'\c_g!2d/LΩ;Q&- sགB`]SB&jfz"UNg@ Q6PO&G?mPVrQ@&L"?wN %"@$DBQRGgMVk E6P7nB 5ػcnHeEDԷ}DV !~뜏2\JI)elPa좛՜lO6]BAB&S4 Wd9 PtQuBkoq۲U ?<޷]kU;J("'({yvb'l (HbdV " " 4{~{WzVծ;F~BȽUN(8S6x|ziR jl^GBgx\c3ҵaffASpAZ#L.*ILh1닙xȍ~P3m}I[i҈J!>pOwD1e. &Ke7wlfn6{ BM`rW9hXka09tTк$D@'Z5zNJf ) \d5[K[l.916ϳ Z; 6ꗰby04dc$KHCP6d4!+FyT?6^ 4M.|"EYV  tRqaC6fs+5{D9I8]10LV5öEOvJ7JI2=dRBE,ÉK~q٦ʙ Kp!; kf3AeQ\N'"O*HHX-%s\.gb!Ff)BM*>cA0q-pǮ"ʗ*#^Ģ4O'T݆{snݾ\3&(Q<̌H('*Pe[-ī22[jѐ׋]Ib";~j.u*`BSHA"J$\ rs,09ƙz2/BlKqaԄв̍DVTn413ʹ;ؗxfjgfB+>fcvs'© ^[] qw_劥:DQ%=i:r䈵yWbZ /r**Z5$rX+ ZG`M,v%6ZƖN4:U 8ca f`i p xDwO4qS+As"-Ad7lϮyMffrJSzjtcvj*9LA2SI~ /tͷ4J:@؂2 !"pHRKтC&- s?3[4آՁBӒqyyG"iۭDJJ IDAT6CZcEcclos`-؋p $iA\UdVAbn8(ZD7iaPbd >訔Mca;c fJ{@@/h;bg_."2>xe ѐoQ({cA^9Dϩ!atT3^cb.td`T1PZ|WWNwz;˟FPɠqԩV)IFk;wWo.<lXXONDKa3@XL 6[S .%ѐˡE5\7!a !\f.'D ŪBE/(,ƪu8>ߗ}` cΊBnEn'KY=p+:м^U-2wD0@@f@ˌi"`@#`%m%r%-!$_`{;Rc )zsBŢ "Ȟڶbm -dFBQ-dey8 (߲ly`,cSsBTȦ;ւ'đ8J0KE\?RS/0sg%^gyT2nj)Uajᔽ9G 78Y[Թ²;EF)Wu7WSRVd˅{Cdp3ju}(Afn*LE`458Ĭ`:Eiհ szdK.nwr[zcBƆyyXb\ ޓ!c((!aIDJ9VKCH*a9 S`0 R< RJ>ƥ)Wjk=W9d8AU Wr 3Bc)0SYل0ir3VԾ.&+7Ve۝VcGcE;:V|ؓbfT+\)To^=\J .8 sH L5ϙʵU\=2Nnu;:Փ;[ Ot;Q\a 1ČL2C4{ F+Zl>{V5R'T3 ¦õ\u#Va3~k XJ]_Lk-b:\lK "3WpLzjX9'̰3&NQ4a4ܾʬ*9 B% q/ a{ۂ8r98,=EwX׼`* V_5κOh5JI*Xk*r|W= .G@A=KȋVjC-Ei_Ikd(psZBaC84-8;l; h.we11^> 40~i*9Zz[ˆESq{>мn`t`ˋ US$f*ێCyZ|fsϫRjOT;(^!s8 㸿ba2pmގک ks9Dmz=# mC8ޑif JUbj l ɒ1F5C6'n7I8;D]/:nnȃŀI~"dٍ`Cl }%\"*䐔dA:~DB&JiJSgb9.9 cVr>A2LKTm/[$IR_ce\*ث=`nHucU6$1W#j,?V!335윓y 0qpx&} #BЙR.nFwƙf3\ջ RW.ɰw1ؐ'#uMoqvq4ΡSE0Y)U^%I TEb ɘa3  y;CIDLB<90# ["D#3?>*2Ո\1eAjTaE͢ K| kNq)ךU%=6W#"KJzJEswwQ,u~cajflC0VtmAT*Ѣ* i:[6; ^ݰAGn !l#&W q6m~K !%dUұb$̉3tD[8y-._UG[kpr3"BqՐz;0 C09\Ƭ9X&DRAH 7Im(ʅr3T|ɺ/[ؕ€qa0 RqYE]+µt2B=tj7fYrb=w3c&ѯeGެu.o<Az6֬{`ȃ(Q%cGhr`(ciFOO/&G!!xɓ5Hc7FFu`&&~7+gmޖ7yͶNZ!Ca=KH fh1qG%}qOL"2K.rT;Tn(Dsm+S⫝̸hED–Nf EphQ̥sS0#Vȁ@6OD QȉPQ~X s=j⅐7nFqh&9Gtb0Xn"I=YZY!*|Q0ZC%?@xXKtjiy:k-ېܣxyoi)Z;F'Np"#d=\zYex2Uib sT/ щATGOfYo4ю0V6 ͊>AçHtY yѰ,Kxq}-5r4KTfg5 Lw*-*`u io#az݆)Vѳz'JK0UTm1k(UE YNٶ 'O*"iAsy%9yqNz'Y+J-Vma*)v 9c|d1%>f0C4-ΆѨ4)P6.*xKL&8%Ze܇YW{§ar.vORX7NB.U<'2y?^*cѕPkcS)-?6֘$n^*| D"R}bDBOh_2V`SBՑO?.=C&Zl8l}0ZvW2P륞nk7Dh(ˏ$*݇!0,vD$2L"3D1b*AD87%JVIVS*QD )P)GQ.C֎0yN7i aLIv4!c"z+ Pw"c,#a"]P*(TX1>9/\Ш sN8n};.'v~]XMg߁\!q($f!{Ęl\3ԌTPF(Qkb({ByBDA\!VTyܚ8 y݋ѰKV[ݏzeK}V$V|9XcpyV^xT6UCudRQ46-(9WbRXrk<ۣuˎajeAe;Jx3$s5`#4\ػ"bGgKKaB@+z΀9>o2C>8>~W"Iُɹ|i DJ`79i|cH|`ch܌FR.!Zju,сAyJWU)7:j]a`U9k6ܛaôMr&v;۾D/j&$>Z^g6](A;6Y g&ŨȚ!؉ˎ*bU_Ra)?Xv! ~U#+)QhUhYBPEْUqOϊ"7)W&dQOMS5XϦ .j fAnEY`\e%: gPY̋圼kQ["ep *_"r劌@Hrͤz `/IL R}4Fmk ꕱp\*lqY#Tjb;6gìYVJXZJƀ1fvB|46!!t0ܑ W_ ZeJF 2g6 t7 A0 f [lA_o bj[*- IDATuJlBɦɨ6ZNЏj`v]cnl"PQ2(տVى")ʧ6 #$ξ2fW+ok`tjnj8%"V;'hz7T1?TQMcܰY&a#OgMQ`ZmFovvD%fs'.I w4R硠|#{D>dXUsR™: )󒓂 eOZΪUGIDy6{{p.C;'FT J'Q$e3$&(!7x4y< \ϩdE@ρ] Yَ6&7ٔ ~NaDu=U)XT`^A "k8f hiIb[5 )I?)tZ:ʬ8eQ8YѪ͒at urUAaӹU2Ae@)f_Uc5yOHgEo{\^|vy;[EݺVɅN'ͼSŤnG&Ҕ ^Sy"5qE@/E0DB6r`7!ٌ0{OD847$LTssqU STA %0]/ۡLpM/|=#,Ev6fi *)*b0'}] & ye"]`-7ɉ U5f;$>dyr>@c*'keQ Y(iXIQ[ TIKdRҀg+׺SNV:cKAG2+TK9mdx$U%tc`yT[ר56a])76֘wߍFmG}PZRF-wnVa含8k|w}'jVuƤ̊[c"!̾BƷӌ(#l$hl2P;.ό  @T/0vf$ 6̨pN]Đmxy8Z͌ȳc W\H<ߊ[.5BE#hQis0VaHٛM^vI*!ckn]p>3$jU$٪\R%ilQI#^ert+KJ ֲRw`,uX뼨4Ӡx:J\ضfIJH]~5,~<ĂXZƹo P7*ϱ?I,*!h  %T\nD OgN籽 rmxY#6'fiiQjL]T{AL %@/@`@Bk-OӤ[F2!MufBkS2Ӓu昄@YyaEOVI\Wg*tF rf_)uY~(ec`XLÿDflw<" jnZu |Oo|9ւBC^7=lx 0B b!51]{qEBȯ3ԸzxӜ #mxdz?ϞB4vv(y9W*lk8dwNiBÐt{7;iAn z]RX\!B!ȟsbGs3.J;i9fK: T2quT. Ex.ɖ'fXƹՑeu8"6xaƁ54F[ ښl1^Pq0Fm ^JqjeW 0q i§#aqQ@yꁪ@=+̃6J\ ̈́!k-@h6]FhVzJ1];Di'VZ]oy&3l-$j@RK4Mqkm|,d)^w ŝ|o1Q00˒dm2phB\b. 7730n* @VzߎXKw-pC`c(>!t bqSq ! =/6T-Q%Z²`v_ ~*W]y˥֌XI9ZJVsQG,JZ2hHXb 9E">jaMJ/5kΎAhi"`"Vd$/eMճ\7mvn;ME\E*hK4i1sVܨ=XHAf08;晙qMDfGB]7#<fQ/dej%DBtϪo1d%2K8V"CErg:\>_3~a}_(>wsυ;^6g8O}{Zw ce판:0Ƞ+ )jT ik0wS1R[+,&q ɿQ(%i6P?CI(zĻFJj4~Ér׾Wn&GČ I_G%ejeTAq@b+]ӾZ7VqX BWcվ2b&>2O|uSD9)0[dG=ek6r`J#gcJ4\ =QJ3=2O)2:YkeybFlv-IOjVٱS(2J:O $oT`nj; \*re1ņiu|ew:K;8];<#$QEMJP,;XVFyp=I63eDczCqD؍5]n@㏁%-x?lj;bܒ"yXcݒnQDbg6ø7++|$믚 !:724MVkT>YG;:qթuɷ<4`hFl! ʭE2 9ɸ"YktlˊKY-5FbG\s"0[*nW*25f M@:te&F}jR9;r>)\mqQX$WDd뤳FZ31Ԭ5;C`C48ZC|cCsiY>&̖'R o9ޔr?!,\o`C݃NmE?|?NǏ?|VUK L7t@{q>~\УOqĊ kGrNbnQ2NDA{?L჏;{Vyyco9`"y6 7N[% L$\\Wf-i\3Iw{͈MIBA /8gDro eFH!Mc8D삑P#cG,P@ nUo2C?;\:FB78l#zG#)3r ߪ ^94**vA7v*q7eŘ QoivNRN [c/ a Ve 8;zֱ$zϫէ&4(pɉY1ls7*6*r:OrG,KյRYgu0 ^d;e{5+ՂZBšW}@~r[t\̘+t!po[m#/9WP6ew{ǰj*Uugt"8:G %j4P msI!HH)6y54dÜ`$޻10 V}՗ޟVJ=^`{}\kʿ/w{g_[='~N\bUܵb^?25_ Jˍ)c>z54 +H뵛8_[w؃lhP,m̉(b(ExzoeM-~Ϟs ^OSA|m'A)j0$_do>C"K[  I\<0 <7Fn$*^z/{G}`>~'~AQ$I/mq+;ϗ)~͎-Dܧ0#"ȍ7mq|[5U;̿V*|li |ѳ(J-xeGT~JsOz 6x)Qb*h[(A۸R="kuɐ2D`Hʀ:|']崝K$%$V$?&-OW[DVJk+貳9d Gq@"V.=Ox ۜ!5HA"$` AeϯlKuʔ:,x^ET*`0&sa2:rqpuw j ĚB;ْAo"خ;c:NjfTAj2{~Tyr-|Z0 γsP˶V!h颓E!`95BCtx1Rƣ1Qs A/⌂(!Q}"L&2ffXsO$W d1r|~s}(ABƑs<Z dmrLJJs4ʇ@!W+ R޹ys~./e"Qt,!~}x q0 q4F /\E&\ar.r°8lLrH]Wlqg#q>q e ˽v:) _u*%~{T~\}uhnc+~/{s'GϹt} }ʑϯw?߳oѴz;5 ^4~9In%9$! g?c׾ogW?93bvG1=9ܫ4ED," p| ؘ0xAkEȽAdN,p% Dhs]D*Ӗ/HJ$TSbas"rQ 3KK#Bv8v~F;5YmyBcpCv\AS6u%9 mxa{`=>tȽ LP1D`!ifpqE2z`eta=nc`fHsPWąב hT YT8,NBE1*Lz%fww؅m^WЦiz0j6UP'U4X1|R>gpsg+hƌm<ͳXa 8N}Yv19;7!i[y5q(<4ΉYLD0Q9 IDAT L3 ͕Q@DIzMp_OK>򤳇*zǽC_ȅOMݱg>#n'>m=>w򍏞%_fU?r獯س8v ޱw?{'Z3}x?xC>v}ѻϳ?G8" 9ǟƋOػy~q?_s j]}뮛0t@sxD^q8qo狟g_۟폹){W߽? ?-/~cF]DDOWWJ\y/y/?ϽNͭokm׏?p3x^;m~}7膠 &U xEפ*q=/=>OY?}ǣG}g?8{/ku}?pFxYO}[?]fcz4y {7^/M5[ڻ̓__kӵz۞\Ww;䏜aT2,SVtGɆIHi!>nIZ$\ @{^R\HP|Ҥ%ZM&+ܶgkL/ω!ayzdɽ!HM6`؆1{& v6 Az]Fdk,*V (^@/&Eիn6B홙qc7a08mFc +u3o זFK@A:_^԰VYP, ɧH Al\p $kXS64 8kA)B˯AqWuj"/3p5Z%A՞^\_"ˍ>dQ&".Yů;ֈt~YR\yF0``$ +R&v`({ yZ&½q"d&E(mLn%`⏊4[q3= ih7l$cpMTVZ;"_K&'UV({0c(vN)RZnj89\ԕX*PȒc)4 oMYJ,l$yvC ¢:|;X`^Z#ӯ0M754y˘<hj-lSs}L"yL(ϑ(Hb _O~nti79 p[o_ewKW}hΫ~cMU/x/ ')s_'g+ ^w~eĵ_Sg{knoΪvX k3y<|?yN?cn{} 5<]/us_q}3F5;QOY~.o|_\G/|o`_p^> Fx;p+n=yG؜.\x=AOyo tݻ]}z;S^suXH~쟿7F~o~:os?sG.|៾}q}ݧ'}Kᾧ]??x{9w8RY-HlN3kqDDhJ9G|W ‹9:u1s<%p>}{~ֽxd7˷q!,:7O~7^]o<`<}S|y|ur?ag0}X]/x_}zjۜԟ9#י`z~o8_>M8?>?hO ^}+sY 3;>p5"+[MRQZd *b)K$igAG$+NrkL#C8DbiB@͢,(QirLѲ2zRfe?劚kR Át1shkZUd"q%$I{f7:A)E w$"6Cd}_Y3+b~8 QrPkR;-TNπf14nfldl,f;zd\~-QƋڽE>/d|A Kg|H'ΥށфD U'˩5j)1a{ɪEZIAcøN]lWPXWi@ *=@zIJc%rzfu҇s擄R!. '*o@9;?03{Kxd̉R'04 x<8~ m>d)%3\ʼbHn0v!Du^BHrHSh D-.Y/b(K@ аZd ruzʳGcFkOv*$Wx/GiySҶEzf"Zc,(<)(j ynd=ƴUbX-vchjh#R> w(ppNRy@,,ȐS,xۭkއM!l!KO~n}g{=S/Gܻpqӝ}ۆ|w|0̗<䖏œ,O(Ul#I?7/Zqa=_{'x{?>mo:M~70_uٕ o6◶.CU vfge݂jcukː1hlyQgPV^=GU 3S1i$n")IuҫSBFVbi/HghdkyD"%R#F U7`@6)(}bG)dB9ÿ *EdQTof@У.7״/+*:| a:yG;Xka;A DB ~5? 'Z> 6ZJZ/r2Q'5 >y;!0Bc9TBydmaz6xH`%6T.^ӢWjvi;O2d*zʉZ*`!)L׳XʂmMD6L%f.,:75 M."Mܻɗ#vS+/j2QW}K?'v){o|[a)_'vuÑa'w;.{ٷWؑ :uW~m)w~]`s{E5cWϪo_g&Z_W}.V瞉ܗ/j`N#_v5__ᷝg8f'Qo Ի?>m)>O> ǟ }ϧ7:YM@0p]ʥ|Sc(iuO| fd/|˜zGY>e{򔿿U?SfGyȵPZ;?xڻؗ}X[y]`8S \9wEՃuuO}o{^毼[S/)W/}׫AvlNPF)9¤]C ֌EVֳE*G\Dk_R+s -}wU9Vu A%($u]QWQ@]L+b5m20k0CJTrf=7ԽU=33n8~ŚQP%O7)ɲ4HŬNE#C#r\ bE=\U҇H'|EpzCT$%?)U čP7"U̜= 47i@xʋdRV>*a^ L0ӗ9xBqwᚚ0 =:taɠUm iKwLKf86VG$yۤrs4= H a)/GD ![qYpt#UqOc#8*(V1RS]DaHO5Xʤlo*픸"JmRn|5-9io{=wq<+s^~eK'rP$P7ȱBD$}zžS߯{]Oye\) #ME!$Ma5p^˷;~w}taDO/߷W_p9>(r++d"e`0ܯn ]c-nc~sa$}lC~6&)C <9yrG%UzF&+{rȐӿ_ ;`R_ZZ bHN0ܙm ʴ@dJ0 "覤ē1\PnKm9vi) F 5yi.Yb8c.B6p"cd?Mɟ1!t4#Nw Im5*dki6%;"MT;:!Ew= AFQKû%!$XM10ʄ2JVin布 k|m윒\3p.B,N͙ @[4%FnMbtu1;y\bcmQ5~A&R3z<"0XSF7 #R@ M VtF YYn^ZC%IrI_a!M3Fk̍?Mx20GGgSZ]4GXR@dsFRۧ4oebЧ^tӫk{WJ#ip}^?VTj\pXۣݎ==Ta?%W)C;~mO}lݣ;5'^Icl)ba1JPq'.w2wewo]wo-mJM?7@۝ 8_^N.͵=p*qMAIMYtJy" c3*FaV O7v'0kݫAl C֭{tܻcU-7UIPiښBO}޺q3\f s_<1սb! BḮX3Z{س ND}oK[׍ktMTݷ&D/lt1PhaQ{wۼVV6N|o k;/]j_ZI:q1]J&. QLb~AX,QS|SiEd*暈X&==6n$G.M:[u \0?{igd=X&Ere+`wM!8-97P8 !g24 !sP1wj^sCރ6 ُdvJ>k_b88j Cnm~vgY9A-s(S օS拌aű`l1!u} /A) Ud [^T {0 $&oCv:B"sGZ9DBj&CQуS֫ YUrvYfA!P.BP# gڍȓ&$X9(`U8q ЋOn\?ui.q0Ȱu?tή55=v_{CJk>skqS/toCm}bHki;>^ٔN{bjXlΚ,n{z[gk/nwC>ߔV]u].,yػckS>W:gîgs?gV~f;9mЉs'.^sE'?Wn; {6q+*{N\v¡':_q^=po7}C{Y^׬uŎЬӰvᡙN;M}4zt+[iqd 8d0.SWL_ 7,z~7KW}^tbݠ'c=}8M箌V!~^Ǟi7axdv ]A2O^*\Ӯiµu-G4m;ѻg>{_3څ ~^ǟi7a)xdVSj4dz_>]yhYyͧwz{ 7O9?g}w;/.S) ħ/Oۘ&Q0ʬӀT #Zc!Fqs@ımcG!I2jE?'DdT>֪KRbmSG.9˿tJrRGH'I9^!`k!PS| @'>2 E,Ϝ~R' @ q)W0ِ(ݓĊuW1t5S(:R׃т:]DCy]3ʭnV[AWO˕VӀ!K;R^L[ֺM3M$Ι$IB<ɚ} 2@N'[pqpv Dt1wܟ)yYFtF=" 0c$rRo]=QNNs\J2)=p~yE,Z*#$t̜̳S䅠P(0$K K%&crmT蠶` ## 8cD!,Jhkw nMN)g"%;A7R(- f*IILm煀\r%)h_lYKv l-_;|` @~'Z5EbNzd)5>"R549gAQ,q\*JewWj r R`n"IRI)^KaA&`9*N\+ J-ϻ3,}cl;N)/`?^s.e0v4{+(Ki{W+ո)D@,&YJWr?q+G0c.06wF3@Ba,ɽӰ%QS&KkQ{CyX3U$8R%*X*aPSSSS,*ѯthaQIăU-a}>d&C4 6:)ȸ@JVEk-3]N!PI}GUȡ)Nm2$< W5* iWW4RsV`UrfwevWy:DB~&TrڎjKcnO<'t2 6"bDMbOaVM}WdJUTRy! 4 =TZ U8c^I\nC51=2H=&Tz3uiu555E $T>$sbȦLe!/^9$QJ~.sES\Ij+[H  )b !7C5<tOO)1YczF@J`2ZB=owC bdYt3Ϝuιz1vzDFD*%s(b2q)^* 笮P(TrVDQQ,HAP(cB c ,(69 4NMW onm{8ABZBM\Z|ꎆA!̲qSg#@\o8b!ʋBVr RJ)dkhKƐs΃PhoI+[99PQL|5kW!ݦenC[yw8UǴ{jNQ)ݗ9Ĝ^9BYN bǕpב%򺜑-@ٰg% !SV҆GY1U ElokeWGI&v' +uنmȗ0I@]&cf1a/ W5 fqx^DHUxR4.T+m2LwV9Wi/e, E#)8s](-Jl $U"*DWUH~\"#ezcuƷJsh ukd TUF 0U@nfF5BYA4Vd7%oŽ3@塕h}aR??H@3>!ꢗzN!'imH= EONR[aB,,51e@֐KP+$~r]+%H @KD$p[M"RYT(ZXpjo*G(Xl$ynQJ:&3 bfq!àpJX'˄f6- dh?-&A_tg*Lk2EPBW&>DSV&^[UzPIҫz_)bTjB * >+kVpD)%3R!1L Ժ@ rJq\-^)w}''09g IRhkI)!I)$"'bys 8Vj6z!"8*XWA`ZJIRKR\dJ"n%gR?P:霑U꽜 ((۟o]ۆpj8{xбkK.'aQ87+Fo.T{H~eZ)&8)2 NҼq!{ # 灎zM"!CCV|9"sUn1cLH xF)#5ɏu)DLJ %Q$)` 0bKGqS %4MxɈKV90 0*) d$UA oj2[dgE8C@BF$H竪dȔW"\V t*Hg3!7AƐq"ຊIgN!Z`LB۶%L"!ee"ua,B"ըŐԁ:dx)nf ɢ[PNcR&7J"#$ rGq9 lԵl5̛q2 ["c=U})88gLaXOd5cGkqN$ $(ǢJskV/fqnwBTO 5ʁakrחT6`nf &rD3v˷E y ,A+ VN-:2tJ;gj[,$AGJŃHZwXڳƯnLJUlH+NBڲAQHQ)Vi'8u&&`uc_7UX=;./ͭe\Ʊ?d dk+b$@>%g*E$=S.2$NQ e (9pwXgZĀUedD$bFLQiU{ K\cǒXȁI|6L2Il]Ws@(Q@Ah !EY3mY.bmmMaD bgC BFq\.K2"kQW[S, !3tܳ:"S|d$ z1YI.;[E*Tz:W2Fd yP9٪^ʢWB1Wy@`6U 52;vdb0 Œ/&nPdT1۞ɟ̓NӰZ_3/R&!`eֈΊ2- '*j VTls%*Y]U:6ˉx0ȕIi̓$h:kYLU+fIW _*\'S_@#֋Ԙ H?Uc1'JDc:qe Q]8Fh2*U h!Ej @FXWQT$8!gEq]>H5k&R IDATdY&%0D+&f[PJY VmVV?X(ijε"AcBbiK0ōMMa$Ldr%4xM@}C:Ƃ c!@n 9J2❱}7ylӹ#*Vx Һ ^Q7e I*ToU)ݜу *NaNg$i8wz9M;!Ry/IƀX_}b!eaLWo?fV|Nܳǟ%bP\2f2[c=gX[(H(⾬tIOrʾ"eJ3VXHݍ3QxWS?"L@aB(8NahYV]5"B2.@h{희A\21Q`84Lr*=ү 0fpszMؾ+[ّt5bA Y.8N5-.үMRIaT*56jfƲO=HI)`sZ[ȁ$ %8VRF RRJn%'e`H; * al3MvnS5q^( BK6Bƚ˸2$"f\Wz2:i9/5g?._9weHV7V?cvrTI?3fOamrnO71Z]/f̪>N'~} l9<_M 7?/^|OEYL'ˏZKq\ Bg/@ ƈH!SܷĉJiͱJ>qem!sn/=!#`"05=TUvSVȦ,V%d乫qkR^5 N;Ǽ v.V̐+nrnc{z; w@xXjgU.VɕXDT5EAL%" *XHA-ĸIG;/n4CL# uBMՐ@ "AV:9f!%D-m(P"YtΌ 9jL gBn<,տ_(6$YAJo,V!*1J)PߔURqT*E4%*RJ)>pHq,VNfnUG*HĕY^Bӣ%(G9'=ק.QoX|j7׽.53sV_qcO{^ ]c'{?^A: %v&nz( @JEH?GvՖh2$Ч|#gSv~ (/W$׿𮔈,ڼԩ>εu]qds/7¯ -.iђ^mXwnkoa?TK%^lyV?ߵas9(ڠ/.@8(y@"T**C$u4@jNg2UPA#niH{%@@V*7цj4H!(R(_AdTL`Z_͓n9w9M9:;g!vݖ=5Oamwc$}9/v϶ɢtxo<01M:N}]Jk~;&:M7Şd|5s/G%6)!;hy'wxvZ@Ú5bg6~J+?yQЧاzl!Vgh۶4]ɟsPc!%{e^3/۸{橓sw/r ᅝgnkxSoݷ {74k$IO4Ǿvʱ{o|m `m#n4'ƝtҿZvڈck0GzaF-= ̺3^]IO{ǿ[Ymz_|ۍ߮4'cHWO=B}9力/TJ۶aVl|u M7,[Go‘E?RDr&xA O|M$Z(;u YǺpRP' e bsVUع_v f{}CwX1',,'=خmy9:{onf}Sa}p57OY6L{{aa?wNm lۮ6\B@OzӡRW<ݷh¯~ݣsJA _y킝/'̸ȳZ%As[xֳ[7C.Qnr~;+'wIFxQ|W"l3Gx@1Z맮9$8ZpPWFܨWGîPs_%E/~ǨpwWM~7>҈WFxQn [KhRHS/#F2"+E8cuB,D$$#M#I@)eX(͍q3@F$cbMJ9J[6W= 1Tz Ia6T 8XCD!G&2JSo 7}YRQVo?WlZ #l ranpU[VdlC_ m oDERI=d"d^\&xrY^5کE&M];9c4R U)g,rRhXqERY`6B*zPU΍&6$cŔ .[\QrBAYb"'Rsmf+Ji6NUu f^"-(Oo',f5lW +}Xzƣ*#We գn;푉g|[ 8f`zrwIa靚wZ3yc;Ϲwֲ5O9j x=8ʆc ;לһשw?? Y#}pS:^d!7Λz{nrB4 Obe j n@9oS,̧E 4ӴuaK"!J5D%"Ԝǂui ĴHfwD95|=r|gxn#;;WvY9SlmpOݽIRH: P"Ҳp!|MsǙ'pՏLG~_ZUsVm)l#~{{vn㘿{Ev=gv kH>#V>y٠c^nn9uՏOh `N5yM;"ؽUHv8 8g6P=XMr=}ͳs%ʇvĊNpz}gu/ BA7 5'}̹W?:AOpA7]k?<1lFr:c4vb)UU^ "!LI)M0ȎUƃb>EYn䑔BssY0Mpi3YTĪ!1ѺE8֏ E(`TFMtE` 4Enj=ܐ|,3L~nNg+jV` Bl1sAaJ L\GT) )XťrIamM1 8H+nKX-\.s[Ԅ!I)Pn)c XV ,>1ȌOĸ2JX(aPd: 0JOWSd}`*Rn=H4Ax f^Cӌ 1uO5"Mu*Wtn^yOrj, 0(8RpdhLUDCG2 M)ӬHړCU\xN*֒hJMgT*g<`p R"sΝV>2]NMS.j&Rr:uaB m\ι*62*x%Iiʔɵ/ 8nk%۶M7k؝[v߮^jmj9tϱ7 o]SF;V ø%2Ǐ~9>UGyC3Nآ2\gSFt+? 26c6{]ܱb8eYv}ϼꢻo:?FDAӟx1ѯw9*orAn--{{H.קY7{M[G]w?z}@c$qGo|广6rA]<94>:aLw@l~-o)k$p?R1/Dvk>zWvͭԧ0 >v']x5دGVD9 hHYqnYa7ɘW $0!Qjִ~mͥ;|hzeݚ[6,JucPZ<٩u!,`kފl$TZz^AkTA|C?]z -8$9WaS6@b뉛ݿɣn+N_a >lws."Mj gr9֕M綴l׳yvV4?D ?Z CN ߼/Ni%w>s 6в/g.Y!hُs'06;e] IDATvJ ?,)WBMz-tn&}\㼉Z^'vխ|GLqn}·.:ss6f/]%aO&KW󧜌ÑLTVHHc/bZӲI_^JʟԃCL "2&0Xʭc!8%[~Ʌ7)M=^}f6K{&9WjҕV.]0%M5}I igNUUL l$?ǔS2UZUʞ !l(5ѿEϲFZikI`AȔ9/R|,YjU'G<\kPhH]NQ 둰cR{h?~JZNdzHj.^]U%Q !G B($d@<8<`XR"X.DZ$2&wʤ7fL) )GEmTAp@@1kD(a ;֎ɂ 6TD>]9@>\QT0Y\-8ُ,#[B;_lzI򗗹xeu T[Y(KZ=("~VN.E0x&oDPg|1DX:ɨu!+ V$AR# X#)dHg:8,BXLE-39̎<04BB)`ީ$57qRt$1egT8?'iK85Z6DTP=f{?|m_Rnu @Ns],tQeKaCbisS1e<خO=0 [ss9ﮭ~aֽOؿVʙP^̘>·?u }}J G 4ՏSg-os"߹ԩ[qïFҕ9nBY+Lx]_mN֑3DwkݩS7٫ wn>D~Pbdоl?駙+|ΝjL\Q96-p@m/ Uh5FPlQ`=[Oܴd+a7օTk᏾}hʍGZBH &w)huyӋam3t 60zn[紮;]uXa9Qˢ5V Zy[ҋ&`k 5qԻW;xdXطv5q;5xcj^fwo[iHԨ:hc{$jE%Le"47i޸?9rܸO^o|@j*Ħ/C_wkwГjPӜW\lIK6~ؑ23&*%fLiT7֢'F{u׿я!ni 6}7}Y9yZ'>9=Lq/|zsM_3&}_.i0H]@a,Ԏ6~#^ '_BEQi˜Jd]g?'j;n'F&L7XH4oO|}܀&Lw&jǏ#PJ&Tk>oEL2UI"8 CZjq[p2.Ҥ'h;I_=[OzQ%11X\ʑ"ɵ\ʚ˻UI2GDFsDƆ'@)+! sNDq,4@#sRsQƕq!s΀#:K )(2Z Pjf`F 0ѵ3tckH(Vvz ='gMTRl2kev`Ѡ-Vn~ψVqFIiٰ t(Z:صC+H8+9g޻.(%v`T KQhbF HԀ"MPER;3y8eΙ{w>rw)OX/?c浛V߲rjku6U,XlM= H_'BN uhvp-?[CGUoY-Z }{_\MIqn@ދYrv},tH`l iSTu(0PcM=0vǷ ۲wNߴ: ?k޼ۖrS Ju+75 VPQC#+D@ ){#< a='~&=춓{0 M,_EqWǕfsow~8t¤3xy/{~3b>G_xy/3:nwAӆ0l'<:N:şRcR9 O@}{^\i6lİ}3xy/{ӆw/&|˫A)>H7}?<':]>|n;ܗ,∜+Z$:}{agc5iXsAo3b=}iuP}zc_9rKɲ 0#ꋙ `Ӓ 4]DVR_n46VDS -FrR#+:M \lGL{r >ix]J6q0&6NG> 4xb'& *ӕM ̆!j`68'΍®@4yNM3n K D B9Ⱥ<,<[% D!C!FQKŀrB^DQs|.[0~8Q4Ok1}'\.Uw,\Zs"ٚv $?KY 3ۤ|- d(DvEyȌ-М[Er&@ +,,+򏢃wF))EN`AŒ an˚2{" X/a8FYPҋR :+PeEQF"H&mNmD"*JRQ{KD%+N%o3$H6-Y@B~|]ˤWQbIɬjX>!YTrS a{z#o D9k#w}lSA7,[uﻭ0kd*Wtٲ˖-_(Tp,3]}swf05On{m[5D2۴Pvitvٳkg)Xܹ;n^9yE0.ύ߾{]k%=+zw !!f.1<Ȣ+~l4o;TwhҪ^$ȑEw'"^;ubuŏ-vW+~;v.Z92 hH %߭wU>TCxu-雵!Zۏ7״fe˗.[|uS2`]QD@*BY۶Dى) QPPȷۙbD# 3 v,?rA_svBWECba 5nY8SZF$vޡK`Բy횺b]ۻzߚTt1=WL}si0n=zv5)WG@@.5Ffu-iĐ׾[^sC)H6~w^~Sw9tp;)2V~5 ۩=3Nں1|;'{ԖNp;'wL_ԭ{2J0 SkEdh,Xo̾OuR8euNݺwIX7ι`j·1@!Z\Ͽ׽"wCטSy9w.\%84x0( 0("8JSƌkDV[ktSmQԾ`i[h0M2-97?6%Ͷ(,/ĊQy{2J 2EaN.q))%&jjΙ />.t;晎C&!ݐ"*!ц.AZ @FRI=^[f0HTWW!-RK\6_(s)2m$eJW%\GҪG0,vd?UZ1@XsYڵ ͐!rJly\&IaͿ/gKfHaLVT6ԆblD(e=,X;EǴ d˸Fq<9za,,U_m| !5.$-G=ﮒPi0IEVf Fq`d:s24K`N:&WWA+Re\Gf23s@9x.<zt^mQ0DuJQ:#(s+AIb^xO;}׳K;0tحN}ct ;s[פ>h!CuaUACvڷce~xU~3ϐ_qpa_lTZ\:=^y~+o n{z-w\^JxuCؿcz Ӑr-KzW65!y>hCn13v؀>CFw7ب>?[SSg%4|M޻so^<@ЫoIc];ۮ1bڢ&Ӟ>_.~u!; 1U q>ŝ޾SJwt^V 뿙}NwByz]|ν{|Ą {5xe^0=힅 6}9Gξj/Ook¥GһnGMbw5^΁oh33_A4=0wR}O~_UsyoCѰeӃE\ǫq^Wjn~<#caG]~];P]fד+~ ūg<[SNi@z6`;a\_nluO\ӟz'N# $% *Ba3/;=vݵG~-ulz1h|rjo9m^w] #ܡOמCGwū^1{лk!Ïثo뒝)g^r{'1~DP7k +/|qͷ7r>6kvѮ{cvܻK#qw97޶c WEB}Nm{q^7.^Ӣ䃺bQs2Dsꎶ~ԆrACzӮݪ Ù?f2∽-^ r楿?rzw9tĘ}o\3?U@R QP R)Žt[i_[sJ X50h(%d@)3۬3nnն)ΡDqcmڑ)BK1SH%}P_fdI鯔g8-*Θ @i8GTȌ)=7!G%l3$m8;dO[L#)ѤC &AEͥ$WU((<DQX,0b1B}瘄L(!"A5"U'i*cZ!΢ "il1z" /H[eE1̦饎:bq'#e:6]SBsƹ *bAcR=PX{sL7 e/7 (bSrqٷE2P%,M5coXQ},<᪮^ȋd|O--@~L>N`cN}.͗=ҥ/L5D`ٔ˯zՏC^O/-`Y3sk%3V/sOsS??zqx\U;^4eJNyu.㥟xjUSJ-{N { +nT;^àn;wGizSO9ާN>vuVp_>z_.ʂNc&h]2vO,_X'а{OYbI@aW=}}>BA"?qӟ'cj{hXνoELxzgt[XzߘϬRl|k;_>g8x%sGuqX%dB49Kz!F&5R餟͝:(V47-KyZ[l/kk㦙ØtKI(oY[ uu3Axצkv)[_(.vz]9L^xu;wظ;pu,VF>xKV#sU^ +ν al*Bqѣ_.Uuqx^huĚ""~.맒aINuAvLl{.Kyǭ7rƛӋQ"u%W_vsBq3=A "K?Ox"(%?iIɜXա-QpRX=O/|t;[F.J$]tLuKgTꔸ$o?* 八:~sšR󞿻eULl{&LZR%Z=薫z=n;ᢏ~b"ޑ8.m[5}HT,v>N~_Bb1~߾G,sݥ|HaF<7ۢg ST8r NCз.Z2:B܃ t2&rK4ɭKZD1mЛ![O 0,6v=Rt\"f o|N:w05 2zY~Ȅ03*KQ"F"RQIX3 EB"6 42ڠloKqALsNgEeD#D "#0 P  ð> B^]sJ0"aIƤZEKh&;.1 IDAT<YAE%Ӎ4i-_JFggLL". ^U *,maJ][smۣ_H@8Z9'k! 7^xqTBh cWZ2 lX]^MSs؎]bw1e&H;hZU‹|lF <9;;mt*LpoLDxܒA& QKC!ǐA~jX!81!DKX,4~,#V1l/*SELy e> Ў #P0R<(p]$L*@b{s*K> W⮁כrtS*h'Lӭދ0\Ca@A6SC,Ǜ T̈d/a`bg]L"h3C!Hb叄2[lhMeʞ$ ,Ĵ}1 Ѯ*qf aT,Q}B',<,3DΙqsTQ@R$ uLD4ES/N܈ r1:=@+Ǎ%D9rz  ]-2L>@ŢqFQHV/{!6E\ $ \Ķ5DS*"`%dzIc6.~Ha-ιO`q8:s'DTn|I4Ƌ_ #3y20WEd-ItF*QRH0e D0ZqkFQ#Զ/q2D(yETLl?p$Omh&WR}4ZDK"I֥Ŋ]VAk$BBE4R@u4w&Y;}0KN,Erv:Tw2漣j: )DڊNfk^" k@cХ]6;v_`z~^w#nǽmWpY"la6hU˕Beސjm93lFOۦ4"\cZeihG,ӢPHI[2\;~O$)2Rr_)g1&%v6@)Aﱸ9d[(Efg 0`xu~:3[ C$Hh- 8$L`Hu1.ɪSgBЂ%G_Fn2Neت%c9? ys99йmIOLp ,ƩI{$~kb bW&-T:c yTl#SJNօ1\.M$ UA"˺lfDa)Nilk Gb3zcB-bzgzϊqٔާTM:pt2VCM_O覘+1 BƖb1 H4R  6DBX2Tx!8'-$%<44#/s9Ή(" "@, : YU! ,[3@ uNAJ5==i#˒Dڃ<*,J"u guiA(7WD$Ui<֒qج)PZEྦ2M-Dla^R2T;JYAb={XX"CF$"-9gJݱB(.F1i/qa +IkHa!{3cAYM x2Ҋǀ2ZS{m; f{ O9qi0kzr;Gfi3T6)[ۉ-7*BKFkkLnh:C1E TCPGz]'>I "3F `69c[/v+uΝsӧfn2:aQٙAEzX7$ѩp`v(JHO5281GbNJC[k+(趢m %WhJBJ2%sح] &jX{jgS鍜8"rPEvcbFDd{^.,7MM΀!gL9O׉"!bsdd`egɊe)k\W|>=O" ʈ!;jJfUhcJih!1l6WYdd=~YUa/,T+_ƭHz3&HHoD=߳H[t Rm,)ZUU8+6KӎXQr)5r8H{@凂HU_έYuLD$dQD6f0 ꪼǹ"V1 K(  ^YҪq?<2#P$U'J 'Hmbf +]q-#Re<-U-IH\# ,jڳVft^ݹ ެp}'R$#aٞ13AP0F F)DPHSx LTLhcXJ4>S$ٲ܍DaagíLV9c,QDlfEQR,A ƲJ^1"!Sol'Yl(K-zg6DBDdvz'\ m>DO ES4XMrB``R20 AӴUdfk؈YR6!+?3YucSlؼAm̾F9J,(_'DNZMM4L5m1VV \HlVv-q( څBf ܓ\wEߴSvewJ=Pd(cq:o.b ˗l`.眗J 90|(T~wlF!)3,=ᄞ'eQ.mtsTkvw%< J<hhqr˹JnTlnj<,sM9"j)Ll)TxYUOz~3j AfM庇PQ A43sL I*()s(KnoNLdcΦq%FpY^GiK벬،kA #{Ȧlョ'P2u/W:T>LZV2wbk@" 0 CA$]d@#Ej?DӝmUwee)ylvZiX>x'\R0f[?s%ْc=:T4`1dOdUFW"m r9! r@T!66=jɝYP01jg@G_ٹFdhRS>7 ?js4KTE<%0"&;vfj;˻Yh9HfZ%}D8Eژ.iNH)YS3BQ*s)' ܧm*LtV\idnƐ!OQaWPuPjݯCOح*#˄Ip+wcťmoA/Nyڌ3\]J ;81cTcr^.bA W: AZyi4} KR̾%Way+1q h;k.G =I !%#@Sc֮lmzZ QnE/=WD$TW'sA9k}bBFN ,0%z`c`jl9 E9%ˤ^40MhV6Q 1LTZU02b2\2]@?j//eqcmSLjfBɴ ?bBHI!`0:A2V2y0exAXDU9aF_2æ Hoź^c|.!%(Uw'(Y$C-+v4 e= 8CX* !g aI`3JJ!{nZ H9X]`+|\X+~"$h?at!9H(F70rW "r,VkT^Jy,%Yoqss#Wv\{i14txboSx5G)~ R0I0aF"\Yg7e:Y+FBQc(,Kҏk\Ic 'j#_Wt$VDD\.r3krbH0HFAY3 d$"[&Q$H&tx̖8gJJ3)G(0 ysE$]}7,Ph+vbuJ eo}^0kޗ>~ uO;oy<j5uߟ7k—Y^;e'̚s7*#랚1oּyowkxz漅oUF`=vuߛ;k—OUsjDD˔ߟ3/b)cx/3z){]?79sכ'"T+X1^3%E7Pר~kGD?#QR~sۍwΚ?oy=sn *\-v9^/~_9G.-{+v3JP)&~Sa~AU "A{N˯q/.5o̹ fΝ+nxS9˹:}{x_>`Sf͛?sC;"^s̹> ]8m+㯛Κ9cmg=kC&FA-E|E]0sz{5o ՟y 9sΟ /:wޗG'8cDl/|N{|:o fΝ?saAՀcy̙&\\@cއ^;?i]{OxcdlPl簸ɫc<CdJd S N`ci)˂Ik! S DDኧ#a QȥB/8VЖl_D282HnxD5xXI*L N3eOk+r]i%%q=ړ[% *gP1H5񤿮Be|'Dy HڷI2& *huv(=։mZ,=hhuʥeP ! 7 q?6|g)Η[jL ]S]5tEKqJ2Ӳ1g"r6\%PD%!"2"b }s9dL6@L'[]=E #*N[sA 3 B䦔Z(? > =`"&$D /DHM %4JbCi5)EB8v͖,eERdZhƄtsE@/3)>ߞZ&# IDAT˯m~q['?uFUOWU5.xO䒮Vuu[vZ VU:]u߭lXzʤ%~ċ_R P|x̜8gnq77k-lۧk]觌q%XCn~:6 ԤRLZd;lqǿo&nYBsUSD};cwIюw\J;qE12i?㻤@7l2ڌcOeػ8f㗜>#oo,ocMFDc͓Ɵ:KO}"gW7-?{xa":ꪦo{9'}ǵ{^&|mwן9k҂ˮ<--&`SȵV1:Vťu߮ƃPm+vٺY 4z/rY;&j?{PEmgJV٭O?7>~w97Ϊoy)x:A/ݳdOzkOb}#[_uz?=9m?xߴU!O<=6O@"Ҿ4sҀ~Nci[׏JDİW%c~#MCf>tluۢ# f}u1~W6.=`'{Ľli/)3@,UZ+5-(aLzA# E8d6 dLC6LP+UD HOH\@nXT.φXؖDƸ2u6(\S@uMYڕV- &K&z'5`nNOh(98קi`хa ov01H2s$8<;A<*'JxǮ  yν( Z!"3`lCɦ aP}t lV@DG=n&K|P1  Z eș=Нte5SFbk"F"jjbOJizi z~xmFd50K]>R͕5Q$(. D0 DɌz%>Nmo+ڵLۄ-$<&;&Lk*RahZy'U.11\lh@E$jƐ3 c8؍B2ѕQS2٪F J93θ?0YzqZIvpJͳo;{}3.g9yN}%%aGzуga ml_>.οk<G]8|ç_T~OyKħzģ=se.niӱ-66 wOǗ+6}6 s/f)zyu~Jܹ6mh Lq7 iV<@Dhj9_g>뻖_|hP֮svT_Nosu8l SjS!v^Լ-BO|NSxYVSO8j|"ɫKjhX$䶖=ڔO6'>}ԫ'=h}ǜS&`WwXBYB?ܯsQx~%^`z⒳uUyo-x|m >fXer,pU6}8W.?K WmAK%It54R`תڔL i`m'B񩈗B.} jji)Al@T TH0S֐ ]؉ghAq2es9Oh%4X0K\oÌBpd3l-N%dzѪ!28ql 02rF#eԔQ`j`H$@GP šwι|3HRv#ӈT,ELh.TII0\(aQLe9yr<Tq|WdLݧXmDDP)2u~*O./ld8j燛4`v޼U%`o:]CFUL{fAI܏%` ]w^瓞ry}_ޞBj:3ѡ$`#0л|>t\ӧg藳w:/̚+cquG-lnZ[/=}o?7\0[#nii8+A4m:fvִxճwؿO¸4DE3\MC]߽{e]vW-0"mss륻)yr7nMf.kZeHHw_o2L)씷BSEE2{,A6<=fi!&ёD M*[ ͣ)6*lM:~%  N:C솺C,r¹7kt e\j= !"!C0^=Z)(YJeFjdƯ%LGkٱ2gbfQ,4XWwQ )'W84mh@D<1-DΘyu@ܹ~Dnc~ABb]=]A@#t.aLK'n66RX,><e-aʨ+q 2u3IDShXm[x?I # E Uh0ljnil)Bȡ 3=}O8D~,Ś;ԏgg(B-TdI0YU3rF$ǔRU b @B0WNYȿErF3EU 5Vw$%c(V\HHϓB\\AƘYRH15 mJ]B K$H}+\.r~93!(IPc?|.8^#NS1]2ooT:Ҝ{yS]n ђdYT*A`E\!@g/R,oMNZ ;GҲjLG2 ݷ-8,SϽy#{g~>~~gҭ_:nW=N<}_Zs"=x9'FBYKs.|ӓWFG'^qx?:ONS/:~}:Ak;7O󽺨<ɵrK󀮸iE], oGҼjvR vƵ;>vDzZu6ݏxdѩy'^J;b˧^Ǘ?doNį+q#vwt{i٢VRtEkEvkz_oߵOgذx]Ȑ~peo}ywt<`yM>=,wM[1?ş(8=:lهӻ I>?s̜;_Uϯϯ 2*br !ض}⦕uqΈ@H 2bw_t߶c,SϽ^ЩuZ9G<'tls6B "8!dB,>R)a or{7\UNWQǔ`|j)޲eQee+$@C y,d7=RpdRD(!ܼ|+Ric$9~WixBA!ҭ,^_!(" 0 H3U{"Ƣ6YAIRbfdb$( !({܋}1~)X5DzgNCLL't V,[IJ,48zGQKM-%2% EN'Jie꘽#Lte&ا@ECr[Pi8"G`1] ͌M\0 #"Fu 6W>DRbKB(a=FHI#;cC QZ g680Q3<(H{:" 9c Dk::#?%0\Fv] cVM+XG>qޝ^mJ7")?O!|#|;u!Xؘs[߿<{]ӿ9~mIib,w|52ǎ17m|b쌵+ee{ #--aLS7*'#cZ ֯^x!lܸf 4J&ףv"^it7<t_3p4c2޾kPdۛ2q ns~wh݋3J9ϚKW=;O~gEw{U.Owk`_p!\Nj  M+_yGa*H)Чwƙ5._!76&6%Rc ,5k_1cBxֈM}Mqe twŌ WAI*&g< CjQ(New-j ri1ąN<Ǐ޻^]O$Ɩ2aÚWցo͟,S"J4̽j1nb9ZO0ҪƫjBA!e%+9 ;g3:7nߑ tB ۃ8YK{\TQZo(* RRBgqH M:iyXGvc6+;(%0XA&hf}K[c±T NNbG9ٿ0i,|`9)k 钊0Mu<:<ЄL2-YG݉ C$% ajH2=iNUCweE(J2ΔDZ0dҡHe" RS 1nJ"HX;!"g!2V${/6L 9lƑs'-$7( H!1 \[ڥL/ffpCAԯv]wT5׋ Z  ܺtL{JWn2X'?c浛>ޠ PZ_WpnY9w5鵍PO>jѼns5@uـ* 5M1Ns_zrX/^ޓW]MV n8 IL"@Հ;wy7?Vd›rQ{NdKfI4mj;5 1jXW:Um~h|YDDz_[߿+qH-oh]On=KzD-ԯ*00USGy٣ٌ6䡿uSFuU9cU45G1)V_Ul&'1Ekl(_,.Xm5U^_["y^K+[~\^gؔMB)_鲣}R&H/cnEק냠nwK6-t M 3@ݮmo~(+]QȘQnS'NǎHn !Dc]CDRO[?kݸE64@Xt`M?mj9nĉr?UyqC75 yc*QT#/A/jL-:jXDm94fAn!,}j46;ׁ%k۠JYFLIe{ a[QF$c!r@|WvxdG_!c*wmnctW*t`&ooK`׬oB`陱 t>qS?mo o'VVFr ARIi.ln+V3PF cumg`Z97fYXL3""qNc~<kpfgAG?TKV[gQQNo-n2HO52cǷin~:x摅Oӫo^}=w.ί|rŵSi=M9AdSoN|V4zU#+!T7B'w׾e&B`g߻8eZ՗KP%Y9W_.=Dqjm% Pj[{5w[+ܮ:l_޲[ffOoiQiqƈ:D[s Ӣ&=^ Bz'T'i^v%3 Mb8ĥ㔝:udEE"V^B~%1"$$˴L4 ܘ ú`PCl_ F4*L40R zC(4!EIjEG;ɘiZa&$F1=6hFJJJJjjjjeY2F _Bxx UepMy#& ιc;iZJ ,YMH`[PM ' UYIցDz뉪1{PRPs~‘9_SgU9hx{T 9F!  8GLl8 NBL|T 71 L>`-ؒeY))u3a0sNB.TU }1218T3CJyH!+oKްY۷ô۟վyB֯a_ڪy.?55~}ʢ5n}ɀgiR7[+ջڋ.uf:?]PlWfi ۜծ}z1LkئYZ(yKZ){8콡 7lݾ]30-uKAo|j%rc] v%)|y g^srM:]wq6qøkiwYڵI!f:-cev(sҦûv+8۵mעN n׾]:Vh]&tmtl`Um_hSw^֦%W>_/54k>2)VȟZ347l_hA8mlT7[혥4y)mڷkFjwVu-tmi7<~ϵ6mw=PҥwQ2w^>m]OOUZk%#0)7Mokx|Ϛ 3m9Zn7GDE2^Y^QYQar>IvTm~zO{' +:{e<. ` =h~It SIA E̓7E$k.pdѣ 2.TyIZx.tg0Y7b"G_&3.gPêfz#W(v8  z0C%aW .T0q")Řr=@G,ds@c!ym[Hx@Hv+J {7 ð %xBDĹm.dFVC.ޅ:3s8 l@%ւ|WLQ~|"H.nF iZ&cB@HksefjhU)*&KDktn&_RbVjjS!1wCJEN0$|䝟3gwiێLki~JDZK W+70 4e%e8!2`HI2V{5 ]9(Υ&3^\ۑ^@|~D_=` "۱i/"NrlG C^^-;NM0Lg*M괂 q L!\$ D YџBܵj’q;]ɫW Ɉ^1Q;bB!PH:J﨤&~Gc.wNdX|~W JS{S Ӑ.V $~{ zB-R7GV#.egN떑u_+X!hpe4+1zAz 9PGU4Nѝmے . ӆI꒧i)ʊ q<|yS=xvWV#y VSpJ:/g>4wr:FTړ%WI~DFI%$ 1YCw3 r #GD&{SaY12 DATtd%LZH7dC4++OrovQQk$wKRwEY>ɇ|j0dBC-äE0Da0DjH/+iFRE(CV{&NQs<_ inT]j_&-ȉ]YMXy"M+;ftHu C'I,+--J˄׶x#Q蜫WE;8(yJZs)`vN/"=th1DZ_Xø2"B3DLF!2 {X31$@I/#Oռd֖J DuLb¦egeV Ag#Bk>KQܘ_7CdpdVg#]x,ѕmC\Qȃ2" l{J@@]1D۶"h(V٢Si?&dJku9we_N8]CR]B9$Z,Z21@|VM7*ۉ2$4į@shJ( 'X D?`8RiU=UmBZ&9'W;~kbZII7G~O~c v8S`i٠@ӫ%1kܱ"vS^nwhza c5_J`U9VN)[nAbY(=E8lFRAٺN'bŻ= ' ٽ 5H!?FXV'#%S(qNKMB?VS P+T`t di܌wb;Yp.'TJOp d\bDF2g#iZ!n^v0 _uP)H#8bJXUU MYsrQd*',2[WBv"8mZa 1Œ{XHh F4׃bfJ*( +"`TlY)%rDm"0CDRnH֕H%(R69ꩇ.JԢNK~D/P!#"J$tPv"R t`z*$0ILJy(SiDA@ [ B 858QdI%nfM`̙!Ʌ# x5Xo~bLֳrxpc` ]cPLn-cia(#8Gv! mf!bTW}m;Dd0fYlWszSwEwDOғقs##h\p"l?3[:YIE_䘐V&V'NFK[f AR -V*BL}~) "( ߓ pvm͡H#i k!2fXqOȓg(l8D.r tR OT$thtIcB,I*[ D z0 5k!'}#fkR1 .IA@Bp&(V1TCĪZE ?zL Fe?HBVRO"rݚ/2XTTFip:'"l R񐓳D~Bp$y-J&LdX,%;p@ac,;iHomBl~ D4PJy"CpΑ10L@8X &'%Q~V#2J(imuP~3͘R ˔gŅnUo1#ҩɭ6~t MQҸy YIh7z &A"ܱ!rQ_|z^ {QtQy_MkP\l Xu`;PJtHLAlO- _/t6(%k-y=[&HPZk*˙|IUP %+}r"ZP%UlRFH-zE[ A Fy0"G%ZaDW 1Tdjh1퉸YH)`Gw 6&닣R#6/vhJky,xDx+"X)M1*M 8 zOiuqJZ>|< _9*,5B^F>Ң 9ySG~5l $Q[`H{9޾N B5NhG'"T-+J (Q8?,FyUU3 FQx2y(HF^Dly?%E(L*C&!jYRsta2_eUuI'kLI1|N%!0p. <3ڄ;a%Rv '$aH(Wuq k$4 .O+IgzFI yXT:GQhVH!d1ONMDi#IqJV7D ?yҕx@h) ݅*ɘ W߳EϮJ!^r7л+n* EB o)LT~W Lp*\I"08Qj?`$d/mCng(W a؎QOXUT7AeRbƲ"WaW{eh2 а}|K1,ˌbX4 ڝH]YQa۶bv4?T}k3 i.]!Oq %02:Ma,Kf~$~ѓYv1R  :5P EֈZpR lq2eFi.I3d j-'an6c JZm!~OU Iϣ跊`."=CF]JD9KbM( 7MotmDF$J(Hz:`ϺX>]BZ_{o OU7G֣'ƔՏh,0&׸FU7t*ہ3\@z3 1c(矟ta(Pς"`"<6ֱ{,B "/1Rxjq+ܔcD*X[nC#XUS4 _ﺈ A݄-,y fr n B/ki!'VeTV'cU@C_cm|k#DQ܍m]M n> m?􀔙K#C=CL_bq"Ƙ7]0 `<=Mdv5_ay0̲ԶKVg6#0--5%3@< HiP]?/P6D62)I_TH;U_pNӤaiZdp8i V.j!&4B毡$hJ`voH0P! \YcEJcpQn1/ԳQ`!˄TTT*wG="c;Oli+kinb1 Gg4 0d~ b2[f,b4|SaB"Νx<^YY9Wp:)\x `>@6!s~2ImqmۖH hw9I f04Mdo):>8=h@J(pDһ]n-iPjd_vK~sU+M{kou_?|•fIZV;Κs᪵̠ Io/]~՚f.z݇O_Rrw}@ȼzF+_޸8 rfvsxjD޺Gẕh5u t3;5f)sgS#1eg/mMAnR]Pm.f^^5kvQ*}}/ZdUA_N}&)ѩIZ_1f'?]S0玦? um]A1̜?cdk=&@@r5~ W|nMSlj}kW.hu-5V&}kYgר哓}}3Hgtv]5W$sr'?{vZ~y ?}3,?.\_"pEeԾvV^~ኂ+ +}}]V+ +XW.`]^ڼOz7j_uyV_wUNtfʵ}mgܞe\8vY^akWfίZM,JIZ- SLиD!IN|}ey ?{k󜕅k qC̶X>*m%r ?N p.\nj_ʂyVͽ?mnOkrʭ2:RÈ.zy& d^8vY^AkW[}5k_zͲ|Эu5˕5g^xc='*ƃ?]|-__ME閟".8-I-iג/JRywyūsD1Mf/\Y[rai|`q+jyǛ)2b粧&~~u .#Q&7Y/7{Af9Gy+_\6̽~q)qi[+;*5؏+Kh[0ed;NxP@YieN[ᇳզfk\UUB9Dt6c~H8PJ.J]k37twLR*t 7^ubڿ-v.{͗:\N[3(uUau@|H!aqWL /ux?&ŅWDmjuW(ҝ(?vG^XR?_fW?ቯqgy>(H_sNQlĀ~YFM{œpsJ'@ᱷG^qcr {IOnyYO3qCpvV"Qdev1Ic/.)wR-nLHa}~u(TDb-oi/@p>ZkO ]{]?O|'pTM[[:_J@߰Sg=pvdy;#C:xڥC^q~SWӄEZ\Yob֨iR? W/._41Vs3o_#Dt'ѕ>{u!Q04rpget6`{-ޟ uQ[WE:DZ1d >qtrs2yk%yd“wk0 Ꭓ򜚺#W+lOvq*1(MhP/jK( * WD5]L\;CM{>pٱɃyG@?32G9I*nߴqS'BEE~oԿ[}cﱅ7(HNɾSP+ НP\*JtՠT{M%y^L|p2֯/lvFā|Yi|60Lm^v}uDX{FȬ_*سiæR@(ݽe#@fl޸DUQ R1Pbͻ]_"ל(ХX@]&>#< }qZ!8ˠÇ^yxӆZ-/rXlxէEqޜk=ZΜÊMBAW\s鳊.%{n(Eӻ>25IsgZ'Nk|ӿZՉ1kK >soen!4v^vo ,2=Ӭ\~M]x~k(Ic'& ! slfڿ<-ƏnZ41_V_mgj>hxKBFfzPv\񝛏)뒻#W7wMYywDD<(CZuS\}e@#eͫ MVG?;rQR藿X[*3{n[峟Iﺴ/^1 q& OrU<m3nԃ7> c?|YxJ~ŝ`־p`,)s e}zV}vlū>n;vzס#׹Ish };#J^_#Ow]U72@`43Q߮~?^b)ȸj: nm<5ޅ>{KK>rٱ{㱆]>z׷b{+֯,\ġgå:rV+Y]r ~^jw↓>}6$/?Ymhrxui/Y⇯&wY=&Z 5)CޭS]m`\ m>.fsj}JkS)*guξ[NQ:6,ߘfHdXmXj }4Z.91oꍥ krlW ?*@.-B(ëW;%[7XNӑ*)B  md3L>-ҺfvHu~~h5zUƦ+Wgce״L q=fv~g;Mػg /xbYL)֨{-/o?mc-fGشUpG/`X2ёi %juF+m8ʁ8hZ촴f}~M3m=P)ͯ2cW~).-SQ(n!DEu!buξᱵ[NpzhYv;U.ݶrO^p%]wѷ]zaǻ=~j>pE jSYi s!e5j\JT8Fsl_"ҵם.Ò]qYkĴW?ni IDATI{~yV̺NQw|.owGvdr)]ѷ]zQ Eo8ky@V+^Sra;I:!Yf+z]YuH@kF>;K:",Yv; XF^8빻{9-yَD>߿e69?1k1=$"sq+`g+K@*V~Wg{c#Xf^0{9e-ywxLyuI!&$ ~,ڼ/Xf'jx; ׇ-"]@yg':x*P1+Sa+W4֛?;|òC+~w^/{hMNը&_WnrqOTOuזES{^85h޿JD' 'R+-vCSQQ!լ!JTm& U$'B Qh%>foe.~Z6]yj;3uK9[唇xVThҭ~TEo VRIH/uP?֖n}zD׎ / ++^5>ȹ[= 5?|+rnTuk`5M;lñK[5 ޓ44E,P۰}2o_^b8buÐ -%LALWEkhҦNO~_p{N+-[!ȹ&{!A9˲m%Q9nB^rw9gLusa7?焃@8d*V> rg3o׬;P7O"$g?Ͼm} /VPuw.Yl~LӾD9Lo .}liu~ߧ9]#) #?#G]S_?@ H7ESz\8Er&fn;M0F<77j,a@lwT )=/cH"{pyl8 *[s֨y_{U,Yjg%/?^Nr+0GRe*|`燣W]*9gcTXJ4m )T7.M[ i^E@y w/WN>[˂o-Hlb5 CI:t*!D<HrnVKz+Yy;vȢYfMӎ^*qjñ-jKPw_wxhdX@rS(6; :P#KA6c_yeY ɆL$w)UjKn7/ `@U EV\1WOteJPAݡ.O@d>3Y?S.d4bhP2 !ȘNFPl՝O126ڋ[$fFk;pL2&7f d`I<qO[{rpՊP~WAOzSgH8A3E' QT3rݎ78tV2 J ~G s,(9GGJ))H1u 62OPǰ[{e0(2yZc SƧq(]'|PALGȮcpfL ڊ(;Z NYP~9Y !g('ߊFRf&&t,xS}w|U9wfwSz HQDAi HGlA)6Q PT 齥=?;~xOX63w=[r lܵ?^;@\Ns!W%[< 5`(v&K\j:Dȹha -d+"cw1^-D-CtQ͓o&ky"CWG̃Yt+}|UzJ[< p f˴émBGur;_T9Aw'/<|tR+ ^ǻ f-=wWRyRJzNVF[НV={^( AzX'!m :eޡ^ʅƿ+e R_9|)hw9twㄘߟ RήFO5w[.TTYdPv%РxpǹY7}x89C jxc$Bsԭb EZLx},,Q8v!N̈-iD?_5"y>C֞ P.L7Q &oM:޻Z4Á]g GTSÚ&-3 燉sMT43?0n>ӧ b_( yGi(]Aljd%EI_Il%IZjqMۘwHJ\qTgb+6l =k:׍C~`g2*>/%\j\ׅɰEQ@a8lWnݓ JVV$OfBsײWYoSN |*JV.7. "#;w<++hֱ3x֞su[V 5Hq9ǫjbdzxx+|>%DW8ge+e^dG\Wnjb% TjT];}Mpb`v3Eݙ󢚘TbRjKsmQgK{ߠ­̹sOjeYA*޴q%ԼaŌ9$>51b>D+8|\DDz8C<7kϹغ- }qnpEr>"C"]@K:x!,P[sdg>& E @[p T#PxxyRjwKv@%VY:;W޽z3+:,&D+H6J7N,,]?9(LIըLkz WCܼܼ<9(7Û5YNGɣf?oA/xƍ'ڂ8s#s3Ѧ(6@ lXmXhڙ0=]PC@GCi]Y}q=p߇{;nZ[;PE6QHdQ,ApVN9նs6ާ]W.l蔯rI*&%@FIhzR͸^;wJX^w+3b___}nޱй}*mgΩZF G?[9ZC\~/R;ITB"nW2Zbx?65\Ŋ=g޽zճO7 | xQ-s[#kV~j\ ~f^vcӟ.՘㞜1A *V(g3l}pbYA]bg~8tYU"bTu$iW13F8~2NjjRJqؠ<;|QS(g+OjP/%ڕÿ[>sSϮ+hܹNXS r(Jleഹ,@Juuu`E8'd>FB(]#ra" ߟҦ(|9u+f:l}aεc/Q2tRr|\=0*L$̺nʦmoᙌlj 1DY\!# j$0^LXӞ,?Kxjڠ4K~R#RL-3Dw jdE tN::"ն _i!~D*dJ3ז=[)QD-H b 6֧/"'78o^BU3FbLt%1@B:G VPQYP7Qt& 0!SL$㞈 M 3OsˁƄ`͢^-3[&Մ4nuMf%bfB,JP Nk8$FdfdQ(?B !+Ea>UeBusr5> Ҳ5Ɇ8@k[.Ro4%T?_G,xwWfSAj'*@ukV4jSUXŕݠ^[v#Y͙j]ZCݎK,㥠Yc|?n| #ME+_A}|ٚώԺfz~CLw)<:'z,.vjclZ5ͷg*jO76].~KoX6 oc^H;noҢӯS a#?zϳW+V^J5]Wߒ7;_d0v]5k7JǿH!&ժW~R~MU~j(s0Кs#5ORM>֭ͪ0'j OWoB)9ZƕjŘ|`7_dUmjjO|_G YfU4k`2b Td'-7}Sf1쭗S6i>ڱUFM_MowA .I$co?;d/hՠN㻺48WEߴj'/ǀ%TӠA kX^Da'V+ޏ 6WZo}z'<Ԫa7َ7 IDATm=3yqXxƏJvkVH+iPAz kРN4ձ]5Q7VIF5+C!OqP(kݡԬ61e恡-4ʂghZfÞor$ D0\$TS_ܟ*u׭Wy{tΈWopcݹ Şy2:O )J &6ڈglؚu,;X涍iZn/PIZ^ZU$Tנ^ݪρ(PkA6y9DQ0*J1(W J}wMw;}Kaת_~D3rAK|$ gjGϚՕ:iͽۘT2ri8HYu=SPjZM?Ƃ~؉`Ŷ-1"_3xdwgk>32}lw)y›tnռq m?7ﲿeLe;u,+;ةa ^]&(\vDbf|bkݯ1|shunZ? 3 o &({ Bf7AT Mz?Pȗ?Vꀥ\?o%T~>%wòr77tj85:v Trr'^울k__?v"XM$`l}}셡ݛ׫T~w|lA fPu| V>A¾::(mv]꯳ e'0K S_`GO?v>%X_!򶕿/|߯>u;F' EoYt-@ڤ{x '}契 dK^Qoح;y)7[ğ$fuo>wyb\"z@ϿV}U rn=rڎ błJR&EUTJ{?zz/oIt?kEY ܷV~c䟫F)$• Og5[ Oj?k r48Ӭ3w~5TcyplIls%-Gg7Ct'= -_[9Gv/жh^l^v_'k"@{-?A\#/!"cPmtxi =@˖vrāע}U,x~Ϸ*ÄA{S/O=mՈD^>㇥5¿Ӭ_ns5K1_@\0jRF} Jlgc'}wZVxZ^,CO<y>辡5+9He-fq/wkOŮ`O.xNw壈[ٛ"ogzF `D<ޗnɮeYO:4Ya)| C|_+ʞOOpoqqE|P0XUgڡ?RHáE3:1c.u=B n7qGTp^ѪIOH#Rv3dTˣY;7,(̺C1S^8+(82m|V{/~,Y'kx,0Poef|q9=_~Bw {߂] S8W>@+Y;~XzA3xn!Ѝԙߞ4aʵ 79#NOŬf"x $^xhajDPtB)"u"H*N FTEU )9g$Ғ32BNt ʃ<NN9GpꑒLwWoyNeQtWQi%?M t ݔ_F90FTAecP\W*( Zu9ZAOE JfD2p)#GzttM4̈́ezˬr1@ m#Zn1a0U(H)s RNTI15 (Dm p +#ThtAHك^O3A>:\cw/ڈNc4C.Ҍ:\<ޛ*]ėIN9jVacxgKX뷾aD97^UEOW_ȉZaܤ B2&ah0)fSֈ7 |~TX ŝtaܥl.eC҈׊􌠬bՇS(lDQUբ"hTEQT]Ӹbi7\%; 1A=7(XNдcbb8P0s]3bc9煅\vKa%0 #bW@dPPtK0Rc==3Gjc/?Ρژf ?K1F >4 "GTgRakG--B6Dx|@J\6ɯ5lccpAιl֛O3+kҖ :^:9QoA\ĥp.0WÓz pk¨vEQUἼ|]dSrhi3"Dc* 9es*yWz ^[\HI) //7/֘ FLEjѫ@Mt"v;~Iu+hy< ç@Sf˜s0$cA˜طRF˥)TӢs.?I{DFQH֣Y.7]"8 fUά:q q#$1PQEɜ K#Hd $!qnݱ}W炖؃-iePQDiˬH7kZ֨lM#ZWDF%A놹70*[15,\ׁD-2ŭCfE7@T: cTd]v(s{G&f?"nykՁd(-4fHdĢӞ[>qr"khDžE2& R13]9eZV18| 뺮sA^A1W3+[3 $ݬl?K#{f|=ÿ`%(Odv޼Dpci Pt}ric%(f"b jl$DTT>EUlj|br_Ly9:ω"[-QZ"y[d$ip掗#~]_+ADo1 Apِۀl/lG('9JL>2S~SI wAr͑"L ! !ym&\~$dOÛ!JGg+ɪֳHEm(!ܔ}}^WBGJR2~u慍u5Hj& QdfDZ+=87^6Yp"ukE+ Uz9̋(>Q m/|Mk-KrΈy&"1y0DDߧ0%;SIMs(FϺ߳c.O\E>5L>rE (dGq-ݏCjٖ6h/`$`4ƾ2Vpl<8%&gFIu~RCSy9rDm@㐯0P*`@B֝ !ի(\DT| c 04X:6bG/0ًh_B2;1Vt]5m VT朇?5M{882Z3[sclW*LQU-I qmhlH`䘢iS8s'sڢMEn2SpΜ# GBi$C]82rm|7R)pơ+]fIKwY ׉B!!lʕ3unT[<Dtc!2f ,;kN#Ak\Hr9<>σ*͙ bJsyM,yd`0b $e cT"jiaA] 1g7,XZmoTGM^'`>BP8!>UUáp0k v VJ< D'" 80v`΄MF3K%96q X":̶rԔ"DPDKRY:y}=&WmVriVsRJ|"-#[ds-gX6 xEoXngA\w#sSxU=n1A^T*ߧJ缠0H ߷^PJn{97^{[df2d11C!ha$==Ex.H1++SpYdIg-6 H6c*'r]D:j@- |o3b7"EBe9/zE3e (ݤRi@!*(2I(xQ U| TIQĈ Sk:׹, Gɣ5й HT:4] թ+e-ċ΅PT_ai+FIX47UkXD@ 0M]{u 2S3%x*?a){' U}#GtRnjݑP-2O:|݉lc,֍DrC;O8sz!0u,!~d'n"X!Ӊ򃅡`l6?"cLQRo(d&q 50rrK]aL[i027} .L h푳-]CW>@85MNdV#3  t":AB@GF#ɹ]h nD./:+s 5]74~wJHy6& EkJ( AtoҳDȫ$Н@v(%gYTxYHii:[K? 8ʆV)"?XT{SjR(:ɑɓp6g8Q8?,D:q"2sOL!A0G֠հ ;<(zc)`K<x]59d r]ll cUU%⺀1LSgY:hĕYUj=q-!NָʒE\a03jZ֖ ZVs%WmGߏ!4,87"yAng^l>9$⧔ Eֱ:zE%P)6V_{d.4\Zds |EtYC^HA), B}7ks9)b (lPlXMg?@;Ei+  su?*Ba]׉0$"0('ɓ>=xʟ94 YND9P0ܢkGP>B_8ƹnǰƸ(3s=AQQK ]\lEdT"-Mbszx{jGVcnwo62%n~D CNTFU "&Bѥzum=tWaMoeu"u]t`!="WrV,):Gf_"qN,c}mKfɺ>0ƨh r":X,WIq+wpDuY䦥lcrAܳ3{^!EJH*Qr?8vU Tl9y4YN,=׳wc !z}/X(~!7Lf82 . XB|;n-%dcl9kߧ*enyF| Ƕn,:wi;_k?2ړV#a֊..n#@u鿢sfNds)!iϹaMȉ(EULV$i]E M6]bڵr"+gz369NTLALL0Nb3l[3NZ 7?u;Lb;#8BQ 8!TdL6o){f5vٌ[Gr)ӻf.r:X1B1N#8dR)47<G =Tֈ|E"T)! KU 4CU hh6DJd>ge(}cccccc~ jDiX$P8 CP8|~_xe:P be<7rVQ@5hX k*OHl\.éPB:eTc`o&0R~U ~O1X9i 91A$ #"{4($^H\<<*ۈ-0ղndg`1@7׀qRҰ%M'@q44tHPX@e>~%JBVMj3t KM߱~KWKmW+^߸qO];* ٱ*C,񏝩tr~g+աEj/-jKV c|Nݵuמ{R6X4bm1o-lέi{}>ܸ.@Hg}g9u-m3tʟKر~KUbK6efdl\5se M2\Uz0f ;c|_i&"U2q馌]?['Hgνwݿk]ygxܬ-Ӗ~[zj5WU)CwzƎ-+&/Йc8GMS?\Ec%|e?SR,Ծ$ZI4Jhh{Zzo31d[K;%-ǫ*N@9f@goMؑ ]j)s\ӗݲwkWUxnZ*uUA!H/yώ&u#w g1D!W_H۽ We_votr4uT:=ekZK'v5;N//yWʞ]>бCYkWgd*,Se.N۹UZXSjƎLXR{wݙwgF/B!x2>RE/5c_jgUu^k]weOؿk]JN~%Z<6cR3v01JcԌw%ZO\Yd|`Y#!~a!,%( :F K֩>a+k޵og.+cujޝ{wM#.Cdez,;cyĵWG˫:&BK?"ZŊ4e'!(ezOKٓǦܭڱ'=eO=){ҶI[Գ4RS2v۹7l `A:]HPؚU֥gXDt??NQG/\cν{iɨ}e’vfjbGzDDϢf) n*Zݰ>" 5yغ럨"Mk^(UR3vn+DLhp{Z4c;aS;j;ӒQ*EU۫Uݻ/5T@_3\dfFۺ0$x )i;]6> ^n{FJz?-~SE_x}J{)i)N*!gC(gDqW(a#sq>=5$Q41ȘbBj;E0E@L\LL||\ e!7e*P8z7=N 0 *BHn{U6oݚ=yqCO1<>Ca"(ٛa t?*#II2^:AKv@>/>Dԉ4!lT-J)Y(tHI3[WⒽexw^jh!eT+[ga9M2y?('bk-:0pG0+G1'фnE*ݻz撃g]Lg 5EnھΛsd_x<E)-F( "EPJڒW}C@@_0 ԅF_lL 5rRhg{}S?|cu>g^ؼnosea%{mkv}3.P4<n>rZPm-{+ 5ftyo:=3D1y~xkF%d\#d"_^}k`Eb@>p֌^?~]LshÆu Xq1Auc~ڼ4{hɏ7׍GUk3~ԹW-<t[\Tɯ/=(_ALnڌ}/XH|_|ߋc{`t}3͡!i%Y#/Y]TCgU[?f]ԷgmMoڢ9OMޙw:6}Ң3@=sE:Ą.|IԜ71K/gx`~:tQJcA@:[Zun9M45=,y\({Mzlg,}9sKսKR  zY‰U ܼz<&` Bl ZWO29xU.0OB Z/Ł ^z;bߟ%>14EO~_Cs\vRSw.q%lL"e?7L/Jf NX=5:}~gS~y~׍#mڌ3e}d%eg}ǃuI6WJuPM\WW86"ǿx4ɲR& 79|dZvBZ-2|H"8BHR9cp1|~P{ƬYWm7EWJuEYPcW$uT1I޿ _wI?%1͹ײ.8Tx{c _|d~vޞujc_e?d93KyW__H'zLߟ/K}űX;Hd Z$7E5kho [d(0(Ζ#  (i S|X &F k!2*R_W׹ Qz($"ѱ dP$h4:P+q|{5YbG;ᰪ>OUಒE=XlCˡ.UP4W7$9웇S}g 8`r(BVI6dt0bv$!K r0$NJ!C0`ȃA 5P`S9N(*r E`H`κ OZ$ TH>| 0$3NBmfӪGG1ǣV_|{_?`kLO_ O /moOjn KOr CQD #`(jL\urށ bʱC M QB8u=|uGoc' $+B_#]?p|؄ bnkXae|U>}g ҭiYaS?BL+}jugt@;s,;;nk]$Sι!E4 Ti纗 ^ ٟ_<2HkygN;Vv5l4$yZe-{EUYq:7v,ox΃;KzxW9N[wjBq{rBjx59O?=K +ԻUu4L[c=k/x,"%39,d\Ws1QI/iY9VYm<U6j͓K+6.{/pP=7ŗ.yW%|{+f;C_熧\>`!Yq wWh\ #uzuc}y$r>ԡc'>q|ꐎkW2^>/үXI_ͨbNi:`ڧȔ-W 3>Q ?n5;*4Ǝ|ˑ .tz!/؈'3qOZ6*?!>n]jxd1_t<^vYRwg*We!0~dod+K2Cj!|;8?[o^^nT]1a:q_3iaD}&M|KMqO_83,gɓlIK2CfQ@8:\Namq|CI{?] o]:;6,î|g΄|bc{z{-5(ѱc L`ꕉK퉳wei$Rd9G)éʶk05(CDąN"Gˆj2^ӶJ7gEL4f} D1 + -M!H>\ ).lM}@1PfC${#SMks81)1Ra~˜dtv^s҉D⋍iW$ּ=)γA r6] =utiOn~޺uO.e/o'7-՞u0L%T)%]}g[t3\ׅ 1+e0Cdv/2_wyCۖV,3yCU)LQ$[DuV'/x6eT0WϢu# ]kjދR2v9ϴ,t]P 9Wo۫]ɋ]M@Al>(n12LE;fl(&Q_)@tv&pzXbf 8u \X45V^*wt~-vgڔVx%fSNBRkRbϝw#[U!ڏN"p@T';o޹u)l^b$*<$ս9g~?`]DW J< gHkweDQQvfGn*=jm{]RK7lb))DeN&]%$7K?Ls9PU%PL YBfIv-й.Δb%qFcLUs6U ڀr`v{⫵yv¦&-hğk'Zs9JbT Nշtpul;ö' 0PI*>uc,rg 2Hvl;ֳQងRwx0Mkp Ȑ&]q#Z;eA0@ӱ77ob&G箖\f >mWSS﷞=.U0D〢"Ȃ.o5T7:602 zwP!|xT֒˹lкսq§6m;%7m96v-Ú5mS!b&G}\ʨW_V=Vo>koXl{;Wm f 8" Kݟkry} S2vwQwe"PπMۮWLqO׷m ީ+ߩFN'Ğ%җM~Gnޖ'27RLXvj*\/Us XF+u]U)UOfov}w׌c,=*ؾ%; i"Kv"ZoN\F%Qbl \ϟ Ls;C o|U>{uĸ%9@e/٤JΦMZ_Q IDAT5>+q߈7=ޮ]HOp~و>]=ѩ{ߚ;0Y%>e;uKraZ7Ʒ;\Hu1|S_>k9{]?9ni y}\كqK2r|pnkZf7q| g/ٴ] uj2HTb(axOMI.!騏f?oW `*~u\wqK2r^q-2gz˃OYHӡGR@ =vUHY@ccci*fXtAV&CIMsR<@7謁 rV$3eVO BQq^9/aQl0@}|]3_ץЬʖ>Syċ1KXm B\c8mmg A@Ę6%ۯr` !bae^rs 1)Ai8R_0>dLO5`̓Vɷt}g e!bANme}e .@bb*@慳'1>=So{P}0ض< m`ES}a`X0a1akUP1T * DR0cB%ΐs:]wf.9sgܲ솅sZ]4UO7%mpIv+LaK([US~|پjL\r瞺DŽ:TE>Tn~oMw!IܦuD>C]Þ>ѷڮَש_7<=٧0kN@_Lyt4m7< v.EA(kuӢyOVğ4W[ބ*͎jw}ZY>TlwW^\Wt (PiI_-ڷy2oʦ}'}䋼XH3-zco?.虫Ԋ* /[7Nz}ؼc T@Y e Zdn=,bߗ.]8׏x[?X-s2{sZltفC?]sږW4& A CI|9c8~fo6虧{_뫈y9k+E'inp/hٳ@*4,!CO[,a2_SQס<`닾zc#;m ]8K[O*2_~inxj;\32܁ݬC Qx'O\\&:;`WlisqCu?lw9@VWY:qEdoه;6>h0sjҶ)lO+wZ7U)v`G{.hdZ0 O5eAZhJ2ڟ QNDQYu %6[_gFC 2B$͸ tp"iY@۟x'~,J )߻c;)ؒ胜!X=<&# _طk9>7zc`*U?y^65>{/w=}ܖO™4 ^{l-.|qO{-u9˞@ T.i;|lsqOOh2.. ȸDB߶7}ڿ4{yFM:=t읏_ɫ+cq Mm־3mG+}g9]_Z]NOm'{tB5=篍![Lpj˫"pXGs@f| ◻1חŬuL[++v6}44)]ތi$[i=S.=]pyN{v`SC rLHþ҄wC+*^?oǽ~of|NDZu޹&}2t.7=g;kwn⠤13T>E iW0埛3=?qw =4o]@C[.nW7 [qڰIdzqAkymdlf2/1EㄆRl7N?{օ~^o[*bggvB% kv_͓ 9@97vٽ|[jf;on^o>mU>\e 2D:q K!^;M37ǻμVN%Gm+L$nƱ܊w67Ͽ5yy 6N? -]ox{A-V%L¼2o ꒹l6~·~~;۪%[fLM:?w7Vt̺%WTᅋj j;3!g%O o2,۶mt8ޣ/٦L4LcEE/1sBOz g~8KG)0D:brYCʎ֌fĕa0FGVk.8P,.ҾWS b~b#B~$qr,@%@Y iwФ? AT)z~t xrSRq6KЮ>@(2UJb2< u[^_3[~A}[72x{4I@T< M"rHB*SNy>}@ǂv~fkY6cy'Tsc[@z^:nqd=VnmmFWR/f|oN=@ⱗ]7@_5P 65ͿnWIe^~Iu\xb98%\ |:ǡ,\Ȉ+NE>7x-3-"@ S؈8-P$.nY{` 1nI "ܷ P(8R6wA†?[χ]R9#zi_5`މAˠ^zw9χ墦9޺VX~~׀›?[Cٮ2Ws6́U"?\DuHKk;wUۭG85T)3oۧ5lKCsWݺu>RЩ V/eTWމMo*쀆^$|oD"RV(IX#ǧoJHں,۶\Ƒq2nXkʸ"qb}O!gNy̡V4pmYveǷ9cԵӿyz] 4Z*Apl؄}tVgyhI2oK& &f9xe@^pbk~x5䞠[e åjy-wRFPl/~f?\ஙw1X1/zgwhÁtSuM H*.#?07n֐ړxcUilz]jȔT{Q[EDx!GmL1xc?wK=0Dd7?&X|\4_$36jIw}~v/_2ρZVAYU9VX~q׀^Rdn_38۶aKŲg8{ɽNѓCd?4"S?pV8%%8疝8s2.Ch }#͗/{sN?oK~p*~}s!p4B %Bd:Q+Ι߿cW {ogƘY1\L]34k8C.w;']sѣW }wGbٳWɽzt{3 YLO|&I5'ΙmۉD+p=2iAA7[ V߶6AFJYh"pH#Hk\3+3H%]$k)Ee`IbCTMȥB@5*|cgRqe14># #(-V@׾??1E{\g./uW^-m"E.{W=J@,+H+XXqFpxw $D7l\aƝUe]c\BX݋}!WHT m}\+<@; r˷o(-]tJ WMPlrZoly#]emnYr{ ';ܲҕ{x_%7l2u\lزMa$qޖD1-փ\c^oYXXoi3jOWO&y-՝y]M~~۽,+]3V E{=,tI=eZ|v#|bJKo^!ylOleݏo'[{_b֗I?QOm!&XzUF,*/ [zCU=' mp| V pW@!D's6JTf+SgV~A+(e^-:8[WETTcF2|7{Ɠ]}j*ݹ0[z*S f9MZ4l0Hm$~tnG qVqvoGN+**./;TVFDsnYdHc}),ni8|;{Ɠ> : >_מNz,iAA oa]ayͻ0X;""ioF-VAQ{O{vgW{A<5[B4ڨ+&If~o%^QDm2s R+EDZ8( NCLqqPs(3~_W N@@B;@u-AoI6ʚeVc`$3[ (j dP ݌[-Eœ@DӂRW=>==w.: J~O9IW1pykx^E;o܂:w:%rGw~t۶ڛN[1^Aq!UѬ ͯm@N[}R;szvzyCxU5A%(-( @VNGwi$͏ܹsۦ 9vyN>]YCGG?q ;, Y^ˣ_!QM IDAT:w\tnZ7]޿G#:^y+/+q5??j%@w=|_?x}x zxcqǥRMD3>kkٱKQ& mٱKqQ&6&y9[ī|w4DkڵfXf]nssSoiS3Kt,R\Tԡ yՀ;ֱ n9XnA.E]lCvM9s5|9'総죬*^I;ڡSYUMN׃/;gO`CO]x;3s :ӡKqQ& u|k[t֐gђ"&íun$klU3o7m:9s$6wk49m7\zv~&^h;HaN:\ԥK& Y]>y͑I/5[W^xJv=DZv,U.6m[{2A9{" _ݭ%;!U:罒WzMz_Rv[0 PJ}]{ǠS;v8m6~0wm5@tk):;k|k]W,baW׳۱=#̒*Rs>(mS:t8;kჹk<(nѽk_~j.`,ݫWٷ6NǞzѰ{eܝ_}Z0`m;wj[a6EEEȚ .bv.>s ݥKĞϾwx?Ozt3>N̷wXZ5JKKW-W>7;ݥKqQESԾI²<;(ˊFqm'~<~A /{~Mo||i}3z3\N{ܳu noN^8tdkշk)TUxa}uo>Zͺ*=O}hg8C.yGq@ԥs.E]o:?g^Ts%)V~UwL;X_ġu5Gz_ήmktјiW|ikJg_ZxͿڡc~?b\Gt536>]zvǟx&^h7ܲ,{f@~eN<8좶mzvqO ͩSsmW92:D͕8c࠾to|bg`MN.=]O8jJ޸5ƭ˙C\d2ft DRͩӺr;}t݂֒StCξŋ_džsnoڜ3}nz^<'{/'Ag}[ܦmљCnkm7OɌG~88gzF[ˍWS yvܦEa^}N]_&v?M;a"CK^Sy=S6Gu=못5zh3h ֩MVEυ{ZP+{‡fФWYm;77׶-A2pT\^Gh`E$j"LU0x\O$$3j:AB%h4 2f[pNɋIbye0'Y,xAHz^ΔOfp2I7p|AUM;NXs[ɹxh?G?05q7p߭6ȦDr^>\+WI bQ{˳3Υoy[2(MR^]Mso7ґdp}qɣ&Z Uff~{uCj˷Q޾/ynb؏9ahSΖ׹//_6蕍%[9w-}{?X$8c3A$R;C#>7ᙛz ypP һǾf7x\{ի܈GfnĵaWwN2@nNcpɣ3/nkתlI,oͯ#f+S^6Q<}[c͍tv>u,JIU}/͙,kW1f{?j۷%o?o[D(S'/˱Z1iyU|;M7ftcye=ھ;Y!~ +;Uxf\Y|Hm[*gа/cP9 * $z5;f^ys V/^>.ǢvuQ8MKɢQfj)?_(}k87)7ޛwGe0j̬m-7߿iS>)N2Mjcy~37'8,+v]Mg׉CowC3Cj_8@U&wÝe=1s'貣1ֆڵlOsP`JG_ߜa]L~_޽7q۽l޽7L^b"U]uAX6-':>}WOo[kH$ zlpS~)'vSVR k{ 5|T#LZ6aO}}@bZGVy߫Um57{zui7+WΞ Z{*8dTոQ>"RJ~^(j릉#ZcO=i]!RM{H&m'*0qu W~zKER$9sdLe!6KL:1_J#!˔24(cBJQ =cU7x6p-c͍TX^MhQ(Q0+yz%B騛k1ħ ~X(H1ԝfgd§jB%}U* qIўL*iQDB 8cLp J=6pA` Qy3+S\n2BDH9vPIxN/o,+gcĔ+P,|0!F ƫS#$bޘW .PNpJX ̴WQ6 ~3!Q=l]̷`[ +/L3# 8!""ud_k' :O/~BΉH$)c23f!xĤjTt(ˬ1U_0~|Df}ŇjɃZ=Bzgjk(EfMKb˱>=Y^Ku3G{$QM@T+ޑ}?pĐ ` D,˗+L+8P!Wƙs=N!|bWlq\[YyoUp4^3*Ŋ,uyELY%shhK;D=Z! h*џ6#xKH jicШMs&ͥR+ 2xuz/Iڨ`}:pڲ&_՚pMb(R4!CZ]oUcnx9G~Y.'뺜1Γ99Bqv:fpe3+7 W#' u+t/!5P~A ܙ{Guz6[u<(&Dc!-L&m'l˲d "y2.LK9} i,Υ*2猈 DžG%aF}$-hQqWgj! KFGe[5UP0*1vR1WQj wA且v/3$"YWǠE\fBǙ^V∶ג"9[Vu4v19QDŽdͲMmmrt!= AV#"Ged!MNe^$ ۖe%롸KR9gNy$ (@bq]C&p]ד(K *际,3u+O 2ܲJ14B Y}Ӟj Fbj34odߋRTfhb>7a ։ eW eŀ!+ o1'')iW朜$"VWUfa 9=9ZG,OT$69R LE2g5aU Y2cYq9џ>$jʔФea,&)L1j^l}2Dd CK \D۔ W +LnhMA!hBBM6S Я=+AdY!s]u7A"\T55߁9 Ƅ7#&9GD@¶m@N3W#UL* P#Ƽs˲-۲l˒~*9\^N$L7? IڣA,BPu"G bf+DNN27'q /Hsf):8v¶lKO&%t\-3@kB-/Q3OTLQd$@=*22*BU@?u211{pQ#jԴ2@V.Cr \u@2LHr ^@&#C,= BI3x 4:;.$\[f9 HV oe9g^$TpAD܃s JCfΐq\Y3{K_YI/?PkBޠkV[rlD (H{)5TfzPmFyX1 x6l yF&FaA] ,$`pf1؈s+ M!d =6~?+8&*E @dzk{jgC Tr~I IDAT' *mƞD?#HΟ/9̒#E~0VzE6.lKvW}Íz$YxԞ<g2$8LŻjV3HXQ3LRdS u4}WuVd )+W `oW QT,óF$O[34nGPcv-Sبjv7W E"չsD&>C/EBK/3ԸIl#%1M#/C J% cH3ܸC2_$-T$bk@`e˻u.zyg8OXeqND)I椄g6&œWx_4S qQlb-gY FI+븐d2)D+iM [ o=Otm% yK+@:%RgÛ#sH-Y}* _͢?zB+ QBu}s6`#݈3%ZTo%#|fha"9bm1d^+/Jemȱe&Tw\2cwS1O-Kӌc k(N0YY%jb(Qa. N9= F0MAF=n !Hvp +\Ar& f^7DLiRFw6Jd`=yV/@Z'#1P?+m)LF bHtu`f("ƓQ笄vXi9>?/(.ʣ3:pҤ8`6Vl1[FBp¶<(|AUsG"IT<,cAR m Ɓn5:StNE%bAF7Ol=5=%i]#y[I;d=Q#, ƙJQ)h,X3+3Bˠ8'"6atSBK(0NԳ_#k\s7 G #`!P! œN#>rM#/6P£(>o$ (+24&f9͛(5)]uZAxC: a[7b k9$Ź4[1X04Pr !YMQ SWWeX+S%!\T|]E`uM<LDDN&[jM)ՌDz3^ O]ϩ͔Bnlr~H 0R ۀK &ƶDɳJnຮ S x5St]R\BX! ִ,K8^D QN!$2L2L$T2\ӁT2d,O$m#C=R$!Hz O~\A6k!UlfQ."$8?NO9y&y4:XB0-d>@m b[u؂QPٌBԿIeRu-0:) )ȓ oZš|0FORB!;W,|nYrթB{5up8qpJ>{VP:R"y1BI-;-28DMfŋ)C$HdeQHu`E5̒`tj:Ġ0ZX)"z3pׅ@Zf!c_@BcV*,5 )"ܒ(vT%? *ad? Xdz@"xRs*\0V &ƀ%6˖~YqruBB]&ŽuAd/`|ןa]JchMKǨg.!,rHB򚒣cbAqO±FP*Fa3$OK zF]4y+uAZVjOf*9.+@﹁H&>90$ D`sQ{/!tFksft]؏h9$.CNi*6z)BiP ~nKЙ> I <\׎ 8̘UU*ǐ?@$ (?O)¶B HOp]+QAкT 1?SE+DmVq`5(+O3*%T-l򘍞XM8(lRf ClQ QT5R S;Bx-snqq?:JNΡlu]a@34( 0cñ>>:h5;54Nԙ'!#Ԭy 5X<!f04m$,MtF*MuI~#1ˀ1@!\q.% "a](4ԩB+d}4 @lPV\MgbP*C͘}4ȈfrK m`G0G/C+Fȿٵ /`(vS8V\@5 M ^md1TfhfUS;־Tf:o,DNlJ$ d,JB! s/A0-Otv"c*!@ԩ m;#}qv8u!ԓ5 ~Do=Ї$lkAT#}oݧS ۶mq)_)^EOg @g4KȘmDB7"%s"xjz9:Ll-hTdt7lb,0 '7!8`dܤSbD cI1@ iW/$py`3` -.u'[Lk9PHjG!BV C bȕҮod%]GvZ}-Trg P44YRa2FHdRSl4qLB5T+15 L&8 Ѳ-%".ax>husZD _h=u_5GYY9b<cAR\Hd4og)&lr1$~hvjOC&pDEQW <Sh( B)!_Tkipmu@t]l`FHMBh'lJeg*J@AI*G8c pNQGjhoLxG#- u-[)S *GC*^a( Ë BTXzD=N6%BTLde1pɸ3u0́\I*b"uegTE My_Ԇ !Cd&~aĴR#F@:MV6h{#31@`Z^;IYֺ@SB ӈ AhT9 zfL:-WYY!ڌ; rn02SY `qn%lAtH0C aaWp]g!&l۱-ybm'_K.R >iztPBd2N"t*BDá4g4ݒt6?d2i^zZ)(xI!RGu5μ !j>03[xgcSAK!6$l3G% KA )3 ]gXX"UPFY-lIK@T"Sm2>;<L&NKc:.5_ί('%\A\rLz1C]9I{>a(Iirs"Tg83 +#;A#(p\׭t:dT~gy ոTvGAڻrqJRGOm3ErIu(L6P]-rU$/-P~'/Q8SBb PӏN9V3*Hj ,k%8RO=>Mb޻5JeÝ9w/""Kzq-!L]aR+&48d[ ]E Tҕnf#S˖cᰨدxjöŢ `w:QN6i[fAy`M9WD}Y\}~M@QՏ &?X!)S5_V^MVtW):^G|Ȃj#:ru~Քn=$[ZɪZ"-m`n&UizfD/z6ig6UèfNQ;}+3 ^}Ρ' GhTpn6qt d&Dʺ r|u{ ­܍7CKY~Ԁ2]nպjJs>++k&aI+- xQ5c ;).]V7&掫Qc0)r\Ys;i2HGgM97a -±myOEx7<;YH'H&d^^3p!}30ȅB8̓'^=7 ;ѐ^g_O8R;c/NW+l{/ҺXs Au-3l/g;]\z`,B),tVwi})x3x9X~?Y]Lؿ#OB!FZX#(1}Ow}{5:@B 4)ulϝ6SQ?!z\Ϟ0apsE'E !&!r3w9`Jw]z뭷z뭷z뭷z\73 OIENDB`glances-2.11.1/docs/_static/screenshot.png000066400000000000000000017402141315472316100204650ustar00rootroot00000000000000PNG  IHDR.[sBITOtEXtSoftwareShutterc IDATxw\TGs{W8(`{ǂ-ػ1nb5{W;(MiW;sK`ٷeb& G;d kLPA,ʲQ{ٺ&651<ޢA5{2F4QH Z?i=a.QE44L72Gb̈ntɒu7Xa ,$W=%) m!:1F"$VbtxLUC234"`s--,=]L4d M󓒒@Q(y~[`dO>#BLc҄")ËlkDDЬ"91rUC}T)=$3e9-1]0 1 0qBlhbnGSLl (~7fi!8:L;{#i8D"TH|JNOqrD Ҍ{g%a 6ƈkĆt6Yw#D14)tĆ˶LL̲J6ZwbѤ>I(͡l :E91ܢi'TnЪ|$a+Yi5L MqD@V`i>֐U@D˲ '`a y堸̓ 7ݺ <>؃oGjg ݺytx2? ɅdWAa܇']()_A)1L7'f,M*ɳ1%V@d]ç<$٨ |ͅ}Z++,˲R!WPtJ1+X<{{ ўPCOLR)gTj'E(έ( QTa*BQ (B 鞀V<؎^ZNb‚21E;'1-r8uރdO;n HWaWwpt!K3*Zڠy[z+|}|/}nӿeL*-޺sf?x/nNQdJwl{WvlQTk`z> _8^&^C׵p0Wn~]WCwu=;Nƅh)1]Wi7|3NpHбMaѮڠ wPI:FS6r7$4mg%[L|2,88Զ~pHW!wvsWӧ]o҃1_]˶?4ZdI^^-%D?l:.J΍JK_jCq^]ܽX(:h}'BnKiSn8;Ch:CxV`Ck5s9V7oJv޼ K_vߣ~tԵ|S7 g۴:0fiSBoR.^yn 韋wn<~B lgQ|/߽wv/a [fXby"@CGYn1?~k[%3DؗӼ ?S1VЊ"Ƥ\6M&T7޺P5 [;Q~`.}Kـ}h QQ#`\m@2TZNv*,"QDȅd >!2lMqG! )(Dw,Q"! DA(d|$!rC@Cm{޽G{m= o$f;>L^_}V"_[2$XL9 2v"IĹauFvqpwF/|+3,*9`Ţ.I;'l2~U_%7H9gqR5՞GU/XIu}lbY~aM V~˽+Gƥpn̘͆QHq~gX_G9jMJ4:cǟx_sI~ה-kQrKVdom ۵Szi4lIo_߲7^z33OG#&֭uodek.=(YOO' wQ_88ΒF=xR|G,˾;B/= wed1 ܀U۾[3o`LFC[w2~u/<"Nv_ Hq~:ZL 2O,+R-][/Z'?[%G?~-[ˮɃ9`~9{vrEtުon8vU[M ^8gѿ- 6s}̒W&Q#jI_]\!LyXD$܍v^@$r?;>$r0D.e P=aeR~,ڵeLz0-ge+?Da@R8!:dj!#vDuO%\*#i@A8lQpr@ QhH9"5"c'Jz~GHc]wnJvBI*Ny,ex*twx^GM^U6fϯZLd̖2 ʤ(1$ko,+L H%W{ҔsRBpwU*|8C hGo̯G[nD]~OP%꽧>HHN4~4JSOOVzց{>zvTVhb!zdR6O8sar&P~F8Mvo?{vo#l1^hZCBwwwYz#4^M_pKpI#a EpbƠN^tnjzh'*<ڷz L:se{ w 3\ƇyRo[{*HΆLu.9lӲ5N֦6>dC>|~~{_ ;bog׎e9f͆OHaڰkMDƼbݶ( :AbzC7y;C&yo)wkp)['y!͵ia|gw}^MV85QΥZyȱ5wEr#Y7*]V#@$ߒ>tפU#m͓'.=|jӛF4rtDC}uք?tJoaDkBBvt5v $0`u B֓ ˻'q׼QE SJ+ nJS/"6uЁϡt7~ !!ک;_r/nԃqߧ\yr7ѕC|:P);cüx@sCnSP\۲? :z\J#ל„Đ9p*,Zk_P$E=ٿϟF<{'[2A;8yK{qː}Kwٵl"gOEDG˛O={YLuG~h1e^K>sتcicN$uj4nNG{5wy{bڍGBR|V*dTSTjWӔTƭ#{rhO%:|6բj6Sմ`#ՠ jP\gUx5iߡD?GY|j#Pć?KqVF9~~M?[tJ`ȅëXs^ C|[;G5(sbҀj7 (oMEÆtgaՓxn&u[1lj>xmt__[OS46ͿRxޥxGn.Xh q&N2W,vM:56{pIy7VE ϒq (Ucn6~հ2)VT(%,T--60;&u<@ᛓPTWaQÓ9vV3i>ZGqq?hʡNƵiٺïM9F%,OMݫu7.r/&8׫\ͮmqpGȸ`,T)--cĸTaZ=zͳVQE%lcTJx#׌] uF{_ˠϒ/ёi`J)nhI<61.Eܛ)qæФ<ռ)- i^$7ddQܓ.Z7m&l4ˠ#|/{jxR~c-Ӣ8 [:UUkUTZS*"ڈw].۾S7~Wt|ڵwU1MkM޼eܡI{%}*!=wq_)J.sLc3;n޶אk:dE;]lpwwre_}sΝYzguQODMI%DP[c ;D]0;;8}2BV_6NѸ.=p{3iZga*K{7"x svD0cj]8Gݾak7vqH# Y  -ׇ3y  e<犞@đs~4G6FxN>1D0*Cmo=+%Uٰw+v}WN.lSrq҃3X;g@+'*J\>IZte}҄p(nOޭЭUެ7t[Ö/U|O^y# /߄Yu.ZFֿTW"|h#~cשW"{x-S3u4I~YסFpx VJ3fIю= tlAGH7N^{B]_⑫;@Z5.k[\Izd6 Т6.W}Xw2Nb;׫<`嶫/ؾ. C?3}u*=vcԑ0\]_I5PVu+wKK>ƺjmzVu_<Ȇc/dYeF2ySʴZrƍgqK\I_wSm5"ZDzH6cJ{L̀=.M?IX}6ťRY?*c޶O=Wbu(tƧƩw}4+WX%SVĈ]itRu&gnf!6R@0Omݮw=WkwW)> {q~|}p+I@s7zbc͊+e,1Ϥ7ݻf$nUU^?x +KTUٿWl<c³;>ժTD_:ҥ'|ϒ XbsNć^ڽTJ䖧!l`ٕ#FSMtr& q}6 2Vgo^^>ȵ%e!fLjS59^ĈhhQWa3b&Rcnp”[7/]vRV&9y\ 7ql~ .o_Jb</>a"eZ2m񠗿l})1b!U[n\B*wvCű%n}e:@lދd$(x?kU?F\Bv.늱!* D`\*{Jl.B*SM<*g2+yD$G/" .pӹ?k/t:.̂[ZN>:U[je-ADO[W6밦SbN})`G\xeLlA3oij0莈fcAo$C4N9_9@[]Ϝ)\7O~ҝL;'ƾ6h_Lo$_waљ*-*O?6XǑ׆)F@N!E>YEsPKo;&{k;G(oXw @@@+cyk۝}WPˌY5b< %"ye06 Z({z'Pg n]I妊#hA+(C'> 2DslzQ3炣dgA8 E ΃LпK˟+.л~hJvVi6FGکJ墄`ṋz$Mr4|j,E?I/g_u߼z!) v} ] RRU roo; 8I\z7Rr3z}?~ԏ ;K-ob:z(%|UI|1uv8V:h>7e܄-& A(L5SgIMv1xyMK [?ͶBN Mb_c-e˳TyIe/*9>JS Gm@ݪ6 %Gbn-| _|6Rnz[aI&d.1iOh_cy*,DݤJU9)1\a^&rHcbDZWk@4fX| їm62]Gh [Ƹ6!pҦhXH x<E!"p**hi hB8BߥmRHT1ބCTr)Roʹٰ̕!'xnIݟ ive4 @ y@BX Je !ST#cv6!x,b؎^;v/(EȥlM4o;z_E~=mK8)"M^/ѾkGQdz7f`WħdSĥƐNEx&Ñ{C:l^눑~ IDAT~Y#~{ITkfK.ҬSe1 J ]W ?hTFJ:†ʉ02{S=+RHIB1_,&h%w;`*Bxpt0bU pB&Lq)UU?v zAmz>=}}{4FfϾx Y)ٕ`kVtE ' ϬzIʛx"yE݋@rBf?T=h ՕϹb =~$qo"###ƪupI~@Lw}3ʇ~"+TsqdKg'{6V,LxK\3 ]+yR4RYAE/qOjҢ#t/F?O08IȨH~c &' UT>*X}G&k#8! OlTr9Crۋh^%yMwsFvejea \"uп*w# ~7{yNp_9ZH(xUڿ:/dg_ɕJ6G}-|QqWo_;y`CzܢO~)xyDkߨ}~c @;6СAۍsi[XI}}\K64IFۻOכ=wHr>UZxdu~ &ޕՅDd@yԱ݇/Ԯ[ن=*WzUODYQK" :ԃ[; 낟=?H+2 ۥ|2hU\E(r)_gQ6ؿ}5ǒ6W>(<:nڗ)_BrET&xvxޚ(r*_\"|9{+_γ(({u\ǰɾ<ʵ;_p7c& nUݣ|:Ňc7b2dG9N۫^I~Ny%͚OMΚo@{2`Jtl:-{cG<:~ŵ:)_Br>"pط!R-X}QhyOr>*6bTO(8{Ѡ*@:9LS"/lZ$3A9oY*ID4`SIV:`AAW1}2>U YyL772>MƷr2,Z92iۤaP?٢ſPӳLX9Fi#Ԁg.6s3pi[W,U: ׁK}8LvX JޮL&)D: l=4?r$h瑍%Wy!SOѹnyOw_˳Ymi6B㐠\VXۑ"ײ+U,]FZN}}=9#{}K nRlӇyF=R cө FAuێX·Xġ3ozN]8Ǐ j֬&}б]Y6ڹ.֬m'+zG5=tz|/v *1e$e$oݿq!(;r 1!}6_;߽UmlSgO$M[x#rQĜnf2fξqg^*:_ZբG,ɂ'pȽԞ=g_*:?~ћV=cQ(2y5SN)eN[huGf=H"u|I̞}!"0JF8y{]y_^yG/-ɂKL΃0y3Nws [Q_W=g󵾟_}#CGow;bCW?ȲD)TG\Z5fՍбSa-?m!j[I_ 5ŞBy+G`/Sg9ϟz0*ywg=*h!!gI,29hьf-7yGi2]T6\Eo̠7DAuy$Z] ]go횹_;x`gbruXm>д5jFYs$œykfI#F 𲄍8kzM[ }3\>_Hi^҃]gg\ܥ[ZD2G~w*0܁nϺxU|w— >s’@՝,ƐY,y\7<1rpqoW>6SʕJ-{ʗw=1ĻCM*_="S̱ؕ#).7+8v*, +Vkwվo~>"kiZr1Iӝ*Yc\zuc=ښQvJOEtIݳ/VWf:b̐!Cr68!L`)Iy.7Uڠe)x;2FWph%YS!Aj{+|sN7tP?ׇm'm6N!Bɮ |qGv_mL`"1FOfN{y7Z2ѯnat:mM&4iRikN9gm14KN̄1cI+$c!!f#G9elS@aL=uo4ƯĴ84 yͬ4i޹-Ĝ2g_3} i~RRڭ_S^б3;<+5<}J]Bs]RnZ}h|/4vmy!ʕ׾p[6'2"Wvb΍ŢIӯ$ABm),M_ bGWn< r%3<)^Hh1GetyO^oʴߘx,*;+re2yI4?OYz }Ӭ+OM:+v5yeѷϘw9ӌ|R)ptI0&gubo]Q$7l@hֺ*}kLOU;FHG3nAvy-3ˆw;`ɳPOcK'5@fl6ox/ n>R b[Ru\/3<hA `bq.cnMVےLuв]f--Tk:${Ϩg5 {8kTz&9@_/7I&}#}b 8hDn- 68sh#3\GNȎwRh%B,}yXO-zC:6iAvB Xf)Oe"|Z)|Oq zg|ch@&&w[_$y\I&:nКH.m(~̽O^ۂy̾b|{E|(N!S"|!(;!2RpOqrIF>_K+<ήSKM#ỸeZ#[h/02ݴt_бЄ`΅rj!b>,61 bC-hyfkɿ3U*Xd8V)siF .2F(х}K4Ez1V h֘9=j]ye"~L32kKL* +iW+Is99K1< Sʤaϫ W䆹 QfGP-m?TV苘b`{[-MKˋd?^1mhAxv0X ~ xD.:RQoh 5K# @!S@Q<!R: W! P@юBF GU ȥi2iȣ9YzZD<oM<_IAj`%~޴ru:Z[h_퉔qH2 mߖhÐ bԬ!Y'] Gd )yXTCq.D)V&(!r)K ۍHF=r1" !Ӯ@"T()J8 n0o h^H(R8@9 (4פNwD!dQRS*9>C!V)قα)Z'ҖKb5}XCFr'|έ1+Ã~~l$俍ht41 ƚ :XC 7 &ҙoX2 4N"*9dG@( -!dMj͉uʶ iKXR5c֌Lj/tv] 2 f&/:XdIn=s9M)ƠZֈFHKȂ< A3~ JX#ꉚ lbU[ݱ֣fb P0[e #,vVXG!3]"1O.C䞃XB(DFIVxR4E5cQ+8* ,0x(`'zfi0ƺLSRڭ5\=Հᑓ N)-M B :ee4@;_HD%k^ͧǷ!T"Ɍz ʔ!gf 2R4!JUa "X!PT{ lǁVZT$??婂}e8?dXB?H拀!YeY+&f1|Hg] Y:wc[2F8 OPf$󥀕q(LH#UZf!JD)1ўT**I D(t@Iy2X8  43":GVTp2GoCQV -X3WGMR1ns目桞Ey`L i ݗ6d,% ٜxO!!iFR K幍1 y@[ A@!"Nv"!@8G"+"!h(B$  Qd,Ѳ[r_8LA v|)J.?< V~2,:QhE?sQx !F@ 1M6]`)ѣej &?Z &d`շjCKG7%z}BCA+q+(|I+zz}ДNtK7;>ր@iK3I=`^3[3DX| Qe%V;\m!jn,+MOYʥe>Wo Iͼ`!2ʮk~i~p$CI$bbEXiZj$-t OD)I˴y~KXP~͠v',*bCwb[#!f֐|<{g3!fE+,ܔ4$܈9h 1k b8B5"[cX=bB}mtt4_5C*C79c"kBb+F|ǢYж}dY<&&ɟ̇;2YւZdNߋ兗?ILΉШ4'Db:4 BH~X͆1; .-|K:r1"?eR7ccb񢵛{i~|Nٔ:&2/0&46".0Yx,{f!Xyqlb^p쩷QwL*4A0[s\QET}Z'F%[*"#V@󣓱 &s鐜7hn<DRz8 I>ڔ,nM.6zD[_/r:}Yk%X1qWZ+wm'9mC}d\4t7dXaC[27o: 9?3?͕ XV|9zA#y"_o@5ŷx?ޚ |~꿛Rz?ׂ}Č >b:'ā,4COM^t3/}}`S1d힑4MQzQS4_ȧ) A,ۻ"H1B(ҥJkpJf"-ogwEi\ىeWܜ+ցIl w3n]@-ט$4 ֺ; ">hR4jsw"ܿgV[h$b|2])A!WMv0w=A2q쑽D*8jn d:OYK[O^s=ڍuDq2/l*S ƵZ GgrXv:K.|6%SH\9W}7HXp%%.ymj O]dy|kf l!?>~l/㡏(מ^qws( ߻˙@}E﬘?Jb&`dF廷pj9ߗEh ,K;riJ9Ϳ)C4uJ)X>q@Kʤ9 |%+Y2lL?{4ڗ$5v"m6geGL|kCUr>U K۟B2S_, ~}vvyn.]s<>IY4@8c%s*+&WKxwtbW>^ *dG1f?՞ҌPcR KbHIJe"Ȕ˴'GlK&4t`֣ڄ!{4cCV/A׾ltVBh߄!94kRaLqv{ zWBؠ_v?xb(R y\bz,9k)˯8ĕs)BlSV٩4QJGgFUƌyDgwm ƣEg& pj9ڵE~Nޥϼs}-Nϵm3$=V\Y^/Q9'7ȃ^DfqC+(V/B.Z Uu'XQ+i{*+N3ރ;9:oGS:_3 _$b;ɤrNwnJCV3w5i6ui"WY\8NPp@]{캼weG*= V繝=[UPzݪh+3dw~ O#GkyK*dr#@8VN$ȣ)QР3`V/|uf4&\Tuxh͇ 0,qR.g)/sJ PZ{]"c}?a>:qκ{hJͫG7,Xڶ~hwբ?h%S1Z&(n_A~aVq_<ݑ_VuVPmc%1؊K ۼ|ӷ?j!w?\7Md{cJvXF@_{cUU#T*#$@8PZEE?ڠ]?o֓6 EcʾzYN_ ~x&w~ۚIjUu[\ ։u^HskZߍ;ڵA3טsDżpb]{ D b|e)nCg gU1L@XP&6u;:1u_  ƙ5;$,(4,.<5 Nm蚡dc '¸5X@Ph؍39EXx1;5CL׮G.}EkVq% ou>|t/GVGo 9rYٍ! _M o_djb)CkwWshԢQEO]VEH*VQ7)Tȭ ׏!)484mWVӞU\ީyUziȅg2`3x).}sBSG%L"Je  IQ/^y'uṕi"J"("<ًڇy=wѕJ(7B:صֻ4 j $~"˛%-[.:hNOFk*8dxR?OA<%a 3;ƣU|dҴf=g>7j;M6y١Wb ).Ufģe/ߥ" LeYk{3B67ի{Eo;5@Ȳ)~xs9uHCvu&nK9Z7I֣N-ТyMFrʻZ4i7@_7jhhI DX^+ Iۃ&o X%g[jѳEƫb>krK}y_W\޼²\twVڷљ,{|*pօWZBAY:0RIqZ.P:9eYRQI͝FOkSc3jۦWk+Zە_r̻SMx~̧:]j>+chx"]0t"],{>yŧ>>v裠n#w>VW'aB ;'e +֣5,|zx_hЋ^ 1o.m֣k+!zI_Hsg+sQ"5A]\H.Gn{p\Y+drd ,cɇOB>95ӛ,s}3 9<[S>UӴJl 4e|"n<}v3@^|xzW ¯>Hfi](.s*zuwWUj.;JBMQ8"Onר~iFc`; ?CBip{A KLsK$]ylٵO4ӑΈ$pQBG'3TR7㑘ʰ_fXs#]s /: =w]wwoNfnO: +-rfΐ\J4ڼɘ =$"kԽ?awuzI7=Nw5eT{'oJy8ζI[[Ugr)XWMY6E®\3kU(M70db&LҒ ?9̫Zu秿Dh~U?_8'%jO2[ʤˢDvWq|;慇(3h dWqR!T"qzW ymi]s7<_G6-Q^1)l%=WH 9Yc)Ysح/3h mI3F2>  $qFU] L2ʃ[ܹ#{:hMHE 6PCXZUm;2pnаqD'׷g#gشnٙe㮄Cծ_vNt_rc؏9T$Eũ__RL A#jJXt)@GU'6WχXWàd,^`.eC>`][5u#\S11g6'>"'>}z slc9 HZo_ZX:z\ln;q9OM֒NUYq~PVb.7[o 3pcS ^o-hbMḣٴ?YՆ]o=?ק.}O,Az6qH .U>"!>,{"7RJH >.3b3QJj9#3iW@Ω/݊TN LQE JeKao֠v?9v?'~Nf-~Q+.׵u.|fD5670~qZf7_F_5JN ƛќ'ŗ"\^J.H쥲ǫ<f94( c|:/JYPPPIȼ#7Ol6mߛyQW6ld=!Rb>@(8UJ\(R"['7)ˈ{5Nt>lok"(9yU(csK0Y`2X⪭}l?Y37aGK <qt d Rш/ E"@oaZX݈bH`?gּ1k׀cVs8E4\vCl6Ģ.z3Ց@\,B&Mk&~*%]Uf$gPz5D|cų-?XƜnFa5lNt$jH^d6́I \s8#g()?^~@ѰA_N~Ÿ7GyR{g:46h{`C jED ˥ȰTұ rRe!ɂAaH(ymZ9M[0E1C帜[!"aXXH$V5TGge۷n Sص7̬aeek܈IbL&QHS߼JSfy IDATi%MJ--J&Wt6Eq9s!B4o۱7&n;t̢KG3LNik?Z(EQK>=Vl_>\}/xtswڵr-4Z9睬Pd*! S&, YS}zӳ߼s`쐟o]J9YBćo߅EfRٗ}yfY[h<\ΗX^RR*driGH s\& @%[Բ4år<Μs{6YvLWی";wnU<"Ŏ.w-scK+bDQ9jX.u?h3$HNL~~|\-9UO6BljR\L'߫ }!m;yyר^Z^5<TD o/pS *(U<g |GV+7! 0C,149̰QŜ>uu*9:Woo"r:/ohi@jn^4X+a,& ql_S/F~39'}!\,ITD7l8Y/F4Ų<>~=JV}&4c=yx]NNױq=:M{NX>&{95ۦ^5ר & s{z ijذM}}wN̝}Z!\gGǨ\ zN蘏/2nu=]70u@ f͈NFU:6u Q}/?U56GI+.^2M5ww/f_7]VCAbTT\rtc~Ag-ۯCc>MzLX6˛}rH <.&{5{#^xٔg! V?խF3:٥BM,+ˆ| W_oT?y ?:++HW3_Y{2o7@a];uԩQ^8kRu$yݟH}X$Y_@peD'EEDFDDFDDFfX%*A{$D<1է?_7G=Og7ޝpu=< XyԛIfH7<'M_@f/Jj=q{}`_cs/("Ù_fqG,_Q{Kه ^j͙N)/!1j:|F&S7S)o|AeL;i#ʈxu`*Q*(C7:ؼvKg?4xهc@'1w/3 2?e/kG7?":* kwOmCQX^]~PWefh*ݵNeKwn*B{ޚ2ώшpghWOrPY<;VOoa!7i7]_1Dp`nVӇ5Js'3n9iŧCrOk[]Dr -1&8=_} bWQXP~Pձ6LWO, RJ` R`9%ymy'?Y@^ V>^=CpƪcATZ=yԨ aC`J!Q,gs{.zWRjr)Ԍl>F"MHPw@:.E 27Bvr͜Б"a 끂 Ov܊΢ qx ++V/D G'ַoȾ~K9rkW+>*ga}tR"44 ɕazh~PqYqTPTN`BW\>X)/iL2'o(wKg 3a=(#CBS 9+%_ecaiGNL6*&ZobCͰ!b0dW\* H;p.6=2^.(0I.w ` U珣W$6#\tI fHL !`9WB~?t31I)I#l2𾅪3Nha9Ly] oL{'*7!(uqRa FFBG%Y28R+~v9v"&x`#@2llFU$}#Gh,EFB# &*9^3 hA%Ri:g(ECqY tkWݘB%v#PK0EFL\Kl+X_7҅*5AXI;Y?a:0"IVhraB@$ 1P*M]DD:E&XLd1L~5P܆5'+_\\kf5Ȗ.b{*l |uvlOs!{lkdoK\Z &YR۟c0"B8y~ V߹~} i1:'ʻCT=R{sVbD|[ܣo--d\2L5/ E)dŧ̭yW).<2[! .uԩ;9Q A$ 7H5C]ls(U=l4($ӐOO3E*)8=ťx|Q')LJ,CH{XbmԩC DF_rd\=.tT:YݐC<6/ V/ZE3,˲,CS So sBn#aEHK" tGh")*aXӝs/O',؜ $BR`&\'iy"R 2H$Xb"E?G_(ֶ .D"HŅ73I!/IB ,_eѿ+''<59fsA]ZV[ ]]X9a߀]4+?yjs1&D+5ek.hA'̭M[5xy7(m YڈlRRSPl }祶>5 $_X]ϝ\3q.bǤ4Z呸oJQ@-.65qkj9y+dTW@wi3}>!ù6݊Qqzߵjfiښ#z5%NS߹B)H"2.V)Uxf۹#{o_&g( 2ʈ5ҾɈɣz5qgwq;B_!mFoݞk3 ;S#ʶdξ8Cj;sR)ooٴB5btmxf㶡tWkΙݮ( KÅ[uuŜi6Dl=b c4:v<*˶KR#E=ԫlKFp JRfw"Rq`9eBb $xflɈ]er 0`!cNPwHaB3n]%r!u B"bhF'1RJ S$ J)g1$@DJA!ȅ35mPŖ'$C)U,|@$M13kjFA*0*箘3CO׫q:S5%3,l_iG ZG'mrV?{8xtm0e6dix|"JE6ndjK>>˦~%-rc+Eu,5+÷<;ԌO:Mdk狟N<6$jbx #ߣ6vy+gYNf۝c|O,>7ie4]]c+^^b?);+bק*ڼtpRR̻W-Whac+7abg#o-l]FT9mECGd[Nuٺ˚>6=kWMte6e>|Orr4dڦ\^8{9PYAzR./R 5&ûV_,R]q mt"{3e]j7oTÖÕMVgD3EɄl+lAw <(Xav[5?dR)s#n(ÄZ5(`&' _,V]>D54xN}g1O3Z4Ϧ 0 M)$JuŤdžHM4K3-_Ԟey>Da;v4,cWؚ;OXއLuP1X A/vf, :մ!!>09RX C(Ü@q |\X;$9yk0GH0SIae|9|"x*3REE<.Ra~ 1`X|ww?l8mca<p*a1x /@_n;l9X,5 sD55*JC"XVp+TBK^.;2fD*lD˸׃LqzCр\||ߝ(f},ө^griWm[Z% 6]ژ7pb7O?@[ edșoC(5z_٠U/؎ +"yrʩɇbMlľ !%UϬɯkk އU}F]J.H'ª젍y'h9aFZ%8qdaz#lm%^oz$"3 v'zwvt;1tq|ёĮ?dU<08 0 "U+01#'FV7B|TyvbrZ}6,cn>;vs@z6#ڡ5kξJVyhek? >[,3JDg|*m>bt'<~-l (?zbCE?Sↄaqm ?=FKc}'<ٷk[2Қk.'|.~η~hڳy i]3wiŗ'x'ngczp`<.@XnV)C"߉$`}r500pG@8 4Rk L]Jjsoj54ul_Ri=\> *vmkxaA}U)A:?ڿ=˄ ɓR;; 䥧t1,H09It|\ŝي x,˱S.Ύc"`gc1L*Ô;helAU~Q:;jֿ @ݺIٱqN,me: w&ѾWvn{P) ΔJW+HڧkfrB+Bפ)TTrLG(]%+ƽOȌ#@BBl-v"gg..ut]ܱW%/+fۆKӯkI!Y07[2CjݬvX)Uw'now0Bnb};gJIkX3#E)79{v볈`+PX}0u}~S_ϱjA؞^~ȱ*zϼ/_S-/SaK^͑_6@7q˶uhٲqf0c ά# iܪMiZhܪiTk&ȲɃԍsJKtW?_r²_+yh#¢Vpԋb+idvʰ5k0MVMS}vƬN}"̬#˦ 8`Stna[8`ֻ%}j=4Ž-7idTp*~MVW93 IDATfttͬ=Z@,w{g Am 7`΄̗fXP޳"E"4ȳG7nоXH; `Q_zi ]FkܲU4ق-5ixU5ԙq^{8j:g#` nҲsiZ4oRBb̈́]6o@+O0d~A{Ξ)8un>?$v$b0`XZ"j{Yɢ%!g 7Ŕ{u~R7mȂ;.} [n5FJ.]|cҰƬ6ebG"DHd(L璫YJ!W(iC@d&4)2ɹ,U;)?W;I9]lҫFtaoߌu䠸;/>}ˇϮNA7]_<6A_ 4`Tta#w `8Pr2p\TN< DŽ^/8y@K@Y^7/b]27 y.#RvT~#8.AIϟ~HLxuiE㑽7y%=]ۻ(̺Ob(E;/2u PBo`N*ue:u[9@KœIEZXL288q|co v+)<ͣ/Hg?n/ ݶ/n9Y6X?÷NHAoMTi` 1npʦ합` Et٠!:7͠l,}2`D"%};Cm=/Ցcܼ“wQ o;AЍ I}[ŅgѨe3/s#L-dDg1'C ytb7$(4N~%Vܻï^˞]|Cu@X_= 7!ĎTwcM 5T~P"hЋ^g _\ڲGndh;E^38-_b߂wP)7w?gL>f&7'23XǸSta|# ĵuٶ|hlܻ [7[GL/>6t5T8GrYvGzH$%naf$v`,m&̱4M) 4"[r_8DuYOmqH`T]^w g!sI/)[5"XB׵na^EM[AinNJkVlBc37Ps\;!mۺ:Kr:+OP#r\n(ԝuaBn"7b:4AcUQeԃ+ϋn(=a @=Y{.?Jc;۹ٵ @Oo#:HG%:vÚѢVP%KajD<ֿ1so"rӲ$ȣuVۧ'%ASث)Z7}Eb"sGڙ76}zJtҙY#\Z ѡ5TR ωapDH4#ppl( Ľͫ$F3m̠ 5PE]y{};X>G |x5Ju, @@HHPҺO Dlazؑ$"NCA `cD$Q$",fcVT4`T`@h0DIBff11ϧR2  Y%1EX$ b8@I(8YH> ))F@4 _@]D6-n;4_gIKLHƲ" VRVMq] x: E O)F("Au=ҙL{]粯.5{ "f|7<ܠ#ͮANKuef8֒x5ndʹ=ݡz,4.$+\aYj.HYOu1TWDK.Oy)F>aq%{'3Nl.gɆt(}A,zk”ԟaEcf<ʢmv\H eD-Nb[5/L9}S.N1^&3&[Q)rl OPx6f &TƢqiA6n 4+wc^zwd;v/_,}6]\W+exLVL4r&!M_@)c|PYǂ7k0udeST=z "'GIUY~~Hft!x<< _2X$(/!"2MA((c C05Qn:0k61r!O&s,heQT10M>^s/6N =GU[:K KVyCU6rGN* ᴌߌJJ+,MmUĈk2vz 6kn5Zvi(@9OW4^4M57wm PW\8<.l$ O*=|ǹQ<ȓv' -K][_O˵ Ñ *w^BqƵ1yo4(J=s!O \wnS>SwvZOB'=FQ %|Ee?S""/ ԳrA39%}1\bGNҡ*h[@^9}!\hVD)Ui5dD'*IE|2GmWZݦLG>FN{OriZ^HXA(c^8RP=>}n@O>6(LDg@Wgj2=`~:W|w|jBjԨ^Z^5{=ۿoTӫZH B.+*FמHc|xR_:eʙVrtlEx\/(`fOUͧl<1O='+,^2Mu7*>mf+4s{.0߶M/UkԨYF1QjzhϦlZN[4OuXODRckT⫆ ``U5܍ĥ*уYMB_R֙2gmWZݦNG>udD%*IⲣbT.|j~X_/Rn`W_*yz؀5Rf~b W y/. W 4kpmeuB)̩5kz ةZjV }s)m^Z&[;~ﷹ ¯[d<>`ivGXVYU *pasGVПGG:Y5+R3_~{x|NeݞE?Lا* N~3(;vDf.3uV|a~Bf={+EVW_.V=#Lu!(S@AHK1khtM{g.=4ed¯ˊi`Yss'/=@ TFīS Q7qpQ!9 AnYnѦL雩H_#il$=$sVJPS;{*($WX͆~YtggСϥX=j8{>hsl bYqOkݡ=1g29sV|*%{La<.>~uVʫ1{{ bWQꂀ:vCքirq5uu}$,Y2d8Z+.El](*.[[uu:njk @eodq? $$!Pkq}}=\yh9qT垚|6EՁ`{arMZ)|g'Bc2ʊ;ߦ~COf}{1*ycǯ=֬XM 7ݸxɴ` '>wҳ7v.k6nA 5~)I"~[{ĬKJcPhBmFxF>1ǵYg/V3U%`Ho2 &n9伽CQrD{ x_] nψɵ5{>,$`cwrΏ6\F&"u $r_lXU>&2~¸**U5vYgϥy8Lֻ%NJUf=L*+1-X&?CIFRWm 30{]/ aKg !EO- ]WU74 a5*| ֖:WWlX0pUH/F(Tb: .cRouhެSU<+*wQ|*2XbF$Yܼ\uIhkY46.guUEN>41je5%4c's飑FVKsj2IF𩕥?^ekP$l!k1z}?Oǧ˸&?mA+Ɉ1aTpi2H_,YU8FXm,BwN‚od܂JDłoi3>JkaB QFam1#Vܖ'I<:VKi{F^܅MM8P/8流[P. \z ՓG$Qhk^ !=\Twb bPzegipҿ@Z/KA@-PT#;cZbTFTv7 ab ]bս*+hoL⨪4)$ pqY-0XKWFnWD2ji>AR,.e 8QiAbj:%RΕ̇t%G~-~Y`zЍoqX][P7^]6:muwM1P ܞ5 ˗kkoxlM@:zlh.O!U[/zr5o`88t^rB ojj'i3VC MN(*gjنO9ZߟՁ#0/y%oWm_A.PgEUr(lԛL+_ =A%+k.ZZ+Rb x+݋Q*@wiCo3`>m4x\~ܚ@+w״In,|【ɔi;G|X e18a_”l d(_Ͳ?~7x*R !Rt&ԟQs?6e}Qs<6f5Kz]0˅Z,aiӜ!AXyyCaIVa*8GB[%"r:niCX"UgNV#BfB~YJ x[@iv-5?yhÖiuI7ҥw_[_bvgɽB=窦|F gƟWT𩺖B)?#V}~A76|Qoع Q_V}ä?m>.ή{O'&X u IDATb}{撩'Sk;+5q9>>߆M*a+m3ݰOc rnU\#fG9Scm}J[NJIn˳YUmHbo_e}Vrd$1w%쇰=缣!5g#VC;w?|~ 5Q+W"`ѱ<{c<1w?Hj;tJ̼X/^ b4[>[0som9|',ZM6fIOr?14$kX!S˶?ifY~=As{~;?O;Ȏm[NlSQ ;WﻑȤ puw8|8׎\4l$٠5? ʱБXpeCuڭzTZB.OvJAKasd$Z4> B357Ɣ4I@p#Aḧ|\,3x@l_r"!LRc)F f(s,DQ&1D|IJl4mXieQeg )S²u@€@SJ+BXY֥q& 6"(6t vaVtjlxn=ۛ=ݺQha~hi'Uũү?CH[#Hb!ףhYl1cnػ #5VTrJOoQH{ aT+Œ6 XdbV,HxrvC$ǽn zG/~ߜlx`1$}@7Xs>"Vx-8vh|*Ź]^O!ȳ#8G͞~D!Yf66BfӘH{Y=J܋.3xtx9I׌yrց!d/㲭rh..2/76GǗF,U+TFЏ?] w'U=.+mON:ga`\:'Ƒ/*duw?OxL8zz_ovĚg*-8F rEOwW'n#\}\HʐkL-u9<ᇒI@6u(9/.3W!8u.=w{=P㤵F ju$YGp,3X ޳cy.V%+ 6D=б76F SG6'9d?fME;1 0yW_&s|{.0ױd!_߹zE$WfnOĖ}uAO] O/?MjWdUCxp⦾GZ7cG#ujч rHtߙ_7:;96sE܍d +88&;Ϻ?7N$wOdv& X~ xg yWfM7J@x%[s*\O8i1ml'\ވf~"NvR9.6wA#A@Rpf:,ek4NƘ( Tdv|tět XB(,i\Q~x+lcNv:0nWXc߽]m;rݠzwIo4ҷ㇩,kK AU/bK(|6 Q8,LK D̄/D=bl=tuwݘPIĴS3ͼ_j#e ]3v eUu1ˏM׵{Ϟ߱G}&yAJd49,dis YnvI9{r}g<8Q~dv2|s\ШNھǰ}j$nV1AFU0'=M7W)QĮH$A2_5{q4)ѵwQ)gE.]w8qsLa sPIx!cx^NWk8d .T`J|Сt^ecźVWW>@qw?gO\!/\:4܃k$SHq/];(gZ;@if'e鴜2ujf@u.3 9qЃ>:cX3ĐV}]a:N^]FH7ڱk$:w2JqK.z +@BϙvK=sXahvY8ڢo f|sЊ) !+浊=~ȷm +F/˜Y/Vf{6od@W}]z9܉Wp>!$ͣg7"g29NCVk{ܐ& e]SsG '{ahuu(/%5(|.Ren}R7Td4SpS|gOɮ2#".#ͨq< !S58|gcYɏ>m^<_G ; 2QeKe(,6 Ӥ; d\+Cw1m6:fX"hYogѐQO޻z vwf^L7nQ6g] '/o3֣Ǝ߱ݸ mYF ?ָ6s9?k*RTH@}H@lm2vEZ C.VZ2Djd:f1EX܊w'KiRj>k(DVQ?o2\1J=iocGb)&ڰ/~V2>*55Es@Gz>N { -qz:6*l-G&4Vk2u6O:vX׬K]ȧ q&fFZ\|ltYϻ.g >_-keU,6Bf։yZ2Om?'a#fu<ʶLdr OдgW iHCƣBGz6٧AiFe0L1yč9[΅Cv9_vp;ٝ9H!v߶tLji|GI$\nIR.Y4m8N4ͽ}ysU$hv"IBSRIR{3&ǜ;u6 ii,Ĉ \,~úsrHuHoDd%P'֮jퟚ5Z$YC]^rn5%7xm-{ 2󟬟}@rߌ%sV]yj]j14)JObVR~QĵJ(鄂~dKO YED,/->D!LHNQI`&/~K`ozĹJAgT"Kbd_G$daQǀE?%(Q1H1(/D<}x!v~mu`;I!$K0 Sp3R[kfy"ŘbAf0 œ"8ieaSaL3)5c 4PR٫Ucs֨Wv01Cũy ѧnʿۨ^8>Yˡczɗò1/n$-lw Vqf s+ŲlYp8 HÞElUy;Q575|86)S?!u䥗c]ۆW;p3Uò@}O/^$E5}ۉ]?YQ*O}\yo9[|fXI)1r)062_6k5&@ĩ߿l>h׭uiؼ̓<5Afz,ȼ ?MLN+w iA\D K|=.BthRG݋r":^}Pƒ컯wRG#W?]̌×4᏿P9 :W-XlnCG0Y_gRjp>2\mp&;=`K$D9냙ݖ {i:Ww3&6rz6҂+ul9&(%"1ڰ!j:8}7}UfI(\8U:{jO}w\yRvUxp68M/ j} ֍t0F^b%eB!Y:1kɦft5[yQ)Ҥ[7Ǧހ$04'H/_߿2x*~x  Ya*/z_SڲEL}(:pꃊ~' o'У˗&o` !"Tzp\}*( Ltp b!a0`H 1[FJF xf. c)@"d:;X^$W$jAAQ 3y crYFR䋱Y4j`?Z=u-|g+@<_Z{qn?+4&̴j.g^M'e֧gBUJi)0pݴo䅙əd-0zk]MG*\UT8>]ysz#XLJ@DytЅ[ fA+T"C=Ic)vBqa~$|Wzuhӹ״_m~.Ͼ1,Ҷs6{MV6^E9xBp=~O+38yW}j/TPRbK)yY`g)b7"-ף:YȞ:\z|wI&vikN ! R,l3}7MQB"5qn}'Z P-J>P HL7G|jվuӷlv.MA;O NS`h$PmM!Z~y~j=(MoI*-/)[fxMC {+l_u[=jרUkS ,MmY/Ms:Kڿ]OO qyiQyjvO,/6Jv5s{φg(}᪲ !:*Z0UE 3f~+s(`elotgځ/d{7LO!JS6wKօI}*紳J~6^ bjvH |2munwpN==x3%( D`L*O#YZx*3t1ƅfS  c1r⨷:Vx E eTbS(u $#9B]ؤYJCWsJjNe% 7y;!1A_mumaC ZV>m(F~KbY!wT~HնD22Py|W$%1Nnvv0d\~cu<,>Ҧ&B#SKMX)woz6+.^N]^:R*';M}IEB2CϽ߿rD5i<0 FUdFDUa;:ڋ5Lm׷?/ `2&^ nXdle)K9RJ-{xX`Po뙮D$AAf@5vuLZ2Q wha@F$JIm2$ y B.p4WMs^:sєGdFdUccsBݐb6 @rlبFȦIz8'9Q΁+w8f[,Q1yIyIys X$Q/}o0Nɢض_8)2uԅ, 3b[oXP? kD%+QZNG/:뒬I/V\Uz!\"ìQk.ǶecW24FҳIT"Xnɦ~n/Y\2f@f1E{/y#Υˑo3G cS^P4|j4l@w7lc*ibkZ3uak̵(T1*4e ܣ9 ҍ:F$:xQiIL) 8G}W WW^޿*@OQݴLL~>ҾximILG=;<))9@AKV_֚=oCEA{M#I VP-]ʌ/:u ǽ?9 rȔoe y]R=Gں3k{T Х0D"/ܖ2s7Gpˑnz%F<vsfB"kGgOLݹL@jԸHJLG=;8?WIT6hϑiDP_cH~3gF~vM*ˇ-1t#k*R*ƫ[ Q|s!_OQ $9|xf8ڪa>n" IDAT陧s:4$qZuwl4zhPܔ2[gF(++].{@k3}qt&)pr%~#%n(tirgmؗ1d_uG> ]EɶBFv!I=OO1ࢤ׹u5J2k7l3;-ِ*$/\r?|MƙG)TH\em &1_ς~w5nضOokKD/ha[MzR6 kcx6k!5V2wNĻiv捨xy nF zwtͼYIfns .d$d E3Hfb lF>tI6Mx|Sln {yzrob&imt5TqɡQ1W:PzaoAN !J"_mƏF,z] [q5P<몍_zW~ E ރxVy)VnCv:cT1?#)=f|#~$7Mf:klM)QH0yq7->_μ=!ߺRVE3<}૫KEn:_2C"Ľp&e kn}Iūgσ"GxibC}fM ݖwLf=c >t&h{}  _myA87=/ y:܎ə{Qdhb1?غƚ-쑈v#ng8(q&U*gub+b̀bwI#Fqw ukar|SYW NZĒʬv,۴8G3ǀ"O_<CD ω{s:Κ埯]x2d4子 qM"B(Sg!t(q%tTv݅1/>@g}?} dTaMV]d擩9poLt7~oyyVF<ĦS_w}xvŒڱ+\qh9q>Iƥrc̶Ô; &/ƶd'VU*e#,]WD<#id@?`ݪy[N"r#0;9=4kp@~ĩeP7%W5<+޹?c_Snaj Yii \^a}| 7+цQFmhY嵻[˪^kR.%MW?ⵂ@F P7)AwVUna-?>]_XQցt^\~Mƭ?48A Ts4h ` lPTuV_S GW'/7JcM\J<'A#M5ŧ ݗrf26 kIxd*O?'w>]'6xˊh̳"f\"j0MQ#- Z\PEJ0F49cXY2.c+{j3L!Luç)^Ѐ^7k˲4́z\eRŻYd$e>\('Ie`# TB 4H TESZE'\.ER")JX\>M0Cer5X|3JQjZZ$u78M1|:m JPq>2/y4K3qTv~ReBcP/t},~ȿ6\Jݺ#;j\FnW*{zRpdNPW%f'JO)bquq4%38<$4OˤrFCi m?]r**CU;mU]ZUaK!RPr.ղ"d5Hq_ض'0OrzFJTY0F+ VǏˠfW߽ɽ{ONNomn #^B<Ҷrŕ!ڠPDkme`D)sڎh{\+02qʛ ^K',ো!C?/_CX-I|k?Lri)Dv1Svdr0;Š ˇuaEm+vɄHcJ/4)UbqfBP(4pD HM SLW7 _[Pׄ"*9WM,tjeAMnIHbo_e}V ˻vkݗ" 9N笜3.laۭdRwE _3,Q1c%fy;eϜbckd?Z [X[7Yk W?2.-LkIe|Az1"~󋭧{!\zxY9mQCHyDG\BW&Em鰢;/ U^j ?w6~gӈ_/LubR!bBYsnY'xr|ֳo }z.*k&y`8w?ifij~=^8f;t|]عzT@Q﷧_T @>_2^۶7Im׎/r 6<#P#3|7)v Aۡ;;E!~{_~>xᢉ[3^p?~i΁ @BBm=Ecg\[vE*`!8 BHg8ffyz"H@p?.#Sy|C 1S" x-̩5u!dp^أ%Ήqdӆ7ll щR@fPt/c;ꚭz;3⊴ff7'=blG_u`]ow.Wi+/M0`9²4_0 ,lk nbK2eNp ɩ5uќJÞ)`N.SOT ĹnAG<'![eELa t;J 8/)Zyrwф~li-rVz'wBboGŠS;Q{ً{|nɥsbnٸ+"6٥wOEm;tÉW~R9].3 zqnǪ=R(@'[4 pDG}ѦW:7=ں;*<86sE܍d +88&;OGyNۨjaI[d D <]U6Q7ˡ߯7fpYֆI?Z?_f%|ċ tU%QȼĨ2 ?Y$[ulN>&Ї'onvC43)"xM[N:}C2x"8p0 @!0yly fg;@7 h+/ŷlEس:,"v^ΧJz;ȃK{c=3g'+Ivz´Tq !]բ+7|oK}>ADXnrx}sryM헎w+t2/7К]Z1ф,GC1T䕘jU k =eX*%+~qɏz?*fᒉzZF!~Z56vBMҾǰ}r5컭XhyuJ9styOs҂:{o %dqŃ=8aXu]+Qi( ZDŽȬo l7Кq|#Q'cumۀ۟aNcV>>8uVmoPygjߥ߳ҥ}Ne2Hd5R;j9Rz,0>5Ym{>kӂ"*6xyp.3a-)LE,8idllq pq،[aai1KT{e+áԹ T{]Xqndc7g5po1R =g^=w '{a@t/뺧RJHs݆pp.BC_˔l{C>xr|6v, H%@_'Dm3ǭ[[价SdU>7lɍ#w?d;, VTUӇǬ-[`I#w7m]y]KV kγ|l. HtRO7t5`W l{7qzG*4e)NM>BW^#(I!@n=.pU_@ {^΅O)VyIȉS*q}w|s@]N'D=F̡(Ijb˄}^H@&s -eBC;".ya-dGk~+f &Jk,4*-`Sv{qwYN6bv[΋(y-#}#9% ulio.N\[;FWz p]6V8&'8)(4? `#?q}s2Hݱߥ=]N @\ 9Hoq tg܌}Ee#vLڲU0{vү{ˮ/]m '1֛x$'÷DQƋ]L$Q/Te9Ho'~ٳ.ˮ6ӟd&8LZ(A{֝~u;̛c70h]r)nÙ移5ts#,TB+l-4ʎ+(L^sp,q;wK:@HAiYAhTu-]qbt1n]~\3{BaZQ` /).8,UBp=;ZHN@jIJ%Ku-")Q&ۼ>3cbVI*O4 Q ^(q 'ΠtjiM{,/"u>V=F#c(+- IJ0Y2E;`քσwN"44߷)G~q_S%? ,lGx7S -Y~^kUJNˢx6-'x6-QA<6mH_y%gL*hIt+c!u:pW/i,Gq}@IxPæ?'=-<2ΙC}A#, ɺ'/}̡0SfSYB\",LG=&[\ݵ+\J$ i jߺSi|6L?+VI5xRpzI36OƲ=J̣v_YT+;=R,dyhq㏾?B1:~Gp`9MqgWÍN%&Ll4!8U3 quKYɯәNVl҄ș:oP+?*]*7)Գ& &s&dcm럤ZvyF&|(!uw=c*0E6x4T+瀁.qup c !:*Z^Y8UO nO; 9@MmUH?R=>7)ֳfAE漏Wŗ>LW&%b۠ 3}z_~r8@|eB'`CYvú5 ;UjB` \6^g0|ɜw9Uφͣ8#]f19enp1!BlcRy@AX3cc3̐45<ٜF=F"u2aA L&53 l6PT+1-H1p34Ej1dj1@(=zl@=(#ulɋdJF ihaoasnA~U{%2+tE&eUz!LysXT뤱! Ҵښt j0tƶԷQ˥暩#z0¢l] -6 X?;މjlI޻ MzQQ"JQ џ(Ebo EDTT.( vi[Rd&r/_잜2gd\ު@,׼a-{BHBfʕ*daϗ՞c Ml?7uyc:U!P>7\Wby fE_Q?_?Wa(נ%B6oY Ȫd*X>^Mcfg}R'K*F? ?_Fٛƒ.\n;Le'c ۜmW5:/da;+7UO]U--Z/.^gAk;T=1~.iJE/V˕87ɨYMZT’H>mR|I9$+jb:eBUN>88>B*Yn^HU NZ ںˇVo(کC%!C) YKy~)2U/X/"FU%8U,7$y\BBg Hml2xyVnȯzUe%y/S0X>Q!cr$@< QK55;y *rO (1 {"pl\Bve8_ OR%- T%kծY6O&:|R4\r.}ۈZfgdEvv8wZ(y7lS-zCL4?ӧ`wKьU, (yce]ߐ_9] e˖tp@E޶>7ںժn|m/=(O7aiq"`>kWV>U:p|Vt?շ]B(^*Ǒ"ID8/7[|u2hyS:;t[ZƝ|f.`Wiעs+Z_+kW([#FQisO2G1))5輠ΰ~{Ha(jx_eW d8b$%`' @э32Iة^굛\gC~sw@v5}™wvP:Qc#t{͚ns{eXi~1˨T~J;]Nk Jܞ?`ìY;~^m۪֮sjjg]eK#6QJݫ~NRsWi׼swW?0o檃_յY^uףwwZ7E+=7zժirm/ i&cYu,z7+X{*SpuÕ-4!DCu;YbͻfA5gênժ׿]e:<샷wjӼi{-/l5sGŇ'=swۆu궾}5>%]7/W?ںիnک藆4wQsWZ&z?9KmXY{w/ww#]ގ}?^~AS+>vpF5j^q݃co)srodl7 Zh߸ًKwG&}1$sq^ѰatW8в?sE[.e/4ovy6 h4(4lwyNQ3P=sv~7 kr=rOOsK<Խ`}?Yi]R &I4v8D dq G5?6#:pLzA{joOqO^s''}9/[7/7᳖/smS܇H:oVȤ*|̸/@Ϗk.cW??VĿwL|ב?<'Je>JݿͧfNEҹ}yysqT~u>?᳖/xN],PvC KTQOe)QD<JRnU+X~Ne­Syd@:%Vp딇G{FO$RU`aw0[l0tڴ5;&͸κ%ݱɿ0||C#MzHw{;l)bHʑ9O 'F=:R7SV*5oLX9==rda8j#--H|Jp˔!=c m贂^'}9/[4HXVh"ΝϾ߳W@!/0~3yh ޼Gfm>fG~qTب&}4F󻗽3=JB 5 Zmnã=ca]c{^8ͽ?c՟D-i F}E=ٟ< or{>:vm}wuWfCG 8Rn9S2=kva[nwoAZM 7v*-Ɔq`1.Lf?&Ϥ@0!Jb,}*%zUS["l%K1&",%%(NoMq%P N9>B-tM0CTv jgtDE QA`h[Ke`[-9Iv`xg窗2sE<mȆFaX&F;KhF}F/١0*V=d`82Rﴲ2 z eRTkҴ +am#GgI}MMdo;/BRڈN~߬V 3j#^qTk A@47`'q4hڴoDc25ũn0u8 6dht]BY.)M/+$Ay d! hf`*Q,a5} !(AE!1#˗d4 b6N01 $s4c*M2E4;=x~"1dk&&x Mbw66 T՝R<)aVAG`,)`ch %jIf(Lϸ͡*w8G^ί hfB{{Җ7 MΚ }, BYCAi^b\ 4cF(^&o݉`)N0%79^"+-:(4*1}ywl J|cS5!@(9=1oA&nKbЮ6.!FdP&5fGFdUj CRدIP>@5aŠ?$ SyC`48"%@ W B CH%IlLQU_aEI`L~1Mbf=M@K !F ׈,k BâHCD,!d}qpM(k,Z䥫[K(9q2*’n5CKn3<D F2g.'k LBdӂ`>+.^I((qArM*"^FrVx0ձTFG&TIbty'0H5SUEḑz)󂅴 YL}"nC-bs9aK$haQȼK #X(a%J$HDEZSě!?bfbGџД ng&v:f4}Lo`ܱX7T}SE4P _916TY KċnGd& X<ɲ@QtJ2cBDTpkt"y U9 DƯ0O䥰vK.:8XGwd~O @ yWUxPex1UNp:<@L%IV ^t:E)2E^ze"xQw3eLBe%+BE|S.(~9YU#`J%) 39\N^|^N'>9UTTFۂt5cR1="+R}]LmY,L8Di\p*1"t%+!rqV1"xX4€zF({0$|ц[)RwgñeĕcR-YK  @2FX;Lֹx"0k(![]r]qYySFPtg88PD*I cȋ&GfJ^vg8(CF_t#¢N@&]` \6I6 >Fdp*cL%5O,/,PUxP}, [0/ J! (˔.ZR`!"z4~@rK78%f4٣4UN3/4,|ј rO ?LVHvPK1dX$[!D 6%gdp!s:aJnatLi(\Y8 a)j++ɑ "%a1-L(F;}1(` 4t(SId`3"Dt\uM OrS0& CͶ] 71"dYے,KuQd)r_xT"@I Lx% Ȕ1rDA"0dT#W(ʣw8F=fXmLi&ik1q- I[63nq0#h7P/P1'wKO ߣx>-'iEi}rbc2CZ m@6Ro `qcR52$prMQ$fص:bVJB$t/A GIDOU^8DvR GmQ}' <.QFSwSOF1 5@aPDВI% Wx`y87 K%QWY{p|Z&1\ȅf%R dn$ZXä@A3X8`cDB?+n]w)4)AH'l]̐K+Ro%{U{DHa YyĘ'yM`k(N E"NA>x)7;zRh AW],S s$;p" bS䘪|9P*ppzL7կh Hr"D e1 %10UO(g#WI Z H$݀(($Exp #DrHUTp:_f$ N$r TТOR&!m2OhoJM'رIXtjL21-0*n1"Ic!sH]OX/.%L L(vItY}f1 űX̟nz6&cc, ڄiíO"b0mhAhiv[ciA{~JXPl2ZU 8˥[ 1E~ H>I! 9!hL}~-th$5oA&D 1BD"+"D^,ԡх( J$Ts[gt03!] 'SeHdY&GJ>?9LxLD)RML3oi2 W"&3ZvS,F&Phk' FZJ^CH gژ]CWR 'sT"-F@<$˲h0qZVi IDAT b4N`R0Mk{\gn+!Y6ESv,;E>t+]4 % sGA4ɥ<&we`MH0E*RKTB f̌F?bʷ?LL WO-TʈW CU瑴4GФ*T)az"NH"N:}ڰtۮ] 61]`o ?´ m9FO%Bh"@<SLBhEVIIu"^|\,,~J=i*d%)?q#Pl-섶˵7!EJ Ƒ# fSF ,[>`tZ ):[]*-c\Tn i/o^,,/TDĈbqO&[i}vb1§qDMbGQNdn O FZa^t1V;N x\)GK$8`0CXD@ m%L,dcݤHx;4**h} 5:QJ JB>.uI\p:|k$st LZ@"5>OihjL8 9YqYh|PZ杼hQ,V G`Nbu!Քw܊a1h"1YtsW;IK tӦ@ 'S>eB 1Pajw?=KSh99z@fkΉ0P}d1-&=  W"6!~t ' Zbh,BaoZo n78ѩ7rzu崃'~UP=oOYݐOWX),lw zz<+ltso.\+}P ؆F/`OwjW:T)鶲 ּnXBAud =gmm_߾*|ܾ xW%A05WG9{sL6E%{!D!S8v!?± FqCw 7ȺOF/l;mܳ_ Ěoνphf*CȽ#54qW r~sKI$=yCt$gww]?v@μE?3Cwoݡ-9I;針/?l'+H/fwqk~k:#c *듘t* '<}TJ,O7Q0? 3r?w-Ͽ딏I9;#u* Nۛ|ۏޕUV~KT. pfoZf7J79یM{ ҉r\ּ^~yjaS!<<hziM6s5ݧ¶;$c 5 B~eƸ"hk|V].w-]MF>O{'ޱe/]I_qZbn2ֆ9cA5r@gphk^sd߷++ '#jV_S߱3_O\[N~Ò99kthwkt6MqԸzzL\DhZ!M[>òUS=}@r:Ķ $=8443M2aŔP,ngte')oOI Ь?mE,)*#@^t.y2#R˒J"0:ψ!fkz"@+%ɰXy8/domXduEl- ؛'e0B'Cpp{vعcy ٹ{ݻQɫFT뒧)1b* jhu.Ӕ=_kV^X_DcaP&Fdi%ܜ94j;hCKzLK\zJmÏP'Aud5 bQw]A=kiݢMa%]ӢMsR g;ܵ@vn; п-]5[[4q7$4teBVظE&-5i~=3*oCwر}eֹKU_nTZ;&Zl͡OO5m^p +uh[Yy]2G~ޚk3|V^9 +#ޚj?3sDj%/t:f׿YwzWq|w{Vй(>e'@b2{UW,1K@;2g\Ϛ*|+zs:Ӂv۝K]8\ptͿ}֓O~ǵڳF{ѷZ^,.oG.[jղoP?A@L'ǯ*A*\Nj՚/ ̖o]GO~ޕE_ŷuƢtwܽ{^q~Gs'dnH|r$؊68 +j`bA+iyMA7q0[)RC%!"F8(. td\(cz[[`]$ck*~ ](.(~*tFy"YR$O3U/3prB) " =ZsDMC 6 IQ)6 *'^R" <!@8;t:DSqaG"Vh$ɕ ȃR+ۢ2@- ˻4,9؉? nVZ^&J)?tz,9e 8*p>fAG^ ruń6і|f6z N^w3yFtƞknÛ[77_dqţW#c~wm+ZNMщ}{vV?֧rOZВEkt߸!-n-v_v `Vomg{ hqyzIn푽{:uT1A*1woNqÓ2>sΗ{םwӓJpᲮ#ֈxd4Pi?bO^ܪoYv yRlܙWIݐ l>]MR e1$1fž(7F N"E+YA;߇GL 8}*BJNepe$21iX`3Q֑霄qBL}o]iiv"F/1E>C`x x=ǯjinJJDN.RoN$g6apy42R>/ y+%bABĂnތ~};kL@Oz?>=⊎)[A>4@M .a,8X wB̲2`ħK/kQh¼C>_%@ۯӚ;@cB +X!?(„x%`GDy/|u?S泩o1r!uO?ߝ+qά*%ğm9CxdH"CIuB@Qˊbyo?{%[j,\9ۧʟ39*S%iSGl1O#Bąaj *1H,$@B:eІ#*_ :C{ l wO{_gn25ԕlݳ _77qe0u{W_krY fun?7_yl8'h3[d!9E”x*2zuϩqJu*QTx;O09ovdn~yt~\ ޛkC bkN_{θ}:lwu+z~jcYJ*y'u7zW~cNuܝMظUWff? j'!  2ڳoGeDJS\:oV;Yݿs9༽#2B', a3f9۾s\6}}r\|̬ G|;9c,N~pƙ|]>ӺM=r;_^^S:d(э)EZh者N) J)W 0YQsM(!MӒ@BXBԃOfXL9$S:W)jyH × D^I,=@!4y"P a;F[~"D΍,ET/8,#NGrc D "rxSeʊp jr%DpCl# ja$sE|{ʖٽ'mܦM}Vgv!PЂP IDAT[UeS?Cq3Kj 7~3AC[ZO@CU@ԥ1Pe=yCH'Zbx?dʮw= -\Eф o>d4|Khkޢ3\5G `^Uʘ6oO/\‡9YQ⍃:~ *ȿo=onZk{q!GvŁ@QCUa!"*/l o=iYO<:`[5-EYSиmMJ|Kn8wӧ_|P\i9Wee`럾{OTi ÃwmtjU>; :J_}ݟx xx=n~Knغiw߯=%*6]ʬ_dmuٖ. 58X{hiejW){ DAE<4urv5[(WeֲTP}15I d?8Ӄڼx9d@Rᙓ'!_hW1#1gDI)PJ+P2"ӢR(g1֬j3hf9*"ah40v c1B!rLUp@3BH @ׂ(c;~% )"r@ t-#ȇŁ }=\ H*T@LD*(|ȹ9PQ2Ih5NW-8!yHUTt:_flJr9"H xA@/1*c Fn|O?t.r|J3Ur&tieǓͻg|?1K&tћ{MB-V By\ 4?4:@ڑCc*xbP O>kKUU5l\it֝[]Dbp~7.mwMn53tI%(S #:1nx (`?-t@FjغWt "k6}x)1UUmPUU (eY {Cqڏha$; 7Tٺ\)KT.rXfJҙS:oCm bjwgdܷ}ڽ=7oY/?#_5M ·XΘv>uUn]mMuΨjES[K>Η/TM=NVS_f(4n(-+ dCy+͒wvM+[w2tʽ]_gؼꮷo4焩Ko$>gJϤfon)}n/욪c @UnfD3Dx$ ӫ>[7RZ6}Pb pb!RQ |N6']S`(DQlYn$]v%##p9Nw^e )~?rdd8*K_8Y&.J>?9D[ԦZ };\bOfI897fTΖRy l'~۶}>({y6{Z^ZV*uv&y]_ [a[>R TF #D>0'(0EQdYK~IE{\UE%IeYjᎹl/{{YLEz䋌_)(:۫+"+cTPP?׹3_{l= 㐵n#=Gs9Cr\ ]?t Ct8CK>!:47}K7Qt8.WFﭾo2IQED^SطRK;ϻ\.t9EQdDrbPl:u'rD*~Oy];:}VAj׾-5:=sfnlvm)TKe5˗-_zu] ̨ؔܬoS|rE|.{ ]řLwM~ ei"<|$2rnE=vȈE]f*Pki,JbÒK&7M[Zkrj{[=+Wb:e?F4~&V@RJpriP=~ގqw3e٢^+5aVQr je5 n?մy%!ɡ@=bεL\AWH:R]l"ru̸mO33e\|`29+6U *U%")[Vp 7>e!FPzli|yh(l?9$u4!Qd(9g-j̻ d7Igsf!'t.mj %Q+$b8:yH<<ƔB4IeUW%m_%7_fI'Qc2(lI~be,(+yri2 io9؎+re%gM7R}^0SW Hzd2̏˲#T: (0u {HD'O\fiEG)s[mݺm۟_=t`fQ@P;&7:#918NuSHK'}̀K7\+3|z2n8U#UU.kv]9!bH#S/  ,0 z T"LUh?!b$ӵb7T7%w-{.b1*+Nʪg02AQ5Slz)qf~|>z}^OOx<@y=o~AAAAAaAaAA(z^<`~]_?ݷqEY:sq,ɒ*_$gnT)[a<^(z9 l뀪$˒_%McxAyUeDL=^ 9'5N?gp\?y˱[y_@D#r(}iwKqknQ];TMF,ڴi[]MSג[PAZڪ7oٸy˦u_F?7@GRne;n_/+6x?-bh>}y ի] v/ r}ޢnt:+wIoqvWZƝ<Ґn yDz~c(}Pn[76TZ:3\GV~+ TLE #mv\G__jv>޵ƅkva?K:]Q̮V^?:[h{_=ۿ^k[WҨ- "м9>4aTצ5*T:$kuD׼Qswe@3oڵy|'-i$вmyq˷Yy/(Z2蕔cp1杊j1b09;}JBУTr@Umm,шDzW1MS1.+u8DEQ@rXQԜ%oh k.щ]9Э~Ϛ#cOy%yݧj\rw,xe/Z` EA7v'V{J+JѬ0msw5 ֋%4PD 3tQ8O~}f|3xڟyDy3;8a7+5WE _*qCdq,wג7xgD~#c i  ;0F*88GO{Οz3.7um(8Բ| -D A B]q׿JmOOMGiq~O*uHѳ$\!Ϗ@T}ʐ11? s6`\~Kw^ҋlXa?Yi@=gOxeOr^< Aͮ㼰dur~W #P!f] k{j1`[SO=1Ppyc$P3F=蔹D)g7SVyuCrvݛ~=+xoH3Ps0CN.zN~xfMW[g!Ѕk{@9z{oB PGS@BE@(Jo!AlW¥i!4Ʒ^TYACld1aEHC_o|po/0H*~qTHz؆ gb'?:pGstԬ4JImQJ腤 tݎu!"#b6%Zt”ORB5 Lcly[ص LB #zoŅ̌ AĘ;S|3-gJ_$eTt!#&c }ӂ*ں'ȤR=8FrDJI"0{D|G ౔fvᖮ[Z`pۤYjYB2ybJDV8gF_J "0HfoC@JUQR56iS/K6prK$JB"W>OVЭI6N&.5IR04 ֌gߑ1g>pՃO}&)0)AfF/K3CA)% 8gu4W<9B)T3M'292t.scBH^ssrY4RI" B*D") ,.2:L'H1d t\GJ{ Qz)Ir<)qJ"tlk[Q~ݺdQ@Γd4짆6"@4/ZsZHzVXmcջU&C`4fZ"-Q.9g ιR2z,NNݚ@?)I>+LM]`Mkaڊ3-8NᢂФr;pu o9BJ.Uil<+VF.Kno&͊r;a< c9%F$Y}Kl+QG{1Uk)&$6gpc>?È $@RJPx-J0"OȳjcnQ:U墸QJ07$*R?ƨ$ CDzTCuW$j?`E,E)9:ቢ*@%%ed.y0ZM}o䩢?+"1ΕTXZVJH  tjWDՔlwsS::RFVud)ĀY_E9;(R)sHX)ꛒ|`vR0Jޱ ;EDr9O\{7uӖPA(.􉐁H+L)RjznT)kl}cNFM)!ct,#Cg 3鴷"ʫz嘹f6Ĩx&+]JITf Ԩ}Rl"1VpI(Ua Dr3RX j<`AѹSbN 4,'"n)v*G. C1RJq- 9WJq0] &o)",)8Ƒbq0GEAE s Pe,2P7b < P+c␘b sETu*Z9Fk9ݢf g1bToRs%eV&BQ# 3`%JRxۻѻDu)8q Up1SJ7fLnV&K *)54KẮ޳XwH zR Dէl( W @ 8\_آ>L9J*`dK)P ^tNr uy%-1mJ!&RvӹC"owm/KCaS2Y|HAI=:,Ð1΅zWz>` SR gH1ˌy}k(b>ƔLsdS}䠅RtHWj"NT2!Ns֥TPK+/Q>I]R6GNK+yIQN>^[LU(;E\F)/C° a-~_pZ}Nz jm9 L#1J1D)%!=`LޱSFRb]}  GђME R>24a@$C 4C)Sb(D&Vd[Wbi z!t":Tcq9w 3P)*JB!:JJ^w\W¨lCc#2DRDg#z]F Ot8^IcH{nk202:zqE B$I.2 c\hg^ȿrUH[](!Y}F..-zq IDATNH*Ҙü1,K!2BJ%PRumѢ!w11D~8B8Jg0'rYє w>1?i>H19营+*@6u!NUrۖc6>,_1'}+5>cըe0B^N4l1&r%YYvbkF:}=pP;"ʞcD%zl Jv~Z* )!ٷ(O*" mQ_^SBt`0䄐EB)HIB;>zcw2s˨\J P.^9\RK3"W  V)Q) w:ס]te[]813K!?t> +`M `9ѠF 18NZcEid_ؐ'B0ƥ ´$н>): Ѧ0y%M""!q8"v6ϣ iMqcAp!LBcH9g1 !#KĬK,H蛎{HMFP9skat #JK_ 2DΙVDvä1!*"Rر^Ƈ9P@Zt, S$ V̏EJQeW="If52 $lKIg3]G,-0/j)!= X c] 6|;fD0t\'*^_C¹-p4Ҕ94fKsGyR{^f +@JPuESA&Ib_rƏStU1wE3K Cm#3 yC=pd*Lšr560CUk `I2A |8D>KK=*SCd뀈W=pBZx SDhњ4!&TQ2|߉i /Y cZMA!OkavZ\*)}!SD^G#ZLO DA 0f#N!CNqp'>kAf^B2 "d(,< 㸊@LBJ8B*Ι1)u*8SREP:E& B@p S+nX S?NlMECHq{eCAReH*RJR'y^G=TL.Y*|4MʼfSܟIm« aT(sAِ:!08$RmtuGlam {[MnעnPQIDM #&q]e,fKO(?bڈn/BVβ]d# |w :-ԚmhZEȑ} !%gn%?{ ㈊9.ZMD&}KEozmKe4@^(c^r!ՉU)Dp!@@5BHRʨrWup=!J'{{}t*]R|\!(AG#t*]%m Og`< f^B`<1+oVୱYyf+ço>t͹}?IJ2uH~F!Yw;>~ .)JhG@L:_뱛)Nq\da$Jt4Hz1C?0dBJs QA i@@#R: "( IO28EC7_@h}Fd~`s 6s]G-Wj8 +~ э.K 1u;qGJ9:J* J))$"-> VWs!dݦX [($E@T*gIL3ݣ ``\kh(#[VMBU1MB I`RH\kHGOU%L(M 4L&>IKؒG!ϒALcRj1eMQY "KW(V\Qp@Iu(3&,6 @,pbYnc<^E=~\,d?d?F`Á@rH r$¯1JT m31# -R:`ښthGP7yV( tHXF"μ ^IyӁpU]B-Wy-]VPAެH9)7wvp>}vvg^wuL~ ?[(*j^!C:KdA7ar?χ6Θ&OpEŞAw&i ^M($̡(H̱DR6ڰQa,v' ʟ1sXhEfɚE нrMhwDqBeCRJmSv+χ3gGdݚtD{zs"S*LVHD!Z>DBEty59M`(")!t9C퓗,E2|Alˎ:qle;QSjkQMӺMZ7)⫴^?w>?N3fJ@_qď7~W&Yh4ߔ=u@ +_⟍~z =c#1-)\HPXo"8-V82* q2R3ň-98" V`gtVk;iq^ C:TlJ^N tED )7\-d"<$ڙ%gXXhȘDV`lRejK"3+Hqig냗s'ԛ O`gz.9ayMpo g®'xGlmv=ziz[Z:C ;iU6` [f7"4?>k۵vq?ԇذ+kVnQ[`^{1}/'ח~waVo;{!6+gOu jh}*K8sεsS*YT&* .b %Ż( #uT"kޒS&%?S:Չon"Rjt 3keEx٬oѠOxEL3 u??18 cʴ;@KF+ER)EJkCHS[ dL߀)M(XJ8ajD0PNfs !3?_8B+Jix ;\'HJIAI2JYlCI"ؘReFC(0;<@I_zR; {|͍51#e4Q F3~i1}\moT9O}{#}z/clKյ[.p)HwEp}wUa-߬M۹ˮ >abͮzE8hٷ4oW~5{c>]vE#ywj0z]%^?gUA?el!7[㯆0^e,y:nyl&<~_L+mʟQEH|+_*=qpos?씓`aG  "@1P c2lې?j"hf%>ȴ]j6ŸB\NR4>Ka+lܭXiV<9%IQ= a2%|UzH+,B7ia BPZAA/$ր6حvb{Y7h"#jHh[OEFaٽZ'#-j}p?:i6Ar|1,h"oFY=%oqԚXsO#LD62b`}dƷZļl15^tGRy ,$kŔ1l5$~ih&ǡ\!mNlBupZFOqy  :&D)ND*h\z5 tEyO3Rm;hp 7?rkUYsR5ouc/,^+.nGE_;ODꭺ׺mC?k9nn"%~cniq ϛ3_bT_(y N@; տU|xO~GS6XŅ9DٳfR.h#Jz3aI(Z p]הߕq$Lr-`a,X^H 1c186o!h }9+!&6Z]IYZyi{2$O)%Iby Jqcj-"H`TBmrŎfTVa,Z,%)ѷ`,E91cX*y0Mߏld- 8c =Șs.B.K)ɹ,8_J.TNR'#ūècהl0jn^j;P_MOVK@ x5oI,j.u8:K"F)*J@ޞA;&"c@"tJ.SRb d]I!J0B jODE b` }9rd!I@h%Dt]X@P'U?6g/ EyH(lF)uګW 9`k ߺlm3CЛ0Q?^+w}# e,x#P>^݃*?{g):~I9+\3,Bjɼuzhbi$&C̫'b)ep:>8DQ\rI)Lorlr8=jkrϪ[;3M,^*qAԯЛEm#H 0/F~SXDY.%D" V!BT{k-d!n"C$b;_ QPX.Ii˔RrYtX;cB0pŠ$ɰM!ED)s4cULJȤTZYIaQd?"h yK5RH"'sǒk7bRa?"[2jSK]넱X;~8^vn`>K' 1;*jZ%ۆ :Ky]R- ] [RlğRD [ҡedZK^ "Â+A݈"+B2"7bFGt!:`$3+U {+H˨I& D>*\H@(pGU*aStTPv wEOϑ|mswVם~m `y \!7mIډ>է=z%>57 v̞O|!x}Neo8w67(I;M^_5 Jo*y2mx~b(ufϼo-C׬;>7W9 ( )iO@zvRDKO D*"r;i9#hU=̐(}#n$ s!rP$Dt:RV!P*Ҳ nˤS(/a!V |B hrE{ũG5̑Tz1X!܋BWӈJ#(%!BP&K72B,q~r׍ny(Q$p)D_1CvBtC5"YHZ,YD BQΗxL,d%%iJ:H0N@,@bKV['k?:*ߡ,_pon{Q{NZA:)Q~bIˠ20Bو$+et?W?3vj5= +DGɕ8ΒWod.6Yw׷eyNټdk*>8}C:| s^kGՖQ%%⬇<İ Pzۭ6#9z=:fv}Zm{Y?0>Oc/9k3#a 3=:fh{}õ<ՇBm5g m ČhZpmer\FD/^וD$uJ%u9 Q)HŜjRdE|ZXJ*%&+1ִpeXF(Yh`ȕQJ))*~IY󣷐B iJj2T$eK()J)R()4J M0;фkgGDcc:b:aHNS%Z!s;|nEwиD8"Cm BH)Br"% 0y Q )U*<-Kr\򺺻RW\.*rR) IDAT[۠k}>A(JQQ$6fqӁ4(sB:$AQJB~A_ 께b?|ofV>%`BK1 u2mj[!NG]Pj5@ mތ$.קVjD oHߢf sc=O+ ~8VD%ƳXg)v1\H#mJS9EWuĦ ]8#U{ʀDF_@>lCkiaߍq&.v(ZخZ]NSa!桾;ʟk03Du ~=%W\Z2)Z[HユO wABQI{cxC6 %%cL rgBj5M%[K8:!:q!ihO|!۩3htV E3qC QH!2Ιz39.Zd)49.ƲT2BPؾ0"TR2\"΍Vuι!VR?6K73F&>t=k>oTtG_+-o2QآNvޯc&p.Bl]S<_u-m tR)x!ELضK!ٲKZk|%G˘";zwYs?pWڇ5lZMmnve0|IvSOl1Jm:а b,AS*}JVj݋/L|!p+b:-4 ?=r+1R !9׊ ZZJ! 1cn\QySb\l8 XAʄN}0}+ 1m Kj-eQS0mT=gAsOWל`7_nǞo<GC㷓3j~mWCr[zݏM4}xlLxeW&e3cqT8ߓ%ra{KunmĢpu%Ӆ7EHJ5Ds8 R2DfYoYS/ö5Rb͘Fbcl՘uhں^p[|VLYq2[9-s,C0c=IڲΰQW) ߪ \{}o_MBnt- G9w]gEg ŋ-uQ|c[~׹N LU|߮U?.-ˎk{)mx7 ^^׷u4CZ|-R*E%|Q?t+]j!C@xT*jM$&Uzd]偲N h1ȢEH++%p@Zblj(SP( lb )p5E63R$`R)% ]D͟ ;"\ p5_(kZ7=DHNW P)՗TB{q{<.m_ʼnQKřEY({_WͿ'Ur;vf~TZ.sۦ.2xFky}KsUDz8k`d>5ھ6mf;vˌmj{{54DBLU ԜJI#D"TZٚ9N2@:=~̅VfkclXxUGa1"M-}$jNnJC>#96mO|̭O`I3\9n<)㨿S{z;m9d9O~w]vo.Vΐc *op^c<])uwq}my |~AËG7}|lr3gswV؉ŅOE"0o^Y_^bh>i5;?n >oNߎE2EҶ'Xʕî_}}k}>[zK.d"UfԟUw=xF9mk׼o~;߬w?#wb"RU1W\ٜED l}/1W9pxd'98!6W:o?HƍUþxˑ .Q\{'x/b;xG?蜇ذ /'._/3ÜoKwsȚWP;$+_Ï?R_l?|끉g{/\[:ki;y_{fy/OnQ>þZo}y'þĿ;r!':s e8h:zngܴ.!Ïw}psxwK-J#ER*}(f%7H'F(XSTgCvk?qE~A[Ѫg7?Ȍ>:1S͇9&{:m”o2kA {g~=If͵i-d^7f(Us2b-KJCF@亮zW~(dwvr3LlaS:?G0n\D}O=֘LB ayYL 7\?iIw=nۭY}})3?p?fjipB!"*Z+G~0yv^|2{*Nw8j(-*:PG.'V|qω]9l9i<|:{O*S?o~s륝93iԩi&xs5W?6a7&Zc%>n}l┙~m13=wݯoC}֟q?oG猺=vL-L{NRˎ)E56KZr#nIOT%`LDU*Q (V CYǽy#]2 IDATqV @J_0s޺Û֪|LPuO]HWԑZX _Q݂_zgg(箑_"A)7n(@A/ 5Y9"+mVԫ_^ ߷{\xƙ{|c['Ww'{|wA ,ROYN./SXaʒrq74H+9bfr̊fgɷ=}>hpKڅm=wߴqK~;}s泷==HEPJ⺃7Ry2zG:CZk~qDs\_V,5~"`Ə٥%nl.|6S)7lx'j5uPr-qB\ׄ/Pݱ[mC?la2_AP3sn'[̼9~қ?cfW[Ϣyk3CEumN9˽~^~gU6xgr>n9}/+OgBr-zqrZk?֫kpig0"J.uK}~ Mf 0PpALŴ0DN;\ oN'S-pO/vo9rI[G{o7|ԣ{ {YAeKO=aǮj!v\n֯ɷzY(VpU `bn456bT$5(gEkQ{JK6@'䚈RJ)" jԍ ڬ[&!16 )6p^̟c"`hijSlđ+Hma+-[D :k|쟼y gET]j Xr=TfdRԈh!t-_ BRasmIϴ<΂@Fz "d(@[Ks:˭>[N| g?Owݠwӓ<,Xi3fk`€wW֬E }t!_pշFS,;y/&^'/=KV2ħ/?˟iOOVCv:>hu{8 hYV5AgC>7cA`M1w}}w|U93[لIB&H"Ut"MDT:( U"X)Jj鐄fmfvfw6 o>a2;s=y|2q0PO[M8kɔk fx)٫fcŒ7O'>(tr J:g=@<;0y9y>ñې O.MY<Ɠ* -Qp&+[rL&(c2['/q 6p؟fut [[ͦyɛ+"Ś}Ry+*^,D`vCG\+"fQԵv![=(oT}ez.~T &TVFjC (/ssMвk]tF>jW܎ϼGVS_*竍w*UUJdIȮ$󥕳YM'yeV+4A"8B$O Ɍ&z45Ò$iG(1rըJe"*GUR&S[N54L2VoBb,v9aZ@]d{:yts0'S_YyW {J?j=k$P^ehjð%AOA&p~jjEeBjEAsyfRp];%8x~*َBgO0ZqW^, <ڱ״$>^kuD ś5l}v oҡn2%CtrQnDlS jkna/* ӭ×:ÇtxRگ @{%zFAY8j{6S )[%jTTըժ/Grc;4Tv'y10'~ZTt]zx, )Ŗv9:%N,%: J?tP~M4-V<81CAuY#U5X#- 2Zy=FJfMez;1Wvc.xʈտ?lkO`6g]7ǑmZϹ(Z0ek-COki{iou(o%"UV}a@׏8}dv-OǿE)R~~çK $Rr. yIfP8JR߂L[y`ҵ^qȡ.9fԪ'thR ?U열% Q~tѬ}&g\F-_u+ߝ3q%%=?&[}Nk:*v2˛#_E~߹` K]R<(PQStK* _Ef!,vU>$~2r\çÙvk~C/@;fZu͂hOj$[c98 y~t}&rh\F_V_nWp}l1g&ޓ[n4C?F얝7;#Sb 74i7-]9O{#3}87BkV)-甉?`oOfPvVH?#G5 '}GAozP慅cL<|Bu1 e+}mLхϙi6RJK=ꬉ?p/Q~[{ݢO^@5l ];{!ϟ@ .3|l6s5H@uBśd/YQG<:k`#}(B~i+2 "9$K+!l{?eHփFJR~( yGOsEj+uH6$"CPpD/[d<z.PۓO@I[KDz]$_D9S_ѿ)V9`U*^E 22x%酒i͇O^rY=+deuiii3!aIɘKlre )m0oKrпI%B?r]x'uT` K!q/ܡ/I]ռ=08]ΐR#%_ ve+0q"r B-gWIcB/Jӵ<7GT4rK^`VpEcQ<_TQYb7U<>oy7ȄЯ2L,e&o |"^^ <}a͞+PE{wpU2']y ];CU}G-x5@') ^l*`qq7T1A>k~(Bu>dʟwߘ|X \:Bu\@H=IN)Usw>Gٽ*u; q ZB<As==5KԬA"q"It90_Gy锷%δ;oN2C]WDH@ĥ$1(;ы7Au Dr:Qe;MPS"[ ׵_)!FČs_Ir.&@AB}mLWCOI񈪡4|B"3rYq%T҄2ֵx{EoĦy|ü$fm1H9EdlVi8qVY^)j6sB<V_F j&d),|?<͂^)f2ZgRDfr2W~O>oHUQMNC{l>yPi 2Z{]]9Y0j-RkL 67 ո J ~mE*}fn;}"6f I4@@AtUv0Dl) .h ('7˴ZTROE狕㱵#x46{4јFTQ 2"VR ݅ 7Mt'RZ*^a`}RXƂbiE >=D;FB u<@P5⹶ĖsС;N/UB~@N6l HrYoJ6CvRr찀=$vt,Ɖ="bqs~zaoN!;v9 11ǣc5/;s"ף0DC-&χWQ+GXPcz;@ۤէW U7HHWQ42ƷLX\JnNk?ׯE.tW-QFQ#]wTo'7f~Nqb7l:eŤ*M.۲/䩣'c0ᵊh8w=~h\#Mh 'nZF -;t#k<@kAuRYP C? *]" B GhlY- 8 p(!`2A4 5V"9@V@_GӒ%7';dFZ朜4:S1dg RO5?WbnUxrۻKN*y3 nA'rus]yOnww7cj4len&"@eIW'=YIH`m_l',_']@0#j5[oΩk <55oƂg W޵(Y2#YⓙSO1R2*] e?J2Mo^kٶg-B4e-e7{)|DMҥ y+!%9`ނK9& ;n3-M~/6R'*s0ջH (RV͊UJ x:l\>0Xi堿 M IDAT~\+2DIWL[< GH^AWɖ(w_MA#ܮڨYX[Oݶl_C+Lhrx17yx˦>|Ͷu)r+fb` KX#ǝEe]&ux {^drUgmύ>KJIk{s꼽gJ['n|c}ƅ'/+wl('$S/X١Gg?Y{,K+e+ [u;Tѧ_ؼo=*w%e ib৫Y4lVn8xc:9svɈ8{#+6`{aVQ9lIKG:?ws -h ۄD mrU9q_i.I[:r~׳І{7չs۔5%Ӗh;zuʇ踔kq)%ڎ8E _l]B{?mCwVl[|F槦 \7x9?8!{-52do2y!m# cƝ+?lei|qs,zsxřԋU~Oxb4yDۥ,RoϞԿ^1.qSZ 2y;m*FkFb֩~au+zAx#"`Z/ zL2n/M'w) U(_I DF-2HXԴ}o)'t1uRP m(Ww A)'?7ᴰ{?y۩H15 mӫc>+&^ c7 W8,JL>+ ZIG$R*!ëfP l{+&lV 煾׷EmoTzg찶^ջ3;8̍ڭV6mmb.A~eˈE+z凬{s6~fyc.'mY3;o,6nlզAD@Mh 7^W-(zvsyDz-li-EktTi)ow6 dn `I ɨ۫wxS ,HHJl䏚yLs3!P o1ܨtF ܥȮ)Ov?vjVguނ30V#-T dPIYqoʁtfa/TB`KEvumzs7+⯎ ίv{}v63oL6^]yP"#WiR鹬6>O \xwPW[hE5k=t$5|L{[^/R-}z<Z}؀@ $G{ɫ/Mݝ߽+6k\4Vlf[ o4gE0zfS8l6lfo2 1Zk/aElWݧWV`| &O3G~ۋ`B 5ܚN߲3EcKKv]vCT[Ts nҫ__=v: nh٥1r:CRO\ѿaw<ުqM^7}9C,[[͠w}8lWKlk,VT>kN/ۣWO_׎lfuBp>' 4shg<{i˴oq]Sa|u;^ܳl2ZfOIq ;urbңk\֮u_ԕĤG_sM[A (nwF>Ϭի[.}|Y]䯚FC;تu9\`kGYGA2/{KZv(l]2^\g|1Y.@GY ;];~Um:7^ӃCwo`Y|$eaΜɃӖA@(x#yװ@HeQ OGC{.q< /.#DxtVrw !ukk H=Pn~k C@Xq}ydu+%TDʊ'>} kҮiwK1`Y PJD-@g>{t&oeX RI;&`szN vN}ra(v Qd̊; Ǿnɞ_-iN΄RAQ;bO)[Scoڜw]6L[:$ؒo9y2Ж-8>GATY{KqF--#&L@3@@X{ˀK˿,_zN߲{mg3Ie!ص2u)#z#7'%w2H.])L/N/G\(_GAS6a9]J `/{w20qLk7~ox?' ш=< 4x"ҹ5i#ȴR7 "ٞ}·q>pcȊ&xZٞ}χ1y>`,~L{h֎o^Pq aȽ{-Y[\! 4 6T[2o+e;ٚUA`ayBNe3sFZ^K1VDgЪ )ڬ4gu( lqF঵Xko'λN{01/9[Vco@Fz{;$%釧= `h:23yse(n{J,1+ZiX\zNcqCكN^l Y8C詼 $׺<$ Sq;ņPdɜŠ:Ok~nf:iIF X4E217~?p׾$Y҅υ7s׾~cئ^sKv5@ں#⁩ǞHLj-5X0΁9f5[sh;2ީh{+ 81f*YTRr+#G+. -Ǜ][W-r,>J=19w|ڱ@Hƺ#w?:fսIp3OItUIzo}GnI F@"@pA]$6wpTQ49ˑq󋧲S 23c|`ĝ8[G ?WX;(~d{71UF g\d-Ad_>4k_\%G7@up>IvOӞ kmh@G1's}% BiFXܐvd!gC"BόG%8e4vC"BVSo-65׌zޠuPxkϵ䭦LA"+"#< H>@Xd)D!#B Y/l+0l@@xCa2:Ax6!PBbJ??L>w.7ɓTK]^Fl`Az%b3%%= ݽa9dM,njKT*a#tԳ[:=@&]5S5kܰPB@WfNF>" Q uxAggISFydPHJxƱ Kp |9\ap``KMsvppʀ:]dS ~߁IӎaKMwg:$hP2##hk{~N ~RF C@`HDdXbV{)7\nI1z=Ѐ9٦H{`%YzX^@[ŨoCua%4УA1e *V2H z;;C`>_/lvl{y[ ${`sϺ{\K*a}p'ݹ/(#^5B))AtϢPmULݸd>'aw~%,Br|stO,"3i>!>7;K?qVSvNvdZL998SɅ*fssxkNvNǔf0{ VZ|QJFV*WD lwhTN>ז;6>pnY-""Ձ-6XӁ7znc.~`J=).;-µ/~H;G"IJLu+֭[eX퇙v9qRZ@C.U/߲?n 0IJ/Nۛw0>x]հr ~Zs;=%eEڈ^{HysL,vn]~*Vh{̀;`^9U"8w)jY \N so}ҼM.ylw n9#ϊ VD9aLJԻ6Jz+'QkA5/ݤ)qN 8K@SvXXam^gYo.[@K4("4'v>c\1\g6NWw[WERV-_DRUU-[D>WTqӆkjYq'nD-㾎aJ?uX녗_>sl5WM2]-Ulҍw+UYJn ]("%%1FjT:Hisk|S͈5:UWFתRDd[J1ATr|g2}1wUFߧ@'m>=ÿqU= V!Җm5v؈>>Ky0_[5jV'æӿ~ lCG9SP G\'V]0u{?U;M;]n;693+ο4@#۫L*9g7gR/n:z,zˁVVِz=0(hUfZPM@ny>)/ fRnt;UfS>{̉(,vVP^~R̷;'#ZO>\*mtMN>fm>E k-O[zXMC }uوq}r@YSڻ&^!h\ꗇ+_hԕȚ8ru7|M~l3mq[^n2.s`8{Vi`Ǜ߹`7ȵe^\тS]iԥpߢӏ.Mfߏ۲K}y¶9?՝ꮤ:]#n=qIO.>Vi/Z7xw0#çڿx ;Y/D(3L* k 1Rq/ʊ vRw,]Zf;[Br ޏ0'+fijj/n YmW"<>ITw6 f69ÂK0q^gi9$]MEn> k&0~̊ZR\B7<{TXPIGD] N{ln-Kt-tQpKꔑL,[E"_ i^.U,YCʼn+gjVO?.1cu2[?hMū%6F?oؚSӂh'_x8S\g'C X/'s*m t]W7S8 2+뽯V79uWVAq 7,~HB)ev5l\;xX,>zH]OG$9gVivO=@rNDF#\:;; ԚLyD碴2wE쁄E%֋%$y_%b#^olSZqjGEaQ J\J-X!K 6QPnW)( /k zpIIG Ap*S +92Bdp9l K)ϲNb\rP"(P - gUXeӷ'Q_Չi=x16+tnW6#Z*yC\#u% .Qwq;PRN] $?{|  .~DE jS%"}!DB4H..^Q0fzQ("c6$ CxvRTC3TG^qR0x}TbR x-%Ct*"nX%-}ņx̺URwMFŃM=VmQ7ݵϮUoS.1T )p 5WҊF=I8 kͪ|lVd~7?TGU<>ǒQ M$|q'Ge0)Tx>lG"*yBi$04! ,^bW TkuPPx]Yn9߾0T@5YPvj~F:kĝmj|rL9<?$hXFjXay'1QF[uf[ HXI4[ ͡ GէQkUj%={WK&L,BEJ[7R;%7V#I Y/p٤vnCy"Kq ~/HXnKy @ ̓@Ot1aFFPjPrI݈ FX2=T6| ȓSQ9(bZV(1G_ 85z-DYl+E\9V-y( X$]Vɮ<(,tnGB!BIJE‘!ǴIl1P>+W|qRp)9!.";A F:J,g:uM%?0%OT utFӱ,àQq 9TY!vZ s\3'# 0 NM9Q6`$(=D$x! C3 ϰ< oDyHq$j-8?QQD"ٳHKU - |ԖkD6Āi_ԎjA!T3!ǰ,H9CΕ17dߏ/"oݨ7>׬)ijH›J^)#](&w[HY>bu8Vo+2"9sI#\;0'K"o; .'DC-&O$EQa>bO@Ev}wӍB|0p* R,VM1O ɏUI{uIz:DfX8dOo>@V#.6D^/ A^B,|_AUBbϖs̶!ee}EsS Jnذ~O>':lXmRV#X<=2bƗ(yIO,64!'iݡ_i DTtn[纃(I}fl9xXL) UJǼ_s`cPE{=rd2;ɗT>(L}"6|k:b (ь#1qGb60ɜݧQܬ X52+dP[& -EZ7G { #u؏r"q yCGW^FuZ%E >-DqǪ'; Q-$>y=`J )~Z˪zqɘ \t#!V1$RSO1u| uBG6!G;pj$Lb88bd윔 ek88MG^[\~lJ4"LGJSL!dB FnK+!eHEu !!SQL?)` kX`4h2g ;FN  4cDD1^<(Qw:M\{'m~|Zo#xӉvg/ݹzZNJoF|yυe-tۏWxŽ?Mmxx0(Fy ϢCbHo?r+&(Sxv ^q<&Zy c/?sb ixc;v .=|,gל:+ԫCovojxxmʖhuF9q+ToiLǢGG5ӲM?ԷRcu# 9$p$u[ &s&i,<1Yf7k#[yӍûE4m>P'!vL hw]Ч߀y\sYX"?8AMJB5VM7Y Q/OXpPn&'W_m@+3K2vߪI|hH  c!? c?H$6UlH[3IVwd?Nl%QkKGOmĖFXkouhܩHcwݱS3#r'zd0-&qG - Ж#F`e:45Y<%`xH=:MJٯr@Z@9dX8 @^ǺG5`p3en! !g5hŮ5V":dU@whtZdRs?jX, Gί͔mנrd%S~݃tU-1=c 2tތEipǢ{1̆9ko%eBg&=5@1pxwe0y=2%>q y`XyBK_z\QXrk |lCOsƀsv0Tzoxvץڞ=g .[MOm3;n3-[~9gݻTfL9gaML +x{652zW+wݱ;5n՜82`_ź*uTJ.5vXQӉ$h~}Q;D#.r :${Rn[Q-nATR>{HsW hY`kj}vӛT!SAgjX,B:M1 JQ`,HwBJו9Qк[tN]9fA[(%NC+h˾5NUcŌEZqǢb%&0 qG(>,h'o m7gI}\t9o{WRU$@ @aToY ZPL|(PL,/|s\= elS.1^6zYLA bQ @D`ۯ@=e: x3eGC`l爮g@,0A@Y%2Ob|Đl+tabHAvĞ9@Tvƞ9v"f㚅Ć6j뭧n?wn#;֞&ݽrTR,_36?rb ^( BuegΟmŤ,5-W._r7~-qxFw|ﳺí&.*%ǘ7٪{R9);}?mqĦ\qR;xtM!*vQنݺaẤ2];Vr>'~ºGwxE)F&O5OA8oMwڵkׯ_~nu۹g5RFm?xm]kvc>vF(XGX_m;xq&K''֮޲/̅s{~\Gzȋ5)7Cq֣^n+:0{WŤٿF>Hlܑظ5˰:Xۉ#1'vQT{ff7M@ B/"U@bCATµµpE`]``GzSi{Hh-3缿?n^~ˍ3=o} |<>  &C>9]<;OraQO~8,/ihWE :3k(z8?}~}O}^|vOaI5rQE,SuyY,5=Y=s,)@̚7{Ѭ^~n=eD:A2H0 삝={*CiN"&xN)js1ȕmm R:0%T7Ψ'1M{?ڌ_SLy-d+C{_tޙaOI-r)rlظ'&jܷw0U^bů<6/~#j:`\ϽG9Q/:nɜ %%|:jԶn@1GԠ9b̝ӰM}ko1KW= 8&Z%krz3jY^ @n<Lng,1qE٘Dy_ Qj_t{]:$ > ፘssDvajڣ3$}|?4^F]ndPlxy੧֩ڎ|fLuo^7!/h?ɑh[@ O ͺ$$;㔳+鰲H mwYkd;YBtrgĝlCY-Hvgu+7>ueG_Lyvѡ7}^9qV+)p drTؾE59]VPb}%KW*hߢl n4./@&7\tnsmQgrUϚޤI,_ng |dlnNuN^n@!/֧Fv7W.wϔoYzP˚9}Xoa%g2g\K!L$* pm1F#h$GF`JS@=Jj y+q9D,cD`$x"*._F_‹߬ڸjn ׶Pp]O}l~'A+miY^N\s+[D /xܾqᤧ߾oB$ADR+>}Ւ_?~֪< |܀+GZqǶs}zڸ,<?Yz8.6c5߾ߛP^+907!1ws߬ٺ~}y%H`4BxePzEAΐG 0jg~BOcyF!_?۱q{|>] *T@bMFi>~K1;X? T+~v:~˷ڹv'/MY@m$Rzuݷa=nvO^{-N|_Vm޵Y'wn<3gxd~_ܛ_/Yxן&OSi߹.E^xe~0}t-@~17y΃Ky[͇]k*=^08S,[-X Pﷷء:s'Eힻ\}/M\~I(`bsʛP`v[%6f[&Oxcϫ6ڵvQ:tn 6f,qkRË,Y{cwGM]f>_7wϽHHX27o;v.>O?_/WNS^|ތ{@ѡ&tX ;5ݒ*uR?ߵb_bFں9T">=:z];;0?_7~QmY]%\;gnEPxRYpTI0zw޾橋~5aϢɨ Y]㜊v-\?ܿo@~qŋ1jX8fvӀ!u5śMWa0 zNnj:y,E{RZ‡4CKO>3!e|.F=8N9GqU=9vU"v }Ƕzap2/7%I9oO{rutyܢ'%F8=敎]%OFs<'9xs$|>}=C.?ɡP8Imm+<# A(]]u7n#"{𿙺oCi@) 36jSŚ-{iM}xޤv6=VU;*@ݵ[K8LsoEkM'?WE]r? se1բ@]IfBp!J$h^":QR{8(%T`8s).C ڞU+^U 6/aOkg!ÿ!wʰsu$:?ߙ$+KF>6hSe.Le8[E`5>zO*E^6gS}kB :džF>rsG~mW[Yeզ!Yxb8y-IҎ-/v;WYʾ߫Wo~敷71-S'm/9?U[8XS9'9{m; -En9c~9{l.ߺTԸ:w8e/T}CuCAfCG@mw-8M-}pߟ!?pOOFVZ2C*?ƹZ\9G|qL9UM<jQƞ+K~Z`gI,"#BU{iiehJsPQqF>nNuzp,#D+ʹ}2Dd!C7듐nosaurb JsP{(1 cIXD!}aME40㞘jJVOư@8ʄҬ- KA r`;;_C`|~9,4?]Ͷe3bs3t~w,8}p6WYXe9u4"[z0o1}2Y臽f@w2!uϡ߮ > h x'eM9Ε C"N5BBK&>"5p(#8F\eD RNw$0(B 2H?#@DF3BUӟԄ*DB$4M g%ܙksa׫Jkhu8We%'^9yFHu}W)jS'M첒9 oco:|wi[~Jf#9P۲ІŹN. (uNlWUiAP6ux]8|݊uEVІ%' )[Y u=}r6ux}F_>e9-.]o7&Y{7jtJf5.߶j}Ǻrvd[:mj;hjm~6BZ ! J6(qNm~4~ysUQB=߳~(lZSWJflwafs֞we 6v+ ¡F%@ 7jUrP~PmsaN^].Pv筛܍TZ8k'5Rrt8NH/tyCp Pի&UiWn*L]J4VrV̧6ɠDc7f/v%_5Eh =0 sM~|c#yE~~Pn28>ux Xߢ6a"u K@5Z44?mA&H^ ԹZQN)ܾVC@@ cjĪD 녣/~qoc ,kM'#j >޸$r܉uy}B=+'J^zEduٸ$r܉uBJa{Vi;#]yEW8`ï{(.W;O1VV4q0g/wѴ@HLa+mݞժIzx2]m Aצ.o} OyʟBFT:/ⱊ GgIj"f_O[~Vo8ͺ]5{i.0-fPZ1;Fgr:c 4mu2#2c~#}$ˢQ7ۆ??p R3aQݽt=7L4CirieNU`|CndɊoͤn<v#ޘ^KN^:N' <OC3!>[|Wl3viT7u҇7+>7uTD^Esbnp<\A#C&_+JP?zl}>3iۿz꽣&Y`jC^y}Vxb H~wvq6tCwI?/}q3o[F(ɒ_LρӒbΪW?!@yG;U883m7#X黫OɵpC|0$c2\~H|1GeO9{螩~9~H۟w;ETKWgr56\m[poTӦtRCgXc&|fS1ɷ?=;e&~0q3bZ^雃W邻6vɵw,۾wV{,ߧ J!%Nx*A$`f&tTSe3;n'F!d* Gʶ.0)EGG)hF)O5N9h(?z6>h (Oo(Yr0:T) Vja}I7= 2 I&`Cᠻ(C XqoCFN3ɬ]g|-5XK(fqRhYh( 39$g|;"BB?drC\#3EGX^ ɭP :ӻTe4𨙷U5VjUMQ)$ַy8_tUqb#a.O#hp肐Ե(cȅ@D+05峅kjbȈq&I@$a6sBrFs#ty 4)KvvY@>hu4bxՅn~o_"hmqv lDt0YQSYbS -#@xYH/JL3R]N<$y)!ruU1SR- i. a߾ߗIp7O73?W;:YEǩd!F@\%T`l`gP@H,/XapuwCSNQcHQ.vf\jqK#yY8HNDY}5 R=3H|XuU;5?0P:4wV, VB\)kG'!˒ųO֨aEe֎]I<""dL/!cL!HS=p]^#$r Q6iH.K?&`:fEzXZt8YX6Oر",t$s12Qp̆w&A$݊Í%v1PDF :q7|XKl23ڠaE^;, J=QyҔx,O.&6|1¿ S۰O'FWJ]uibDyxFDOC{n#fzP!0M@*ٟ 'e[/ais15H4"93c@@i*5FD&1YáP8' E$I7EE$I"˲$)ȊĘĘ$Ye& d'-RB^;Dflf[C{.+& \[1D?^ " U~VeG2tS`'>WgܟR6(-f ,Fȍt&S}pRle;ʛK>#k˰MӅ'+^݅ @{׈X&ΆB22H_e&GR*#EW{hq*ioϨiD;j@@/Zq^2km ~H2T5U\MjsW |H\ӜD}ze^^Ru(RB!,PvƟTGM%G2Va#Xuƪ!<ƪ3 #g:cy ,' R877D#9  Cs#C0+H$D2r.#7Fh\u*S9h眈k;v9'cI ? ²Ha4<붗yEOG;Ri7n9֝|n6OSweOYQgvl20Xy84c%t qO9 y0&4+*qє K=WJiHccF{ }J[6t 0;)@h84`M ҇N5+l3a>,O+1fMqX\&imcy2d* wLM*@?0{'$@^IgN3$j 'ҭ>V 2[Gh:()I8h$ $t[ɑh$V!!\ 1Ȍcy2q|ߺa. ȸOƧN=`BxEyE,eI$***bIC!XEyyL%JsftE]Jsa#V/9OnefYz'Q x+ghԃϕ$T 8ʯp3Ox7V&nثb`'$@izӏ7 6fƒ$;׮5ݍqVy 0"YjY]`I |Ay=pj=]NdYR xI76uWtSVdXفgdr솑 Qd!鎋$5UeY;׸Ȳƹ$!2F$} ݘ뜚*i $g,-5Xbad wcsdҬTEB)rdƙ8OSJ3ɗw.3mϬ\HҲ ջ} r $j_dɷ*gc?sdWyK#Eۉ r]N_K\6Dˀ֣b{R )HM=53TzYRGN[F.J d"Ђev`8tYLn,׻1CAqJ/| 2}\#q: J S1"x2 ARrr SP "_a:Ls@1C)F´$!CA:8fD SE5r9di"0\JG2UUs;9sƳݢL4uIdAǠ3L G0+~uw6/i V,fHQƕORK~KGbVgR|z]a'I Jh2JF\监 ,)si# U *)T-i!*BkXMlWLQB 'RO7qz m*)#M8`-IpXa;r!&80=BBp&0*%HC "OF.3#ʨ\%Xqj3g-U(_>e#(FZ9`ԆE"H$q݇@-7*M; ،$ku$Cdz135c_K}>وg蘇lrųe=F95;N;bBKVݡE5V ro!,yՋw&KV9 kqO?vȣs=ipY[>a>Edx.'*bz#1Is.YٵiPa2g]LKn&hg~= sNB(/>[3l;>K׳7t7pi\ӴD2;Z$դij2i~I5 YSj2iDHUUUUIUJ$ɤL$㱸jְkhTar22d@%d<O$r¡$1. o߄!2T^);Q=#~4viE/:"Gz}TI٧Pt==+T-$1ƌbWm0`gF_N)[Y {}zR vUf_UfJ;JATo)HNjKŌER`0?/춲423fdly}\2%yDN\g-rB˙ wDpxJh/TYg{B!dB(m%(7HAx+MF )I~ӯY\zDx"*ZV8n$Pť:5`I lH{^{@8u }ذcX>!B?5 b/6[W; 9.:ґAWť7Q b_9 k^#5~Y;ol]?Ǿ< m"/5.`LBD ,ń "\$IeAFVnyCO̚4:qX、ו{4JI~\mwf}N!m=Kc 2BI1]3M8h^tNᓪ+Bi\\$(T5**4F[ 6эUm,"&@CoZr3dsYV¡,K,KC==0I}LdIb^y@z-Rw$m0ly6Z*QGk"8լ&K赘,$O4nhPn74GCsu){=V" =̛V@C A#YCK8 +gC ]HsmP7r9)Н'⧇ ((|6$B R3Bg0V P+-Vvŵ@$Xƥp\.tߏG,V&RL?|@03POf]:tac'L>Y>]?zztRC3hT` 8LP-5_>#pQb:(?IP8$c$!\F +C&+! e%%1IRaU~& E#cHȪ12V Qrώf@ |QY Y+3C&gXg!jꍿشhk%-l|B5}!nPЃ|stAm<=y~D "fѓzáC_J\E~H 7p_]5wC.9H٬WXϕ?׫7=;\45ْ3z 7Mg RdIS54~ t.w\d_tfO?Y7Gyίc~ڕFnIFEţD9 mR"DzϺ bBgދ! 4 ! }I?,JGdYѝ"I8ׄ$_9Af.h*dNBbL$IquɹLf=_OĘ@EgbU fy'nk IDATZocOHa& RuI {"@0*vFNSq5)?)pĠ:d51Fl)9G?<9VFE*Atr1vRXxj@ WA Ce]H %ֶ C@8\> +"O?4  EY&)#Lt>)oru#LON\C1uu`:4ErdpNx%se%%-OjFI'0 *Մ>09$+FD'QF"tGÈ %0@X(p"ؠ`b AS+Dj%3CWMR8'"i9VBs2%7$ F"KVLkQ}=+ӓ_rdL/ji÷g/BpKjbώڸlwIEu**OlW:σ x+0zK+UjPІŹ=N. -Xsג_ NXF׶.VZ$@һ#dEU5@f !ILU՜E2DM bNƅ ʠcFwmץBUڜ `uZՅhfQ9K4Xu\D̬4 "X p.0z!#;2vtXw M>9gD$qM[b7!ױ9EVH 0&1 D1Ecz" qD`4Џ0yv`9= :v&kEwN#(8M6bs#DY`ݠERbՌ\SE/"*[>.05Lic W| rhV*Ǔ-F}\p C$@|\0*OHYD^w ?si'&፽L!j.g ra7IR  %HxD,Ǜ|\*ĉT(k0VPrwxLW_'cd* J-pY\P2GQe(#tr+Dy׬P߈cl*bU:Hj%gd%dLrrǒS4ꅈdE)!YHIH_BkAR[B7MuQoBƹ  @$I}GEo \S$W5]ntzxUScx,(++H&fQ h4/WɊ б#wj̊V,*&{ذh<80qͬہ"v A_`KFۋ,˒,3ܑzSt%Xh=1h6x,kuŒ|9)Fh`V3RXcd=Lh;,!|DE:jJ)O$=5RNL6) `oqv:{U8Rɑ0) "yXkx&6̆T7~0|KW=t/J{c߶7VrU*3^Ψ; nfW|3oGdK_qfq#ɤ4%"3|϶U"z9@HOm199 &"+BI1L>pfKz [RJt|bQGYL=BF3G  HbM?)RD˧7;[Чڢ%~F+/hge^}P@.TxvcN!}<@qrK$UٜI)*EлuL}J>Rf0ɵa\̶ҖJRbR``4dWZF 9wfZxrW _S*y9:UMG]~!DBJQ&7 0 8Uj-THr8ǜs f 7DBB.:RR_wTQ~g0 0Yy[X$ )AC陷(xCi7X= 44Bq%J2a1.D D4M|0!qPtU1"MhqΕ sM5'(k7u;4vqW 9WlHўo[n`v7HT2*!`UZu)!c9w @PBӎ7$\ĈloAr,Zn0ɀQ!X_~nѸ1"@4MMT ;qڅQD@B, It!gX* %jN`6]SVDޏZhUp(U=[NpLm.a#C|ŪƲOx\UC"8td&Pa>u-o0duZY[6hsJ^5ve+^gU(E(O1I ]S(YXޯݿB0#QQ8 Tڦ1m/G>t!sEЅ@`6) 4yb\/9QgMwLr|׊$%(hz˲N:_״-ЭD!I$@$;TPkvlIWfOKQ $wRp&1eDD)a~/ 0ebRK †JRi bEd 67.\ETtVu8BHƀsn52W4ֹe*D28^Ǘe㰂-L cBڶ92&C. sB`?HEQ,iqMLȃ Gw\Fi%F._Ʌ&2*RB="BRɫ(.('q-@JRx!!$b1@j2`*E~raLl8gDR Bf $a tI ti)xb3 sdSL_q4,q.liƐ<B(-Y1 0 {:C!Lk&CV,@ªtvK)8 &'"]E"Xb 5-/ǹ P" CP‘L'd8k#8 ȍܶnYR5!)%I)PݚCf SI*a\ AqH$ "^͈1R0B "`Ze 0bih֙)RCRbjJJE0%A?&bbϧqP)THI3_U G(VWuWqKπlyQ IzCf^xX%+\1FQX2lcP dwwBJ\sѪXP8_X"`}cV6FU1Mv1@B~s!g8)i0>:I@u@$x PHVmDHi G%b  a*J.!H8q d*4VJ)5 PӸCBrͱK)QX>ƹR50MS w*!f!6a@4MdA/H* lo(C L`s !$fwoK"2M!1B[ WU<a< h0], Q,ymP" iJyY -;еx*ENA7lb3~Wuq0$1&UVlPCOg i=4M0 @p)Q Q%Ķi EWGT8H/@Qx5Ì "#I,#:""8ٗj@$!xK^> {䓓oĤ;#60J*NSW8')!Jݦ~h=?=h 2fkGVk*!HD54sGa'He1J@(Bg{0,tia*Z9()J cL]4PTuRMZ!%LB3fK%Bc3Ćv;Wl[R[ [4O{`qeƓ/1lm*b8,% 1y%9%ן-}V6t[TȅO{MW:J%J!A͘~Jχq}YD}]zqDI4QXV6I/)h{ 1h.b*j5IɲKa)ܗ4D"!0A2|P1@Ja}C ) )>QXA D0"@OF5@f$6U`pA,L2^6 tĨfr)2S+QxA{I. J]2G<$7u29!D.mp =8,)1zRn8թY= A iX ٹyٹ9܂eg=Z0|8_=u6̉E+2 Ag}gѓWO{W-@ápwgz{/(J4S.ܒ}MڷfƿzԤT #1 p15MGr}0g kV,1vȍ}*-pn_~۰qܚ 8 IDAT^Vz@6jp[T+ / 5] 1龚ݞpهK S>զ6]iMmZn`0  aݦMIMMIͨyo~66/-LMM^)))`0 RR?===v o SR)ƘOSԔ`J0%% RSSRRiii` ##==#-##=--g^`0LM `  5McSagMt)Aϯk眡KylI)U'O4`[9q e㼏Pl0===lߜ8Y/ke ~߯ Ve_ P)-%%J Av @  Zxëm[_V^Xr9i[]/!7|ݘ^Ttb2f~bi7=.DA\aXzٙ+ǶMD:V )J" cbᳳVk T{颕B[ 35AA};gض=M"v.P4H|8#A?%5%5%йK~ݸT 5tA 18#KGHhk_a!g@ ^IH [ͧS$T_P6d1GpAAAa4#U,/4.$g2Yqܖ,躡D1bv!^H񗢋%Ą=f"*%1΢ԺwAkxbO pB;O;AOa Cqs&'غ[ Zuh 9' w204O7sϜa^ڂ/C[6^tinC#ѭ6!> X \τ-rk~_k3H|]1k6s;׽ d j41'%Ab-ڻIda B+1;E!_\ h+6DՍ ʑ5Mt bc8##LHL/m߼5yq{>bU[^n7;O5o~鑣|0<_w'#l: ]\׾q\N J <,c'Jѫ~~KDo}~(@Izck^%jK:%TXey}ǒiӰQ\I(UG@9+> WwC*lL01G\PfifPҡ#;9Z1d(G1UL E!0KP,WGt(P`;2*9]TJ=sˡ3%&=(*֢^2nr0=a+͏ ΌHA~?LJ~;WP:?`,zm]Ӿ@З^ gSڪӥ~@D7uk/kz]y[KGa~pdvʵ i}M]6Fu 0 31 ӌD 0}(k ǽC^ͫh$"G>ͼ7~ބsϔkzeD2wGuG S,皦i< ƹ0M"I$A6/:3ș;ǎg3~6k|NܖO</êΏ[]SK%biR)iBI4 za-Zird*aʸϨog-[<幎IH oO^SXdcWHDSgx ]TLJHi9 =>){nݿ{];wڵX뺪/3_d̲E:tzYY+je=AM,X$iҲYY?[d +iz@ @2e>RE˺gddTf.-\߼FXU7v;?Wn}m%&@зyC_|/˲vޗtR ԻIsWXy߼9hYxf6xV,=_rt飾^c˼K gҠ˰IsV.[=/Oc@j>2yʟ'v7eWر _i1Yx rN8_rU.7͇ǔ]Of yaLzţ3k=嚬%u_3k&v-fiֲ5g}M,:^dMOS_vmH,Ww-im֊y_z鈀tۇk,ğ#_ugY&v4Rw6yekN4Fј+V0_&W@陷.qMֲU>+YG']gwTЯxYYu7|b֬Keyz>|`5k7TՀ-ώv᲍kΟ<i Uwqgu5:M^5Eߗ~.CHתw7?޸zOHk';"@j1~~Sg>:kRci4e벲@]'U[ ;mY֪uNxC5 Wy/<0e-bxG[nkF,Z.kԤ(B+<%x7RȘr~ !uSPAD$a}J>(dGB iRcp9)`iR 0x6B $yY@y;pDmtq6`y?R\O[$bt%bT<{ +{iۯ/{f3cUϽʬk$ \!Yψ$y35  G@{݀Y5:^-o'ks\=9B>h<.[~T]߹_uZ|ӄ|[r^|3 jimos،=! $D-'+6"14i)^wH-\j)<ڬ"G$d M@*Ok?{S_;MCUot}t:4Vi !"! tYZZZjj*L纮:u]Lj'e9R4s"_"oyrs^3\rQ,&@6Ɏ }{ї#&9ڕ mk}Km*8 mT)/#Ʃ;r+\Y7)e oG?{/#ow\ L|{ex7uO*UkE/}hL~ː'JK^Wn㓾=z˓oz!ck~;~UC8=Zbim~n|3vߢUsNwhզEVpR`jw{wAm[h/@E7t6'DcrOݳãj?3XL9?Vi準.:E~m~ iv{{{|w*wYRʚ;>w?9Mڧgρm۽F5,lP;݅~m{pwEJ?ͱOA{޵55|n[:wLnJ>y9el|V7\׺?QǃEݰ8<&N,zEVwox[l?rcA2 ԋ㮇F5g!4ousN_U< []< /3yKktynW6y7۟D[nyt7]j4싺Z+/ Z{ Wm&-G DGcDOq񩦿J#ÅU6]yb= -ԽEӕ_wO&+ 8J}$B0,hɐY^H1'ƅ1<ĕDplna(lw[00M^ ǵ~ а{$|nĺSӷ8fʋ+[ݽmY0愅|~𷿟RplӊMg\9|+֭`uuДvmLleSK?} |l+ӎ;>յ f`fCyFؖϊ8\.b0ZtPaEUg!)0ÑbQ CB0 aF0"H0"pq[[Tv5uLoХn\&D?aǟ{V}=z+hY 9+ھ.R/mMDR*.Z|¨9sZ"9b~mf !nВK؊?e2?x;_}y̢_;cȸْgmo ߟFȂ +5ȥ޶MHI5Mb5Sߛ8ǎ\:e_f5|B-ͽ[f\ݭa; {@e?o~n~mwnڳD&5y+뇔TDaD/LTHTH2? 36@w6qKOtQ7OK+ocVC!80ھ d(ځejFO _K"65LV+aGs*6]%6UE&J7( wF 8 W]ue'MpX 9C… *\?`SRJ/go=ΛBt]ap]5 /#o*{5<]#]/>U'h rxOԧFmȗGtK&3Z*Tٽ'CDf(( BT\.n1iCA-)! t`ÿn;Z\{ꧻ .I?{'K0=8wb~hXF %I1뚪n1pX߽/'GwGGxQܛ͓K{ N~+cnۥEJfB_㗾z_~߲bu5o fcKs8md(8u3jdN8pC;NMjaYy2Hޓa ?_,tE{?~+,\{3jdN8:oZ,wluRΉD`Z:{v',b3`:3;F4MGSCz|yfOWhܵ 5]*q 9[DMTqjϩJڛ-.a.$Њ~9'שa`j,W'p

]Gd>]t2RSq氟E "šlq8hE=ɀQ/~/'bL}W-sq].$z̽O4A $"}˶&4HĠ kLU桙3y9.:`G6BaA$)D QCD"b"0 ";%@a% *LCLA:G&xTi[}\i H)IM*)"Ma l0 #O+u]0A-FvՆ7ؙ% 9%KEj Q .aC v܃1݋E {/ i&RZ)p{2j.R@Ii:T:T(ܾjKVP]:ܡ=*"s,m w˞٥2HV~4\M4M]iN$ ߹ۃ6j@P_PP@K1>l&םm`f8,*^RǴo|E{-B; v=sïfC3}ey=yΣ |kICiU^uq<94z8}>])t]ӹ55qMt582ΘzYqdk6OUά^\P1řkkAt@HhO6*_^>Q.V+#mĴ-aRu3"[Ar+WL.0ƐT Ew"HQy'\}JDe=Gsw1RͲkU/ Nˢyfy_}|EtIc; Hvy:i/5]TR4ӳ @y~Nۤ@/߸AƩSlJSؾW4ȕ)$d@//qf?5/KS(pt 7h9+[$d+D0OloָA:z+hԞBrq׋ڜoxEYSV1|WYUHAT?-ݞֹʂq9 *4"moV5$7s$\wHgRN.MB+@ݗ}!:̲"b:@0k{JnH,|wҁp;Uz*G@/2DtWy; -G0j\ӵgR@ I*nA03 |b=hee}bvy:iض߬tV$+RgҮ檼!8ܕv?sO4Dg2Fdr+UHTdy]q_=_8$j̜b_n5OljkILg%k-Pn5̚=u"l!D*?>ƵC;aCܝNWm{KuJkݮEMqR* /UTQnfrgʗ2WDRJ ۡbd9R#r ( ʓ2G)[n*2I2G\{q#y">y)s$XUD(??, ZD [ ,,(Hm^RN< "c vݝ(};'#C*Fd<*/ )2Ia|dt~X\?%@o8B"+C%9'hD\@כ;u}Թ冪zFW>U6\Bm3!»?}_C1ɫ=eu/׿X̲E{j&og#jA``K]ҺtXs#Ầ7+C( I5/Қe}P^Kk\sȐ%$cWԽoٹ?5SZxϑyh F7,L[^T Kq.s:76G24M!a0M #p8TRB pjz=w\޹sϝ?_hfzi5BD4MCd\T|¹+8Gxmy7zd왹hoM lvIlQg˵nYwuEb_bs+ IJF@5/Ƹxڡ5wiAe/`Kի_^݊A3AvOӼvftCaP/ͬX~NMrw9eСMٕz]Jew|T'el.'z_mFnʀ+.} wz s]Z|osJ YjĀۮȬ6j{Xui~Oc^-k*Uw}i90evEj o?jsX"q 4n]Ϲ_+hⰇnYmz?9A 37x4k@ԄXg#5o\Ity<nXwudyV]O40:0tlּ&9y5uޞgo4uСZCn*U/my砞 s Wk~u%zU<П+]ڕ*+Rtڔ]u+U(_ǬB[/e<<=8SZ%p݀GխZyAmdƙv{mE"vSv[cU7΍jUlкǓ,Gz.^}ۧo,L pm;2'KဌwzMfm}i8MwA?ܦ^ff+o=v͛C3ZёOwnTJzz uY_+aqKl{ϐ7*RzAדrkX5.J tΘ%*{o쩃KtT E)<) ][ԩT|GTƕt`]*0?u_WòŠ' v[k^?䙶nuga_vŗ\}SG=89a=[w]ۤp8\ ui1*M6{7w @VEBG3⣓Hv|LMLU)RUL.!@QGmy_C?|.o&/ )lT<7gVfɝ)MْT_7v"+O?_;zo5}Aޡ߾;x\r$Y2_n:1<ٻ]שϿ= MSr+DkIAn/|ru}G#yGJjQ$\Y7dξc^t_t'M_sR7v{'㳖h}?a.HZ`uk"GUж֭ߏ'Kk" {L[ >zxщӟC?}vԦsłOᤶy2_40&yrȗfx~Cٿ-[m6(O=;csr[Sޙz?>g{[]ώE'Gq{Ͼ)P rWYr.Z-{mlA_YY/ǃ_i zۋȉmsf ܬF4=ۮ۵#{goOo'T9wȯHƝ}?.0Y/Yp%y˴?R#FxLXpv,Y7bWΨ>:<ㅁlА~[Vq2ƱK|:W- r뷿i%OY9kn6wz`Ogr|0umc{แ&=3{7Is<3UOԐ͸ȺNw{s{~N:#c*yX)%"c?Ͱ׺)[$,vpZqĐﻑ_5y/ n?5fs9y؁Oj+iv#VmޚOs] B "PU` $P_X>$ I!8犇XU<\皦I)M!BL5M~1 d3,}܋Ү{~ʓ>.BCO[cY, uaa( )YZ8\>t+퐥vO7`q_\8uR'$%E]8\IK24rSt3&I ^ԞBq>{Sr%B}P( ~?XClry1?"q1TQa|)Z퓿{~0Fu|GCL8U9oCy{B&u '[w=0@ b!ǛXDLnTмP f5Y&ffpdY9Z#"@kqMh<&8tϵ}Տ3 ,M)1r2[RJ&f\"#' RGJ3qDVâ |^nq^w5XDit eyi$^I$i*4hZaaŰ>5O=Y+.єpi{׺'t%-G#C υPi(L<A3ٕj8c5U?3 p,F'n|qЦ-[ @瀹vgG0G 2e;n옢HosO;e/]lTݰ{#d!E[7χEvm ʐQȩ2"J%m#XP!}Rs}&q Y>]d4ʈGqOLcDXzW7CnHbq̘"q*8W0Tx:̤Z# )@ 4֗)܈fGu l?% > ἛA)Z$TeM4Koi˟M?)@C(;tq =;<]A`bbsu6 7M;@,bMX_arS> *]w ۳j_ RiJXkH4MYf3mevC˰70NRJ&&F? Y3Yd`##՚HKH皉@R$"@4rW$4T.M %IeBI! l`:YfdR)5kҖX &hѐ L8\lrWMFK-F^x IDATҝ烈`ugfB!v%Ij9qIPæ`/#.;tA"3Uy<θZ%DuQc\uo@ǪWհ97~l saT\ D "qN3K7[&bC+4gQl%88|0,XK22.[@Hap,\|˲jR4) {Wي)?8v\MU=:BP;Z-4 #^a8óZkY4L3r +2`\UX62"h5<l`~V#C&|=9^XURC!"TNw^_qm]@)\} hv:P )A";1!28XWFv zuUNX`n&pz u<86q*؅* Ĭ5! !`[̧ Rn({:1[>bB0Rk`5A'0`lMMIX  Ḧ!l` M̤I)M>z6K53K)s$!M:ϥRL$dkDJJ/o gDjw2 EOύ0Pq40Z`0{?i 5RǴ#A3Bk2lv-\*-_yT(ov0ォqG_|5Wꀒ)uJA/E=ӟG4Ou}+ @@v=RT.8^\u@, P1 {$kddYUO]Mo>bƄKqptib.W W 90r"@ z/H΂!*c4hxPO DFF@vDp2rȦL !$Mnw@2H2 wE$m% ' gIr~pѨWV0ڦ%#X/s⹍=;l Fud:36=0X!C4*De 3°i8Bu'%w)pP|D.-?ƹxmչ>1OL20dyT dvX!ĜIBIITB$I-Ϥf4J I)mx&֚~?00Bk6,S SQp/GDѬ E5$ƗLe#Ll%BDgBH!&38H9by,#I203W%"3!cGe b.AraG C-TTJ:6k[_FR,ǟ"dHɁnai6C1NXvw9a߶P](8C腰"GG:׏5T6D `{ۑ1k @efC~ 0ڍpy˒"baG [Eφ+<̚l}JS'pv.3y"$ "i-68 ƚ$PfqH±S gZIu>LZ6PO 5 =̀h8tSnKPBo{g8HCy=@l ҅І\ c,F;XY#<l!mxQ0Q)s I,Bυ JIARߏ5=v,Fp*y[{phgWDj76310kMDa7ר|P%|FP`pbȑIkd̜eRmf Dd^*r3ɻ @Z)eYpM :'D̪!co̠cF.$sY2xV|O J&öOBvXǨ :8of5DGZDd<Ή2h Q!$QL\|;+H2zTJR6D/$0bԴlf=AV0bHo %4uBZjV犁;sIHw@):Ima|aeYM±D?e×6%O396?&[,hNEHP=:a~ZsEU) @Kp?du!"W6#of-N,4_EfX ЏD1,m| p0`5]Ġ-I/"uD5LV Mu' dbfC1,H ! 6c9Y@$[z0peJ$d48KKk_AZtl!NTp C8h|,sNH}.Gas\,Pw[ gިS-8Izeړi 1iO՞Li${Y384jOMHw"H@3vk;OtZ Ż =4|by_yߝQK0u=1ݛj6z8FqZ}L3tzNyC&MFE7\}ڮH̰OWw#+تȹSfK*Lx !շn_k?soz6UV씋o=za3lC`VZFOAa+": u6,RMI+(`^ pHZAFC5LadbdxTA"mM(ODBͯAÉ~ !&ƾ G@ʹxhc`dL]W7hxh{]Ya~(JZ>43 '| |9e[O It.)w?yzbUI_}^nWt`wf⠇_ d@ã@s+~{YuO_|F+vڑ~]So_r?ӧGG3  _v~8r~^\vZ?ubSW}ٝ'N=ßy5-$*U G6"Ӏ+l C.V`= a6,׆$ ,sG¯fJĄRHi>2ItR*h`tg$b%iܑ-i rѪQ pŠI~"3)CsoˏPa< G:R)D(%>%S+/)[Da&N(L5f&`o@cl%*RI!^in;333;3;3;RR 4\8'c,Kf؏nhyk53 $cU!AE'CW/ʹqWT H913N抁Iihxp(*J*/Z2Ʒ4-69GeءzeH Ĩj0ohQc='XT5O5[* i z;bU|41:@hWW>ɑ'V"0Vg/9Va?}bM0t`uq%w8xVRQUZtn&cЀ@NuQ2CT~n@j>."u`(blq_W;y!8* :gmw0M5oȥz-o}?Qw?2nhpԡM1Kxu9>] mw4Wģ,`w=rGs/Tk_͟˗#+n㑵kVs-dԮk˷YX|։'rʜ포%xtn9W2^O >!V0Ә@-윧;n11R%[lZcAD7̃,sM_|3qQ`Ρ!ysϒB]'ɫcz)OT9$`Z#2 ۙ-!=a5~BA$I?$EAn{uwB@n8 SH;u,iC'@(27A` M:`T+ND˜ T)&dGӘdS80 \7><G}t>d^px!G>f1V'Fl&LACvLv^^F.(- Y@&T<|m9 qXUbR;\¿EaZ'Xy4?)ЭRTBKkKRe9n)fDinA])yωcS&@(s@3`䆱"ȶ61367}b (F;cCH!Yư-x, \џ7_,Ug_r'l|` FV8q<}O77^p6KU>ơpQz:w;c;Ky 3W\ulzw/|3=dSaΝGްd]ɻ=m[py~₟#w<˜s:ϹGxj f"4o|bkqa 8R)NM;a^!9< 1| "* Z+QJ(@ލiJV=1155hjj=9њHJJU4P(3C7KJoh`sz::7(4*&'''vیǴV+M$I 1ʸO""fr*hgمs}qgb,YH53BH,:lZPGԜ:ip&yorHf./ A vEp+Xd?Fh 5l[ƶ?Cjh۴Aѹarq L}D q"_ |⍰6<˯r"Vgn6Lxʻ ?Ԫ&KgLs< 1Tb7_D'P3AXLwI1ˁ7 ±Y@G/ o毪J%Rk`i+B ARaPL!N!=\$ps#fr;`bEBl 1:Θ5@"D=@DEB,rK!Zsif4I$gQX|{^=uǿ|kg׬w~`b >0wGu붛#8i~=/Ak.ofS]c~Ƕy;Y=HfcpȎnXu/ng~G<=<4r+jPO🄴VY=~u=F{,PJi|JH3 aWu[ARJ)ͰWhat,J78_ IDAT!^S:  d<ϳF!p՚lESSTJ*#r]W@ )&fVֺu;~vg;%KL(՞hD{rrrr=ٞl'ZTI% lzM&]hq0;`zM]r<|춛dwMy@fZgye`0vfgfffnYIAT`a!A7 ̩tOsPpD$% O޹/imW7+/|y }Wq8 ӿvk~׽ow~={/x#}.~7wm_osYp˿|>?}XK?==^: +?CsZₕvT]Izq}S_m{py?_Nz_~Ӗm3?]~Mi`L05`7 W}"h)}Io{rϳ*@\+> z , cEJ%4e&팷DnegR Iff$`;I:E5BYc("(֚CDFL0ȳޠgݙL3=;,9$Q2.5]\k!%Y"2aFL!`<g "u!3 E4 ~ʿ0 :֛qjZ 8LQ|aL?ے [7\yԏi߽w/]뤀?OwU0K>wd#sϽ̏G|Xb;ۗl|m:%@tYrmQS#}/|gngy9 9i䆫ΗO=j.^[JKO"AV]w]͋$~ ĽAt,w5[CU'Rj"p/>wZ\i"^kCa26cKQ)BK!5} gwaYBR`fm:ΠvhzzN;GtXt-4!$nk8,,ˤƷl#(ЏNpCS퇱QQ8wnd;WD,dfulmk d+5r9 cN"PRReMP墛T)ǣsXXX;+`%-^j` , ڒ&&4H)RQaA7Kϯ;Ǐ1jgc}^@d9_}0a46#l뱌4A (.1$RnK3V&KVV$$n h9gkR%JXcd׷<VW,p.ؠlm8ʷUdufCIpNOE&܁o5=̆M-YbIIJ&Ϩ۫e w^@Ɵx;x[N9mH jb pąkTfMng1^h:ֳξO{U$Fl x8}aqů-ln3A:|v'_ui/2/ˋY-Q_V9OzǺE5gK_>|"!H8x mJe-?94mW5&m|겳UnebPNw9|5ܱeυ*.@!,-XMDlh]nذ+&@Wv&5q"2Dө cxy3K5@zϻ!M{J^<^U1eJ)NTBDfii PRYauf @ys%˺H\y9ˏ!6qVbèIz8l.h# jr.@kzdC[e}A8ՍTlq;;V8 aX\IZ4{p"ͬffU )/09l ֆ Xpv5cGmfCh_/1CŒ  `C(Q8,䒭3grD͖I̾<,^O\9!n\*P-YfzP3b'CuҘQZUS-' vI nBژYk0uXB;ب!X$ȥ`gA;pEt'sM}HIk2iz-@nJY}bm%Vlan`xXBJ۩8Lx-`SdXBx`fd42]db!1)ϝ# -TJ!9_R xL! 57TNgkx!^Bsf#nLJygh•FO89ƄpUQ)b'] `uCC1[$?,uzʅ{-`uU8Dt/ڇ62nJ6H0mz%vEWop\W(? QB?i #_uSch!SyNֆ^l(` '}r3z%Fu&q羶⯊nw^[qt_Qq3SBE \JgSjq'yޭ!@+_bif1܏CtevN.bɦB MM@! wQ]uWS`8CS 9Bex>x/ڼ;v)eO b>[i7f_X7w'"!@7HHIȰOPKstuJ ~!AhܒqT}tk u#PS"8נZ X`#GU`舐_5RE4;cdcm#am8vf<|"q9tgQq5iG #+|v)ơa&ѻ;dyڵma-1%tcO"[I3G]]b'Wp<"PNl "T@,]Ou<({ ϗ94w clI)Z>+m.0BtrR :l!-!E+Cih* E}8pMLVʅ Ϳg0na c.ygM˅o~퐡͂VweP̈çQ(Aȡ@aG3"1Y3ZD4`)RQ`$4Etsn\#ɺG 8P Oc#M-h]Syi)6vȲ{F:IDHQ"OsYA(b@l1j;rm% n96$XmH%VC DKРߣ* j%:Pf%!l@<9O*: O R%k*6E8C W7yX[Q6E!LcO"qGHRRp \^=EQT{d[&؜?c' n.K1IҼ)8n}ݖ[z;s٪%zȸ#uN92B.g6I8x@'KNEW&o>{ L䴈,(Z UU:QK.(5d@I2 ˴&)3q_i$Jy#f0 M Y&3dS y>J51,Dۛ RފKM εF%.@k~Y*IDIZ-,4Um?x;M^A4-{CN6(Vy%a8i=C];9K(3xNoEg;5U ł Dt*ACC0+tB<,n. Iycm#Y5ࡂuv]]=k)Rl4ˤ-"*u{83HdPgD%PL NarPs;kI sY _b@'2b ?N- Q,( -D qQ@`=2P4tĀR5= I"(-ZP՞ԟ?AK J}, P?e O:o^~/~o OmVHNZJ\N@Dlֿι.t+?Wz]ҲӘ9ss?^ˋn]q˭WY/%Ź H.m}ӎ-9GB/W sz8*K4kn3s`0 Oܳb_H׷5)Os$:[s gmZyۊW7_uN;d;˿v/>L(!jW^-'|} @Kn)˕oBL:?o)I%}V^_y+k/ w:+KfיSwW8~v_{z3IDC"'wЍBH@Ay,ΦM6nܸqÆ 6lڴiffz~9"$iDJ[d{m-Dv`#3f*6I)L!!$1-I(1a$qpPG?Mcy;XxTx k*zgǴXjbnԵjjr,Ƒ}SpF 5bwڟ2~|Z,pY^5ѹFzV*G6Aޝ h"/*{)gRR?nqi}`W#dyiz@2C[K5~g,ZxƥbMx/+@^s)m@{٢g^o9wɤX,pe(dC%Mĭzی:jsФk?{Lݮ; @y݉"z`( 1ue101"Hx-px1Gxۿg|Gn/+|I{sԞ*0:='^qڷ|![O+UZJzavQicSeo$pbд kCncEw*>㈎Pi?/9-dņQq;YV4^ȥ0*꫎^=8ɕ3 Is\/ "r$vKQ7@@vDK{hMNM-lׁHks$i7"N 4&M=@B@hѴAE-!Rc]uLffp"v͌3Y?ˉIF~>ȈYR*f,:.NsK}U~ڹ}[7&^w9w"Տ}c6Mz//A=sǓ޲4PG0Gu*=̪ K{Z1KnusM+?nW|W 77hk|9k~7?z/={ӷ6kEk6o1;>3?r`-BϹiE/D5o=3n+w[?''\Kղg,Z?q\sܳ՞;v3u7S]gҽ!T;a'GQIű۔( \Odu4!ڌg' 뛎uuDW"yfP՗&ȅy+d = 7ӫ.}~pekݼJ)77"ͷ_|3?ց.A?6@?g\u'.b@>tˀ~b'^t> <7;ow߹'6$Ƚf"^[a`}[iyY&5 AĀ I4o- o)ֹ:#y{xwW%yV) U22vn! &L5ff,M.&v#Ҁ"Sa3a63-Enyk(1zo +OD!%aʞsV!;}3a.~ E2s$`V7$/K" M,X%tդb0^2aypJ# pjD!J;3doԃL&91DYjMs:|bl9a6\DGH(U!)f1"ND,F\S6i"ց(4ϴe|BgY$;{;Z7U8:mmι'muf.[S[w|5ǼS>,1 0 0D!\ L3ѹCA}FUՕuFSzs./{C0dkV>ݳ^C%wl콖s7|Ӄ/ǫG/_Ox3w3v5w1moBGMv!c6JFRJ)¥}U$1i0<ML'@G,b +9eEp l vB=E/1[buFDZKлo<@7vA#aoD!>?l:?IܢhW/~ڟ= JS)eT4IR$I&dL:'"L&ZVh>lsp`(JR%@l%ID&*MT((W ]*]8eD`)I>61-<ϳ|0J$Q}p t'@"&,ϲ|0~t:lgfzfӦNzy{b%ޕ%RI$u0{<⁨ثY3zpeCU Ǜ'qC?vp}ou :?1yx@p!ܜks-6fjXp͇'y暡!PF}zm[;DDZDH(FԌ{a2UZg~*U*W|¢R`fV}4,fk~t岭+n}w7ooy6\/}#?7?{}#'+ȫ88ҼD}>b\ak-M\Ţm^>n~uC \,֜_3W|zm(! iv8re Ş;g9%?H/>=}~~}Hݳ~?o){C/]kO_?Ӛ ~ž'ƒknX8;8[,<9ͧDyPh !Xk .CABa4ѻ"2`jRDSc-Iè g枅S_B#Wz|_k^}c{d1lt&~Jm7²mF^t I&az*oLxl<|@gfJʕUX D3P̀9C 8jż;p $t6V}BDF5]ty334S"N̳uɿ|ozvj ;⣷?ÿ)|򟬸+)ZsZ:#+< $qY1K#q1_̺?fSs}Z4<TEz]>gljkލV]exg:y \wE yfg@sͻ>(!ݏ>4]ibF Ik+DΜۄ<3.Nدo.<-{Hҹ[zCݧ;/@\.h+JN;T* b[T( r\.9z \x .q! D !$ A )<iDz0e!/dL8r R9I#&]L>eHQ5'"k<&Y~TZſϐx^0\w.<4.'`RQps V*QJ7tn6WB M6{-eb !R\@yΪ|e oWzd2][uoBB~d,0 d ШwI@ 0:JE-Q>q^0h[CCdQ^# 'w#"CQ4@}#V=\t~k5D5e5E8p.5S!IC*>}lB㆐ydU-c}Xa>Ř)-,C&LW4dmK2Y HP6s78#&x3g$F1%@(!/zH>4I2doHU &C_$b: d4tW: &ʐ!;@md[>K2d%'T12df@@Hg-kҐGz105*X Ύ;wюXE_Jߏfe)IP_y`I /9%DBlr-G/8$ZxQx)A-Q!]*p^ЍV"*% X^K8W.jAQZ]mZ$:ѩnngw/^׼!4@k?7咫57Vn~i7RvWw߱SK?#oQYl9h6M~ ӶEv7'-w.飔"HlQuU^F CHƮ+<,Zfж~  !|גpsw}y'~v5&} "~Q 8S? ui7ᔩoxg5e ]ƑP|2JP }g/:Bȃ%c C|#_~zok}>3vY/,XiϷmu.}mھhm@K'_hyzx?XDDu꽣f>qm#Դu ?I>M%CwO~n-C{ Sϋ=0iO?!EJ!BD.S fBjJFJ(1^3* oȠSZ 2vCDf H"yXBGT@)y;)XMbB/ c9EPX")]KjC{3iAH)ə6+X!q/ vEu1޴'ю1^ 7aĂx >l$[>}ȩΈ=Xܜ~Di3)~Nε}: 8q[Nۼ_}WL7xto޽0bKׯ]gvCλe? XtѧVF!K4dM澕Q]L$}6UTc4XV|/+|Wl͌\p|ljy)܅^N @iq'twKA/]ss7m!M[_W\qϏs^VwW设Sٽ.5xg[SK_xYKK}sG!gi3j+ @ ٪Gg8$D=t]&#/RAPaU@oQ@d222fVfȞ*%!Z#A1=G=[\1C݇/o}.|mPx&Tg>b; hnI~sės1㳆8 ; p諲b YEG0QpS/ "K깏RWU 8 =Ш!g^?Ĩ0GKTc(kJG"uw!d `V.AV*0T1qεb[_JG 8fh4KyXc mـ9-& #cSBu\Wkspa!XAm >B*c!jTY4b'Ԉ(4IJywQL  Ќh<"Dň*(vUXORNaprL~bR~o խ9orpt}#3xч~Ig1+J#(ze&%M<`,56)ծT$mMبӗ]Sb]{-L97}y9ڣ``o$VU H*gS[N`R4: &&A@Y$MlLrT)=5KxFX)urm!bV dϞ`܍'YZd2Bu1%8cNm8#f$ * ᱤC1hi"DO'~΁CD qԏ\@Z _M{p!D /\*5"ԉ !-Ƕ-=|?K.3:TB^ob`&![JfH>lgpgC*~#FacEHuYC 6"l4/`4ױ dv~6W]4k֮][g?ҵW'EN}3F1bE[XGZHMѲAMK+9o/ n<j ֬p}ZBśDPl,aq%J3;JsH^!"l;6`Ddg2HKB |6VUc IDATA(ʒHc(HZWd y:|#8  5"x0{ tréZCQoB- (Mㆴq;5fPR|St\BurJX!` vϘ|L=BhX"V+2 0@jh{*-QpƂweK 4bR[ZO$"'(%iH#J=!Oi.dĀHLh .n !",QF"&$@RdЕ`bsF5T%ܮ[&Y9&u|kTX-O|Hà:NOI-疣;6uJlR 8nT 8 :1T|}-kxNHJ*lkb^YsRQZ=jh)f*WQQiFO>$[%[i1dB33LM0E Ar” ܣioYTd*h/]UvJʁg*(Gs.)< x d+&x6KF"SKh^s(JQH70;`ps@}ZPP<`D\YVHkΟ: a$Ӌ`Q >#/I#(٤l 2VF[<(I:u1fI}h69ʅ' d#gum(F xR+2wd/A$1$mɟ CQB'=1 EHv%ů^1*5>#a/N:-*Q.֡lgDݤ%fMS(ڝ#"qD^w, @7ǭe.S[KF=,P6h lagB0˲,Km:ΞY'3I Q0){]]k+'F2T;JbGIc%%Eӂ#qJTPR)izVd\ֶ, B{_v6-@uʎot\.k[@+ʞ @dv.w*&bFN ۄy^v`1i'z[ kP|SCSe'Su,Ud(qf^$"~DqoIQ# >AVJY3?@" 6Az_-ylBMtId@2D% iJB:XǣR"X"QY3օo>G}e(b uPOmC@ILhsAB['ׄL2BM#L=R]uAB" &~6,d„lTV[- #`W(gWkG-HRK;Á $J5=Y>^) πѕRɳM8)YRIDٱ,Hx%m;ԧVe3!eYg7s:4ݓM&@D{c8 UVIs*h7T 0 Ņi"G;PĊ1RE_=m;0& %05} p+* AL.PV!ǸS*qR2i)/=hp1 M)5%tH?V6wmo-'mj~@Cocv;cmbW T bJlTT~`PLcKEӚVm!!Cu1ܯsG^@YU"?Z-jzr8ns<|W0 R*z 2TJ f0uB1d2dV!kmk5 WS NsH|h0[=VR^g4ǚH;Q, f^ Ș 0ds 5F'Dc5ȧnόu3 Jo@(udDhHlej TyK*yﻢ,Y$g!@_T RA3@y?m1q) 2ddsFӽdu\Ƙ s&=@39^4S9Pb}H2[cBxAtVB$籿)֔.3@( Uqk0$zɾi){f}n: w (0):$, u\O8vc62?\gȚI<<p" M-F6yDmDX3C,H9'iTS`elִixpӧ|2a[Ϛɬw_}[d4pjx<婙^C??x]OWsדfx"W<Пg3n۩CnZ:  ʑHL_95-Շ'F V A&' ֟#Ѕayd."UD. :-D_pI0GM9e'?{dg9>'<>sʴOgdwO:s3LI[e2[7ߘiSgL6sԙS͜:C3`[/ϳU=>5Ěs7uƔIKU?QۯuނByc:+k׮~Пm ,˰|SN}ћ`{lχo={g|m7ʳw[ݓ nY p.] \@T'?鏞1|{aW;)=pa_;IUmPˋ) ΅\\\p.N~b9^u+|4퓗ygU!CD+s+G=ϘGύ氁 r&ƒWtS# UFCÀǕZUqRf6DR2ƆRX{RJlPI0dY9d ,fDߔ0h#Z,T$"<@ b#cvo׀c4D;kSlkk+jfh[T.dVDc")Wjkm+8X-dDپ?-.cZz=1)nu'HD$EY VgWn>?u ǜD7el@ν 3 m3_﷚m>[NUA_b#)tmGUJX=ԴM=6hm۳_C5Bk>u!^[ dMDUf~@~N:iw5ҺLdᵂjsV(,r 0L4i '=pg>#O<Ǿ;n='*yz_lv̀AٰmWpг4 qg{WMZGAG j_D^G:}KmBvye '0)Ndfl6kg2,)B);RWpЃ Yr&熜} uo;ԋ|oySzIW<ch ߤnbʺ(?_HHOJAH+>yӥg|׽*~E#N2>A.qE27І\D%hb_ PfhܫN?=_|Q׾B?8g[wF]yX@Z Br@RG˲-۶-+m7%d7eq29y6K;sM/ڮt+O}z/h&KvCd (8=qR)rs=ysK5|L)e1f[- GY̲%3n?8#T,iB%8úz (1odvE֥^=ndNq䗓CKA~ 0PA!SD΅f,!c{D @ 7r+^S<ԘyYubl@"2+a@1@9_o471@-BrHAZX'pcYWD!B JYKQV!ڄhMbĿ]OTyZzˁ'bTw$vC!G̃vCw^usM8+O٥G?K!\y~;(W{[o׌V?=M]y?~]_,rC+J,pc11 dHE_Ս@bf5qxЁK>~_8~/zJ`bnD{qA;.fvve-)!}3lqf\8M1|a;Ɏ_䛈i㷽ڏ] A?nSsgCsV⹟i4uO\]h vZ1/ϧNJL@&>JCd纎"Z"Ga=@*u[Ov `3n=↧pӉq^7 ,(ukA''crvsMкzUX$g]!<8=j_ We𥊃1߹^2m==o 969kxt$AB}8.2" ~[2qt~} GoН}9) b]__~\|D9`M{4am2Ie؁9w-_1d_guoT6#e0wWRe>kgcvݾ-9'dw˕ l"#-ǃ'(9e[BCX_& V~G>rR'ZViex >}z_nOv_XhoTn;TĽ+BP6̶V(ĶY22c ^&<"c(,` @l<&^ 1;3@e#!+X !e776q#CƽBܝyYݛh2p Dg#PٿHvHq mdbJ*Tjx}($}LC %NԾ9cvE2KwaGqFOoQn\s3i>>6f_s&;4GߥVC,kF\{QGA14C)>)ĊJi4 7R#vd'2p~˦~sA]1i`nCW ^{ ld,oF͎>*]:˔]Mo;o{p7?xbՌbκicWMyx'Hm]BЭyvnعC%m_zzt4쾛٫eּo7n'?.(zB ÍB@n~D7HQBB8xuPp 0#J)* SaN4| wb:2j?Jzu~?L]Zi޸}®]ͪaI'{ew$ٵ7oMl^7%Iےx .c ˶ 0D$'dMd`^%at#ձi;d0i)SOj}P`,xB3g:q :lPl0-&Bhc,) yiY-n߯:$΅ tg2`#jUΚ7?\:ѷ޾c|S`["@ySl7mmpOwWx%n4׽3HT0\DU"kŔ͕־C SBm0\H IDATW c,Er/^PH3J'yĽ6yv wO~sI{w<'Ľ?[]Tf-E-^}?{8q{'sI/}h y`aKl(w7 ?Ds&P䂇|CCj#FgC/Q逘ծ`р2uzXA)G趕 !k (%z nOU-|YcQX 1a]q N`14 LHlٶ T/l9mH q r9@H LDMQjv X%y( LCcl'oZoX)RߥϾkwȤf|/H`z3\ޒ2XT5ϱ\vO. z^ּM~?['Fe,Gj"=Ubu趮X iSl^wǙ O_u_ï:WW7gw]9I?TTG.mFj/~3pg?*vj.۸]FG Tr׷`oٸ @uK4}Vپ_q$ࢭHU!@hI_?jQV"BbNkZvqp=J =ǰpn(2'ᤴoeCIמ ʑԓ=Ź`B,*goc>?\oKxx[< ߜ7y091J?C!`ٖJΌƙ>dz"&j'hADso +2HDsRB*ki }r.,S:j=-Ws7pI1"c2qAGl.#LF!+쌍 `v6gWr! 0AD%F.q}R!Zu%6R+7#or8(6 jK6BYBdU;"NhY @+ ?:cJ_6ӕ'wrK?s]r;?wܷ@='Ĝ+e6ro&-\ ~kgvZ)jG:/j)GoX5ʜuE 4mڸn5'NDh.вEԗ`}pӽN?؞p]/N-MЩocytsyG_=i[=z*vZ85W.- /;\G1Mv~%_%uf6vxS?f+ﻻ^xӳw ,zoŴ bŝ9禪(M_?w:݌ٟ.h cg7aUAGLbͪ fkOy.в|ARBv_ٟ-^9l1W1g_˅GO*vύgC-ѡ^rs1 FUVnP@52NMJ6o Bׅv LUJ!3mu i*Pm`}&tE GWLz_`@2]zm[/mᆍDD2 ;#m^ޜ~V^=b |S [٦,㭓oztwl{ۺ 3_!L-FXRha*#ݿ"j.GArL|3L=4S斢,ĹF9?ZL &ppJb*NHtuEU-2K!> ݍoTJ@XErU$OPqK,aCoBx5N`N$ [.W*x0D g@%XHG ^+zcQcg wL mzxߜ)A9N8mmNM{ L.~N۳6{K9KKç47ll=U[uy=v Rs/ ͐l`1B dE8%uȯD(,PDIj՜~ɗ ɠA0bxE+| &m~U64d!7bC ٦&My{F^~r>g\~&K{qAC2`,67?0>Yڮ#x iS|ukF/2@Swk#+<_·[:륭yi"dT}Ǩs1[>WtAϷ`$jiLnE̽9dƙ&q 3h0i>SR>?:5!^{>Г9w>vz:=Yo+g.ywnEPiȚj&_Gf !DDZ}on7~tA^ `Xq3q_sN[ᠳ~[ Tnyg_xY4ZßԢlт ,\`]*jѷBF,>I*zx;=vaG|ߛœ"[t Y p]4XSGK:Ac jJ{2#B[m3d9yTHnyƒϾIsAKdǏˇX}{f^?&{ᡓgT,f>h zv~tyr{w nߐ JAwP*4)jm@!G C il@@\7s뙡b@ .繎㹮n9.q.@!)f<?S!5]BMV#ń͐ _W/Z췝;Oaf1~R\qsN@oMR{[=B#,J*_ET:GdND%lGݹrra 2V*D VO+"O{~-7obb~x4ⱷFOe6?G}k0Y@ =p>vgO( I`Eu11 8{p>xɈ7\qbkf8U ݯF?xp8E/s6^ލcYמu2$Y irȽ^JWM ]k,|jђ|xö4_?/zj=/Ҵ%.ʕnxWc ?*gSmj1jD$dPDTW?=Ï]z_r嘡MP\v7\$*utKw>voYFF;zk cW\8ܻ3n{tdV׏㦅1'X5] aS٩|o]9z~`:a\LAVǩ Y>[Ϻy c)N_qK2K޼ ˹GetɂDLJ7~ {胾}E>Ҍo'Kyw=+fk."mZi.'vj|^9R(U˧\sQտolٌxԪ5^mÖ@M *Y0#3;ap)9š'VNE:%r[j)w j"w%f0 5%Oԋ79h`Pdp bT!0HX ]3#vz|%("TlȈZLz)$V^p(6~ Q]+ɿq#m aR@@6ǰ/`Ooxa$3Q0B"dl%&D Df~4qLf]f)LSq?2`-'^%{0Pƾ㠸KsӚ5k}],ِw|f}ڠJ*EJ֖pYԞ'M5nf5~Wic 5g6n[tݷnm 뼋v U-R{W(GcU>ɗG(~ײL3VTN3*Hwjn0$A+z V0q J*8Rc0zŔB FW}b.7ﱑb2VeAMB0fQH72zh|IUP|&ēd(VbgAGII%&KhwPH6.1z0YMxYƣ1Լ1OaTN ˼0P<2H.cs81Fµ,[IvɽÃFaۧ %XR牫'Am|23( I0QB~C&c\T !,"1Bdmhxyt9]f(AM. èCf+GOuDֈ+4|,+de(I/k ̛k\Q|1gmB1m]Y{}qϴ &X)70mMj4pO@0q}i7z\\. [ PM6Oe#40Mnkj_@m%f#O*YHdpw0XX{J%_Bʤmv ofMةkn3)ŧ) ם$rT ҥ>BJ_W O:lnB)cF4A )ҼR2,zt@Jbb !c+(Lk 0_3YDƞ(6p"!H" J(4Ĵ{CiZ1/ΨEB|ӛgdž@$B",X00jЗ|.Ƣ3DytMWMmVUΈ* y0_7\p'iZ 9soCdRT9>,4 1Үʷ'"!87 }>:I)mw:Z\ֶ,Q׷mIXw dl8~奶Gv60n(cEؚd'Sc!ӿ ǗVbY\Kċd2޴ :g&b.EW`':kgTY-rƴ'צ=ZzʀRZ)-@T9í<qN;1TrLG-2$B-D!DA=VX)ʞRPQ'o#@*D7RM$9h;m :$TeZ|E*&CiEwQ૰0J@NtUE=XXy54C+Y/BIIE#!Oo&G4QFʰ<)b[ IDATp+fs\.zD,RX!L9X&ϐS*z`<7`> =̤`+0?_P~`dz1(iڜsޗ LC8ClD)~^G# #RLR}XKG; "6'(TA Fj6 KBu,= [`UHN+#k~=Z˼ZCn,DAd0e.Y&- e'Ә0̩n:Clbhxa @## '*p[ my7Dmu m" *wah rʸ]JCh74P&aĝb1 fXp8`1+e2 AxR8TykMy @c_, |Y?ONx{&=#~;f/;# 6K7̡ȫW[m~U釟|W'K)4U9O7YWvO?ӗRTܪ(D $wŀsŀE]3qͺFPW] 0g1qYHVarqR{~ nUW 7{nx6ɈzpH9D=hj+Db̯pRqfG" R'94 o'rˤ  dDE?u,,^Y\ǠTXFLS8sjzRRJ1Mu!4M״8GbٱynAGDSQiYJz O`&Ei;)DRzw"%$7]SdTȚ&]^F4irɉHc 2i rw<{1&tb8s"n4"zY^QcLc9=Bb yLu$șև4nZLPc #[bRz?L Qj9C:潢@)YNd_r(0׏Q`Ō蠞)[_[[[Ιy?Q.Cz*Aq#][S[mlYЩ Kc`}k_ /jng $ՉG>E>4NɆ +}7a@v62hguz8ߒӲ_'@2KSLNdET*fYx@Lȫۂ)@:+{S@|3VX$P=,gr܀|IqF6g$C4ed IB.s'sۗN}Ͻ/WewyհX[v$- zu?>SM`nVi9!$}c@LquŴ:q~߼ga#3edE<5L-u6 [ƅ|( vH7ΊTpzT~6S.+C=u%;Űa *J!"Vg:h`C^@8=."Z21N$J[v2!_-Fu'!cG5j>.0M\|ƘRW<=ΪW7 s"@ѻ|^56%w3s , ?{ɳL-1$nchE3"t0M M% kwF/0 SH)&36c("6 ?1h4:d(\:%##㯜+f8.:B2 X4@(c'qv+"$\gl)t¼QNE'w1#ԋT,0uiSNҼqKFbйiKtzviɪ}m˭N+ըxQsWnKv:c#Xr֐5{.[Tly 'N^(2Q6?=dfrfίaF*x77E;L[ȭ1fo*FY2Vo9K a06Ry)|rа;F.GX.Hi2}^y < ю4QbW @) )Wewj8=%9VR6N :1N "ht9Cy[3fXw8(P'ևt*@C'0̯seR.M]chp@MCj,yrP d ҄L 0R)Ĭĺ]AXxs} YXv,xOB0g7QYyud2OX?u9)kzu?P Ͽzwkefn]K}+_XTg: *UT&:W8ݸɖGTPf5PSv !9șADӘYYI/5W۹ɾ"4`!]a![5! i%0 ;MDD 4Ƙ^NTSȜdޡ (qBd 19$I20Б ̌r~5fu%'39eIҵlUfjGVuiu3nk`zӞ\vB)ۗY= v[lOKէ:.{y,SS1=dۧ#̓ 53pΨ $ccne(iG$ cr)M+Et?HJ9 ǭ9{4-'2  <Y`SQPԼmzw64qp؀N/4MjY m`d>'桰c!঩1 {* FV-pv:@(jEnHwK^~v +mh2w$K{(Qi}a]js(J!
DhJ"OTpC$0`3)F8Ha}6Q]VJI=4!CL$NMȊK&aֈs@PqFez|1X<KX]HA~__Z re2-z^+*e|¯F1jq̍_o|g |3q_ ضjU_[K(c0?6qӪ׹ )Q̠DQ})[lz:uCoxyI6sH nWoՃwb6BxO&%ߙq/ٝq" J{FU&enudY4%˓#dj0oH&c QB,79}yIhFA/xCKl% @&ĉiL2QN 0=yh'prDOEIy(TLJbEa,ѝPY ;V p"} 4>wec`%hV?d"(&z_>bʂ@De[n囈*BY7–_&82WEJ(BDICJ 7H=9B75b!R4(aּTMb0r-Dʣ)0GrX*,ҁd 9F)6n;+('EiX$ E99HDEЗ[2{ P(#Fdk2n|O9"[FP%2 G@$NĐU d 8d/V 1Iir\{R)L<+i.T0Z?g&qSCAU gF< s0p}ɹ5#x buyzQ J-e&n@"$ ,2uuzB ]&|>)SRsE$SiM pB𤈐I$ 30ऐFɤnVyT& ltnh;,Q(E+7j1t\9ǂ cFc7^G1\t,@!J D))!r;}A/"jr"j#"'EA#U}f<]i!cvK鷶$c(gܫ5"SMF '!~4SmBJYn(EYrjDt3#-ڔ$+Of)Jm9GlqJ8VEDEL#с!> u1s"V|x{5<wQdS9 4UjjA|J$ li pt@)^u&J>$Knʕ]U'Sy>Y"F0LS;ȢL@fCٳC.&V 1Ц4*~y51 !9` ܯIzQ1Ier!v Ue*|uOM ]\X(vN-+Y0:DQ<rAMR"uRPa>hxٟ:j^ӈ|\ T{CE`?8x.Ϙ.E$yvp$߁xeIMɛu1щHO)Ddy@-@@]"^s!ȲIPgIąrSM IDAT(kIChtG/'s!E!:= 'PۍJh*#psND Y_0MP4`b-0n&CfS%i$'j7PX {ww[8Dbɒ=[Wo4&[Պ|CL|(|"P!@2{\*dIa!j[ cF>I]NBފflPeJHMTR%ףK.#GߍkP|7u/C|RNXLgɐqW@'6.|B VWLPqLwrA2CWg# Nͪ*ImRΈ8:6PV4\s>ZZh=TvO.㘳[cQ B QN=V sn,ĬG!. 'ipb!24u]':+'P5M*kl ž2h7EeXKv3G+8cLSP{ &Mx/*e(|A;`,x1+,5raĀFlIɷP6y$ R91ݸ1b[1$HHd!9sI~¶ߜv6&fǡKU\"-z(v5 X-ƨ&H+Zbs&@rP̩ "nEP+ t?!/k숢iT(@ ј|/ w)ƨW"I{ [ K,vQ"äEi^tE${,T1ԳWD*4"q#kj3sBm=U .Éto89}_ H$n n(^CפT 9^рD^ 1¼6m29b5&2[H9URK `M&TtY߮𼷗!/y/Ef @ Oadm>3KL/4DNDD-U)K B"0rvC4°6p&UPp#@}N&X9C e eH&t⒤QW%DqiҬ˚$,`Ȥ3P/*-x ZܘCˤ(b硄*HHHrvhJ ^L)̀!d^_@H] #|k 돨Nb͏7rw݅u9'+'+ѳNt> DΞ;}ZL=g9f͙:뗩~yoFϞ;:CLvbVLdn)7[O.ǿ6}i36i3LI1d9fFO4dŇg͝>sδYs_fsz+UQVYϝ>ssO]qT+ :ݙ*fH? Ho}O0qYە(/H7n̜5wƬ3f͝O J# ܥ3gW̘]!4c[ ^2zsg̜;i6IO!}_=KD_^;{wQW?93fWLSw̘5gݤ3|FK3f͝>kY?}ޓWO+ yk)n`1P C?bOc.i$\Op^9{ 秷N qUgh窧ޛYs?;N+0^p (g3;Omu1N 7{ODDLvYsg|ty[<kή1{r*KZ̟*fT1S,?{؛_2c q~2o:ӗ=yQ-VS?1vvD̓B@ϱhOIaS~|rX~3f>2y6D{=]r؀rg{s;$ R1&cE@S6&F14CƘi1{fHR,hw.ڼLB2]בL_%t0rf#bT0Ĥ~ Y1bft3ԅ/[3d9Փ{ 0^]1II<'u֥vejk3Z&隚ںl ˓*mҊ64Rޯۅ4#ae};xR[ wwxM5o+~xL/5f.h3b)+淍zwu$ ^nˮ'nK '7ߒs;';e5#Yz;PnKo+8΁e^z7%g=荇MzlZJvw7\u{M`=j-S^iC.߮r̚]Or}]7b>ދ.*GuG+Ψ57R\'gɪi-Lj' j^־c^ZN@<욑~[@d{+뚵?W6h&5AUs읎(Ȗ;?=|K+YY=~:v}CfT׮f]z׽f/qo?/6r_$v>=ro־{^{7H<e fļhYj vz/O>埬3G'@"&)$pޟw|iTz=r k#:fO§G 2~hАt{jL59,\D@uL @q{Gݑ|3jvf/*+;Q#2vvb{?i‹@~2b^ZPmXWЛkmj]V \x{s7t uï`~n:n \ 1EH*ÛLcbsB1d65"0384 UƐ=RCM0RKrȬ7Q( Ns* d3V,E &j-C y]$B;8p r" yveL@k@ٜ 48$ALftqz!G YjX3Ei)Cϯ<׫]LۻmO<-~䣾K](+j̞:.%e?3 !hvSν4^Y9ZpVV[P-lY|rc/y9NRHXCP;oʼfe|@*ͯ?Sr"UbxV9T1Ыz#>s/n.rx͊PֲNoY7_cB##OwWCoaN>˛, cnے߼Η*3J+oo/w'qd8)-v6—[<O<'L\K5@c=fv?;23~ԐK-~gj捛w!5'h߫{)l WH)|+W>Z3k }ܴ]"h߬m,?Oa1HKO}~ҩN}Q+MQwӦL1c_VѻnXrR(uʭP'"ܙ2-OGyc[LOqnĉOďz Oc?TDC@P~U []=~">Ron_;%c(χ'*2`tCheˠvsinVe ßCo3$nZڙ?[Gm~v?:ڴ`=~v|PV-` 9=j軶 bhόHأ(iAK%RGy U#;㰩 rk8w>{cޓ~Y3[3f.NX?JicO/wSY _xa`ϖ2[]z{Dv>qjۃBDžt,*n31w"]H rM.Mn CԐ 2 H!s@p֭hI)52`M `scob1渇1烎9a՘b;bb?Y\᷽0+!!IR2 ̒o±-{m蘏Oa/3'~0;)kmm֡V;!sЀN6^ ۥ]3T e7%{['d riL,Mj} 7yڀDΘ^on-R[&w6!b`,J4HO\ݚ,"ԯhl>i!ܤc1 @t6"c4$ PO&7LN̗vq5QC֌ԑjz+Gd" uN94a1fH925LBMc9joXbZҩ[Y/VS^,Ǩ`ڶ?L%We*(XRL)(o\%2 z֡HQٳX &XoRgxm\ NؽaRn f8cϳE=ef@fDDք㟛0d/-z<&ӳcU&& 슱?_K.5ؾbAkb.˲E=3^%n:wrlIJ<}cf =*hnshG]uf%}ʊE;:q7[$qPvz”Cslm⪹Ui 3"wEU4j ']8y/}6쳧:Ǭ/mJ줇||nmz ; y*]7ߣl_6?ϙr!="3-\5yl䱯y18f#dT IDAT XP'21^+TUW-]oWf l/MG&ѹE0,gY?*Yn[x;o9yW6 fAmtޕ1<1'X1=Xel1s[*7]pQɍSvuPij^yΟ[k{ fֈ 1=s6ݝMDuӉ6{7Ӡ,re c}R)1`idLeYPr #{.amct@E{熩vUQ4;$U'3TNd%QgǸfbD*QTDZHčlM (HN~zND9 !jkpj% u:',C,A! QIi䊋Kč\CI=R%6I/(Y0+D:EvJL",b{R˃/aN "4)sT|DL}g?s_eϸ2 {M7ҧ{sxjRM7v|{c#/~1Gҽ=6?`lч7yT;~=Ut_n ǝpk.a0MzS=zaVnG YZ{iL +EUd(i0]Z{΋7%jR: jq +-^~GBB9Hf)ޑJ-+*M;2;xzkAaoߎl`nǾ}ptc)2D~q5?Ov$W~{|iv.8(cnP,]O 3,S>eŖ>pFQYH쌯uق**ldX/ݜ#@r2!#gmnnZhlh^ӚC|Eܼ~{~y+ra]4^yA?;NYH>& `t:PWXRqGi*mV.f cD?\s4C\ݘxeNRsE1;XWLڱLCdv2zeE"]Ӂ@Onf `Q{$Cguzظpٲc -k A\X| QѣY=ښ>̦9SZWF}mM_B}D&jjLմj9 6o5vNa_jje-9m?þ0Vsi<ښںL6[_S~\]mL9~L~.2DY_y6SR8˛]o VS+򾁡xbP-  GҀ #:omߴn˜Vjg+] <}~μz2sb圃^TVVZ@\2ɏH<{{ySzvvҵsv*W\ !eM3΂]6]`qv)5]všWdB+k۩Kڕ1,o{@Ν5Ga[S^vЪ@ٱ$V2PV3pK4\S^vbk ҩSNtܹCQC_6ztۯS> 6F0>x?VֶSΝڗ[6v9o}ozaV䀀Pxל~|57ϛ숡/ y~{vmOI4o߹[.ݺt֥K|\՛S:5 qӤ@?C; Uw \֓ a-4+];wnL&yJŇ{lnУ!ڬ2}و$E*8s ?WvzT;uܥ[.ݺtұu1CZ>CճYyN]ujWưMn]DB͜wnΝά37SS-{]zۍM0֩{v9Ûm65^!belKuԮ\g՞.7vj-KVN_ˮh-UHĵV^هz8綴y{m[٥iG4۲`` CMMc7~;u]g٭s^_1da4-=?wgϺCs|TQ1IiX8ܾlEfJ{@U]mKO^ L;eЉe7lջ/áx<~Sf \~M(\Q PҡBzܫ?dVu0"%HFC a(Tb&XJjGk7ztͣvA6Xү\Nr= n3eQ}79ydxN43tl}L}~E @zZ9ɷ&L| >#*fgOa}>ᱪzG,;7=D7z{O˭>7_?jY?0%*Xo=T:I&ڨ,nzR_Ûd ]=u^kd=ט{znAwVϒ-SnԠƒaTNq2sj ~μ+*`_2''0~縋Ǔ%ɪ~r9#*Ũg|6QmU$!z5;w=T&џ]4n+ 7E~#3ɿq{vY[7Olş{2r>S R&@0jlE{Ȍj0.^FmƒZX6}a,&ۜya7s LQyV5۞YhPu424Mgۮ,jߑXݜo{;:NY6ɛϪF,/m8qEC{n޶j;[vHoi3ᗯYotv!•U@^SgZa>EoG~7++FivE]~;R3]-ݔQ a|frӯ>0*4Rb%79b0 >`:,@ icGYB3'?l(%4aC$Fv")I`KS(Wk$rbLK'T>頰/*+m|Qcק5 l`8J oywU},ɩZVwcpˡP]]Q%,ZvO7sO F/̔Z+HE2ctY͞nǃ>k-Hts∀Ȭ:r"r5Ms˥of $(i99#d o--?_OL*DTYdV[nx-̛W#5q,YIǐwY"Z^0a=>cC%"BVS%=B'd<0cⒸ5Q.irvbv-ILJ"lk?Ƈ$SOrld3BR< B,:ao8qqHS1jFS ֬|;GlB3gUy7oTM7Rbee}9*!Za1DDL,0871t>DIEHDȐGD[0BK#$iIsuLa9'Ng=_۝qώnDAX℀0Pf^{!i&qed8u]H4Ь d@*Xg p1&'b"K+C u2 ":X{ؙB_'D XЋM|c媠T˜xpDD%ؘEEg= *5?"p2D\iqDaO>$wBR9<))ApH6ޥ|'"kC/CrXs 95!0'<ĉ$ X'g4"ƙ|rLJ4HAaP+ l p[+@Ț~@t=BH;&f!l#L[xz-$B\؈}, _I\r$l~3D`"8qd蛊Φ&asI,d\,'D4F\ ;\BF4N$Lðܪ 49wfɹ&P ZVNYm jd܎Yij.z[Ӑsu4 Gd3jLu89bLK8gxmsUC" >\@_H7MMc/ ]ӏ1M\MK%PZ"0MS+i}-X%=5Db/xH`;x*r栍S4'`,xؐ-C $d%4zDouyJ=p 6 q#kjoG6ls'RbuNd]]b,NA%dM,LC}]SCx l_ua&y[ZwHVX%)!ɳs"y@5E8fExo|rrCrzoQ&?j)LҞO|"X<0c7I*<~W2/ &QHvGqc'SB_]H :(0uؑq*^%ϑS*oB8F#=+89ЅGP^@!O`IJ_ }pfB!GƮ7k{]QށQUsT%t.誠kC"(vwa v"vQĮ4EĊ( H$@H d<֙Iuw6q-OzNaUV*5Нd)xqh臤2@q+vZ`҉f_H83MU@YQbI^"c`Cek̀gBMDds!%J :u0VXr[Xa8cl{Wsb;wTC3 DB]O i<rj ÐR C1VGC5{}AC2ƀ33D uHIR@ F5MSG"MՕ8٩y\\q$I)q1/;uЫi{.A&tLf(a}4jd|J)(ҚXK3$^SJMHf$lr4{d3b1-sDIH .E}u_\bSj&Qw_2$u9) գe,XV;P K*'ITA rre.KeUk-95@HD+%f(!@=9塈ԓS 13i+SD-)5pܔ"<]rԶP B/Jr?ɝ_ V#ԋ?o< -v6L,à=V~閖ΟK#'~`-sƒ;֢='*#g4#A\sd7 u7/ps.!e]]Oyb>;b%R$&y{:̡4JW2dm̡iRo:`eU,r]^q-lέ/yy-߰uLճU2hM^eCZz!_ߺz=5ύ z]OpӚ[>w"=FLYi?NգnS~ܴvg-?9;BԳ|oo\m bƆx_ݰmmfo]agۗqY5a?<5V')XVkPǒKTX8;Gfn1AuIm lc]{h5$\myeԑ-Buz٪uW[1׵Ok6X. `Ɛq ]W]9ggsQgLynpsH5MQ5]1]]10 "2 CKiqӓ_b&?qiT]Yvpz4/UŘT&0n7E^7֛^ć߮}o>uY3:3\G "vwxxjᇕUT@1Q :?[n;6l03׵KQ=GM]mm?:g3j&k' $IC4<[%# i\ 3$ !r,%"QS~P2 PP34*,p,&-`S$e)HF@cq;))PIed(wǞ:VW|`p@ G+}R{IAu3_bSzF9c7yS||3_|_$^M @(ohcODkD mOFF>0;Ƭ/-WhRMԐf+ݸm͍^lR/˂3}A ev)+$V0pM DLaOHzQ]̆W֔q_%6kP>&43X1aly9kp|Ψ68ߏ~S%<$8@hlWh}ۨq~[]d)Z|hev|[|75P65v&:'D1 ! /T:-竝X&#߁5Zndŀv"c|Ց"9P' )c3F⠄)T/ E͗mn;dz~[uu -D󶘼yrfz7Ly>VgT"n!T,h2` !6 rH2AԧáMֱώ bR0b*jRm~rƤ#E/>8io<]MV[ zB"QYD~M:pa:V@A@c2R#ox1=9%pyDcTff)컐swJɷdwvI_ $ Z̚0 MdƒH4D$C2d@DKGL2=\R-h8*$qu3b aJ0 sgc+W_z7=f7_-֤a 'r.2W\ `3ʎ0_.{}{?޹?çyUeFkgWwD~CA?Yϡ|g1-cF6٫>yr]aCGffG07Xh™xmAPH҃w9!(X-- ]gZ~`ʵ[^yRor#cݣK C5(6vU_VJ'_F$¥GUV {֪թpd ȕ<%jœH'[Қnl$JSݬP0t59Ю{^O(ڽ+eSy֓Pk_֤EzRv[.Q~1kU]+?xq%g5wX#ldkGikg)S-ܥ˯l1c?\q\$, ;,^{f%@ois[-La^~K~g>V"!6*6c}U6u q|ׂ)/|[/?Fa;gE^O{޻`3ͭ7/J,팾#GvXӤV"n"?0 ,sB!pU@CpB蚆t]Ww.ׄIMᬁ3gEkog-D6DbcKrs7vc)̴dQ, j#iZ ιiCIę ˘@D`7o[OVf3>y{{BٱRqfF6}<~;629\a̢}{*,UY#"r΄ BgVNf us;#=_T6m@ i*8'P")֭"pn+9פ:D "R9C iJ"IKnw]>m(?97]vCJ,1NDFYоD0-uPPu}[~6r?9}m{;*Xӌev=@ს/d|tRi=5@|R Nz^ښ8ROv]0\_l\HYKH">^Ϸ:ZdU[l-KDF I_'}dȦHכ۩ovGflO:ߗ7]ÝDa!4F,%(A@@{Y|2@V:aELX!l'NN8PCkS-قbUyy d? TNeSGRhkN,œ08үnq@Q s?:X-=}ꀐDbz[>q {'&oM?xCol[h,^OO{{+=r Cyi>}7 c>}n:B4{ҍ;ȺG.ah; :MgF]k $EX&>g_]]${kmoyt< >YY$!,זH5VS0E*S%)\@`Ѹgvn EW>H)bԽ;#6f!2o{{rcL-ҨuĻO}y^uM4k:FR `F 32qsm~ jksi}S}IzꋽZϿqo_FN\viiɷ:/룻{u4 S+P-)@-u+\h4(iF͊ ae%pB"jFeRsv<Y~d`fIBӌFшBJ *<7*8"rb vc`ȒbR CWp&D suO?ahk6fvPG5-h)mo3n;=U:׬.=<+VK-_ ϯT(U[1TI‚{p[^|C78.Q$Y-uw޸zR E4WfD4AqƀY-g•1͔ۆkjfL%K3ȪvnP<1D]%j>T"%Sm,RJf|B2ћ]G*W!´֝XA07,ߩ]:4F\x>;Y}m䑒 sOl߆@{J;ivYQSi^G?,\P7R96N[ ܺNmЦ7NɅ糒W*_hV_jr?YfZC<3:zhKBXU cB k-n:l{>}{pZh h/6`‰^{Y%4koN9FfM.].{ .8[4# ݃(bm/[[ M`im4*߹:7 \O3n[}ǿ%̭) `R1] ??Ir0-H]TgZЪN*1yO.uyhC+gM#,[sg}A"|5!C7ZkZ'q?P&(b{x cfp5sZ]8~ՎynyMѯY}ho^[khan +qp_5WKDWr[J]78 ץ*FpoʭYw.6i{9ln׊Ue^xr8 py9ܪev16FOkyn U.Ma192IΏ %RO"L+)p`v, ӌ$(t5)CѽD$F !BXPfۻD$ov' @:sU}e;խ!kH/Kd;F.P46B\2XZf:Vd^ޢ_?6<ڴHg=5TxwYau`>gt1k7z!nhuۘۊmq,篃&>ݺcol{_`i ҡ ~]yAHoONT5oGA1UF@&Q]π0Q8V@} I*'a!jWг_\D Rvs,Jv'>Y˯oȿ~^m9?Ή?=㙟l3GT5_1_^mpD47Gjnq稼zc{ol͖KnEn9Sw[wnky)^C .&+rCWR):;,hYa^MX}3TA\.`юGmF\%z K:3"0+. Vr|V޴NſBjiw,) OV.6F!c @FJ#Hf8B4!ar9qá aZUh5h<ئXиY4$cĭB%> DP{k<0DPVZHL4 hо9G4v!juNk|l2i }; 6(TsZkT]\ axH+Ekf#Թ~P0(6!-EJ810z:ß>W4U]HJq&w2\Ǯ+EByyHWM}fnښ+7zsۮ#uLӫgjGg X sK팶e U^ &q5Zo slUmz+|tFFy8ۤ;FL=ץQrCe'AX 3sNs).4h_E[S. r-0x$ ktnp!MiRUJmٹnQ%?GX*OD{4c/h]`k[|̺$LruD-Q7yC^ԇZED@poac좶9'r؎ ju젲ɷrT@JGϫU3~~e~<~%C@ˇRfLB!Q!x}77h+]Fk:+/<+J`zA E di$x TA@I9Z$T*}[Q"1$E*B! 3$9g(%r]ߨלX+jqҧ+blvكpE=Qo& fs7L٭?r[O/Wٛ]Qeo͛8uW 'vF|g ) 0" "_Å\5AهWz_y'u IDATp!i,rIBS $N3ic깏Y?mȲH,zڡb8 d܎қq,!ˢVqО,}w燃G*,}X@FE%"hKdZ n/~HDv],pgmP1%( #QTw$?W1% H&-/ $HN}e@(q$-tn~ۤ u @`ޒ\ؽ3qgVU楗hhRW/h1ǫ#,0Ɲ$CIPaRWs9QR׫!x<(W%uceĒ觷f/ܹ?1ʵ/1r(*jZd!Λ:u\IY슑"X*2Hj{qz:qw߯ymZ@$r;PhW,Uiڭ:q^!XLbc uðXJ=r‘><8F1cfy1tMsDuq XfnX*L:q6Ӹ͓JG!>$T93@rk1,?SNw*!XP*T-' tH9YsQ|vKR8La rbwB026Mnyqێ^M&T"̅=4kܚR0Od7 z`0AW#z[4@*rJ.^ݫszCT|I׊ǧtb9CvOıDN?ߵ 3H~9k]zm=<5IqLNHAאX\MHV"G^ʞN'~۶ J_5[*x[2,?z]JF: UXى@MsZX=0TYu:kO]Ǩ cp}{pG.d &4+C"Bn$閰) s$7;pζgrY2{AGrs]1%5`%q[! k|Yi{|P2-?@CGVDҳk#ch]H/morAW~)yy3[hKҐ!V^EضXi^]%9 :l)=Af: g !+^~ջRdCI8KMD4RP0gGe"4̀tJ_9 k fmh9~3 U;m(13g ۽:. 5#!pAxw&&~woIiP\F-[FIA7N"H3VO Y M vwV? ;\vݩ}׽tGG!tpioˎ+evl 0ulDyYH( zMjĆ7A([>Ook 1×Z99[ GeّY YeLZ;ox~߶=ntykq7(L| ]Lyf;o;"uhOQc ݢfgzතGDg78났H]Aܰe)ٺ)eGV9+6e)~cgF >+܆^%xtaZTҰeکܰ]%9Wd}E֠}K̋ɾUNYtcֽDv{> 2i=>ek^Xh(-Rr@$rThݽW~Go~ а޹od]>E,}pSPp8hfwl牊`qIT;P=\@ -u o5sV/ rqR~aC=Zyω.Ԗi;:;*kp`Nl]"$! ghH {o-1/z&|jgZie"v3\qIEp>ask(dϟoo8qs?~Zf aS?uO.'7lբvR:&7hszԲEi-9EN~}-z7}r bŁ[Vur!3|sũ[_[sq%{yj)F\F|)PLVAGxvޢXlHr=|&~ʵIJwiS åQk*!)f}TKB,ɯKA:rghrYhhztˌ3'*e릵O%ϝEn~BX}|Yn#]9_|-xMIlwG c3]3 ϯ."}׿veJ͙d[,ۗm}a $JcMAf \{u+7amm{$>;! {ϓw{e}->k<%P_'Z"5޿aÃ4=]'OkUVTo"E 0|RE֯f@<2rikPzp{jqcdUX:?7נ9 bɉJ?4?Cٳ)ǚ>bFT(?|wX D?i*Ż|BH0sH:];j G=}k#Q~tˢEy晶l\ [ {WȬy4 C_X[0L.|c/Wqſ{fy3]^T2f~ԣf[ i$b ]aQ@ IB$>R)]HhJ("忖E5YZz|TQ I{: hTi)N!JM!;iLT*A@MȞ[E~Iu ƹldTR余ez07y^G~M"2_;X|D8 pi|4ya߇71xQ;Fj cC`WƧѠ2j9 =ΧYѶ/<45;B73{YY9ct"(xsK7=P$;+oIvdECg"6nv>CQiҶ%XJN_ޤ5]UM8C:p]&%001):7w Z;5#&wAsj<Ȱ#۾_{d?e w]^~eF;_}'~0qO}ђC~^Ʃ Tp5ǖ??r #|ӌ~Pmㇿ>b}8em*UJD"3D}9TL(铣3y]_=،QdeT+3 /3fXND#8OglЬ'Fg>ϣ3GObM0.W}Snkhk_W,7 qWG j-C'V "{cHYc1W8HD 0=_}tƁDxY^HUYbT9*<6c)JoLt.2Kǔor5Iz'`9G*K*ˍIRil,yJC5n+&وGM&(e!bG1tP@aMMT9ޯJ4_,XWW-5RqL$,e""iJBIe ƭ9gLJJ8UҸe7_9-A*B#vG}YtXELrlpU,'clf맡{<>t"MӢ:$(.Y8z{$ia,= #,i.@+ux2u,-t]\V %zf?cݘ†q\9u21Rpo;zh-TZh'|s_n x/yXl[EpA^#uO;?{kYY-?9jN1.B ̊crQ Ԣx t0s^ǭw~JWvخ!*=VL|OV⺘;@JQ6bW*h*][$Ȧ:5~g*\>C|6xX_k8L1czѶ6&+YL A0NDiX)$zjd q\:-,&$[>e'|?BiiW7 C teٙ/sؖϺ8 !F5;c`\smHS*ẹ~DQ︅vMӄP c H6-lPltd?vY";!Rn4G;x% )6j\uPìAKv(l7 YH&@g=BIX Buib'&\d+omK/e?#Յ%b -"{],mϡC٪>`r?;sZRyg0:' (ADБY㛃Ar5bcF'v%DP bJU)*'DML՟qRL;4Ѳ]R-D?&Mؚ~J?@(Md*$zrijbMZAqr>ӌ)QH8bb!Bo DNYB橧!K#I@Vr@SnqmT={MeF l=N`3!1Ɛ!'0ML\WF(~ L_Ivl`e RhUWɮIqLл!E{F6C v8'3Pxφ[ jF14tCHJ!%CƘrc3LTqTc2 @ގO2Y+ KPDޣ@$GoHP2>D"HH)* wrq\#eɡ܌Y/AeMY)_LDÍ2s2qPjLVVF/FKf|.X4u"s*̊?Z@;ɔ8+%C% ̅Tʺ ;o\jF0?]qxY5p45QY5OOcs#\Dr+H#TF TqҌ nn 3iz 2@fEp'f$VMJ__6D?Zg 9ƨ S;7ᶁfp᭟ricrC>sj#J)K8ɍ02GEO/AiH)=U|T{C7ڧOuc]UTe W`h̋#q32NB!$`p3l &!RYȾeB BRRc pظ֫cs}ur݊˵Qtp^6@,}mu?⼇JwR Γ$Ϛ@4cqgsqιsc]7t00aOnm뺦3DqMq@ RH5j)D{R aTdê#g8Ou=)x/6z ~*)&\ 1g?z㻿X2WClq4M)yyHdGW^,ʬ:p_\nv߃tqf{Eln*jU@n*Mzw)"]D. ( Л)$lcfwgk6~޹_+\\߾L+? #d/8jt7}dFe\挟*KƷfSmcH{b{ Vd8ۭ\EQѺbeY^D_Up~ȥ۷:aYU*lVUfeX"ˆ[.'wiFۯòx0>uNٺ݆٘zADlȻfnSbƔ;lZD-{ǯʧns 3("سwHkzݝY"3c >hrt͟}3Q#ecg\;2Z9g$}ř$>3oް뻘|DsAN_CU|ː^Dt`8i7;4M2J!\tTGó3/ d/\柹4 .RmW> 'WBhvr*n I|q]BC+8dY#Q_"ʻ0bRBed3u-> 5uMٺ٘LaZ{tyc-Gwv/φ6?bՍвI7_lIƸ]ck>^eȞ%oҴ< mR|,Yq ȣ|maAB~f8d*Su4V5|Gsw[&MuS0|ڹ}MS s#wbmjQ?D \FsYGuSF5 cZ E1d9ib3pfeX`]Щ8^Yۭ^Q)Q4X&*H*Ớ{?.(vŒ?},{lTW=]v`Jun*\e;f^u+ruS+ǣGLLgqL*%IZFգbsA8J ,H Y]Y^m@Hś8B yĩ$@ ^O 99`vrѐ-;>[tLA]K &*Xa!a踨LA]Sd F"Z%T*El1bҏSb%# @+w%cZÃۯ66YiK e 6k %|},ЪyA9-JaCD/W^J! *עyg<t¹K ؒ`eDE>9y)ɨsd5lsTV9UՎ%Hi _ݿ ӟ~75"-hX2=r3NroeP`lr0Ytp;\TPr9, Yd(4(rKD%%MkOvLxo2z3clI0q s=4(z .]<X4so:fܥY$<(Z}g?;@\~U"tT图~=Sڌ~`5*TqҫmUsgIf- F'rle)xUe,kOOxk2fܥ1$y]6{c@tA!F k_B( k#z&-(hGsOȓWZB`e(㟟3g-ĵ{,[Ual loWeIɦ] @ Z{Ak;02j Oΐuf0 BH# D l d,2O,t,[-CT BsN埦X x+{|UN"[5 TYo?;y` kO 2+%,>4u5OO>z>{RxΦ^d9eh:o?}쿨7cV׺ʩw9 o8ۨHQ]Zc;[>e0Y3@-B"E3jIn k Տ n?b;8i>6řnK5>Q3w' jZ#@ 0VP)9 ,+Q( "xD(^edԪ,t/$s]Qey@DsvĜ$UX \X9skG yQbI]&aivS}w r6B ^0,0,Xn[. )_L'r;Zhn,]hN|#!ף6ws? >L\EJ5ǧ^ޱMzOިN"'EZ[ '$(I,)G%ixq5`kGVvfuw͐lw}:Tq}ҮK3v]|nWٵe1e}vh?& Ht!' Ub)*uWtnsNS ؋k'SPo=䝂f՚EH|Gx]f,d(-2X*gc}=[ R}xR8OjH*AĖ=w8Cv̔-T TY1'v,=[6XvoWR;ɾ|\Λ6q9؏|ׁ}~noT=?uCu\ *ZOվNLlw}:Tq'M?/?S!2ܪ,煪J{q^znĥ;ԡuR0ڷt/貲 ,NM!_w#+M>zjp47Vt[nnv n{N$v*ń﫼rvM5> q;wtߌ.cv$/B/׊ t9RGZ)s]MtW;Vݽ{͎ j>/۬ȘXpWM>JQ 6u8kt)U61~{|? BigJerK  `Aұt  ˋcs^k) ^}S|?va]GggĄuؾHt_ hwZȄ.08,*q1SWT;WzLe+/]kǶ. PjPhN޴Q㛝wY?Tq'ҩg=yiK C)/*dl`&A 2&Uʆwpzb+g7[FRh|} v7'af5|/ds[Go[($nx'm+=}8h;yτ滁AǦu>}t -e}֐]>R1k~3~  *㦮ωkr^:`k۲b@ `s, %D È "q"k"e-Б ˪dXԔ'DU<_qL*ClP!\`j!mȄh# ӁOπRBT( ʸŁ(XHK]|'DV<"Yӌݛ_n"BJ?ZHĿ2 M:6 Ⱦ0S\'܋3쇭+Ul\ql"'ž,=[^$T1+\0KA3a7R͈\Gy![I1!o*cJ7f[WfZy#Zx%)SCgDʝgv_[{Kg=7umf?v2 |?H(UhzI{m>`EGGkkcI=փ{9rYcxK~u/֡{pK&wm)Ѯo*~r}Y1b[Ƶiզ ?}5tiHԧoK4zb%c;X=*7-]ЯbüzUoZ&+MJʢ#NL53n> WD$wCUVWwDXFH"C A7H#_$s-]? eČO^#o=*.Feh0+#mTҐϕɩ&>&c:9r'tòTj|kSB-=zO|CMmPW:Kل ˊz9+1V+4 F`]Q9KxC2o| bTXRZ0QnfaBm)59?CVo4|=}6<38-`9jBt0P(w;㐞Zmt#c.f vb@]fG^&d˖)[ohsGˮyܕKS?[nɻw]9,L#AԡE7@P(X㥢dp,X1 PFt k fMm){)QU`$X^lýjȶN*T~_ry vj.A 2#puxU`TZU{2B!A^E ܲ} b$'.[ }g!z-K@%\$+;@z sj09gקH17w*vȜ;/􉅡-mˆlȇ0?Ahil\:dcz>D3`FU ?]$AM^X@u3v6m߃_E;=G~e޿hmMn^j1^zJ 1$?0wP-.[][7^n83$u:_<֯jfFo]QH@Vnlk[唷%,z5݌N,wMo=@Oxm RsowsyHZM]Xz]  *囦0KUiW0 %ȬqpGCG_  IDATA`ilf@^jҎ4޴ϲ0c,]j3xKee ,cF_֭R89],SR/˾t޳9Y -EMS՝L="Պ?!0 eޯ'0 LՇ,gѬ>BЮS4CnOn=Hg8R?@pzXs;3sIr28`[PW=oAѹB+)Yғ،un(A0?2Nχ:a~l T*d[AdY"@GFTdQ[d$"@_d$Fda$[yDE)@dé؄ n2#_3c#ZT`6rn 6_۞vƙ?_L*$PT-)gTx7(E2ojg*Ren2y@ы/R$s!Jr%R@PXad wd1#m&Xݚř{'<2}kXă6W<uF7[ oL6jbEJ͙ওV RBO@@;l<}qo[H;Ok+#(h "HBFDx Vy"ZP`a8c,ga>SȨ;Ub&w0)v/pje/,#0o T5U<h[Wt Urd jXJܛX5olᚁ1 Xol$SuϺYW=k]9| ڼ߄=E. vH0 ĪᲠA*f&Y">#%͎X)悌TЙmb}a'Nnwei[Xu=5$: V=f^D/Ӏ|l26/ʎK=ɶ<@0͠U3 CvXDj߹bb@r>CqaB>t0ںثEҢ\elMl|(lhpL>$ӹ* W'f)+U dE%uՑ S(Ca{73SR,c[]Y1ם~\zm+Tԣ~>=c\ @L3zr& FoKʢHcPU xu.ɱŲ>o杍-mZCv|R.]A%,#t6aμy9_5r)y+( n@ۻr$? Tbē34v#Ⱦ}g_# ,pg1e&dCp~W(t)3iLj+6g6_HT} I0VU,INF F-!ԥ}K#@ĊOr,FN9m<ē|b|9P@Ј! ~lގ?rfw#FȗWANu:9FUD5ӎ.yf=Оh+r>?)6? >O]ς8`~~t=7kjIwGI!ڜ l3iͽݠ+!?]/O?[l?)xGHYf;)jZtN ?p7]2K$@}},N̆e켭ԨdͱpZ8$(IBF#lxb s9k|eGe0N;De r6<_-ʷ(t]il U7VhѠLy?u< >=|C5WbYX^6"H``ЊYޜ=tcQn[kF8.C=ꯐɞЧϗ)m6c$\veUö~&>ya̖ۥD[smժ kFؕ؁X$$UD`r_I v˭RF5V\[jхøߜݧ i=ak rfDVa0 QGq!OfuKש{dK~?zv!dg90/~խ0.+QF@(}4J̅&"BVUi8BY&_{d}|ۿF_P7Y B@dL$ 0>,@T` kPZ g%^RH臨E#0  (Od~rU0ͬWEgPxMCȨSAe\$8ףܭ凞s1Vk3R&rT SP"/?'>9smlSw_r~Ƴ?Q H6(CSޝ19:v GfyEK&>2z4xBE2)`?8ӏtb .*իsfic|NE@!Co&eoYA̅o|K (sjW;wmVty7Ԟ]Ocީ8[(K 4oL;w=]B"ɲ֚%J+B˰/d!D7F|*CtXJL|@&h\p@<+TJvJK 1fD~ʹ'œ?vcJ.PJȆ^fwڲ—_143YT(e% Q~!`|>;. _,'e@]퓎a)V/,Wm3UV>ʡ-WL\'XR(?voFeTWL yƙy$P4 bR$KMS5x2sD Z g⊚V)t$0?uO;I9t,dԺ؇l iyzFHa{ dI\K|a Yɏy++5$7qԨlc„ԩ=crUx2*|apOSmHdOxP^CjV[fs} #urE\'3<G_xoQAa'SL9iJ3D\QC~z8:aL sGS󳥋\KVmp@GmoXt4_Y}i^- . QǧN?r8;UnPBu{u+>w1b;:ʓY~<{qSNI&UDpJ9Ƀ`*0RbA e F fL#ǫj[mGO^ Њl)AZ d|PhvgAz` #_B~sL S/£\tI0<}fb rM?_8o] PorMV?L=乖[0M%;)첂?N85(нvn['daۉy~:u& d_m׃>>dfDd>7>~П_*}2WY)NYucC*>Z2e?K+$̛F%([%uކ; U) _\{1߭}fT d8|GOsêLoR"8M7Qlņ1\Xf8nln+6 >>syl@vC%>ߓU+tRs+7Kg콚ߤI9#r6Kפ8 #: $r*(2;(Ⱦ[:xgiTA }J*7WL y0lM}D 6=cҎԠ؆ܙ1wh=r ߠ}n<7?n^Sq-thS\V⛌O-C lcS%E[r@JT QSOKk:jDe uٚ,dٿ{n{jB E W >6}_V([@Pɘ2_7\&c<oľV暌g| ];燀seqM{siɨevayr YU͕>Lk5)lVۧ\R]^i&V0jE|gP#RE#k7?KRӂGQ?Ҿ}-d1} ?1cѾ;Dٸm2fD]1eMhw+WHn.Xe,`$$::q0dLe̸4}/H6ք`L]5g~Uti>gNx}iɤzj/(dDz\oH`kSp|&[sR,h n2j_FyײIO?1kzE~9?͐vTĺhE_rnJ^v}5ڽANҽj  }d޽9J(  Z!> c,^3PwSό%ߎ}R|T!֍}ﭞURuBtk8:"9Sؾ[Z:2n|Jl4u< h-fa8֔|e'`~{`nKZ%d=>rft+ -yryFr#1Vx]y H:D$A!"(`4S\53|G@2֛iU@d^W\ɔd0_^C ^;hTꞺ*׀rmsߗ5N *1gN;\=޴ey;x7CEkַNۺږף"l<V3MvP.ScжsҞ3CgOX} I.Me|X<7g\=TuoZɂlM0}CXS=9ēnr%Rs2b_/>qWp܄)Mi_u{K'-/6%NVb=07/މt|45'M{lb~+|NO q)d^?}۷_ӛkotڴ[N]G=SfΞt i=<7yҼP[} uԘth =aALs&|n *kX|m>h[\!P/)a5>zG JeimqRcɧċ3aWbTre~'.˝ &1O.}_Md 5+7O_DnSLT:ăÞ>AB)XNLzK7#0nڽTRM'Y?HiJR 9Ӫ!?쯬ȹgS<"^ӛ37ܯG;:j؜X@4B6I`Ez|}wb;sZђ!+' cv! NmWa7ɾoƘLꇊ2^u}!oV^uYgww5ʇ&ʍ'Xu$VY)N^)ؿ!regr\%ge9eP?EH\Ubw]].=e-R^cAߘaA$ v^Q>'/NYI|DFq`K AD2C(\ ]>Y=m<]pM)8n8˾7]>Tpt}6)v4f߶KMϑh]%D-ɅVrW젽AoUQCX۷|C'h/G\`sPqڽAD(jˠK+yMr^#?ΉNw: raf Gi!pBYI JZSD^asUX[䳻6ԁ2=no{OMs}29Q`zw7vr8*Rf ?;t-fHa,+Z#bXdF YV.9]8!6t_tjgd 3 엛T4 ^8R!#nNw K< _偄E?mݝ0~>syz pUxܮH}7k\$[wrJbj>ar ILwPvD^_jW{8ӉFtw yrtzDHsnN"P~ݜΖN.A&\h~$wrɒNl*@$TSdąlQ`S " -WJADi(E NWr֏utBLtTvo{bŋ.>>o#!yDK-Q *ZY5y IDAT,4@HLDvȀJP֐d'j$tŪr.$E&B9+Ê*-~EF0O^$JXt/ObE 9r{+ړa Ћ_8TpmɈK^mX D^.7o^*frs(X M7hUF 8=]-ЍJj<$ϡ(rݓ;ۨx;K!N:اAob&tt,Kh3 pȐ Pv.2x\Z}4 VYJVa*(ă{Odzur5x"H [׺! $=e+$':8壂BuFA-תM[t-Bz yw:&8/!5  mHH:?'joL'A=iHt[ٽ ʊH45yH8,r[;ѽ J. NGŅ57`! 楡%OY6^QmBO;ɋ<*-ѵae[Hn,1ԝD:% sL߂b{ma=?+A܃MEM-a*DEܨO%MW?/U rwbfw^\"Crw]5?z8+ AtaF4HXh02 o28rAAX!ib," g*RF@BVP`7 xȨ5j0KXbG)qӡKeS@?Cȿj'0l.:5:XbyT}9wf^<׫{?)úeӡT ]U V*PJ oMM "MnU& w`Ųؽ9W R(Yؘ,DZX6ZWP4Z____PZAՊA$Th|jZVVXΰ_)y"=FPDQ2P՛׵5׀_E( w 3n؛um.Q`V?9gt 'CY~sq_`aL/w_qβ7> .;qGŀ?-o( 7>G (5ւ7{ikrʈ\lar7M0RIuRup5M #]f*ї`"zm|6Zs~Qs{s9YKrK?B3ο0 lD$ ~vm w5R. [[=">׋g^l昱aͭRmZUܸ)Th&(lNdXB?,uO7X#,HD+A,OKR OM3Lzrf*> 4\`#e=Lm昶FA Z#`eVzSlµ 8B&dTN]r}Do]6!74:bdOE W^J̼۲=q:l_ZE ݗp>}3(߼_6%rҢ}8kA&>߀&PFZ}IV[9ry+?SD (JugS?FJHLqJ8ÙNj+?\lhj|u ϖX4CZӋNEi;Еj)ދ}s| .Ɍ%Os=4(z-.#yvLx(s> F@ kd$XhB>㏨FѼA J7M5Fu r&o@0 (\m&AN[9FPn^kݔէRy@mͮ3f o_5b<_mfL޾Zi7 /~>8",=7?"cdJ5=s|龤*b{UNåu50[gg:@ѡ{|[?!mN 'oMn0,KBT\c A[SzZD[ۤ^F ^Q -45EWpb^ǐ{tQ"/2& ,uBΥ/n-Q璢O-[-[ 'O'*Zt[a>#UK~ieA`q-Y2;'rY]̸B?Re~sTLR>Y /BJ6ΌbY'+=,גѾM?%!?-U~uZލ6OuM$=\RV=ӹU1&>׽6w↱zBՍKNdad;K4n*b B˖~g^xx!ƥ}uɒ*]JYfvwשC'-ɖm7mЊNzjp0aie[WҶ~0dɄG@P7[{zxGRm鶌O٪VW_}>d!ma[,K&4~{༯66}ޠw 9l]pO]#tUuLv]*e흾s$.q_U\35[!,#!4\MT{,q~\w(}}AY`1?|#+СRĬ[j'2~|lq5[>94m nyC3]CLUEH 'Q:kC-RUiߵr;/ś aɮ?wXmF>b^XwX%1Qyfv7=$ E ^Q,4(("{ Y@)*(ME f-3yݙ&{<9n?,RUL r鷷g.#lX牭X蛆DċW}!Z1V^(v{K.sOw+5͛l*O3oGm:DWY@ Թgcw"}90%݆E 1@WJ_8:&q]N,s޲A f60A?7z W?$Yh"RoG]CXм_ _㴃7 ZRI[?>7$70 d$D ("vd^r8g1y95ãfE!"*B}WɲG%Y3bþco(\1d7. < } s ^rGTxC,`L%m#1TxC,Y:rcsnFKvˣ5(iʢz^Y̰|jQ֝olv 797vo]1s;z]yWxHGDtʞv3j]q,Y O@Mn\ݼ,l|ݳg:}pS֬vwxbyCoKN` EW  jatG[,'Ήqr_uջI=ao!cLA) 51nO((\9'7X)hEQl Y ] # @@I J$I=։cfpx˧.zY^`|k֎OrYFPC^B8Hs; (?9vJ=ȩ|E\ڵS޳Qŝ{.zE0;buJr;@9]оy`7k1q ]>q"DYD٩|@8G /Y{~%Ad7)ĕ޽}GcoL*k[{{?2kSo9tI h֧O2xȄuDi7uδΩ5C4R7' YQ mu| SLNIԃ9n@Oޑ҄cA"m;pr$M`GL֟+n%rXrр7/ ehOk_hb2A պzS:DT\;7)*+~QeŊT2_}2n,a8'3~ ri)ɑz G/E`л VԻVK__3"4G ٥->yRKm,>Hxw-v{xh뼰A:VGX44Gna%=֠(R): ~pl':>KPJdZbUa GDԗ2ںRMI Ϊv $I%Y9IJv8L Fפ_4Pî cbp㺦"PW0s4#,IƈX 洚*@1,0< כoґvmPρ߬2dz r _9|$7]gVÛԎ2(3bn/uB9\ ˩JU5Pfoyn$W~|B=U`2:h&ł#ϙpל~wڟh &S򶿗s˿2?_mF/IP=W-1 +djUĎd.a_ժym D1T, JS}nʲ_߽͠_p$DXCSX'?ȾߞBC+~8&JopKMf f:jTOWG/HU'I\NDTyJ$Ot>nGOcqXp\*9ǟ*< IDATobZVK^z_%?BDF6Q@@@%-\V vh59 Yѐv9% a`W[oћ4 Yf_{:<񩗖;2u3px>w,M\CI= hFZ5 9 ]_HUȮy7]wS?=@]Z| (wQrӕ}Z *J&sYժ1@$8  %ĸD+6蒳|Jh=p}n'j?Vz̑.;1ho#]̮ckH>Iu;\VWFo}io< "]m)XETƩ$Oy(GۅӋP;ﺰap*e4jP\U* h;QnЦ 1A %2Cy΍vn& ѦVg>]v=~ţ7l[jDٙ'5=tsyg o=!'_ŒdL䄠Q>ѓf`5 :t;sdTi+.}c]w?ZvM juш/: *۽ r|0,Q[D䌯?:S64_[vɑsў% OdUz. ClM"xnc&߱խ\{Ii\CH!m;P]hlmj; [O| ixKڌH)]^N?%g5ʰ5O%&j_Y9WUޫu~7I) 'Bje$˜0bc ;e"")iԩ۶?|EՔ^^΂"8d$* a -ȢDBQ1N.RT CE ^ad@  @"DETAQ*TFeBQ`nQX˛=OtvIG7 Ψ%6|`9+诲բ6+*ߺޜh⠎43A3 J~hҠMbFU"2K%7ji)ǶISXEzim_sPţt" ?p=2AP1a1Δ#0D + .Kkes&Je# !2'RDA-GبNt,<MiLn^\_Ps;_3mSc@ΑxR]%J#(#Wem%^Lo'*8(Zd>brԫ!F!B&nDo|jӝ䔽=aMKJW KJSceY%A'/˳CtBTw󮇲z!x {tsO/Wߴ?kw`?!>jnZ˄xk-D1"n>kűҼooRc4Nc㖞.*Dz4W`>< TnW_ ݿG T "ȵCtbdwGh-;RͺF|*B2_BQRxU8,I$K`UD:cUx -C[NPg9VlSpo(,ˑ$yDbmbQ Dpa3~>X4XZx cr ֭((oırbq7?ErIb'ehx?ֆ 2):a5K+ {3Q~kY辝gRS˸vNv47o:Z{+l*gֽ^ ۊyà>^5,BHBhukOٹ[l?t? If6^$=$\ cnTW<.y{%WB1L 5j蹜QY$["K(&n>/vVL K͡>[vDm(*JXh [%z.g4^_+> ҎF׹u, ZL1%vYIۋrX0AV?ިcg^!F'%AY^^AE׌CU<ոOh㳯m&h%sW\8o"yENfV@eNީxW KLlJԥ drJ 1^ zpȡ[f-ϾhGp|DܑfpL?R2`)Ήus=럩nԹELޟ'K ` ,rro("*&T4$dWtHvW8Cq{S ҇n6Qb'OoKg읿6}? V,<顋+PǦm1Vm_~:=>Fox3=swwm+nYry8`oS[o勶j>5XxeQmA&O]Rw4ʼn S4>6P{koI]5oWu>%4`^U]2^c PDW죔 -ϐ"5 7Y;F~rp_gKGopZ)wdqz71Prœg~}S{o?RG%>/N5,Dzq˿~2Gr=YV'䏹lu?M\7 j,Â?}w^~Wo&ُzn֋/[uåUhO-ޘ2kVtzϯ +9O-9]%y&iߘ2{cJ\pC(*1K .ꩬ~-+Y)>L `{Ж=&?dwWv:jI<Ւ'0ZiBJWkũAetBuCP)KAs4A3>o5s?*}j8Wi)T5CGE&j^ 9#$;L\X_ V)EOfcj3)PO=N(6xha? Robf?'j cQ?Hj]]KNH#HeNiI0. uOrb>lsi+T+HsWէXf^g>%btJ•6Z*_jN+qN11d6nj-9V+ڽ sXAΖUڬrHG?+= Ɛ!y} ᥩ =3! WjgT=@U3#D^CZ?$܂/F)wδ%aoQhZxʰH*oo>:tCN9X9@֨U!^M 5]ڹlT(Y5DMּ*W$CP'Ww,AeBcUʸ_aP v*+[FXَ6`7KtqEFuVց2/ar; 8up!6C:n? #Zl fP$IH 9(ĉC%띈Nh5)O.b"jK`aQV0o,~oMXS`5 Uzz?Z !ÿԇ( IDATNW;/W{.fn?(<k$ā]r_Ad qHKzzkn ܜ;|`2[%QqZ* ׻0uD| \ z*Mx.XmVQ**v0!] DFY/騐!jQ0L)ry*!4o8wJ@) # 8sͫ>]C"+, h g}A;p"`f^< )eHõ{F? ( S}j.U6Aodk^jLw1vƇ8H!'T1QJ|:ՒM5I 6`$UPx|E& "nS2^ivR5*F1d2qETUD8ceM”tc_P{Cͳj(+ֳn|I^T) N^K|lk/b?3t0Z&!/!ʽ$?ŗW~l٠F^.[6Q Ӥ*|^yzu\ isv7aiȧTEB#1a(sHѫX2GcrsNs4KA+ OPW ^V\@Py11oeKlVxefb Ȝs S'\)ЈҁBR!h"\ #UhEnRm@"F1Qr9 ІhS!)rkI<1Њde$Lp Hv7GAZ-O=NWLQwmm1M *fs'2rg3#e`H mT艉K"ǐuU3lZPaBogJja eED "pNV< TEJ 䆓V ٠<wFX։Aomߛ-:0P_}мIH,om[$r"#׼V=""/DakR^,1(;W*B6/^׫U~".8z}wƽwڃ"ڍznB.Җ zbun4cbvj9g~)& [G [v'CFɩbIVh7'{رQm!mOꢶ&wI$B͟,wv<~#ڏi?ϧ_wYU3 ku5yxgZYw0iOG=?AgX}IYc,0^:6)Y ]RǤhswdYCPAKr3&h)>w%wUbF6h_tv|Y vҒ +'$=@̀]-QaeY\zAD5fEG=j]&c0}t/aLE$I&!C"8{?8{R;d0:u'%ULNC2QO"P@*$ b S}PD`3E#EfXFPDD E$@-(\Q"&"m6^ᒈEUNLL`W'9*~hT5UCI1\l)O9E D þDz] F觟nj8o}Ld]C5Jqh(ڃb( ^dY9'De!5old^⩚.\׫߸>uȞJ6+~ζ=dx vW~pKߢIX)/d຦MPraϗecғ5+Q'1d[E-8aw%>Xo!Od)w뛣E)ӄ-'kKT3e]=YSL/_)3>3ػ7\6" %lPpl]wqkBz>x&w}7>.5zE7$K!o}غ_t[Vő5oJ"#i–Ƞ_f\2nF ^kpY}uo,Lty;S?G$tS9 W ]2K~h*u{7g=OS[W2~B-;ޟ2$^ҰH穟V2ɚ;ߟr{kj>z•ϏMo*H9>l`>CDvS_P;~ܣJ]Y飖]pWegINwz Z"3*e.C{A dd. Z]Dpιr(IFW>2VL \Bc(\.FzwMZv)$97>}8*?T3öyM漂 O̍UsXCrYe.F2̆r9Ec Zx {Cs@2]I Ȗ2_G@eD A4%5 +U!f*AI"a(B4LɁu$mf !S3)t09e*E@UlP뙬XR*+RD)̍R2zĕs\O CEj&/TpղUlu@3Dd)I"w7kh!W!^,}뇫קA[t Ow6wD87U=ژ&V.0W~mtR pi !e c hȸ񹼐(*Ku@^JKBj6%a'VmŽt<]d6yr_WK-mwmt'|yv޳gC;/wkpt I5/ ׽v\~}$xq}=ԷN{8lٲj 6i [&T-)Z^{6wpݷj>uΕm-g2%*OP_?&t-dl9壭lZ@<~Ƕ\H8,Sj]Ruo'GnӬfl_{OQpo5Ϥ{tjo ӶѦv"^;s?9M+:6_gIn+cn$N{ ۗSe< Bk*Jl\+kpC5}|SN 6,-﻽^膉2Qp쾁M ~u͟n8kMovIxk׎‚rxK>bGgOuw^ M~d|M݅SOs8Tpdmz_ n8km|}ݏhX?}6)5f5k>=  xM Ew/퍧-(b`/MK-tIc}]fϻcn/Y省Z#˵bn}n^(v{KvLlj.mE@מuU~ e$!'4taԴ8yP_|hꦔVwT?_^Dk+kϳ%l=}7qNVp0**3c֦xa_^|uȠNP/ci6n{:2 Z+p\Dۑtw:wHf mzgݐ򾛇m܁"%GT1d@HmD("+HvXtKdP1HL@ʣ).I(Q,y$*=1ճF1yk]DCUT#0XGUynjJaXs,^Sy0% Sމ8\eY,e% dI.{CY#B.˜8qIst#j'D)9q"N)@Q=NJV¶U;m P 0eebtٸag/'YvOHoIe92s ."QAQEQT Q/岌|DK n'D9 1H_ʀ~f17tJE/j㊎+jҮb .s 3|[/1M;%99]оy,>SоWH׼c}E5r&^k_ u,w;"v{{\w܂kb>֧#s{Oy} <.qbbá/Ƀ˷C_{$0`;zjs[R _s%ʚ<ŋ.ۘ]HeHG8PkMq3~V$}kmģ)Ai54cg#r^)n]'>>{=3tu20WWƗsK UCMpKiaq}%$5}Vg v=iSlȓ.x QVѷ=|Ē|;4KA#*7%_[G$Fcc~J޵SbL9g lK,)AD۱tΆ X훇LzblVgy0 ' MC&=1kk㫳P}l0&1w6qu]UL ;WccqpeqcK\?_xT*N~2/eƌi^,ۖ|I<[׾ÙG9J8Z˱jv57uzS> (ڈ#/}PPwԓћ1bAlg#f|ރRsߟw]޳r[7b/ qy bT^D@ }=vh- &ki{V7|ϯo=r1&)*Xt6{'yvh a! @( .@"!Z\<0G."FGC.XWp*BcZJ 0oIs_KIEE <êxRl9@ UO沚*5̿&p}`Z˚̊c|ֈZO)FHTI+8G8&pqRh$"E{k]cHμ_zjHO4I!# TeCZ/G $i` `xr:Wo|bZ Ǿn2w5)?,7w5>""]7}ԁMMsȀ_r1&( Jto J'3Gu'VvЪңt u]C$az@C_^},.ٝ#L{{'WpoۅUOG/W Oy(bۅӋ4"؟lHv)wַ_t\kIiN86sYd674tw&Lئ_ߴ#݋Ks\]~G5ے-u&#P=-w܎Bmj= -O|>Oe6OX<+DW *k<ᥫq-[8(NLDvW6&=Fm-4J*2A6DD _x4nۻ:O^-(/&;mu$-F"auD$BwD@8SקHF$ 'a$8< C}F.!oUty8VeQ$˜ T>"6nզ੫Su|4fQP R7cE3Hy<C&|%94r08w˯Pr5]mt!#cEPހPպ _tInCKKp TJ՝V}s*௭CnmߪC dTx~$${f{S@3J 2D_dVm-geTRչ4pMqd>0 IDAT @1B[lw\[LrP`_uiEaw_V[?Nu.@L yY,H=6WWU̟f,=kTe1:/ԫ!}w`նZ3B7iD"`7 (EJQ)*ҥ*sr^Si){{oٳgWriƉ g='PQV!آCu & ]2`)Β#ܟ@ νJm{t5ckŅ̿3n5(1(k<1]/6x{!\<4c)gV##-"@ޠ%8^[ %N*ܫV,TC b! :7ԴSoL}gFIC#G^w$#OCV`X\v`H&gS֩xg^jˎyߺOe-Vt|OAaru@M%ZˆЀDn%@NƐC " +aPB!9Q !ĀC *ejR`Jd"s;]"!ǛF-T*__[nOIxz@:xoa,mtEl h# )BrB+з5uy"!1mmF 8NiD MJ9'-rB~1( mC)o]'A RHj D֍ܶ  w:m5wD{ꣶ4zsjq%fCkvB\q8p;E@F!Eޓz/[`]a_f|Z7:'BaXTp ayNB>.Iͯ[=NLN*S/m!>T{*aPY,)[ =Ƣf4q$*-$2Z5P`>Yи9t#T5 c!dťS5̛ئ1R n92x]`;?H:i+VMòܿ!*{sRcVM²`U "9sl*\ޑrIޑ .Bԩ(lp;`Y:@WѿkԐv0NQ( yߤ E?8ӯ~EdjoÑ+k1Y'@ :dK%HA~z!C9=/DuzJ0!<4(bfg [uȼ1n o'7),znPrziݡ# )䯗L-ʑU2EFqe9[Ĉr ŠCXO*Rj2~rfdH ڐ)SN 4QJrI {ȐnK~M.ڢ_Ϳywj^~zԠ\2 Cb֊ԉ45~ƶ̄t\|T㠩MəK4wYKTDp!U֊0׉25~!YɹHԡg;iWn=qȩ|O(]!n);IjҞnr&LSGۢg>Iq8 ;9r FͭߝҜi;e߱Gs_nf}cŤO?EMn?N$*~p+΂|KHrj*懔,lUW5[>6ꑙoT;~i>JYZ Z?|1} }u Aqe[Qӆ^O8~DlƟ@L×{5p{ ]7vmK>j0?R6|ݩLu|az5q*7jQ&Viи83>)7ӄqo9â/2KFs˃!#g&$v0ѭ#rvB/?T:@8wmK>jڰ3K'Mٸ+΁T0: $K;NQ2_DQ?|uNEWF6xg[3mX~E%'eLtr7>vw+daX=w_JnsϽ0p&n\>|5odwY_̤NuF՞S3X.'˭__ yp`xjJX n ==9Iư|793o'͹L};!{G:GD I ozZQot}@}s܈^yj>1Lsx%k>I:&hEFZ )0!ȲhlZi~`%jǧF>eپ5[ǤDY'U): u+o(jAV脚.(N^ 8xSh)E$EցHz 0먺Y,uŸأnN_v'3@RJh< y~?ͦ,0_XtXB5W 鄀&rsK6W)YҎ"9wO?.q-/K7$8jm^nn!o jCtg]}%ECWB /[g| 6ɝYѳ,\;˽}%o_oUx~2oN+)啧hѿS+LctPgnNo*w%4VS2ɘ-_*[ p^pK7>LtKѕya"_7|iwӡK_Z s6;o}3jwF_} ։-/=08+>2gߚ! ; /7Ǯ5(J.lR,mw7GqWچ$gOp\\eĈ]9+kJ)al2~ʮʾ7$0rw'^~zd(_?+ M xU!q̀QksTkiK6M3މyo+{뛮 > }Tn{=pkļ7uB YcKzlq@ygxSi{~IkV.(;yśF=l +tλČai8fuP4@6OS_(3O R34zӛy,č 7jߠq~JZ1& LɔqH*&Yo Wuю{.*abC9pe=e_;*sX$.晓>zT< Hb2uI \ H k @qnn(أ}'8zrC@  \HMz33[N7p']9=Ȼ֥FIMZb1#!E$}#S"|cUpF )X8T] ֩eS8 m(")Y<8W.!Vl|˙Ȧ`&KQaRr„KyבLvE}gtP@1aQΤk,|n\*]:W]zME,׆EGwKQ(0!()m.:`0O}/އ %(-HWSSZ45l8见C7ez"Ò)R 2CN#A:ӥg2J\1[#@\A; 5Uݿ8#z=[OH MY]xptXeʦ#HS,$,JV|R@ ЇN7V۞25`#ŒF-rZ"uHVe>g=آ01P< fO~,~ 8"N ?,iw]jț+>5G QW_rd*/H_ q͋ _vBY>ٽҥg\5z|2'"µ 7RȿePGeҒQP$K/>R]81/G>9hwSWí~Ydп:CL.1vx2#z1L }Q黠g:*gVS`ѿ><.o2'cc@eCީUL"?r\~epOu.Pk ]&Buj&l򯤖uN )˄d4r: V+dzQ_ĺ$%"N=+oK3P0h\m*^԰9-1Nrzɟئ2:?OߝW r1(3 S#@'_[Y7MP(0-&/Ibr܌$?D @h2<s{*ߧb/Xƻy\Tv;6iL7^^Կm)Pu(F,T,|n]ˇ3LYQ(lcfĘ[d(ϪCȒE|ŀQ-NѯV(TțJ Z94ee}w'Q _@c_P !}@H~(y!G=-jN e PO,;mmCp3XHMeFmx3 {pXjym(LOEeWG#"d5z2O%ƩɱhRߊ .7st3"@b;Eb3YMV3/%"DS4s ,TG2ICβ=]NZA!oB`w/@ҞZȟ!6ʋ`ˆt:c<^eKuHZ?,i:j#yjx6_ttvtv]$@΢/ǭ'֌fa —IĀ{yO=l0$p I[C5$sŨJ4m`>zUKEnj샇?t1'G " ;k4n7/'+|RZnt }^JiOKźK=́-#)$D/l9 | /EDO,"X]F^""R-㬶>?/~#K$\nAEQ\.7!ou'(bs Y{'?/ʓ([6P (qhHpN#Q<sarފ gi'̞@.xqRJ<4XCmb Yg 8厐P/g Mf-4444bh0ɍ 7 pLT$tMG\aϸws1i%;M'9JE{WG@c9Vw{JJ7|р&i^#djqӞzzӔQ{߹(q?qWMhI Be< U9@OAQ͏ߨkSdKOT~p"?TaLI> -jsYӀ@E<}w=k{ߨ`iA\on>qW;'ٜs ΍n#+QB}nk4RYg~/475a2u_>x&j0jvxuQmpugƅo_hʆVmާ ZxgņG>vx NQ,W;xHsxޣ|G~cf<;cَ;Ǐ+f l)]ά9v?zоoN~IXx{zVemi>>x58@tr[˔2suHmaoݡGR+Z}XI=o9:uOR)ڏp=?<NS]#4N|E_ck uС{vk=+P>e|>{=:!??ϗo>QL?r!եqCI?{9A/>G #Eu JUZmjƣ5wע(kꏾU(}óCAyQ2uPmg=qvm!vo cެC̵;3_ݲx wY&< hZw?qؗ4[afLt¼_ u{κױ֣BsX[T7\wszo jc֧4pu;!o1\ܽhq* nÐjڙ}ګ\gϘL9dyb%_7P86>0ɠܥ󓇓WO0K~blUpc!>x&w)v8oœ#V*h{Qy^s׼xpB?;mJ(d~wQRWK os~SOgZB0f9 ih>cG%8$S/8͝6Q ٭̰$WP#*@..PVk1xmBIf//,%\֊oT#5Fd9k Q#vE9#V'o <Xs_n CG)-Cz "WٮD7O>ƝV+2AWlW_/O Ш'D2(0( rD #LYo4QCHp8Ev"} }5ES3<%"DSZG5k$%o6[,d/qr g4Qc p%ā*h8 rfFD+$9'VBn_@4phAtk'0RND! FF$ G W[=o\s@L=uRڍ?\n K~D3_{\ZJg6bmf17J\yG?wW9[yr^6 ch4:.)juu  ~+>3NW#o_p=[TY4m4Ο6|w̞ _7xʔݚFglg&OOcLXps>q3<1GviU/$ػ~^9Kh.lNuWz`oƞ'[zpþ)4~7h ?'ҍԠsrD$/}jq4걆Yܸbk4b]1IP9u.^lTE99vmsCo?S~{wr\sj+kW9k9J%)#/ޛ4y+սJtAҢϓl\qY 1SyӍLNL + m|O6ܸ}XГH\xǑOp}0"_ǚ^<0lК[n_;Y>U{<ʚ#/KewZ=Ө':(q JzY7Z>PBV}Fl:^X|rJo j7{֯so܆&t^Θ#lz! 1ͮ֩)c'sL9r:!pz%C^ j`2,T{U\|帟U{ڏJx?efwi@Wyrx@`nF݌ʭKI "Ф1n@NH"$Mo_7gј&wt625rN1TvAuqjXQz.{v#x`EW ?uf Mȏv@ݛ EۆI!RIXQNFߞ;4<6dz/<Ֆax7QP[C뷪Rw*:} =H\bmZ#RS#r\Bw}{[whצE:Ts2nst˼ߝ+FwWq^=guqp| XҝC`ڽEG4Nl[\{nsŀ` ijzn9[xZ︶"l^`0i{C)|CR3[[N gQSG v<\ﶴmFLojI<.'\u((F sZE?Jh]Y<ϑT߂&F[;H_jȩѝw4]E]8R掠S"}\ 4@bN"mƜvCW;yozEw&!gtSGɱ*:껴{FodဘmƇJ;r;J$-PV `fg+!yܝ)ԟߝH뛷of:beA%P&N;#R WXiKcDDOqshTpq_[mvO}3} +CNbH`1fcnJT!IWyס'r?5Čӧk<޿]JmZ9D\}he}|8ov% rn7X,f0F9FD}^Pw"k x{xK泲Qn8ɑtxw1FݳIu2Y~fz[Wp͉`mާ?]zi׊OϘ>wiKR䥄7jlN0sۢǓ%ig#F>пƥ$_Of}Y/~ُoݺkӦϵ;!Bc 8uɞ=KWqfBXL;#e&۳ktRqo~2ە'~rFc7W^?ۣ:5pϗ%oΘ0v;ߦ3fa5MjRZM7gLxQ}}trR8VhَnKv*B Ξ eSP`ńAqvIL%{~]XGv!UQC>Z=F \u?N-Cd(L̔woqmRQ:ܞ$.~ro\JэK~mѧCvOx]7伛\;oIrkժ6qiM_v=d jX̄*uqi_?ssݳn"iHzǮsܭ{Mͪtl Un~7&nF*Eu#"h0q x2CPrfEʮY k{|Vu5g}SP-[tnw~׿~WP9S{^y-j]:\!J5" -EBrH6)36mrκ93fg}U{}mRMQb>1Ef udOɊ#S }KP9sԘ/ޥ;[8uuJsjHxY1Ǵ]'tǏ}AiU 'kmI(slyRۗ D$ࡥc}j&4`k.(ܒJFQ9c"c(iFƼ}3΋6T$&Gf|q@G!u_==^`fkt^yً!ћ'ӕJ'icE"8K~zs4Ժ #EH޷_?V>Kh^y=\DxMk/"DF"JZ}]Ԟ\ǍZU3nxa:q&nݐ 3*m]ݷWo PLܺ>Q]Leuߞ6}uUqO'6;)ݥB|`poͥԵҥ1`q6Gr{SGO{W۞Gp잛B%Cmm-CȾb'@!R:'B0yrK'OT>rۏn}lonfp,Ȱ^MQ[;ۀh/p<da׏S:uQ]vv"gC=kUO"bL1kՖoow!=n%ڮniL[).`Lgi`uN^WgZpHZ3 !xEg8 hB.#P9CxNDhp"h@*I37h8DB+r< Ѐdb]"F@Sǐf# &Sk x@ .\hoچiDFC;#(c <[xcu<_%~2`U[$v5愼4֠_ qc=\w?ѧIq.ʝF<&| FҢv=W{pK^Rm|=!NAu,\h둟zcZH[\^1VtI= d`Bƕ;iv8tҼ\“tJX_®^?bv ^s0/~3B`߹Y&Ͷ9Iiv๗~ L>g}ff|yф|fQP.ۓs:/@EY`38M0(.*%Tȍ;s܉7Y:z+סO34dqN9I΅UB9htj^\.+y WH,H=zU4ߑ"_pz?e߳ j&ݛYhkޱG0YEL[ XOҟ^֏wZ6_ڤoq8У9ONz٥]w|l'Cz,:~kPce;z8mTxnTxGȰZO6m۰ ɫ4Ǵb:bJ+7j.ݢ1% p%1K m1.qc7:GU&3H#b R#^ I1`Oo4Dp BǡA"!Ԋy#@ ¡ώ+! E ᰀ1Ђ(OiP6nj3nF&FДy,P ( D*#P}t[NeA̿PaJ V 6_蒫1o IDATcL7H+\2hzD?oW~\LJ+_7/5Ũcmr2 b~b|>@ekYNPsdP*(VdM &_aZ("I/4`mip4G H梐)Ր|0\v9\F!)C{((r: 4yVL$Wf|pȔ1s9!r-"s1|0I8~C7hE%vW#l&GDgىy3R @6GXp+W4)p=P{zݡ۫/uڽDQİhp^\ =% P {xt[,8fٙłB٧s%g &CM摿}SUSrWNwjb>2QÊnʹ=ѦM+j}Z!+e@o#+jFR:(f_;׍4 Q5" y]LL(fgIʨ謡Og5y涋LfU#yGJLfIh fU#yW[^]\o_Eg3mV5St&a +%,S$Ļ;&MӉ$[5 ޯ_?[ WIZ«$\;ӵ?mV=5=?!ѐ.ޙ,l44ئ[)-5*~B_̒Ij2`lelvń62'1ɞêd'1="3&z/dW!eg 1[+EnRx%ږ-"yۈKNҢ-#ዊŅ` s0T,|q`"؋DBr0r|hW#L-"*E㸔BŢǢ]%vUpePR,j F\%Qg_?k`*$̈́5-[|By}r칡>cdڊs%.f>]|Bi-`Z"8~[9M:EǗ,:;fAWm' SŚubˑZS ߋ 7!2 ^Ri)R_M g[;Z7ʄ* 7e'ˠIcoǭ~~8>+:_SUOyp<h/רAɏGgn9&Ԛ.oEK'C5y ,ha02|+:+/)1Zc֎ԉ45Aƶ̄\7_Ӑ^.QN#>>)ĔS<>yl3J : T8`0p!SQ}Sޭ7rV߅OuMəsf$=)Q7 MVX-Ǚύ`euQW[/X1~S)_VC&L>d#*}p+|OLrj*,ԄU!8mމ-LMd4_ھϱb℧S֟VC'O:_\u zErږ0|Դag;@֐v*}ߩk)F]'dzВjWֽyl|znAӚ3´!WWmQC%k[FPpHѾ3~׶D?)w]w5*wտD-Ы8|nN4*}jpsM}4)=;nU붟_k}rXiG{!=Ca߇eV!W#GT2|gh Yl8Gu~}1Ǜ֘7223״jŽ=}mW+Π{; .ܕ\w!}1*ל?%RZ)u<s``DTA~q ۵-Mw}=}okyw̟ʎZL֧y{ZmIfe2jyU`DS4I 581pVBᩚAV%9ˆԂ]o)IE>b a*9Dc MRBHcC5[Hnh4% < qqY"}yAQXM fq۷#""ok`%_UJ"+~Vdi4<3F!+b".Cyה2#%AOHuu0hDUI)asbڵ D ]TkQ%46be03UH\=`Ԛ:J/./3yBk^c{k놛}ǹW_t ;ukISF5#^;q"CEh-Ə?hxʗrO M}y[,$8zMbZNytg2u_y'D!$)KWٷ 0͡Um2/Y?y^lUW?+ĕmګCBՅ~r֡lX"@SG54ld_*9b7V71_2qH+⏟ _/7 EI,LZucۇߴup>/?ɇ{ߟݞiopA2#v["$aGrv"#*hڢ7נ(O^[p PH~zSN{S^6 7]>pe-RN] :条U>g+N{y 4GnnojНyf{3'|EޕyrӬIٕv<3B(_Y-P]Dv<1NwxezSQ nwP- j(?׭3fF7m\m>{f#qa  F@FTT *Y#T&TADdH.l`Lw3= W}{0S]]}<ϐSDb8@x@,=drBBZW6;>$@?_ÐSD}ջgl*wg0"Յ~͜[h‘ڗck,kCes@Ghۇ+^y>S汾j3Ϧ%He~YI՗mh֪> N^AW o_ݘ`AޜAyRl&˺YdAzKwHn^9'vQs?s/QPύ@|q⵬+oI9; yF~Rb-:3 :. !NEU󈷽}|OBm%ڴ`mI#5Y !2 !$5#uDj|$rh[O{æ(Lc*q(zRe9޲(u@elSS@z}F)HX. #m%r!AB$|pdq ,@RTH0rJ `S4'>5pТPgwB\fv+K!"KcsȆ~>#aеV f\s¥cCS:85k{[ Ը#xFPlK$KB7 AQjy(ą@DM4MSƹPU'( ԀjaT8*ۊx=#:[^@nZTlHl<%Vu۳'ΉwcXWӛu_hS…+CS[ӴM;#I3? l{rgTM:Rr3={-އ]ΨPpLMy~Պb|r3@)cL!EsCQcLj D"$%T^N'7k+ϽnݪV큙.n@*2 C9'"c^0 Vūl% mw:.cz23h/ JV{ztq?tF[:%۟.+o^(F^1$"xn煎4qubab*@aq"$ EΒ/'^z_MN=ΨEN ]Rk._Ee%_ !tED6{p:WKM46s"\SR^ض}'hnf`fͪILˌKT:1U1"Í(Tndۅt n%zZoQ^Xg oTpgtK<4]0;煂XVMy.8"#c E2DdLQUdm nF +5u,4Mu/hg}5fYtE6G[p3S6!,AȹF!"'bgHDgƘFɌ"K,dI rBLJ} &їwfE`^9z&=ebbpC G"1nU*cL7tpEUD$$&&"qC7t! !ELm4KcCٿG$uJUz TT,:g"$!aԽq`D誫6Tq(R!yW@ g=w`~W[0۱]Xa & ]xh\|J+XEO;WG 'q u!c̘?}&? }JyTzNCH"cA2ASsWE-ON&K=G9rx(b2ݨ褿pkRlYܕ.FR5fm3rAW첋D?]2Wxa;$7%!$He5qΉ(:dup!DYiYRR0IɑpX UUQM hɢ:C\@EgV X1f"YMzsʃ]a'Dy7$dD (FzƲ.a}BP %ȓFD;('2t]%__VX0r5(tP+@հ8(`"Fp?BmThWcZ:Mj8@./D SxR! 5$&%*, TV(*" CE޾g/t:06LʽuVVREx:s0T9*GҷbV_nlŹͅ8޼"Qn ָl\z"[:($~D n%-U8=N1\zgȅ0CHttŐ1o˜{ӬpMVTE #% D,di`B@Uq=Y 1)i^^20>F࿯ZdL"cpzt쥏0y23MTMw(KTm1U"0QmF 7 䝣s^ ;1acheAM#HLQXrr2 B!y$&&r!8! Ap)*E7l^"qAivmE!05Oj$ I%fDTc/$ei! N?P+ J9Ү$塛 -0XJJ dsy7Z/vG󄀎^x^'mk<$F9vXa1(Z\QUf )HKQpw"%5%CeerZmeOf  %WqQ?7 ^GDg 4 uӬV5L^RǏxVv1څvZy\ai;EsEFSl?x\&vyP O.@J$ ),o*)8)2UB|8ʲb˜WP0 o1B07!"'#$Kb)@C\F+7M\A99{ $Ae IDAT0}忯VJalE,Hjl;|ӃF>tj.COś"![NBt; >D? zr۟"j $XoB1!@s^ZBK5aHV."3 ]7tP5U;us!ܜjMRNۍ ).q ʚ YxQ( YPDG])%;.0 CJi(ɗ"$"TEg0Ud@U-5UbLINN$r|iY!37h̐Z[[ĔϽ6} svS}e8vTUl$2npEA!pL!6w(G( X}P*2(KOBBȋ<0˫&urJș:{ ]I1kp=?cP5b[ߓ'ɯ7^V̽̇/wƂh3IoEug(6Nv/ݓDl7`XeBUvc{A&|R6#ҊQRB6,.bl`Vnsf\AcFu px]] SLL( .c2%qwU%o )0TP:FB6qaj061aqH9z4Ut "&>ٴ 1 Q:2S@aA!"SN6 S*@! ʉqiSp8b^02-T$.|i=˪I$ ae~D.}r^ .o~߸foz5ToZz D%H [G)npeYբߗ,6AVo]y5?V3bF_E\ڷ=5翹yXOm5|o𽭆kv^ ?"{"TTf4C%1EXa*2)a  aZZ@B"s-8hVgV7lvԄ1Q@! A0+f fy ι) [u֋;/'ޫ\ \78B%p&O>o q+gMxẬ@t\ZkǕ˖5kJF>鷥kXO_S?B[)W?k-_O]_W8'^+~9U-Jyu䦌nf|#{h}Y+X x8#?m;'{_g?XNJ'<m}juD^ы"/7} A[Z|Ӂ1=O:`ڨw{nਡcN0ѾD(L"8A)Ws~8uTAf~8Az~lnhz:*/׉pe?'e^qi7==#݇m/=*BG?^}" S_P):/+ ( B'Η{U}_yS:xM`ë.K;e7?5OnGvɧ2ᱯu?glȡn S;IzdûosKFWQw%cSkE)I/{lԙB @0pE0hdP%fN_Jko;sHP&βZպqѤ Yq|ki;z-m2hYv{={{?4oGNۑ7H=aAyz|}3g1쭡oOGY]㊾o>poqO%[hB*q{>.{v!A^0i@F}}=??{&֡@Nq^ZVwݑ?i@/9N1@W ʷi$U}ENAQ$*9~H6=Q\5gR•1>č~Y!J N*xbmnEu80y3L0#ύ<ض~; /ys :TW ̾rO3j?]?@;?v(ֹz9N_7 0s;~cwDr'bݶMmsAaoZ$%|hۄM;ul{?1a5,:t!ǂ!()-bϭY3WFm&kul^O׆|#ᆡȹ!r)oBkZ5{1Xrk /~IG>'lzg=׺З{_\[5?p^ݿ;`$д<0[o*I/"4S_9l'+ {=?t+K~ۂz%7̀}B!3mu JIxFLuMxͭ$׮ %' t8AS|>nSUW^Z!ʀ PFKv țϜ['ӱˮ=k?"͢sl s#|PSvtF׃X/BGL8[}_aLvVwlqgv8Ϲ_K׬cY%]%_z-^g=vo:`z!Vla =,;6q P}WzYVq|w_#:scU}|۫Gd"N`4M!#͹L},n& 2`mtH)'墘yg3@V5o*@@H&%s`{uj}=fF>w Lnط͞T;|bk%㒗}>]OmТwu9[Ժ7jm/2lT cNm4&{:J0U?' 5?)gϿN\R5 sV㮺slm)枚$km? ={5PRe@>**AwJ?)ck˜$iV}hayB8v5gYGrrkh]lv}H=A$ˊa;s$Z?ufٶUCEl)Ni )ԝyUGm6[Qy&Mo~Hw/.9D5#?Km:lǚc ={햒gVs`nr[D]߭-6iƑA/<1(0&&CܨݝW[9O'b  9am>k0TTxO240Y7hz͝W:~k!)r02)P"u)wSMn|ً "ksAۻ><#J3Eah~8_c;\S3R?~ޏ{vۘm;)".Ćo{^~Ɠ# yXʵ^<;wv>㾇?/sfa}fs|[be@X_(WbHR(۵6;dgVÊg^U#޴5:viSʿԦ2vYdR-!иgMU”&2#rR VJB ry<\Ax•Euk$aB/Yxo)r}x9:7N|@:vT|0]Dܤu9?ۊ/8(\-{PQsMv@?n?.OwUUk%_2"yMQ<0@µ3Dj @_ȱ/ܺv4h7aے%릖|Kj)DJ1nQK:VvR̮VKSNlsQ|KUw lO^}r6=~ չ斎t9ZDJէw+Ҭ\X0)i a7ޣW6}W h"vhy{_pQZBi3}0ታ~ݝ;f^BR.|v;N~-7?kgS %F{ۍ7yibj#pD0MS\N S5F>^%B~91*ޠ09?Ӊ#Py V}iKܡڈ;r`?`[f5Jw,߸c&~tvy񿔴tI t9][ @3яVR~wpuѰL~'gI+(@+|ϏT6KO^=;:/!e#'go|!{.I  V^׾cv,Z6 4?>sՇJ"c.Yk\re%&ȾE?Zl#)'nY'c \שe)dmb[NHҼm̍yŐBL4/x׬tf\Wx$O_WS4/~}pcz8R3RX8T(-O~o}pczyǾkM~mɼ+Eclh&ONYt'O8ty>#{E;{i ۽@Jd'uu\OHFNRh~n ۵q/mcv,̝a3V=|`ӏ#>ڨ 5Vtt튿dڽ~ﶇY/ƞi =!8Z &mJ|KA.&ˢA&*#dI6;\+D!G?]K17E) `gZV{yMMZt^j )a=RΉxvwF@ۓˮ<3]<8K"*›ݴdJp*(.|hb˛Ffq5Djz1y\|(}s"' τˠ$sp]h@v IDAT0Gz%Mح`\=N>ʁ7>o]|Z:='־q~}RS. !<$\rLjEJwz=Zބn[zhW')ev_ύ;P"8熩$2v7g3bxG(`egcnᮥJQRE"̎Ň9tĕ?Vʾ#+SO3[$NLiʅ`VGL鑫J(@)) ( v_bY7~1# E:ttmi#t "fɍf.֪욇^zax}?pXоxb0fݼlibIցZ s.r4nD?CH" 0,HXr$Pr "BTU*~WҚ#T@a!B7\%Pú@5EƴJPQ ?64Ewoy\䶦6/e*d0U\ЉǏ6*Z xWB*!~J%r-+BHxN-x1'k>)bUTo46=vB6 !){4?]>)ݕV" RMt276 `iSa9C}n[?*Sh. ,ֹۘeJƞ>Ql[)KࡣEƘrLQnxI)B2%ʘ؂$N.])))jDʊV}ujUl[+& CrFC{Ԧc*骪0RiㆁP_Fxw@$!"'V?wO@@828%"\c*!bHNO*Z>R8Dİ۳*D^ǻZ0~oD ,='tW<%*sM ɣ&d ⅕ejl^chZ`r?nYXx\_/cJ+>Jvc~E ]Q"E1   PTE*1  `0`Ea-($˜j K&k.H 6HI>>V ^ydzએ~-FHʌ^|ͣpaR'~_Pz W &sT835UןCIT)cz>s<+Z\ѧz1A1Ճ~⨽*jhiW-z_67پ⯎>ziXanya+8V,(B5B.u3R)d^oѲ7z.#HC*/ F{3`ff\-=T7M%r<ˇ^T(-:DL>I.(Khi^YjS(0 ǼoE_>rbTDxMX Mz5(/R'E2fREG?__P^3Akl1:lh ݾ>*|f5׷m~cNǾ?VVҁ-<P҇T4E86Q*A0*"[E0Q1|M^*PrgPS I*`-7oTE%&2 vJ@Hr?7IF229B${^Tc6bo@s~D " ;e5'57OX(kCFǀ9?hb=$|v 횿hLҩ/+*M_n~-G /Jk2wQ@̦ tzXO<4d ȑtP+]@D"?t`[({[({[y^ee韱)WipI1 Y=}6Ks!䅣倴Ln+@=-BQ?amiIɵT2j^Z5!ddHjT,S^N*0DPF$Lz!œHs(yܽ!'y0PeԼ 1US%Ynf*\UUD*uΨ1jeՀMeFpk$Vi&e1I-^#><)H%{7OnvaF"b ٩yw9jjfzg&umf` F>D^V9{Dd:""(ʂ)L:G:v~?n,A4 ^w sé:]I54T) T1i/-A[ ^r[LoMȃh,`}I#i U=?e/-j Th]T,Ptbn}D)$4j_$|S~`VU^xP-Ď%%][E}"4nZhH|(%wJ"RDߖqȸ̳?~ꑷ0PQԲW:19` C!~z2RxƁj*='cko ӝ14F!`r_PMϺ5Jg.)IYB'&_Y̬ݹrF@ɸ-6W~&xlRT~`= 瘅'{94mΞBtlclBvF `xל99?86ɛ[[`^!c8Xd.U5m~doC?>XYjw<3gƾ}vsB޶_:UnhݟN}My]p^v}Qݡ2i.1jP*4>bޜ@h.LQu{轵9a^x@^HK{fL:5K>ƴߜsQsU7/e%6:bޜ`v h!V(Ԙ[m@$ۍ6 o6퐵ye[\Tq'n=2e-dkcѓK-3:q' "h}Jq86.WPz[z{vz]?,,b-^o!! u=b/`x3x`@?U91^11o규q_'o% #1|ڐ=sfY>ٳw[ְgcwKG ٚm~~iwԬڿ @jQaϧ=&4~D`]z䉞X֜Mt3}Q@IͩuM|1x-ͨQ DR=c_>{}WSgϻc2$/5%L%&_f Ը4kXvrV9+"W&f;LznYjּ_gֺ⌞?IY 7`d;}6@xpPVgvAȖjjw>xw]6_₢/w 9ΚL009I_Nto6m]n:gUΪq3N~⃹g]z-i?!l.p8[/~!Ft gx8C&ޟp7/Tm2ҍPB'? =kg~I]moM_ȄYM?z !?i R>&?}U1Dr|򐹇9ֱQpXOpY3ɰGo!ܠ?AVmƐ_8VcUv5ZpdC@ƋBqp~~}LFԏ_|,,z/M@s;cg>ݿx@k'^'RQ;|0q} ؇K8! R6{f2C=wۼF-΍G\Y~bLiX^ga⇾yq|jc"Ƿ4f9#|Ň'|,\0N jZ;i;I]S|x_^WaEXXI^~ƾߦxy.8ށy<\Uў臧=78O tO-}Fh$6_#mQA=~h҇ =!VmƐx|>pTG!y|eȭmn9WDd~o$~i=0k㶔gW#9꣣ rk 7};Sc> J^CxA%q#>?8}Sf y [t%Hl0‰U Nb\Aدnx֝= #!uݘ<A/8XG PŹ[ҡ/Ozsvŏκ ;,~7tEoĶ E|c[ënntaR$~'(/9pΟ3FT>O z歯Hݫ5Wx& 2򙏶ی!PumThe]J7:%pϕ7sʠ Fdu.lM.8nALT!$ (W {ɍ~T:=ډ>2vDd sԀbhQ +N/NMqt*e Q *nݪ|ܜ6q6b}nte) l1Dp=,Omgʲ|-3F&P [Ox3` \4yS<Et嘣5zKvm^|hMψʼnNw;lnפz!TMea=Q5MҢq@UUpZB$*+` :!* ǹ+X|!1=zO~;ň-/(@#[vU0f^x@zTܑ8 Q>}зxm}ZgSȕY;ӧ~RT lVVuN1`ț,`gd[ãaT%hn]c Hhw[ȣ'rgams]8Y]nV^}ћ%?ںuzچg#4A*)6"aYNU)%ILSWwJv.Psؗ)G r;֗Zx!Um]{IXRh`ehek7ɑ (]`9 cV% @{_ս̬'H $)-i){)Pܵ-.Jq/Z]I"bij>s~$@߾;-M&3w{9ϡEЮ[5,ۣ)BD0>+>o)%xP`@ĸ02(me(x ͞ Cy:I0gg6ڨaPH,@m" f -8BV<';$Q Rޕ BF8^`!('_ 'n-QZ kfLf6XUahKRY9=?u^bӝT'b+VVQ[o.ZtCRB[7/ Cp>_-{,ޞp[XHiV(ioscߗo`R2i!g+Et"6?_lN}JF4bZ$ :L56ty.KAF E 4ڨ`1`c7d@mcj#v2ow4Kĺ%nJب*ea[F ljEyD^CBRm#X8qw8ְ,qEDE ff8²,Y#Ng\j!U5wP%3[IE€#U-dXwM mU5>v/)!8>ٞaͻ@@"bL26s gr>EN%@:MjE"&c&Z` HJZZsfgp  M&ce -䕜uPES2N=ӏ9tUwp|@QC" #Ap"^fO MPɵ?vZVH'A@i@Q4ML& o/O!̚98%, 5U9J9ElĶ7LDS1ĐpsYg=DWqixF'`;Q%74(Z%J-DVJ0IJgx%vYץ IDATf(zHDV{&7:>'Q\(xaNq1b' vSl t-LzI"*,9{MwԌ%a LI'H"@H\ v1I5*Ra=1atvT\@dwYHkS1 c8~]fkiD1V-{<:Pی8".rUL>Sm!e"C}^xvAw$D6aRQ9&gkAB%zglSq09 !"cI(R (G[͕VµhsZ*!6v{i J:NכLfr O$sP:厠w Mz q|NPzI<(b нlB$9|@#5ӢbtRKo`"H3D)%:{wwb" qրUa%)q=bhӚ8?IHbXX̝G0Sq%dK]q8(-Dl̀v)Z%Br)Q5Z0 K#k2&(Z-+>WgFQ(2h]LTD_l`a~${+?+$TD-~M DF;7\ 7oKs&0.%h)c㏣G@:0y`%|NeIP'R25íN1l8@8ںP8,PID9)|AFlP-D٦_ưYpvDV$%&GKЎP'B no<[88(4Asu$Ʊ(:lS fq(vriǧr3Zo̊!)"&$گVED NjJ#Kf8cC$77WTE4jRŚY-Lh"J\T[is'jSE_ra(m9ebd78]tmXir/:#08-!o%MڪAk'6^Pc=u\M8N3"C%Za4 h (iAOF>!E_Sm׊} ș,3ɐ5L*Ьq'㲕 0qPR)Agb)J%Ǵ[EՓ , $ 3L$tU#$Ǵ@A]Ѷ%-19[o_ ֞#'?VK0!I{EցCiNJУ ȲH`HSOUvN "خQ(*I"cg"Fq4RhKx~g6ݖL HēMB[Y.sl '. Dz!A?h^*b9P:9urR4W67W:#a8ȈW Boƛ:=̊,+$I|1& խꧬ{iK nGC7N\?\L# Tޢ<ͤslEҀl5iE92= Cnm2ɫeׄxV]OEgSUEpn%!-[7S* ~{&d?oXGAmqk-o.tD幬SOQ묅 s#-,a;lCIC; ĵL(+trf'  'k4%Q5sKw_G?i/h[|AFB PN8!k2q2M3L .z=bR,GCFnPJ>KQ+rH=fxhPt=J(_Ѐ:$ \*X1؍.ZQ(X i9CqFF4E3Fs-I2_/%,eydroĚ zc~2P(yq'"V6[ @3pֆ#goDG^ݻfLcKa_oKU&z&Oׅ4z{rx= ŋF&ԯb H4S5kG_{+ %|Nt5t6AVɸ"E0ĩmAwΓ7E?gOe.e U38zZx^%xQ""7 *z+t~=zK`ڣRNX{s6.H W6LXĭ7Lh,GDڿU/^q`U ,^mDyo>ᑑGLj"ciu޳8vֶޡ U谛ύM|+꼒Aqn%޹h{ZgiFFt 3{G 7|rz_|9>|)i\Fm,6vd݋g(+ZG7r`Ѩ1B(/&WsM/.ڡv8ѕ&LQVoV?Ήu|B;1.hX ?sb~{I #.FEni֥4jߩ4OrEi KF봮,R7$=@&TРhU7SMi/y/@C2X*|Σ{+2J!)^QDb{w^6I9Ԡ0ï1ӺE,9;X' [:m4Ypz+3y+t9lvs; }MlbLˉe撌؞ 򊽗MlrN ̥=%" 4oRb֧ڸ[^@yhڊ݋?J6l1lU?n6}~X0kQZlqZ3 hFm^ =6 3wZq| i̕GTWuB9?Ϟa l4l_&"/(\֏KI"<&sԄj^9+ ~iLlZYu/nƔldA_v/Cf<~\ap D2RwƈZC%]J#Q2#y)XTMpk)X040|JQQ-^.bRzC^us#P6zϯ;bdcpÁSgqm~LAUq)YW&gYɞX?9s1g/{ZACtJ!2J{Gu:G-rLUyR˸?H^:SR'nu/΂ELIg8uxo1k:lUs/ 9r,ש74!$io9ѣطVͻ,=Ũݷ^es*`^\]kO| PޞFgAaTjFJQpFރ^:ho 9dlvQ̀JRJ!#xG0!!e#p4P(Msϧ?,@DZHd g2Zl4drf3ijpe`hd229Lje9D@̽ :n0e߯$,` j-l]`N|k4dshҌ;w!6Mdr7]kRe]S^{aE[r`:𛭇,t8b@Tj?iV gkʯδmo[ d%z73.ڙ)ZSǜO@iwR"\hہ<JZmX N'-]*hԥAq/(tc؄Wr 6jRS\ƍgG=Pp(4I E ԞZRMؤĿE\gC؜3g])YVhC"ᆏp^[, XX0|Qc(‚nE8kC jP0">~2qJZͰfeMf6,"vw9v]Ou 9aZhz~m7|MBK2rue v\{Š:U L`R6uIfg5)J;ӔMKaյA ( s xa }[9+nce]MTl1{""' f薶l(PS6$!FSs(xkК Sd! Z!,*VHH|R56 X" o nW0%0rP/ot^BDIgIg+48HB ZflDoH ,|޹\Rj&\`:$@9~.C셈bMQ,Yyb @(d|ՙIj4MkYg&ŪSTJ5oL AғY|(}L)fT/.U#P$*QTR fW-`t)YMiS@ #5WVE(ez͊^k# _VK=e~9v_VvN6 T:5*[;^yG#꘥k>Y׿K>}?#xJZglfJS~S栗76~%YvTF(S@oJz]z$8IQ'Ŀ|+iϻ4k{"mˆn8vOç ZƢ0]/J;事Ȃ;WoomfyoafҴq6S|lMfB[gם\A8. Sq5H]Saw~μViA2w\3tG?A IDATmԬy㹑ZP DMQ5Ic&Ɍ%]٤#ݿ.˟O~hM-ek=]ӷs^(5*{+j/&y \c˦zla|IX 2 DVz9g6]OT}fO^UQ}J6(M_M7k5_l ) 99m] ?df_P\c70#\rʶq>;~ιd7~ qU(բQ^cM]r΋ 1WwP]C3+V;>Un)fZ߼~taǖǵBe6ZrB,xUQ֥4ﳎ_/-^qB +/`훩\y&)z-$eB?^͗:EQCJ6qaafGn9srˊ9; UQyo.R' o K6Gƚ3X+R> )Z t,ii<~Ed*㯡-vC<;h߹,a=h^TVA1uR-;}au"l t//P\o ZA$:~OLݲH~}y`v6CQʪ]p0ލ; B% ÛF۾QI>q9F[޲h_]Gm6}L޽{pC7.??=OMzoFZ\.iLx:olrwg7Q5F}bo5F|iIq9 h9P I[Ĭns'EkUu/.aAxvU@J+do~8Jcn".\0[HJ4/eT6K2ݓ^ȫR\#`jơ1/Agy THOk?C8TbfT~h@ZJ)櫊'BtbP񿼹& (\oF֑Ŧܽ۠w>=~^*j֥Zrozolv( v7e@ՁYz0g@tLtWNM(~lî^>5zfW_ΝPЭN jE9h[hMM|mB" kM}mBBR*r:̴n]Iqs{SPw=p^E3O[6+>ӌ\(4 JXhB?*sVIl Qy eL,TJq\4U;O|܍Wo\=5\+GMv1)_$ϋm)|G!!Js\?"&t'D=6^I#hMMLL V/wiUѿyDu_矓jF%~HZ|3ͻVK?/&WxkcƶujYd]S9~9ȊeEk\mm"| ;+'osʄ²SOLԩ)۞}6>9Y=,JQЍzc/ϝe<&cMtPO3OqZjV "_/pG)Z{v[1Ws0N4}6@\~fIPD!ะ >Mo'BѲE k.?bARoU˨lp#:FtXi*t PBCUo>`t/CJcN:>3}u!B4Ҋ>R*xu02%FK3rVNJhB*>YP#S0h23e4~fɱ5}^2R,d%4 72FoxCJ+ҁ`;!1E څҤ UBQag0%BBh񡨂% ʹdr2PLn33l4!-Wi" 9my MQP Crhy>Zܦ7B'Pn,h+뺎_.oWL:cKd؜C Qj6=}u`^ѱf_KC֝mxvaVz5 5u} Q)&Yև_[0 .0>!o~+f41`̓l>d ez-}!;5C6949}qV _N44MQjb_<}yh~lkҏ/u2FOn1l kMj悗dBP3qo@z|y_|~Cbh֙. m}6mqD"}:08QKzo۪nhHóN>LgL<抢(!:V3s&dj ș z*#.m, ~5EUuYHu ghf# ṳX' `!!DEЌ`Q;|FE(ZeF)g\ 5 D58ZfE zBPɀ3M(RQ\Y V |9`EJl8$F[t?Z#_*/NѪ!|JQJ1L| D] w5O\}%]Bqx)1ͣ>q=9w-@ѩOoK,ǃWy 0'ٙIYq^kKDYJ̊F"U{Ow8ŔPG':e]&QN/]:;!(dS FNwޠ L j3='b o@M2f쉪re ',:p łj{z(rPQo>|55jdvpdct!NU(BEQX'YfҶŵ6g$'mg4 `x@U҅ 5l9e?.W@Poߏ8.'?/C$DΟřfe98FAiTIfB#'m8,1㧕ˍ{'#l8zXJC8%*1&<`-M1͜L%[Pϓ}/?0r(('9I"Q**a,xR>,Y)ERY1+m~z'I]fe>liO#E: ~rIaJ !be%:(zWDڧhP">ukæuЭSn:t1r6m{LsN:TA~g \:AA>>B_/L\taM(5 ^1ŰgjYWO+e/@v r; zu3$l;_\ntPW)/VpFdj/@ ϦܺA|YN-9D=A]{ǐۛzhdFJ&Zb J1E> +YG ePW)XnFv\cMu*;fǽW.óҩJU0&#  .w }dѫPe ݲES3W?v{_YQÿJX5Qs#2-\5̕/ XMqIR=Kre*Y`zW%83㠎TKN7%@Ϊ)HLV}[f}v{-h kKc>= 3N f3)%/ ;Ir>:N^}iɦALCܛ_c^U]b?ъg ߞ-o$ljg?T9zŁS vo#OouܲPVۆRz~ *!^݉M)J62{cCkzVOv|mD_pרsJ|Q7{yqlrՄaFXI{_}{kwl űg@4Jp3 f(י/ ip*U@czd!=qk^Aۏ<gG1]n &"bx޳}^m?č@]{¢3ΜITrD7RXW$JXTa9Q-W&7)6.͈ޱUm'MwnPjCxO~oo|+ f}2n=K)K75Z"@/v(`xvholc{E/ݧ{ܴ(u`qIK3hwjdTHH{w̽MS(4o` `@K쨫;`;i #nB(Ko)(Y>v)Q'=o0%wǫfp]\trx _nMވ!_xrLK_"P Ώ~7C 3f~?-TvN\}G/dt41 F5/אeWM2reT@_/x_MET@` mIJڛ'_WUՐ/|UJTƫϐ槩~yS> DIn%E<‑<7_̌Xž#5 aDzP2C8#ԓDzgmh:o ldw 8r֖A`L{ybc~7=Ҳ[;'M;в@YW_U8uk|,k5Ce4z؊)Cꣳϛo(D,dL^z2%ssSGY.](G{FFh+ 1euLēoH͏4eB-]B я>^vTWh@h7n%oHKsjb>Y2lE'~5:7(`ɹ7Boz!Q,4^/9m9G=u`L}xu(+la~Ĕt،!+.e"?>cȊKx)TUl4A fmqSl*c6E*LZde[S-Cc3>4rzigWz`Sb|N>xc23i5槑/$3$=Y8zєC7.9/.ktMe2_~9ymɜs'9SVF} Ɗ)MW.hwg]oW)~)E5v 7&܌Q0W7! ] R$۲J~_לË{m|aIF,9\d" L#hc⍝w{!J|5~~ĘtAK/d>-@3zީE=BiCsEkۺ`WY/wM}re'68k(.~j6mZI{zYu 'ݳ]z8^G#nmGnNxm-E*o2T" }j'uG>4MJ]2xvY1YԉM)f$qٷ^0e-{ @3F U lDfަ[m-cLVWFUots ҋɨ17=Ak!f>It0̆+hZSS'H6%5 >_t2r:emg LP@֤כ94>')bv^Nvv<ܹ7+x!B쎂< ?{q|_h!'yY]whϳS78E^=*-ntDyyg ]saߡE@ʼDTڼM>䊼lkyZ."ǚ!^IG\aر4ώ IDAT!i9nOC|:ТRK; =.Nw'N{|2˾v, Bmq2EĬ xJpOXéty9߿ϸH^m (MI C߯Io*M<G,~wB<2@Tn^A7}Q[z?=t "{#;$/bf:y_=ںR&+.=XɾFjD0ɞl@$^@@a4P=Mn$QDD)ʍL8x%S7n;`W$qKD@(7%?߽\}6w1:ۀ=:$]z~(KO寧 ';&~Q%PAx*qT'+\8¼Փ?Z+ϓvN,9FNnBb/(xGWf?$ONb=T#- NL3;Me\x!~!yXi*>_G(qhGCe*5c,LqN֒My{Z%UwF\K'MR{o3f{̑7fT[k+y;d{nGo8B_,9=ٔX ЍE' P2B޻Cr)WưK\!gRșLTj\5hfBPDtqP HqbLV]b]Bwߨco#?)`xURB<`m"JKlbiCE F'%pZ#h6ltY+`f(RpFΌ_=A;ާEoow\980T8b$+1p_6t~kX{Gy5ϥ ߵ$#x$8ِqqOwg+4 ?{:."/!`4X{ k2,˲h4!i d<Х88hX%BF!ǚ&0 @E(_G0 EPJV[GzW%}C"d\KQ)$T8Vj4 FW_'Ja'Jc "FQ+d Z߬*Fb FLu9qJCeN`:7o߼~ֵ ki_<~>Rnuj7uۘsEj!o=uOom~1W£n>])Q u񛶏ce ['x3V۴}܊y_7I$rw }GUf=}MO{.#yڬGUl S·g*3k;ܬ2#ʠքA(u{XDI]?vq-묽ګZ_d\N#U =grnnp%ikνiQdH[lxf|ga2e63ٗq`טhk5ǽ0̧⪙^^+l?=qo*'Ё9{oZT9' "]Mwi/G1oLu4uܽoُUw'$ I٥شMyxt˾ݴr-b3LγJr=O;S<>z^˧Z}pт)gQ BUOz.YXAx jj=mɧDu#mM3|#E@Qh9K |Nn(ea?YrfT.sMN49~|$ՄjhYpPb[qUw)Hz6E:ZXm`Bq2Kb78)!1J(4@ڧk#YM2b-i| #1ɓ5AHT 81)XQ|)UO$J4XR"H:@iB` _(&HJՒy=(UG )JNNJ{uDZDam9xpH l?9Ztub.X-&:<(46ٓ~C"B#«&Jw̚T\s󀈠g7vOl] " zu=8"qV󒔄'1  ˧~q]}T3[NFpp0*y~=)FcCLk<@ʍ^zP?1Cf*Oͭ+\~r;28KE5d ԠI#=Lqn4I2f&gUDӐL^EhkԃԈGGϥ;e` |8ȂB0|)QQ-dIY7dmGMɿz5 !M׫YVF7HTԊ^@SeeepIG*̸J]BnnrU+bآ%VnSgI$*LMgvj% VP ϫG=qz) X<, (ͽ-9ṟyyX`P{'@;<ݕq \nH4Z؟T5ǚ=h<&Io\˲r݄]~M=\{'| yd[<.>\ 9Rh&mP{9IwncVp Ty.^"0çPO#O tjmH~aԴo7S>j$*ܚ Zc&5ιr?!!˙6vZujC 1p쟐( V+)A)<hgH9$PPE݂_.m@]Cyr}k_EzjV˜3g$OyD5ao.d$ \ 'haL1{c ";ҔPX5 @;xKʼrE{Z6lKNbQI5zOlwBbW2ia D4} f1Us۰O]9AA#t;s//)AVL {x} N> }g٦MEؽ9K^#>}}6Ê͝z5SσSZIK1r`5cȋޯ7gP?6oյQ!ۇR0s/aooM;THa9 zmު/"=vL4J5rig}%S>ˍ!Q!;FM9*?UF1Y媗pNjS{-W }s8[yr{t>S>UⴜOR<;`Pb(W<Tin:fi7?Z=@oˤ(؞|/|Vαf=fJsr}ڱ* ӑ}=d㸅G u@p%_.o[4ak`eGwiT^m{f4iYuAas{̑͡btp;jgp6kJ,6,=bʹO}, F e,6u}dx4&_[obpRJObx2kmw?wa3aۘ“g q;8P( e^%|12ncFD>^DAփS|Dvjжmoč " U2&%ϐ3zp%xRB"Pj e"B˪>Bf}"Kz/= ?mrWZFg1% ?p̦;q|qڭ9sٹ':#d7N=z/ دgN=z8TUqlq²*щ KX\(nЪD=nA|10+d`o[A0 1+ I*eЭ.=21]v dB7>}Y#({}y8YW'I1!<4Џ!+Vva,DOlx~SGUn:C;:.aU' v ʽtGE:>ö vk@HeLg|@{yQHѵ*KKS<q:;Srg~JZpTj'OzF%Ey_Do֪@Q`+n3 ( +}tVNzB5S&MiynȔh@pY_23b^fbApARdO&rwšK{. G _Tml%, }!u@%1XH[=q~|+BXz)R1 \b-&_k6.m]btK O)h8;"lS7:P :Oni&`ax،%^ T{q ,pWN 3䕀v#EbsJ[0W4lƌwrxԮn] ) ݽuU?k Ace2l^ģ+,9d>T5R/Ow1 槣Ǟ~JOAmWOK!ߎhQmZ$؆Pk8LJ I(0eW޾rbR*JIWC"{/\@Zyf@k97VAI"|-`zǥK_dQu?p>GkO!`73ko9v lgaقZF.~፤r[Pf *;zELjB{7"qW~91#-,2MY}I_}+,@V O|pb M%y똴g"l5ޜ2"ކIX';xчo>==:B);<%᾽Co^O[0uR|R^tI!}s1HϙG4̋'QWj&&(〹isV5טּj;_rњN7-v Ӽs&E#_?&_rEQ>$ap/7h%'JFf[3?eOGez^9kzSnZ;h,d_}iD0 D^o)חiiv?2ggCWb:ȩñ\gi2x֯Ob_̇;H&Ý׹nM;s}L1Du3}O{`6?-5nqEMka,RJ`޷vqWР#3ח]E1c @Pi $ Fj)be`5jjBdӨb $@RWDRQ 4Iʃ,9*F,`0*iEb@1Zv&(mP)]x\DKNËi"6,xH ;ݸucV+^#E #*"$%B8&;kG dAs}xR1^۞$P7?HJc>e *I'qn5҂YXFЩ_\OfK@.d% ܽhL$/#X\ξHRaw?z_#nF8t"ȴ!gȊGuZt/N+.oY E_o$bUhg"˲s4+Smr`iъEsKytxh]V*HU6Zy)(ğ5ԟMmi,؆tBV'}Oo\~y·=Q%[ V33 .&{P >N8e>73HZT!.:?0Nneɨ2zAwl=N wKSnwC7_dY3:ՆRV#߶~Z :euZr,gO̍<cEǥsXM: ;_,Wg>y$D߃?ѽJ%LBI#pIRTZO* fzPW&C'ֲscynԁpqj:ߠ4iY57f6[ 3RsH#JnJVGUH9>%sXvtBI\1͘Y ,]uat tX+G6255ҦP|3\#T*jiWUtIcO)_ @dIV&tFZr?L9f2 T/{zxkb1åG ) ƖNP\`c~aMY5j9cy-LYs&-!;>Q%,$WO6e$]JbÆQJz`i ^yv#S#>䰚c 2SpS3 iTV拏2<հuN­?gt񄒲ym ʸ<ܲ ~v`+݅{f(7.4nkJeeeCJ%y6o) 1F,^l벯£Jw{PwZXZ60xƃ3nn{5Rk??Û[V*\7ZT i,|SAϿ,0edagh˳d#t#@≱IĩW.BN?ԧ r>=>#pj߆{>k ߹4ō*={FtϑL{g_Iڶw|s?yy[U{'KJW.=6QǾqwI2_=<3|Pk ,H}y4 k;yŒ3K{8<)ϼ c "QN䳭PMMi-w!m̋Dל7n_u޾B4_ULLidSgna!@.y@8w6-~c&yXr@mLyfytx&d<;GB@Ս:V^R`c?ߺrzv#`֊F;Qܐj}fc\RTDictι;aU_w=N4FFa 05Z^Xhcgwι;#:Y >n͍^fK͗=[mH<>fLU)t7nw>~}1+.& q(.uQ5K] k_)mpB^PH5ar TC ibW=xpM9&50Hl/-VZ e@UƵQX7E)k m?`vǍ9=F՘aӃV(=؁~ÕDㆧևz&K_'pb9HKk]myhؼ?hׯ_P][߬-RmIf1G"PAK=v94HT^k!Sߣ,HYM3GusMA/!h\O|k~Ho@{̫y& 7QCVɸz_ejkqDf5)!NQt8w\ABN>l~@1186 O[ _c?MT`ZNzo&O;Q Rc(Ճ4fJ?Ҝ/~u84sI`@i)I!*֯"dCug&µz8Pmkc[*$J~y8I9PEn9X-T*ÚW8%T5 ן5*vsǝ2yIhy+ʸWx\g/Nm~!!`UZR'F{xAS+jnz܁7GӢBIUù 4ۤZ5V`qT]hV6Wz Wէ9*4Z:&R5֌)Q•Y Ӣfvy`A`;P$`Bƣ1YT1'GEXJ_&K~<) Of |{ 9*P}+vHk";ꓗEBu`aoUތLR)Qc˕*=o=iݗ5R9*BB~T1XsaV=z.K ׂfp-~*vU#VV_eF˄4@y{ITI**rcw:MB+AQUP _ 8U[]q[n5R"ƠS))dmt* BYC8DP \ZQZ "i]EB>2?`f>*"*cԧ4=LT)x/5{Uz̑RrCvk~u(T42dTHC՟BXT'qַ~?\;[\2%$v+C=z9/ }ׄ4q F&`&B AP$!1"4 $W ji@HLдZ'&1t--yеZXZcwKF E@5 !cM֯Y6Trpd]PBZHOV~/^TRϿwmTE#~2.;KP};R%A+ƨpUUjǦacft]~ӼHU ?] w=cFUN4n?H1YdnøϏo+ȂY= (M\nKb l'Idž5DFX UbR, EbD" "(Q"DBD("Q`@F`@$H"4rc U8Gj %h3Fϲ*ԲGk_<A Li!=Юi˞E>p4c2Yl6Ң!DeY4T&%mL6AK2TTwkO,4ŏqƮAAAw֤ ^w34($҆Aft|{k- j4-`:rW^]6ƜO3v^NZKQJ^^o]w&AS^\{sǧNg@=M.V]MDzF5e5V>߮PTc:O%f:i4֘V[#3e}0l\ < a4ĝ[?1ga3z`Pifx,i4E2*OeC̶}@@ՙtjkaUũ( {8X@h!Ѵ[a1_?,<ayN?yd6c^v@3z9Ƭ=zR9l;k~o@̍yl5z)* ԻW!;? UO xFJ'EBꀧ Xw +UŰC7_{?wy1M'J'yD>8aXcf i?<40$, |c6^ ~ta@sz ʿ͘zG?|fC5}3*#q>MȦϾp MuxPQIWE!FPT%0)`BJ` %/X"Hܥ[!G,LI7tD0 $@@ D 1PaD'CcK Uaca%Ȳ8bR+++ j<,ʠST <.OT&B,WRXa\x܂&_3}5$f @{?3+lk`YBŸ78]K6mWe=}6-9;Iٕ3fu>@7CB/v`IQVA~na^na^n @\* (,f@7hDpM?U5`rj`6c:݌ڵE1ts'Y_hTQ<j3ƾ)˖'d:r蛠DRԞsT>e ^U4k9T*lHi.ƈ1uͲVǧT+Y4{LX:-h./譧V4g;lh,&/33=aX&8.3d{~|0r Kn~t50;Qz_7rl?:ۆR&eYp zbqd5H섪6G@ApKqda>/ V12BsbE9 YmM3&`,r.a Wu ;UIֈ86ExBh/Y $ ZĈd4xPLD4\B$&+!-$c `"$,Ƹ$H,QAD$-0Yq&K1 H\1P(=lx@K$p.H %b(D]4;DRX( Myv2:=+@Y>OG}p?D8O-5ЈwMl)CGs <3Ŝt~+?  {~១f4*y7]$$ti5NfH@AQ|W% z/juxSSoE>G.8:vչu[E8!BDŽQsk\?a.qmlSf9R& qh`QP5ŤWoN惎CSViU5S ..:&)|/u1`M!/e$ t=/{Zߩ!U6ffęސYPo3%jY7g2x&x>XB8ziHgc7h5r+ƑVaa﯍On.?}. vsWyRPZk vsBϋC9qɌtsohۛg{J^V1;>gB)NCU lo^ HL z5r&Z\Ц.<y<-_F$;/C?|t;A'}Jm`Ԩ!(Y;r{E:q~&&eF<<|.a-CѸ{?lSB3S#>b0–TȇϦXaKw+kEOl{r@BbW21pJD@c&6νz?1!+649I:[~OZpKZ0zQI cㄯ׮^GzjNS5T5ohDjĬC?} e߈"_ [~[fo!(ᦑʖ{Hy_V[o+UoqwяBGg6X4hMh;̆@1qŶĶlncрŠ"&!ݶ([n-vD퓰K0ƀr{ t5ޚ&4Suy%,ӛ;$]uVhXW 2^[7oӏwf!b7ww_oJ*)FoƋ#g>FEDF\cXћ;{F )*GYn{aB\sjF$Ŗ]Z|.DIyCMR; Y!~;p~pbcy"fQ,Bz[50z.MiLiP) Jd$<1aƆ=AD$b0ncP[x_ciF2hv0Ɔf Mt~aT5( ڕöv:f9z~;7?0|ֵc?ju?TƇ%n 3qr/0[1AK98:#&7ҔPW}ǟʨVn2mҮI}O=\4t?92f9z"4{be\c?b.Qf -E/2ʽKOgHfulTH#I_s#ϚYhZ/51),#bt2N``YyEZ.tdߧ/Jct?lp3,h鬓 TB fn¯/.6=*S qrx'NK/6/3a`t AN8jێϴ"dcM)>2eɸ1t^bcOr8]n6Cܶ;:.qu'麗y/nײ۸YJ c91o]z-*x@uk#JT E4aM"r<.+GFZъNtL_ntApMș/#YLBFPk8'7畀v#mJ!;T_(BQ-;,!_AunQ!u@%響iZ G[n8EE[[%BBV]iҘmNq9-SI_QNJkKnyz>OQ '] {p(b|% 1cw$+uZLvNd ߎSn\UG 7䬬Xc;_F܇ާ yI ߹ye\8#0A/ǏNqH$cvl\.Q߅ yCzsbX#A^ h7^B _yɝ;`.s(&] ~s`Ňrk/$Ef#͠ ;Pn&tD52e!"Ύ,2͘/j}pW'7痀?Vψ|N 7~*)S".w>8D͌ +_p˸ˮEm6Tfd'<=ѬU#Z5{lp{֓YqNq'~=}+0tDe$AsSOWE&}Hw|b mMap}N•[4K8lM Hw7;eA7iط\1LJFMaצXUM0.,)uRsqiq/Ozo?GAQIy^}fvfnW? ILNgQ,i + x!(idZOvӏ韟>=tR[#޸=oo$jhӈNa/ vvL\^s" Ѓ\N~1ȂƩV&1Ib$KBm|lu*f϶cc*>(,8&I‚Y!Yj`nJL>. ӱ%9 ͸ucVCӋ>~d5yĢ,(PM )FR_׼>-]^iPO$Bi&mZ|K M':oK]|94wIg/}*(VUIZ,P@ *Q+M_t5q'裖^;kZu(5ʵL}(M,LU*^QȜO*ڍhLb=y˳r$@2xaG]&gY{Vs Bxo[c[%pfzmh8ziWg{HVa0^3֬53~Brm &iB)μ%@܏g6ݲwX2Ӧ (^?p'S 1\:aߥ'y$@L 6ZU!ՋmRcdrz9kL;YdDz QvI8ORQ^#~Uto65Fُ2ϊJ忥VAtryֺRR[UWKXʮi_œr{WvzwڵόS=g析7I S?5?yYˬeaű=.,>O@rzS.\0p?wwW^daOv߽}\ޫaQY~VF P\T+Է! z/B}O^tO|rqB>Tē~Uq^0|,W@ÀDYQЫ!՘B"<re*4:HN )?"A4ǭ{x*̒~TWE}L]Jۨصkk -vbbw݅ b%LfaϬ;{瞺ZM ur4_1u,9RXYغ#g tF>b@k n_Xc0rBJ): @1͙g {-U1 EKSW1lR*"O=ږͲ|i$f?xX>x< PƳor$@Y;0k>zitsq }:.@YBRۍGЮM 5SI33e WG>R8VJeg6h¹tcqx65cCX@-G,֠UU O2 =|Vە43&\z"[$WwcGoӜ)[U=[*g" )Nǁ aɇioZ +ٷa ;[u3g}8> C۹U7ofjȔ[YW Q_%>g|n|=V _F|; @AJN*qKy73nܠE"N@l}~ VwX5A@JgF#6fDa33DRkTʼ|p]2iHVUľZ>\7EbuߝeRMXèz2 ,ϖSbVf* 2/ՍW7<~omz}- h#T1ndajla*D}w~ivfur* n(¨^Wh˚핟^plY {(kl5ح@U}zJ? 5c.'θ`rQw:t]^8BvwĪze>K!I>D#CKZ/¦Aμ&Sy R[ 0T*0[9y@aGD?/xBJG5A"IjI)1a4THqI"XfaȒaCP̒le\dh)F$X1kx_}e*^() NJ(J 00ƀ,[2&MGJ=Vݗy4IJQ'_IH 4.!K,6ҒM'%ISb$6kj4|eZ'oJ#_7uE)2|kqkdHM(0ȀʌO!?x]H72}Z;0_%(aC]TYVYWe?ǟ}_NZ`\]BvՉqZтIejNDK͖+QQWBiZ!rpSnb_26 77@=f$M{wR+}A|rᓥuR3uq1#i9GOlI*Dr(`xLݻe>i`Iȉ@LҗV'2ǖUDorF|"rmdLM,4SKU=kēsLP|p`x#GU1#| a4JK ^?*~\>۷=#4Q ۖ1Ei(J+s&@V]T:gNʷ0;?1HYA ym%"?h;;n~pvGer{q`JTîecA!UmֈnūaJOPtm;I:9042KeSF]v꫇]H/4%$y梤B Z fJP 4oΫdXXtLXu}"Pi2^@^O]4e %WfQSr`5phrҊd5E<ەm&F9'(DOdd)\+ {(R(Kd M8̬ۙY)$n[ H/KJ(qzb^4-C})+& ]&n]k@nԓ{<i@B 2>+GV@%E00VbOR*e+ Sd|Qdҽq}W*pbϐU' 9OQ04JHi7F3G%dyŹ wl4jg H-TO.ڶ︶ IDAT%׮J"/?;gcy?1Ž_]zu^ʲ^>},^Նn^v{ qɧoʫ?P9A'Xu%){vq5nӒo>U1${Ķ حE䅽5`] EP3^8Dnb%F^r19M|-A{27@#L4 Iͦ9aqS6vAqXi|$7R Ck^k8:sʿ6)盬rQ̤X.}_ː:{a+JI*3EJ,KNJUP8n7K&mؐ+JHΗd&kaJ,KNLF"0嗃gG ?Dz͛]|kմ1i`IkYRfŻ?S:eeճSU[3&R^ayfvu6⊳0bMth竁}g v"R8X;fiJDݰ_:\R(//TP r-m/eg~ .b?qM̂t@Hy5Polu>s[g[bSB1}!aD߈䏳J9}3ư s.s'QEft::[U-p%&a{BȻ )۽c2lŗb՟:ЙQaGG9݊8vzęy MiT%?L-9#N.C2 cU˄E}SU>1:b\CyK Fl$;_+Q{5$~)w8 >O0?ju)}GK>8]mnG: sJ$Vi]󃞿Voٿ i6 .Xet=wΙ#6TenSRuc@ޏmXu @wV{p²hF\zu)D\Z4ݱUis$EUJk~C>8ȰHQ|ʉ qк؁$T^Z]F]dV'~M?L9.8pU9C~io??⺸6Utч;Y:q{MkidABv6^0 a C_.:aNҺAmn/kq䅇  I9[-j/}4 3n__Y\.P L NZ #] Tn|HIEJ͛iE 5‚D=:DoX>E3%<1wc,_dSȋ{snRO2k<3ȏjމ8qkDiga'Y F-߲; _I*aD=ۼ^"/{wS _̍*URY9ʲ$TY3n+d\wWP$OpLp.2 tB]Ǖmh`Ѫ7y/|Yn$#Tk1}ߡJl9 $6xR%o|)>?:klf_/=hұjCVdɢny/Øo9Rfz꘬<*vJSdk;$FPwC!Ȱqt=*RΙdfiWWزe©or~44ݗ,̏v[-v(Ҟ@ʸKδS`׍Y}ݣuK._XT-҉vz0I YkyҰIa,e֥_G;jdE)]"U N$(B"5+wo^_]=9pDpK/ׁO"+['1=f:Y#=HaK~̑"Uv>-0*V1f^7[~3T~ov<+r&pu<ʤ ٮ]4"?Ҫy'հgQi| d^NZgEgۮ>tVr&N)WXwWGP/<+6Ƽ/)Ӯ^2HV9Osȇ;o8daC%9I;Vm䬼@)2 $/}Gw=ۺ2/:̦&FCZ%VB9قͶ,RGk;O?أf9 (|!gQ*N@Sod}3 ύ u$H 6޴ff mƺPcIZ }FHfe~C~#JO%NW&}#>BSzm2N ?:cI'M j.iX`/4QM7132Qۼc(}02rC&e*EBbιpa3i+8oQX1Q`T%]){ Ҁv5X ne7n6v~Ȩ7?|&(m>6d+"ֺ{LX ͵ &hd0U8H:B+H\QTs 'k' Au.f7En,D$Fe54TC+_Q=fv~˅ǥxSHFM'"94~eșT /pWc9:l4軔^?}S!r0tBY3r?=Ԫ)MCA 4v#3Mϣ E6L$ekQS5hشmĒR(5RJjc: ڲZI^55O_• ;4tU$fe+#ZrrF G5L\LŬk"JAX22Tʕ@Й,(@l(e%f)DIϿQ _d cAzef,To{:b+7b]G.c=iL?2&] :ߞV%As; ~܌zoPpIH#utTL2pE$6W5Vl@/*QM gZ?2@ ҫQJ#W7"L!)V)rEeڷJPT$IJBB4RIREJ M|އVjɮzO nj/([ M,h4K͌@ 4Dh4K͒Fb!ͷxJXAȌFX@4’F*Xzsn2̉y|>D!cjD3bp<& ߳,.,FUDИ J5J)8Q![ˈ_<wf!:p_s/"ΌsJZ?8'VrbӬ3C޼}q!nLS;wUG_G?.1]Zޭݱ= ^kC.. Tc?h'ʍ0>4*tf+MW}i\Y0ʅH.Xu.9q3(<Ջ+䨅i6nա?o|sjs= G~"wm@Ex?rHxȅq+L,_v$]y!:UnLt{C.iqr~\mٵzCB5#l~sǝ=!/^yn]I\:0͏ ڻېcDIb}2UʋN:^^QFuH`TeQUsñC7^ yliwGfi?N7/B#]ڶT{Ŵb:XraoXÉY4N^|"K 0i_E o#?hǮb\}ƙf=2RX,)+ iX.rLg1ijf?T5b3J&HΨh1`%mw7ebzY!A5 @0lGC[ϘiSPoGAYg|>];0gK 5uƯbˆzZ!QQp6Я%;:(;4Z3+ge`;&S=NUnF4#a?m~PkBrzFe<VfJd|mS:ɫo9#Zh)7 .,w>KK$Z0YŏS6^?pˑ~sU3Kh`2]F-J_g'c'b[/|IָsY8a>9f kS(վ>OƂOѓFYΝڱgTҵό%F튕cW7)ju=8yxWI߼rhjP3-$vԎQ*>3lK+N侹3qo{p?Hub:42o ~'8R?\[#lAD4f>Vuy1g͙:| ٍSWEK\whF e夡W 17 ?:Ӽk2"ε>!uq) !eUp/H .۱>r2*SwίScPߦ<}x9ƪdEum2hl8<'ݑ}(Fl1>UlYd|0sÇT5~ tڧi:[Ifea˵D*TAC*Lpx,m;>*@ Za q T8F !Ho\{//PRD}B," S!@ HY"dX"}$پ A \EaT2P)$`HL!<U2@ `#EOu9>u?mǍ4?h5t~,PQ#6\<ᄈ`vșÛ[fMɬey#8qT9o/mT᝕* =)MjMaSFH c 4: AW߱u9u?mpSCU qUe慄c$̅8p>i~-sjj pSoң^БO5
\vljP"??e*+:?n$4ʸ J; 9_*W^ieT|zCo_܇*#{w3 н80 L^I[~qzps(Л;ڄ7؞Tt&~A=~j$>joE{ҾeG5E =>Ѻ-k09P^W2bMx.Hfé?6Q1-Ηd- 8XH wnomh_6;,io5WƖ q{|5)}ZćG7nYh$°7 [3ɼ؇'\{r[`viMw>UenܺZ+ytB|% .Y6o= TȦ߯D q9y0fy{_O'( y˩wjg5e rnN8tb#ßTa0=ͧ\:=|hV‡"ϟOIV7|-iXƪ4y^Bԗ(Y*!TkUw:gO+ )?;RGɪ >e  S@tҤ@S?/b}_#V.ڧRĿ:t(aϝ  GĆ77e1:^~+{ ha=O2Iv|G l7fM|Ҕ/G_ss{螺<i,:gC$&5\!9L ~Q9S{{$_-h,t/$ǻ.f%{Iadީ[_YnȎ |Z[iI/OP$ ɔ#LOQƭ 7 n^׳)@Z欜ޑʋwٮy<(\S8bfj%.`UԤݑCi= >Jˆ#.gOtܿZ33i p`͙dޗGo@~ojauw ^ѫV%< 7icDpjId@-Nw^f ~;~macD6߹¬EGum1R щ P֚ɪ&stMFRIj~KH7)}A{,(ݣ'Dnn=џCV^Q+~hp협~:wbhMX:^}lſ|Ho X&- nK{I 2+жY}E*&mx&,*!Ab|m76'0M=뙡RiP'܈S4!r؁/ž1m '0]-%QKGF%utT_Px0e9~>`8ZMNߡ?!fg ҭkEK)h{q+ǡ=ǧ"1|SmZt/Yw#:w^{o֓}DY@dZ3O^Iuh9l{A+Êpr_zJgyÏWR.`R.ypjY;9s Ĺ>Xz$,8[jg{ʲ Ua=4 <xu]m3?c6聆O,^7q ̀P)bs1z}w?8}| +Ec1oJ(U0|x y%=[l3uMe]tUP!I}[,M#\-QQ{?:%-w ұ% <~=FFɒLd5jb(1ٞzHON:?K|M^AyzdQ|އD s,O{M ү-M67DUN7[<؉kZ]e_̓$ZڵoXټkK3bTn3c׿U[ZAƛԌ'7T?qX6Y Cu[˃v%96ȦE-u#^\|!3<>z+FIdz5e`00<}|@S 2o?y(?ǿϝJ($Pm eaYQ_smYȘ>=q#VJɒ_c7jbGS[|ɱC9-:1 >[^yրPnj0sdB#CƚOػ`} $k9ѱIIG݄\}:\O3%Je;nlڌ?yK r"M@].{NEѕ*dh5%F%1o8Y1*CxݥGѕMJ\ mްshS7 S*e I_q}S|~{='Buqr'$`TÒ*O- Q+|D''S]*% 806EiIJѝ$N9gbww{ z.\~lXm>&jxG Hsak; /}oa^۸7;#5>YZRJ`X!1 scKeN9 3g'NndFf3Z!JpȻ{cku! qOʒw@׾Y,U]0sqb~MkMhjN ^i*6ԕJqNz:Yoӹ}v}wy\;v|zRQEܱ?3={o{ z&,Zq\C1Ҋ!8/쀗j~_8]dPfiVs2ts>֝&b<,B^xlK}C^|έҒ^Hqi~)=EH*б-)'[FH ayJozy)(U[@p&RuNL4 ˴ȹR[*E7e"10VҰ Ȣ^].ni\)jW6?g904Na ht&Uїo&YyFߠW_?}7B K)T@*BhV!vS͍A#,"uUnĘDN C:\ڧLR )!tRJ#R!UQJat})$F BB"Eal{6XM2R0wvūe'|avr $)i, ΤPUנK paQf( LŸUREYZQM8:ˍk!jjX)c9 ,x>-XzflvaфU^dz/nT&<`߃4E5m E)dGOHq:PdȸAXDH @9Q*hK&uJBJf.ROf*"=+Iw6 (Q,.$h1q&n4ZZ5Mǟ6ʼ)FQ:b]"VM:EKn! k5aW ٹJ,7Z>\>u%;t62e"=l˙XRvʌ,!l/֌{jGl!etHz̫gNpuïeaCt/.&%ϖ[f\0u_E!%>K)HBԗ8hqWfgVJJiAKkDHTtw\HnȀ*5^QzAk%qVצ 5cJ [ uXfC&J0R` &0UQĖ]v٥C^4zDR+Z(fѥ8c Y}0XJa #X.:%@=cAd^Q@}K1#FȨ}|cX+6~] 5+( ujJ&*kxfWN$2Sq;o1ƤJ!UqxFiDP\!R:g?Ε"Qf Ȗ .>+j Xan}à[XilNR'ĦJzp&eY Amy!/Wz3gBHkO5 *յkr+Lb\=g>V>BY{VXvjM.{uګ2Ij훇=$,` c !EӚC9ݸom4za5pa@Y0?_S>t`d֍4rVGcRW"aēsLP\ 1SSaa7u# rmdLM*5^*XW{ɭځ mX1ZH&@4;,{dP)YA"\jٗ3ƗoSn]#u; M !8[ȪԞ(H-TUjǨh/1ȰH).۠K>:e,6JGM; > Hwǯ9ydEm3Z)|䶅~3ɚϫ`$ƾTfvksVcȈΪZb+LиB f.t0 (4pm 13$*!e$܁a7HN4`*USa9Py$ \" IE"HƶfkOD";_73aRR)G0sw툣WDMgnYRa\DQ"')Y,Sid>I ) &T"0XI$1^ܱ HRݾ|~ИR*ԁ K"XPbE%iɏ=sL9 L&%Cagr̺quj,7Q&P%RDbX&IDeﵧ \E[ע$vsy[q@遹s};[Z80%G[=:p7VeU]ޖ{'C=m:wK&ke'+Km][~; 9HC'm]zvuy[ 2(wqe B>dyyo65"}{=˓XVo%+Vky)"y&c,Aw"7eﯓ?LPAù1E$潏< 0%K.ZM^_.>->y'6Ͳ P*oYҬ;|LjuGpڻXp,cWaC(+>9_B%%'h\Z5B?$3@4!kbۨW<=8:~kbm߰W^  {f[[7_aCOIȒ7-L)˭2lm(9Mi{f8 3޺Iz `EAJB̶n/*F#Ox7.US_.D#͙50D8n;霏",IS"JByQ~*LH{uhi{9- 8s=(.Ћ_0qMĂt$|-Po'q ﹭T?qM&A.'N}=8{\7b?[O£R 9{u>,[Uu4}'}=8g\7caN:u#h,ºԣy*]\ ltw0+0gu˪?fjZo+{.3m6cO2:͞;Lu~Br rfu)}s٫6Űs .zIS 7O+ yQ_b`yBL.B-y$qAaCR\geFcSlLݟX6EG:t#@]ḫyAO% 7}&|5.sg<m5h@A쪸\W&d?QTɕ. =|䆍~Ԯ;1J|;i. !Y^S-0}xfq䅇  I9[-j/}4Ә_էԽ"O-?s BH X|ɋf Jxco0ƀK^}byqoVS23>i<|xpﱤ jC Ni?ƀ_:, 3VaJ]WN},U֍k[ cp= cɻGKE;So5>3mӋ6M* QXcr(ǝϼG.9U0å s|{{մ]5knjzЭBac'57%jf;d!xl5r'ޮ9 {w` Yqxny/xYk'"m3h d|Tg۞Ĝ}:ԁ3m|N.JѴ:teqL8$-}ْ!x}W oYeٲiϛ(N").;?Ni_72vfau-paQK'"yŐ}~ى+VJZJö$Ӗ[.r?X9WNq&)]"UOB8{.ⴰg*,bcEEm.yOOQ9L>pڅ;Ody+}("l90Z} h Ny{L |094vHbe \-(N/ZfvѮ3SK/TEEl.ufZEd^-V֦9p͚A^1An(juM~yU`ry/)7Pe@ޔޝ]^ j8qZp2]ǝL3y>e67EviL+~k<&7Fk•?Rj;] x Iڕi(Nψew֗ dìrC.I3Ώz[&yJ}6!Z˭6ÑOP_n竼*@rwsr#,Zr3`5Z+}ZUT-{ErgS∀s%~v乱adW!jxₐ+noe¼~n.Ky#mi*s@{oیuE5K@}=~⤉%\PMoR݈e 6B5G*x$41uU~2pɽ$ƪn-"?Ǧ@g1LCݨcJ}PXzֳwX`b; boTA6QD@!RI IH wQxΘ|3Læ}d'M!C\zVC&-:ga8y}ipE P #7K06;ER\rzwf^1͚/S.S(w^U IDATqKn-h肟z杙Ѣ ]7 #]n}eb;F%|eeqitl*xj}XXsuoI828 BПG%*NP1%5H6}$TPӠ-!8 .D3&H2q)Lwr-)zCSݹ#}fƥ#lӒ!;2| R7:1\V 22&7pcJ8!D!E,rԢ^9*CEnW4tU\lAE|ha&6Ł|AgMq/u%FwM@H10:!QzО2Th욄g@z m(9A+6Z]Yv!<92GвOEfY#϶p8J˒t~SS5*dnE"\cؐm%pQ0Ge3Hջ>hGNkfQDw+5ǧx!Tpa& 69*2 QsMzѐk\"o33g0]SWK)=Fډ ,$$>w5G@-ӛs H!!Eec=3AE!lJvS6aa2ka06Ӫ2*`}MTN@tZ&(Bc{DPl2߷n{|" ;&H8l$ H aS$2D*WEpXD*W&6&Ժ=덈dy$W,ƅ(wb)RM8;犫E?ZQsd wlkl sofTgq=eH?gd p+TXyXf=6#"^e "f#Jm]Dɏ"^*6fRhǴ\*ɓY~rL"X\//\`#JMJɍpH3<h).PM}MQS 52xXߧ11+-я܆H:44;{ =cO?C,-#ААSQ&1=*=Qs"Ji뭊Wʻ'I0Zbͬmb#.x1zX:tı^*`Nj~jTUJ*L/(Ț\*H崦 3rT*4-I2H!@$F&ahD"~ع@oWRDr|䭶~ ,OVdd9,Ob!vȠU' ڦSZ?VQXR$Y$aKK

iM9;^A ]z;R믄:>1pͷ []uzxmu|ܧuFU,7 z2 ~}{^z3Qҝo[ԮMqv^ wr묶 owBC\3%a!m[=А{'jV {;!ѡw ĩkѡagwkc!ѡg&3!ѡ'H6tW{'jVo~0*QnğZHUb,sYsAXx ;8.3EqF ʦ帍o< zzYڦP1ҀHKc".XuC!m{/x#"&A) W`1a/Qҿ>zjS? {vaW7նLٵݘ1/فe%5cã.۱|Av,o?W@O7$ YLGj5uiXnL;z M(ϞQB998 Uڛ) ) a3rI uU,}|FvP|"(a쩐 c(8!@iBHX`0T 9@bWbwb XKI:C2Rq^^8_U93Ygyޖ|Cƛ{W\lC /[;Z*3]im;prĤǚU^€CN5ZcΧeA4XHϧ\ҩ rq̞Kd:.YE'XKB vh[e~ɓ+%A_:o~$p[n%I@?ߧ|襨^CP ,z(qɻrѳسϧ7/abmS CHݺzЫqPMx?Z%ʷӝ>nmç> UWnj#A _k'vZɾ8pJ}˫ژ3hڠ ۝>;8QXӝ?JnǽM JX1R>}/TDo.Gv'Ͼ #+g}}l(:ݵ;4-Z-sh݅'oQY cvJv_[ [Q%*۝>N&Cx[C|+Tsؘ $5lkCoo#ΝSy.h檯6R";@F4ptm6@p= Yߒ;@NCs {ë ٰ$-R~-oݝ>NBz"A~|yT/dYGXpd_GҖN RO\{$$wa_;M84Y'oz e}F\L2!$CAuv}܉'Ժ}P߶ZzhДu*Y֌t8ـHRF_.fmq~Ay 6}ӂB7h9\4z~MhHVW 72ZgYi"a V9]z9`քZJAȮ^@ |hשrNw}HHj\͖Jxrҷw"uhCڪ(2i盧Rm;{fHǖ#6}Jǡ~;'Ԍ:cAޓYR!wǦ~`t`ORE  _uFHؕfMj\]Q)wmջUFL9oZUrN9o$w6=hCHO2>$֫̾P ~XE˥ws8 -{`MʪÔ^&kӦ/\zz78$,%&01pH S4hGT{!]Y9uau?P|ф/׮$rF{ ,n=UvcӏʸMunV#ȥbDZP`) B:3U+kB/Njǧҳǘj|i={hc72ɦ@sL(6 }郆,8K Zң"D'֯մϖwE5հސ@hN&ݪm` h?{;LYDrlrs11-+ByIz/cjZ7ڢ 1aֵ}} Hns12ǔwO4hֳ迿,C^[ttRJKw?u\!k#ދdO3[@u6&dO`雳ˆvm۪+8m0b״e~ϞoW,BF3y& t!ʔy]rM Y\.j/%oo Vu$IhV۪EJ*q@I e@4߮epd^AXؗwWclwvM7XULi)?25d&eNDDU*:.cwj-EGd2@ q;eN^@ͱːfvlY@hW;we]<=|U#J+Pg=X5{5#YUE^3{߱kԱ13ͩg5hT( sOf0l. Y˔}JT^Ǻ:m}J\M1 n}U+@d-B*Y@|[F =-|(ܺ~hiCZ9 Q1trֶ$_aX)ھLB\nu73eK8=!m snE&m#@[YӏDCxtvqtXS.}mB~nqk["1끛1rOhc]^Mo+svpK0"Sڇї| g“sdycDgЪ9s/>,tk/>$~V6N`=#s |1SN%;!Æ;ӆ?wYIg~Z[!&yװwƽ ۴ Fͻ塹)_ !z(zÇ;=,+f ctx\J1|.84O;jgHr, 'z#F89iȖ_>rVM- e{eV`"VJʃdGps& 50*cW.:B 4`mó֪gV%+yHQM+K&aFLhInsɅJ{/6Ӏ*A F& 1 fL&嘠3,h&x?_IK_͛nR܈MQ9HXo?Fvcw2_,:n*|ђP {4M#Pv=*ޖZ_3Y=ͭљ)Bu9ûUlͱ6BJYND:O^F{i6|jͪڱʊm|ba֗~$JE>*wcЏ:6]GEVl7~|>¢툽:n%wNKvxmDϧ'`U&6%Bi NC IDATn6=nRr`2Yޓwt_V,gotXrzO~"Y/龭W ^Pu@jkT+X7#S`{q~`Tܣ3|#D:ZTOZ\7wvPc>G..G=.l?k1wV{]-\qr+c@#s DZ[7tqe%)%W"Cuha\ww] _Q/Եv(50E)uvfx7y:RTl<6AOYO#+rNQ5]w|vj֤ikG:*(IJdXŲ/@$Ӻ'K<з߫ ܣ}#r@@{?!a׺=+߀Ag^[8qrڍjW_IVyz_y պ[a nCS_!{ vP('2 ٯD^92lT:f [ywf]bAO vOw zsrPxKtEoºάMWߠSS|*fCAL@yJyn5eld?|`i2hAw&Veދ!H!rdF;֭wl>_υ!QqO.yK#0 pދ' I(:}ݩ3e,@4YD3 $%.~jM2 DH_-*1`QDՙ_@e<{͑ILpb(Hз|TP?b9@BX?cA3 tȶƯh@5 @H H"V0(c@$B ain$Mbo.SD9JRy2⺏ׯjy/n%X/6sTGc1 ao}cz)lZV,olB4.n3~zmYS$64T} [ir JjJcwjпDEB7tvJbv Lx .-Q(֣\޵Ql>2ew\صjIgr;T<)d"H$˗J5!fߑo"(7OnHqRe[RSK¯5>f7ltH0,{WNt&z7w44frh:a34OьS4MQ.1"΢,f;DP%#M}FܲTg(~ 6\QZ2_%y"(/7O"ERiW))T|_Ihg*UmgƔwrd_&KZ4ĩkP;3>U;lesX[8y 0_Kpvryk&5|ya^%`X LJ2S"z [zK=m|ebEH_x P\ ?e0hܼ3r~ g\uȽ¾Wdz|#O+{*@]"~(w>Uu쩪`8<0r|3.U5FO^}Vh!g_=JQ@]}wM 8"Ok^g ϮjMw؈W{Mw *5]9{~**_xٽmOd``96ր$j5ݫQ>-ܴf:Dj\YٮYN=mn}mwj5jըQRPͪ8UmF޼Af]]ӕF\(znn}mK;j5kW%SN׬^stHJγtkV׊iar}jhT#~IOƯۭ}f (7z3XǴdg&(?9s6}VbפdCXU{Mb[ >8n5{lvN&*W57:ӦP䙍w>UKSiފb3omlt\/g/ a& v.ԿͯVۄ>G%u@[as^|ړ Necʹ߶6$YTwY˽$/x٬{ѿ? zbw=gQUD.s}&Ԭa{M^>s1П倫2{LZN5zfQnV)ߐxMsFVй^g/IMk Tlؼ\x LYګq~87qf6U8GߣQ J5[wobaEMj.՝ܚ{9bknM1zn50f?| qvwvsge5ȡOi^.Wᾎ}|*U` f/QGsޛ/;V#ʦʄ#nѳ'nRɡv۞ͬ2>뽤8mi3+|9mfNVӹo>^XOjp:Z5_)3Qk+W-{-LvU'tRa7lCiiL9B__ԝy_?D8olaղSVl+E> s/=mćW(v C2ӑֵn.Ka?HY;3=ͳs@IIY7kLߞ<|HY'g)ESs`Ң10IбsKm(悌AEޯ dԫ7W|"7'"X廊A2`!yw_ӶDJӢ\J ktmdo_gQٓ3zyo^ҊayfP{\ qYK-R9*OK)4`ri?g$+$KtֻLC0߽ks.@?5o,G=}K^d_GFq@х$,nb%:^Ȁmvt(;NjE.Hw?s'so=S%I{y7oѢINXMsD7WnC1KiB7bks}޽ `~ 6Z5Ь843&pxbs6&>$U B~TS(( 9L]\<,16-uN*6 25׉F *o0"Ӂ~Åֻ7soJUA[p%}wd>,9Ѣ\7ɨ![Y_^|nq3BS|_󆠑խN}&^AU;r:B\|vbfQaxEyk%IFԪ.b㖲sQ뉨sRV@[qk.@ͬX5R_@*`X'"8`)K `CG&*(e/*J nG<$u: ~SܷjQRS qfAv.sI6]_d)tOQfjc~\Mv$2tF!;u;HK~ne^KZX|8wVAD2c6.SIKa ߓ7 RUK+^䀵Goi')Gi9dNU**=Ca 'L9T=?#6J]g-K".X# lvR.яfMThD.ȀY`4AZK̭FPSkakWtukF(nȑSE]H5R70.bz¨lPRs`%/(yfAgsDz>{`gWY6~zLdxdRF:?^ +uҫ;DKoh& Pt`͐=nSkVqXeKߛQZa ˭ .XE]$"3/A | S )e0 m5 ֌MBaVIh>Ip1$Z?:) D b5'`f7H . ؘ/*l}%2p+*4J~4f2b zQD_V^DigM,2p.dҏ h"q5ؐ^>-r)Kq̘n"Y6EF'V@)@iT"U&EpXD*g0xZ`87A$#$bqbU|yi.˦D;0"X<`yb*bʀKY-\yR&!@6QK~fQD̃u¥RZB%Y;dD&Z#%"BAX5jHD$KL d) 7sm+꼋^k;m~t: BKiֺL˥2X< Aq, X\.UE=3kTzWbyrQl.4 ~8,^BuBetQ触uj`o(|l$ (%!ˑf@+:>) TԽ=lɒvo"$~TSFWH hAF0^ҳ=Ce2Ip~{gG;Vr:X/[˺+m]xklrM}pqz "aAI҂0#.A#$iI,T}E6'IaTF32A,Qe1" }@bX[BMb.e[#?n>q믨67҄זrcޚ#_sM]NSEչu&Oʶ=˭ڜ:>.g[L"įtK"r"?{KBo_Ԯˈ{aaavvı3\&zˁ~MK^rĖ: dWG#BRyCS#BCNpa' =@2dn;~^xthD T*o:nѡNlU?inӷCão5BG*x?:4֩(R3U(ag=XV3MRs,(7n05urs<2ptXыACi0#1AQNFB 4\ BS lذ~E/v@&QcwAL "@(@b eB| `q8$#剕sg6l/&?WVm-`8$BY(7W,@T[W $RP"_܊ޖ-).GO%qqQ%=-`.NbIΨ0W(d(۾N#gs )-˩%/MȣT\E'DTa;rA9.]ٿHrg3+4sǚy#Ekn9G8dOmVLBiٹ 1ܮeܠvnՔߢISfozۤϏrp~s֚,ӢΖYdĜ?{U=|ϬlM 'ϟ8ew('^9Csb5INћv9:{ASvZQҙwoXԭv黲,h֨3Nt_~AĞǣ*B{7)ҹCGVf-h_$4iᖀk?8ȶu3{ #R8]\Lknf#wn>z1k\;iSYNDžZx|kFl(@l q٭k40fuEoOa'Ob\س1iB>ĞÍI_5o_S=H`;BCCC#a v9ɯg!QWX[Ha';e1Q/X>=4tN9qqk{ȐKF:qe߽E܉ϪH%= ߀b{Be.[U2?6O.}{VY*ߠs/A{DLظ||"8oMG<|qv+"6 mR`m[Z@9+zCo"|}r׳:+gWg7[w?F@@ϟx")K\ljAmKBJ f[] B_'FگW5Ə[=?㑫uȡm3̡Ϟ)NLߛ 2j!ʷ۝\PQߊ ypfG[JA;ED?9ֻ >Ő؈гK;҈(ߺӛrZu˺+"x%@dőcoYWu]tn+ظIryUo嫺KnUَTD%sꭊvh^Um=փ'8ҶϱJ/47ԚHPkGo?yr8wgu ݈}|P>ڌN\SOSB&<0R' ObT'i;tsN 9!EQ.&=е]r@l37_xYVA[mq+1OnJZ7JaVMZpn(W Xop泇OoVSHI <qyٸG܊y#€!,\|g#/`K)[~,:qBݣwf)"j O-hG!58p%#'(9 x6)Zֻ}1Oota)}?WܽCXٵc;2c\J1P7 ϲwo:Uܩy[=eVq_>$Iމfס!kND $ʕD"ˑ]*evfHV#7}j6klv'*R :Ywi_|˜*+Q{7nUSLQ#=gKu&kjd=-kVσ̯5hqߢ-b̢­2p?wc^?K_і_y ptfCvG \uaNNY|:޾e"-^ =y&k J9V.&ii 3^Rn؆fY?SW\y&7ȧg@FdT(J!"IDpvI lGxL^?T:dgv_ds$n̘xuOٮq;utD+ !}&C .9wiVGӬoK "qm[ XWm7M=y$ . jgZ>x.KHZٹ[IzGKQc&WlU |-ҒFm,:,ԟlo=?Lۧ?ݪ3}%HG{6d@`vk;Q>}rm4U͛ -X5o=a돾~\2t}?ޣ  IyaĀ~#6%7gy6+i3'o3\3='vܧlڵdΑrKmlо=?*@E×~yĐ>{_Lѧi_FwtԾMc.BGX3N_O oi ;R &ofƃ]3Em  HC76MH)38GD `rW Ժ۶dJx$Ѝl !oh{8|U{m9ɑAcWUc~&CVǧ#H|D@e_ރ~5l-/uL V!~y,cxfm8~߸tbYg+&K:&w^s`Kn;17,ծ[!mzfĶYٵ}Q/X_/H8ů9xh̝ םx,l2MQ^N8y}~lYTi7:}IjVֳ=#х+` =vO\zzp^!SAkw]IH{?Z,lܿMH8K}n\pSc{Eb?+|F2 <%/lx{lZ>eHa[v5# Azaw\U#?)>x~*-С?,ebxc:5zG_!< r,ߍMX뢒D?.^O_%NcF8[ZTOS  xoWћ^x:9f__>lN^{*I*_^=o 3远 KɋsHZ7!ش9O#+] G;r^P; &GmpF 8HTU`46<ޮ4NdȌ{EG =r{lz%ϸvvH7tvS݈ti]+Jo[deK.3Q*_^>,k՚@tĈ;iːW|4.uÓk$dnߜڻ[ITm;Ͽ\}*ҎUQ=߿v矱OS23^޳㱰A<`wNR˧ Gz%~p R!v八N%?zӣUƖ_xx|^JFz\PufӘc;<Ҷx;dXFT*1ƚ ,Tss ?ز 9K+^\/eCǖ<&siUGBpgwu -;M!J7[@VuqpMdB9WtoNaK_CHpõV>ϬUWP~d6:]Ko :-▔5l-ltu˜Catu3e^]?L#zU9VNB̻_}x%~u{vW#_Um'2eYٸn &0s(kbXt=ys@§øO 37l{!t֓lPח,Lky4|㻓f\3 .AgIԋ ^A#BNz#! TϮ; u=Ѹ+ًsW)2E^XEǁvߝ{a?;#ei{<~;];s:Ö=7^Mvߝ{~5yJTfB6|\Ϗ,F",VU\E YU8SӮ$0M4-k̠ኲ`B51o!yR"$NɣٰߏWKW Ryf0i (l[n6 ƘAK Q&E5i0n~.(9x}6 > ?WfSߒwh ħ$aXvr Ir Fy !_&" Ggf Pk,XxC|z#aͧmo޻;Ye ZCYb0\cGbIY$3Da[@R"bZVi:#{P2Z Ŝ=GYa>)+s3-΋w`3IHKuudR h¶'c}gW.iY)H.̀g#Z|[I۴Ect ߧ^lhkǨdK6O춫QxoEYe,5UlPk=>k6WOi~ǤӼiXt!d"(1L++c*x2X[b_QɭnZ2;muab\Tb\ԡ}_7wN:UJZ߼I.%XWb?aqQ1=<,OujݸIԍ9Ӣu]ܙB8eEƿlU ӱw~;SIH-I|E7 XЪJY'$elh楝iyZߑG?e]f]ct l\cl:+a4l.7ϸVt-(*asPcZ``D ̤/KoO%:MׯϬc' a úվs;uudϟL=SA +G?u!gdc=#I D $ ihO H`P4X}l?ÓP@JAyw\ dմJE,p<#FoX Ev[eVsGOULl;ɱ&<c-c1IhïөbF#Nfa.Q/1 Pb\&.s`<mt4Eb>RB H\aQ))V^PK]:F/Dvx'3^1h̯q[Egoa6pl#-:1 VQ]vrbr;`o 3KOܠ&2yF.}Ԫe (j51TmlZ~>&s]RqjV:ށU4O$Fq/b%9E*FZKҢLݭ?U@°#f;,)<k-NN[Fk²WO %ﵨf| ӆB ~hC?*#Mh3BSB·qSqCדix XIh:/)Wkj 5N_|jJ /V€\N=9ccqJ-Ky#*@6o(+r3KA'*HÆEF X=q C=nBŸ~ kYQ5Ns-^MHKS2j":lI:vȂ{FhgΩ z,6[&KU@I W ONqrY'T6Q_bxGxԐ /n@ BWq5NzcFIQ0R#X 5-JRR aQ_ԸГT*hSُS6uxrM2ao X5;42 :714W0E ȟ\E6B IDATİo^N(P2qj$C#2, Pb勛 Ya yR,[0E S0,Kc`)^OJ~)ӑxYڣ|;鯔>a!|L&!/^#LM˔R4 մWu|L%S3R^&WkSTK49|qYXzv9vo _.KKCyغeRA-45\&t !*{V[P,Od4T E bapVUjH"gF ԟvެ!|0zTEryq5{TiBdQzxD$jpH7nG#Du4CB:aa ByIgd3]3 t2p;&Jt5v[1u=;.f+s>]eG^J6hаA:B=]!C>~!ʋo`BXv jyпnXXt-€ ԯU~uxW ɲv?NM3qss2|䑗3wnfTd]}8zFߜL5ǧӨO۷h޶U+{na*@6TiG{6 ^i_c$r⪲鴩}6=ez ډ>w߮v`U5ڵ'1͐=ocxg}ajAGO~ K8uUhʔϚh{Ҵ̵Ȋ`D|>m7J>s]@RD<O`Y?+D\v#k덚>VC7}gYJj: _yݨ< m7o{ۮKv/pO6 ۢۈMo/եHmpǺ| ٢#ќ &vWG_MHjtl]$o eg Ƙ :{d/D?h%cl:L:wT5 N-H́׬os&Ysn:^T<:yA]33 җ6Z}T"*ز-W:0sٜ..٥ůKx-0[| N=W 0,eZ;=юkY & Z9 Ί<8(zz|Ѭ}sdD=Aey& '|vi +6^x2JkOԫs[:'xEQD)աN.yϖi|s[:g DѓcfMS== _|_}Qe,ozeH:r3Bg*Ϻ,;zjh=sw@>gZ%AǴ9Pa>eTPqA*|Vlqox&yvQW(]BSedz.³?0=s /f 1=pU9~nrɢٿ鋿M^WN-̷ԬR[T>(!gf5$ 㜋?Yk]uXT>sM8a̗_sUFء<E h\b7likkBN"~#4G-5B2Fdީ.ul)NY{Kb=;3zqYsѽ r-Jct cZ՞Q%]I^%wDl]D-Z[sgm,+[ΏZ[sIUd\6A\pz]1`D\T\<*aMAk}_k8uz9 ScLoq%)DXkAB탎ܑ;T1c&\"+mܩnhN!O#]6(;V 9#Cۘ֔g9GU^,`JB>$iҧw_{NyoYTGUE,QoZm;}8}׆Vq\ T7\yʂ/UJSb%H%^D*rjy>T|rνV{&r lXBdHzvލ}yH:׈wg,Oޮm&V[j$ K1vXbqݴ툀uKy]EEO;_b2~;sEʱ\X\6wqȳm?o~asl>w?ڸx*B~ T@7WB No-ykɑߺ+r;lbq<Ͱ)r;`4!7iMqtCy|O#;ʐ`;Ҍ%ch#WF' 2Ξyt[ӲB_ 9S/*c'{lEF@[w^v޽ ;&'_$@JVW`;R ͝>iFTLp_>g,-ahhbbalQ׮">-C5v, BDG %-K+DHtT|FzG\Hl,U Wxa|F16',5•3^ q"H>XJXABqy|ChӔRYJREf:/Tt[ m9AV޺o2Iio,dB-6?ro!n?ϵ[ۈ–s؅wؔ +R;_\Bf,0fk9Ȑ*g7RJ% }˻2A2nMYIDW&i"{Vpe-i>TA%cKZFYS̰eL*Tت+fyn+a]2)hVaJlu f]P#hV|*[5na᮴MPQ%dl,a똀l HE[|Ȑnı4Vp<: .G ]1[E8^RQa-ŮUQai5ð,(#Gc "yJaXaj|aB'/HBל+\/KbH/IbX_HX$ D"{f^ߦu?K/8)2*`G-=kyɫVBUL򚭬;=ɒĦK6+iһcfi{*H(xoy9O,~6iWڤHoΜ'?i0iejBmXl?}=6jǼ.dU"k|ͱKMFD~,vaۜ/owD݉svw]I;fv_xV>~IgDY3od`owN}gDF/y\|Fsxq?ܼ}/v{Զ>HPwDߋur.<=펳wbn9o~ {xݾW|3{w-m=5ȭ\7p̑j8m9~f['v-YKhqڏ_;n쏂2A(q\.aF9C`HH,z5 %\&SV9, %0D*\.W'sl̘jc U*5qau8| \Lqq1dr% .r\Aa._@3Y7d/0C N556􁫞o^oR+4sO 42|?cO yXLF;".U"/2xyEazu#wj](97tPdė& ys@O.d#WF%#V/=ceuǙK7$a Oj_+w>-5:~V' +*joe䂞/#g 'JW-P2bGdȈtf3xf5'Z>Ulw fE/3fF,]_<\\utcuE9c;¢#GTwÙ40{GW]ktp6' kC>l+H8f߳luh ~ƌ!QNk'1`0梂P'U wB$h\֯O[1`j f1 f2g()%Y <$V,\>Q* ]qHV+)5(JM LV* Bf)+"F)0X75%.`+d'/W⑷_Cl9Vx$lo%DI쓕O[ +}Ή[%m왑 6'ʉm}6N['x"qہ\~/6I=^:Uxdۇ Y]~šo}y{d큘䔸#BVז"-۾:רLaLn=GyݑlюLCMˌ S?}gϒ3}ϵG6]Xڭ׼c:4QXeן60Ds?l,A5H|?ZQ(+(.tJuz8@trJܑ52CFnѽ~UO|%;+ us~_y#LNux}!G+{GlIܶCWgѿc<׮ȨbVMn#FqzdwbÎԠj|6V)9gܑN#M~|5{:xévQs;ҺԂ.} q/ݿU{O뗗w]߽&4Nv݌ɛUp?co?yno~eE>:vUէą Y`ro۹svSEޭko@qz?m S*ˬ,V+ RE$ faYVMQ p\7`Gf1KY/ |"L#X,  I"Jh0$"DpZtfsq 0XO14bX,E| Cun\Si2"[q<&|Թs%*_w$n6㗟d6_ɿxaI=^]&)=ΝL!C><ef$, DB4b~ _0*L&dJ1Ip"B Fp!au%DVEc)L&Ux@y]{y?ؾmWrCq_-Ǎ"2\K?p8Cfq5 b$Ě}FB*ZZ@` XIF -\ԾhE'KR-T *w㦨G^'ٴហfb]'onTr¤ 2,\|d n.\_+X$vS IDATm\Mr \0!Pt~I8#:p$cӅ+[zjFn&^FbXvO˚" kAʷAAD7D0=uw'1:vJ/0orlU#Ix|5Ӹ(~66<hCڐwsjOOXk^݁t+ͥ౛lR{*K+J2Ha4R*jLp g!@,M3Ʊ >ב # "HJ%x|Ij\.bj5rv&blFYVF&|a8E`HEJljS73r&|ElԦ "V¡f6,%Pv)l$.pve̗2g|ʵ-y MҪ:=l ZեBҠ'%K򳳡v c;5Hi= F>Rs-4a GJ"cBTͯث)w>\9j ܔb!κ'*YU/B۵iiOL"Vz G􎻘geA-O%~/򆀍s#@?W;Iw&)-\~}ߙ[f1-ҭOyt|ڌ1Zhc7i)1^7?E(5Et?<|:EMuj‚)+O{{qLsNٳi Pj\Uk\[qߵ~孊^{q0#{(6;Oݹf\3$ L a@3)ca$ rC= +24Mgǵ;5n$l]өQ׺.?lʌGlUF"2QP)cjl5;fguYmG#Kut~Ų1IqQIqQ[qbv9k,C.5ߑNשwICZ[*2s!}ƵcXsi24{fi!_ $US4K)׬3`Quk ۣοwlͰUSa$&If2?l٧6,~ J`k1`@YpGM?@~51_)CPjUݾ^V"RiuAM{ÙI+ kY裇[?#M#Bee1.K~+Ӫi#QV_ʌ1Ř-K~#WO) dA&O"!G :jMbS~~&VԸ AhVk\?4̏xY,Uwe*b+ "-k0GTu5> oʰ6C?c+,'0*1V+4A^k-h(Ts=;{!@H5j{UQ/ѹǒ;gtapb̖R4=ІTFZ{]6:F(ǮSQ!A|i 4x^4xeD GnZ7 c77 lCۦ 39Ue pJ\YZRȤ2T&SP ph*L*ɔk1UrM|\ܩkPrL**VHe/2*L**J}J.KP2ݟ,Jj L&frc.C+2LPivR&Wf=cR*t;4\iL2L&W`Bo>iW4:bdF;r]c_8Xdh1o8a`vM}ح̈geR&un9VٰW@z ],E޼bN?}=lT_yU3~Doɡ2]*̉/gp0etOP jT֬CB:aabinJzqOfN 9[i䀙WII)UiYR;N~aj!z߳ޭiS '*6Oƾx|Եid@~t)L rݺK1juO>*cW֝WrxjWG[0et K^'cQo.p%yF'S=>ASJ Ϩ{*qh;|ЮDJ0f7 ꄅ9)U?C%f>ShIm?#J4}s|:#Q&=k/fupE'Ie}UM'X2D;Tɧ=LicjuN+Y:F( >QIJGzbKo[vG]#A;__$_#kpbi^ͿՊ2_CvɍuK/nŨ+w<)l%_νP{{GGpAª:Ϭf4k@Y/,)S;F, = S'#TNݘz3AUB{*ZU*uDJ Jx#0qh~Kf?%Q9(`W=cba+!=LKI8DW.[2kDgO1k_vtkwG-.*0<@B *7kZb):o})AK^\:m4X{oqz؆]p5/wO]0kR e#fY9kRn^ܸe_K|u>6 d+qhB"%_4{*eqWy0|"dwN.f3Bnׇ.[2;8ų l8y3Èkz<4`Ou^ιvčЯ]d-<B<5;V3!1霍&EO-B+lIAfjE0m$~`s7(J8hT\^1jR^ *\vo?|?1O\X?绥"[xsK._>0Kݴ'xUמ<[VV2ߘ9GG>4VTE8*l7,lгA{k_k̻`󃌢vWbޕ6✑{~$G6*ETk~33K(,BVb+ Av}1rs=ݴ*r±+sU"VNpi ҳ!dwdc@KQO"ivX#*rb{EbաvFa3rj/dȑ)=@Pr!'?Er`*-SZ.G*B'RvG;*vMs8BO 7d'6F\6tIg Yxvaibqqq_!C8ŕ;"9 GEd ]>;v#]޽WT'_;,Qcǚ`leyR:ب"#2bȶVEoL>RGغb{*\,]m71T 7ݱjl;%Bβ: 2(!doW]d !Ķmq߮6mV!{%V+²<\ rFǰuu*7V%mpEmȍ{FR(Ey7Ʊ,r>V*n .-q9*0C7dT}iw $VXwd?2YU'[G{#+^ꨖ #Fqպq͉6؊>ds`;!)QuT| 4 dsBΎ3쨵h\I:ټt B.%ԋw8@p\;]<ئ:]*l)fvuESa5lko=ȥ-r^'.h)vq~dM-ylnCm6Έ ,FX:1eR$Rr\ R!C5v|H!$3oV`o]9Brmr/`40qAhB2ܡ7v.Q!H'W!L؊~qEO= kS(ggE& E+*XA ABu <.C `)ye y#y\AS*J""qsF)SӜ"얽Kêj?Q &3ZIFIU"_Low`2sbAT+O *6/gXLv%w{O\r#[e5ul%->1?Lm;1-c+\S\D啷%S&üvX5piR3jfY )cRO|Y{ȃہJW'܆y]ހӷ{Lxnlm`NĄAnİ2h7ڟ݊1Oj cVjo !<9oܺv[mEwjNA81&%C'uMޱ͖'j]=RQGdUF.0CӴaXQS4uXeYaYq`h*}Tz֩!\0 &zxl`]GAT!OF,5DBdak>EBK yDue<L;{nyC@, DbH#BX,$5 .O bX$@")bODb!sx<1._ߑ\vӢh'oStHĺv0`eQj8c=u~[]~.=~77e=XT1ֿO}Ioף뻗 c*ύ _KOd0Cdw_z^oz8MA/e=YPJok]zt~y6O1FJ}.o*h;zFeՀ:lˎ?=XX˗Sz7EϚRx,^ˎ??=XQUa}2&^=.KWGUtpL%^$+w@3'^=ޕi~uSy,ƑUTʵk %D-iy@XX")]DT9I0f:OWf\D~(U=؈"@)R2!67CnKon<14`"cBHE*. cEQuM*UgbR)H,$2Ēk EJDBP$6PtjճB3Y* kRH(I1T:aR9 <25\mJpYѿ'W10u$ w  *1YNy<$3f:s،>Bf &ACJ\WQ |lpmk_\Lf&L&H*=_&[/io2,:Nwq'<(ə3fY!rCYL2i8i2ϴww3gc{/|`;g$J_LVQLZ Nr/ç{o|Rsu:8wjrm煨Lҹ˷&/C-:t(I`<(3gJ|&X{'o*rؾ_EY3$f̂* ,q;6 ?5i P5tju1Q"S;ۛ2 s%,q |,8w]y'o1FTEg=Y=6G%GB8n!Mu}\+ou % 󸝛柞8dž=y'H+!rܹyXy^Qܰ'W=<<>L +ӊn}0AGrnyx}0Q-~*d 6fw㥊R#Lq2\uplD.;@*kWdJ e. 0 @@fd}λ$X50Mlz"hL0AL%纈be4־7{㕓豌i0E#@MJicI*YL0EcJe,#ŀlD JbyH IDAT<4D Ec ߣ5.WO W6SOyNqՌrp GOE`򇥓".6w:84f_8 cVlC <~,!1d$a 4k• >:!JF]kg<:|C|zr}(}OYgNx-ݬTKG'&ԣ';kd]9,%X-:f尸C>`UNS*̩>?9AyK7k&YKGO'&өGOW]AH{?.? x.j+W%*KTtE̩Oƒ5Seϕeal^|so儥yr@mr/?}-¤ǚ}|\?>ᰍ zri{c=>{MEo< |pn{Ӳƭy?Ыw}~xxh= cn^\]3auc(~>AO/l؄P۠5pwͽ_l\ӝ o˳4uYKEFy]޳dX/S1bGfseyظ+ |8066eD}JŁǶt?0Mr,^,HK/QQ)VMA 9|oqwO.A'!@A#\s.<pe: ϩҒ'm̮7xdl>Ks>Xet E' Σa;ʻ^Ydٍ8}h֋/C޾cʯJ74yϠ'>96VeEXtMz98p)FuS^x> ` L/;adȻ+ح7| :J`wZxJP/\Z:܉ ~~϶̓W'=;?s&)n<=~ 9` uso՗{ss@-=uPdȧv{f}f)2$|ok9&MFl8"6rԥQ6帻Ѻ&{#rI0@Iy(1\A_~4Y^hD  Sn=]\zvcxIg?):tԿ@JƮ!h͚Ia; h#gdk[/^+ࣳ Ǣ3W_3X~M;Q̏jOsM+n[G豷嚲gﭻ}ؔc¤^ [atPciV>ŕUgɻOqeu Piɬ/E*q%~¤{#FJ /ET\ٓ JV!]4+Ku_¤d!_Fe9EKyF[&zMZ~Sz=g.:9k.W\YǙ΃ȹv 3/AؼU!4 gny %v>6n̞>Pa-r]T2T n$ŲZ{j7 za`qeI%i@GT_xvIjsK&p94aJúOI,J"_H9 K r2E+e6x< =wEǂsH`HNE9Cg{Wt)񳜆huǒ}rGxbso#jXzFצFH%f "y)lar?pz)| cO jܲӘ9ҠU[unںӘy[|lcϬG8PJ<XE''޾}o92&Nۓ/?>1g4knQM1wh7nOa6TKqa܌'7miliмv-5n|l^oY4zwۂBVLIOL޽ǰ5bEUHM:I%t\۬$3Ű7zig -tg;;6bZ=Q\Wa5ܻwomu=BŰ^o>}^i4՞G)\\52ҴI#}y{cg*шb><dY\dƔy7g>zywr|fPa=WkW~K&%I>ٿ4aP8.4K;rӰ/o-mޓi) 1\ $|>">=-ҙ/m0n:\LmG8::%7b5'7bS??<7ýqq?JE=?~8LlLl{M#*!e" 䈬z).cB3`e~ʊ Fy +M$[d{Z7 :RWV'A6&P-{ūl$9`bc̨͑~*bl#:F53!ԝ$R\0-kAzp̔o.܈R u{$T[ƌu9u[͢B8<*9Džh&%^9 ڨxeMnju9yF쯤; n#06kՔ ߇ 1kVfn.}J*.ʔ'H(|~;r3$K$}?)8#,;(-Xo|{o6~)_ ?12$ )!gSe=<CL UNv߁'_~Q N6r>KF"թ1"$Ixu/ΨaSk0c艛 Χb<dW@x2 e}]R$5 L}H cǀt5G'Bw$aQL >ĈWl$aZ!Gtt^؁?%&?ص=gTscPM}%UYa [mkJG;|Uѡ`f5TӠyǿ>IvX&)驯!ŨwgִqJμ0.v ?Msm//lff_t'?Ȓ^d^G=dt.WyOʤi0\FI怡Bvhf.gBeb\GiçBwT]FrƹxynvzxTM=g\yn/<>fo"hf^ۄK7OvHBO)p;7%.Scdّ9įủwZWKhb)'Ay1*2)QtxYLaȸ*#N̖@N/ ~]bF9u`$'=I@tuԮuƎ3o–tYc$'=劤JcpV,Tp.G-垯jz%|Rd}⫲oa$;=Czä '<蝰87zQ}f[|?yO5“~!~*]ʲ"RL̀ X U\(&/+AXvڇY>@(9eЁiDuUH6yen s0Ի3I)ɢ#ī ~_)q?գ8AFMǰ6sق790`yN,@64Eyxa탇~ yipT&V|#I:-]g'VEd@,H`$ `,n^r  8| j;y!`BLME&1bWi]wT)ǜR(&E$HBJE2et޴ S*;I+WOٸ\HP р!0sr K"%~a_ƀ,%C`0e*G%o&Fx\ZjD6/5%ŕz+K`?xv Tqtѻlߏ͍]m!!J!ݗVצ$c)ƌ3Iin!*h@(hKp. <0 s+30[|Ӄ?ɋTqj\Q D{]$xvM$UNMk5izg̻^ /ܴV|+ϺcݰTC*J-J诱2'Zңۋm>|6SvHl 9@TyҺ"uHT.!{-^:/t;d*McPxw3LƂb[ 6L`kz xbܿx[zJidS"JiB!$- >EQ%>cc T⣛nyl&vh@cZiE4-|VF (i M1!.I)*i̎2L&i*HM4]@QE4M*| SniIIT*(J (Jh D(!iRn.zZP$շb.)*Q$FD$(I(4U,lH [+i,ezaAI@(z E:o0gCHh HZTz B)+Hn ++"zIIM_l R8mB-Ɏ/`8YyI4?\9L>dW)6 H @II-d^l yIFc ;_ⰻSyo%ZMj2x 0 Okw/y ڹ:q]j׺^_y &e9.,lD*  3ݤĒĴb #Qe\LbI^R|@)y885~)d{tD 1۵؅ QICvctD `2?9>Kdiάɾsi#44Dx\ 6kؐ/ȌK*pk_Xlcdg 5>d`W?eq+aٜ9}I2}K[iYDj%.|#u+nٻl0⮷9RZʼ V+c${x+sq{NOO!U6Yk`A_S zuCL=Gq9>56X*Hފ3dq΄Ljm#_It?SAVٜjF\d%I5){f#[\z&epc)>h,ߡ l`aI샛qSEu;>|y|~G* Eu7>ob-lê_Wު/pI<k7Iɑ8 y0C\Ƹ$,4IU({.Lj IDAT> ؍f9<1N?[g2v*O[cI"_{w6ŰQ!kF%WgNla[Y*ڷ'):Ϳ3cΏR΀YC'#|~Yq3hQ: 'ǟ)7'ŮY;)@|1*w˟khEƒRe:v+=:lJx&Zh[,I{Rp v\15S$ܻp{HљB]_ (w_ %ƹcuo\ߍ+l^XYwmKXkŊig/A˽Uc @dū7,{q E:"r=o#$O~ OEtE"-U痬ްhũD~͵ &HUq".,.kk킳Rz;[Io'!p VyWiLDh PK#d҅%+/qZñ"d+7,i:qs3:a9 :Biƞ~3oD|MQ(X>{T{>A<۽hDr6uuϏiwӎݫozO3(NùMP+b.Mr-Wޏ͊zsWrXw{1A|}k:MmLt !,{ EOL-oUy6 |Xm[ǘ{tI+l<$?<-4\x-\s'`Eq^am'j龛eǘ{b\aׯ]t)=={c`M8;QWΟ;aV}U"BO0ҫ9r*9<Q+U!m#N>Tv"5Q w9d+USz RcT{~vy4>'k_#ƲWDe3\gu֦ZJNPEF)ȀH}sՠ p6 ~w>a>].3i2= y-WWĢ!K֞@eLƆRIRߜ9R{:j` ?3U=\9 sH5 Z&5d{h~hH/~(͢W5yXD~;%l9}ZE*_PúXX ' MXO\#Y7=? .AjըPl5nADs38*KUE3 ~ڳLR2U•|n(,Q!ѧTخHUiCXo˾CjpQCwT$}ӝe^h\10HVS>;U+ |G䑸#9 "^G d0T'<^ܔD$Z#氙 HDJ!bX ? VXacD")-5 $ biŸY~mZ5 vqMS[1U?QIH?rO!T?d5i2C@s-6@ FK+- VpHxǬJ \5f*FC2)U H*?rJoUl/W@$$1L6ZDЁ}Or/lq(:U[y!X,ʴ!>*ebVA27jՌ3Z#pVjHZT. R Rj]"M2)[^@ U}EjɩWV-PS)6*6lze9u텁6f(ou//L7~ָoUK Dz KXUKqE*QN<Ȫ4,[S]AfmD+};l  wVYn_bPaqI,T\dǮGo߮m+_gڭ˃mj"Hc@G_=v?~)0w][4ڱL"He].AM)?4b@ۓZmk1ߞz-JI(JI =GpV.*D1XF<1e3BNbF"=ITQ"&76669|c['$Dyu΍x<#br<PtdRLp|prS"i|ψ@YgFF<_>mK#S2ke]B@B\jIk,QJJ]Q^Һ2kb/ˣoi<{Og,vm~h)٦O5*%]^dd|S_np6s[ΗwE5).]f}rꎹ|nrw#^? {Ԋn0;,>to߻Gq [ӜY,i}>^=Nݑ}8;^/fw[rNﻀ'p`n /Gȴ{[Ӵ[~A7&hLJavʺc\;#[a@6}Ϗ/T*AmÑ܃/@c˿Wwv7jѢh'oSUB:{j,`Ȇy fw[z{?N-ᨇ~aqςCܽdz0۾㏂=:O/GimoBއz?>=ú_N<|8ZGXfU9 el^O<  ~tnSA}'|~tvE7tx"m+~r%K۷oc}K I*LljWUGMoqd>l /zB5Q?u{woH]jaЦL1=/ߟRab #)Z{9'> 0EU)="XBHLR@,&&EBQTMQ̠I)f![K6┩^aIP.`qlLB1T, ERy+8bru:L’8LA(L>ߛܴ aoWu=ToՒ5+C DuGf@KsjwP,ڳAʡ:$&˹'fD,gUWGdJsuŔcxhF>A.N0LNllB*ŞkэsCr]rgǥL]kऑ۾y;> 2U7-8jH~Y;6?pkwzHj%# l=cگdiuNN{1:5rmׅ ҹ˷&M3E>>zlKue[柎%Is~I|aɏw"QxB%G*aP>6dV\\uFZ9>˻rعihdذ+7*u:{wL.o&JdԼKSdfb9۹yh^:߹aOnq*~L'ƽ:*Kv:i/[mޖ9v*M,>ܹQ2dugsIM^!Ǻy=wnVpr޸ײ vm؛qLziVb9{<Լqdڰ'1ê.zx؅}@VR0 ]އ*-}pwv!湍a"ahү&Q0P97xWA$-*8adҮ&њ^DB2幍ci |q=[dֈE8`D$էE`G E4eKRDHF熐8b0 4ƔLJXFz\ X,%L&%)( l!ƈ`Z*T\7HBRac1Ib<cLty@-Ǎ +^2)I$d xD0c3vj(O1ۏ`O[M}kb`M#`Ń+>HXpM{mm8re!7w>< 4rA+Lȕf h`bXf"´{3B :'nNK^2dw~&,L@<_K ZB+]{vtB/MTO vN,Xڌ<ؼdHhiE{W,rl֟rIXǧ[]"X#Ⓑb\2b@aaЅ؛s .[t!*Y3LL3=;[sB d<F`a;). X{e BpowB0\ou36)ai_νY<.x|Erp4mj'>{oJ{4))((= yKS|Ə9N\>u ~?ׯ9sD[Wi)/y藿Di4TZpڛJ-t * Z_ 22Mu-)"u .Vq5 l8ZSM}n0u svnh#*L~Zw>%.:w4 ȑQdѭK^oI}c퐢CGU%L군K/EVU25ѭKnoIWk2)sy,*?S@M4s?}i6l'O)dWC|o ʊim-q-hns>uQGӤ1F:2aā9#F~Gbg-ܳշ5pDE{47%V| *#Gu-t5Ԝ^z]}-FDVolbQSuR.ڻշSSFx(][hGUڠ9zø^ [a |)nVT+`iQV.ʞiH*DVANϲ/3eye) "dVHdIk=;Kގޱ񧨴=}\ :/j_cEVC00tj1 _/ֆ~˽vcnX-iA&-?XӞޭKׁ+EJEXrWk?AD=MS+xrX{J}MbĖ3ԼATSǴmz82f-ڷ>HX~;OYكNN֥o>2t֑2mJp[uZ$D\y؃Fw [ w/d3oiVev2E+KT6g-ȈRN k@10"x=N87GȒČ>]^ˋ+lYlRBJ񻬳rꊷvr۬~Fa 9Yw9iׁF”du_l\Ȉgblnm%€?PQr>\*ɗPˁFDY 8\tXP(,ܶmr]ךY2XF4ۗ?{ImG]L"d{ y-3IÄ!j1qU]w_r._EXc7,kadhq9)T!zgkP_ /VJu1a%8le~=8 a/vaɵqdq 29]d̒㲯Ɋ<>zfʒdDJ,ßΓWsU9c֌+8˻@DfRܨv)M͛mG$S^۹lɌ)W_h0uOG,34СvvlĴl=z\}cKʙϰ}L V@/%gӒDG_0uq5Yډ%|}{h &=N|J/=}d|zZ3_8^(SŤ(-Mpevd{ώcROsmGnā“S#ތHUV; 䈭z`_Ivy)'r/4N<:JEV}<u8[7=}xum 7?Ŝs/RK ׿UKҀ:<;W5) !M{OF*|}x[Tc:0-kAzp`dzfʷG ʺD@RT[Mnju9u'IVFCϢc|\쏎*7#|MWb uRaZ\ڴa'kwtfjF ݳ{wq{hp+Z޹pᎿsr^ ĄKo@ IDATvchhUl ,[f{`JEw7$(\knI12V 6bpL B V&Y[#zMeK1kե}O MxDK %񷗦F y,}fRI_2/΂If:ׄ2zdr*œ (&0eI^fQ$Yslvy]#@w8$ƹxanvzD0Ȫ.n32ޝZiWYZi,;-;s5 TAc$'l@4W879z_{z[>y/UT%IERٸ*xI"dzdtl`4|lZ+U^ۮi]U3C䧘1d5sr h LnbF@ ,ٷwM (U xM ``l0%Ҍ` tX83DP ` L+aL0,1jsDBDI:C/YP@0h\"0b4de95YѸALc:{Wi^5Ē{5XҌ%ػػ1Ơ"XTwkQ8c W IB@kAYKVM? f"n ]}iZ$4)i8AaP "DH "1N7u36A𧦛rh=3;#b"c91A?3I)"λ!rYwџR3IE "H,b,8{ЧΜ06zߜ"VY#5Ypaهh[ UiگZ"ko`^ Lh@Af]~xLDzf ?7zxvb^i֦n a5|RN#8$;6ָ97^\t}X*j)#>'>2'ŸGB?z[qVȅXVŵ:6֨_L=uaσS we4E;PћK&+6Je֘"č:.ཆU8YUQr7MŁN6|~`o\D_/nJ%3d-μŊ;o}+ǜ3drQBmt|DiX}ntzSxe5𳖉?R%4*t}оms)Gr4^3 muxKDdNZ:-|2xK3j+Ś"%"yVKb4YaW=)IŠTN1.{!5: 0 pbcx R_ hu[!Tm 55IPO5An lJHG{!;c˾,K&łq` l}}1xX6F?M%:8rRUEA Z.&4O.#i =-6QC >D >߰y'pLYV( Ү+#"EuW(Rr9b|0P" 5nՠrmVި: ʃf'k9Z=\m,$uu?q1JWz f(ڵ!zmr0 ċlا+m -S2K&ڥ;,;F$ xп'h$ ]Ez)^)eʧc@9Y`iqF>LjFߎari.zD"E) 9 F%o;*uUɲ(( Í)zu;P(9APF>HhFߊfrm]Z`D@*$`#aH/ܪہ25YAVH|B5md Gm\30~Syv `Mul;mύzb!|x@烵b9 FaJ/ riGlF7N{m=ɏ&f[³a֞-, km1nQ5eDL6;t.è1Ul)n(v@w&e |bVʸWZ熵 _CζTB1<g4ґBthvEea Gqa21'<ʈH%<-'zNqS$4wM,qPK6+tj@IGSQiWX$F=v9,֥IT EG҈Oz,gv?Zy'] >s؛5bߎ#f7) X?.PX+ <"lO/k0=Sc`ہQD#k )Qr0Fo2Q^}VnM:IN4V]<79*.Ka n<cfdNsF!ͫД=,Kqm[OALf&¸Ywӿ̝yމt@R?=<}'f?VU-HHuD9_G̹oV}u9ҺNrn*_6VKux9k3ՌwqwƔϐ;G ?E;?q{kGhO >fK΅ڽrN>v+6Pc? oOy[eEb6hLflTF3b&HsDŽ LʶZD= <{DXJsO{ Wf*AK.uE>9\)?_[~.j2H.oPx_T0݉lmNF#XTS>L;{N/eAizTpXR @ۻNv-\럑Szt`C- Cvo_zWn>~V+?ğ'9Fso&_.Lpԫ1Hw<ָ^@s`wT uP)'[HsÌgW1RDuI*X>ۘ쳨7sӑػFΎNёoh6/E ~r lQƺWqhZ,)>R &2ǹI]*k6,Ɠ{κxI^aJ-N.}qDOwֹO8K>W3>S*Z~!S~/"UASY{3/ [6긽wR'K:x|1b,x1Ң4y'z8\򙤓,jmd'@.t[bQcm80d~x63nn 1)O/j*OVٸ_w]8{ D 썵ԟj8m>bv pތFe^?ohyOV=pVcVo1ٕ|zo~y}i71͙4/ZAE͇urzD+4]s 5]Nߞ}Ցso:DY#ʇ+g~ޔ=G!7u y--?ϖw>9;hOsr^>7콑6Ov/H.Ҿӯ +z޼Iܸ̅]a2n"}}`|ų@d>?`Ξh@PAe>7;MLkQ#G:on80|z|~u/vN](qCc>8ӔߞXaʹ{/E|:ڊqYYq{s髍?'2Î/K^UcpΫϗ-Cy:蘇LD[q݁#"?5u".zk΢x7uQ9po+ ij%FK5~fX|82 rc1{M8 u$͛g\y\ /iwWf<Xx9o/;Ȑ :h{J02t+~?}1{ȍv{9X"i}ųQ< %n0BriyG]4*>ѴjmʥN3;G:pۓſxw->RҩoS8(pشw.RsVb6, ɰ=eJhcpn p9BXٱ'9siIe w -^Le׎y7W:N3LPBgoza/a6?̙9v ֗+AU֫XeU =dd_dcf ncdQ!7XGk*XbۜY.%$.}EoKJ2=B04ẠE`fAE:p0mn҈8<2 աV䛝mZ~wnSϛf:-;w)&էX򻳫}b?*'iX떴VCܦL&*~Xy/n\oUs)~>);Ӕk)GRydg?Fݖzq?暶xןy+wqZYϛA_yJPҾm.HK D#](=Kd.ڞK0ungv-w#@mոRG\uiJV0gz%KK[TJhfQFʋ JMpY2 YY{QhA-T0bƨT.* в*BR|Rߠ2ѥiʫZUhWoƁxWb(CJVۑMfoC̕-Valz[;~qJO@ecinIHH*9LUDd"Fp!hi:ፅ0,,LT.e`Oupjioק*Jeiq9B%;V`M\IRI^oaK7K09J 32mCJ;:I4%YKDX`-Yz(.XEש Lt*-ob1%{i` rj\*gm3?WoS m0*\j?}k2)9b߽&?nVor͓۾A/گW{] yo_u17MI'n ::Y[unP#W3ɼ|A9G"_tS'"Qo45͐cc Ãqn޺g@ qo?%PDb>9|䶯xRc{A t^Эؙ۫a’APG\Z[fQCvDkrD*]Nݹtoz%~×ݺz5_vK<^3SôGo|;{Pۨ÷NZݾ~^{IWe IDATB2s?@{tv{w (ŏ<}b {/~0.v#,6 eR_+cW~/P1 D  xH_Pǖ(i5Db4tkT*)rGIhR`4jZc&hT*kU*X"ַ0IKdD3JֱA3$)8wPc?ks+&<;HeZ]S,8w>d380#-1 )D5_M=ɋ#Hb{Nf&a /u@wuoifhvr ]] s\Orlx6.޻D]>dCװoX;&-CQIJ\ӄy 6A˞k x0{5=dFKP)aUV5̸y鵊4U& RV/s,W.^5f{ cD>׮{f:zؓd{%v}ok#Go.}F+Ho,3J˱XSHR#_7+*W-韵s_^6=ro TCµz7wa֥E,%+22<`hJD@H ")sZa8JRwXaD2$XA0s,KKE$8KMk%U2'V6e)ˤ@.ޫ^YM W Ai-1ɋA&k3P72j^"sHg zZm̵ I]{ @T#'F6lwv\{ wo۩F҅No̸^-tu t\¸{k'3r/"Yם2zLz_q G%Hܰqjۑ %9 ] W)&A[A=5Q֑s5)7w2AIュvn pj~o3]V܋,}Hnd#>taH:6U#=G'=Tk`f.D3]L@y˕>zB(={Dw(UvޤQNK|`Qnf~;k ?xyy'[?4{!S5r!2|\/?]g6wo{jc9Y~i:('_|[<ŵzK?hVst'um o*j?.{mE`mOq X:EYFv[}hRucZ̥`{pFYu|>xj2+Uf{A@uxy#"%'/DL02E C $ rq:_"¼Pm")A!@<+cR1N}NQݒx0owY_;j:`I2ZO&r7U E$yH8 ܛ)|}}@\{Ś%n3sv;x\|kAΙ#gzx?D>~;Sd+QLԇ}6ot!~X@xbܖ.a\MOs\ֱ7KB5j+'#̶%[_5Tڴa0L}L0]k*ԭqo }6AK}!X -w{tmZUt'L|O*s v[LڴE$ylWvyVЎ@6zaX.zu:Zi-ĿAw6>Ql==xSwkQ7yKHJm?ӂg}!8RkY7Gw JN @k,m=?8:=?[W SJsP<21")DkL2 ¼N!^-}^OE`*qQk,ȤsD"\_)6cUH *.*ߺ/,PPaMMoW 5hUTMZݓ'3x%Fφw&5S IgI<儇tm7pz?ۣ65(96.EFI=z kN#sa( ^LR5#|`@3TS;8CRQQ\ Ϝ8u-ωU4'A#CJ&1ST^^u,(ʆ]/OoD.ܜ8q?7s/5X{B,]WK ~CF4MKbt,\ XxP7 >zݗtLaaC붟4:!yfM rrۯ&{{C2Vn'<>MW c,m<4ls_Ňe](mP3ys>RTUƵ놿.mKS]u +w_7<}XoaKD(\|ͽ\%GgnYYؔ+jΤ3?Xc)?+1rW;Pj]{l|eK/#~Ȫ~TcGVپ`X/wumjIۋoF *⏩roRХ}3@[G>1bAWs>)SF )>?9D91g֤OaE-wRThtiq~Ϸx}>FC_21"82' A q5#zldz2c峿J쟠$ 4:,0I?K0>+,[4s,h8 \]1ƚv A JՂyV@"JDغ{"\D&`B>ZKB8rTKL.znUmO ;_c&ĪlJrX~R2ݐEl]{Q;u~*#5hyes4'7& 2(-ˠ ]qd` D0% 9&wlOdj|nxfRMSppq SM:3<3Ѩ"&ŠHXA]u]V=UF.pYQH.U&rSʙ]!)ݷ̤ &+s 04+ƳlI펍5j|lig.>'>2'ŸGBߌjz`mir.DvOg&cE0PrB>IT&b[jTB/1[N[; bl8@h]P( a%$`U.c=@+ÞԦ>|KNmwOŎP5GvLMRcjM׻w 9h_?Jzt4w7 d= |aIATJʲn,4G(Z˩?҂(mXĐj0yO>;$G(|t-ϩk [q}O^dliXi] w*,5XZWA<}2قSR;Ҩ~hhv#f3_Eht'tΨkf'wҍQ=O!v31S8Qp8~NNxVgY"-.G?_:'mZ{z>v4\v2@i}cf`xGڸД=,[ Yqm[OALuX0܉睈9hJG1$uӧ}zOn>jf .`cU{-ud9 1g#tf,Ug_'liJ9rh.(sCgKm qh sԀm,I1mb]z\LBu9al /9X{!*(~MhKtH/1VʾStQ;f/'L^-:L1IU822FwSI fꪫ|a_7|XGk$w|KL9kw睺= r^|ssm9;hOsr^>7콑6Ov/H.ҾS꿧|ry&>2r^?we6kAϾ?wL 2X0wIQS&sg?P%9ϵ66n]ppY{T4pO?AgiJ'Zt<~xF#'2xb͝W6Ld˲hoN߻)|.|d*`rwRqmၱ\Xґ]7)og>h]zwFA7CͩwS& ]Ŕ7PLM퐷H J* 3ZJ,ڭY̱W\ [Q獠kd[".x.iCi+̀U2r _! ̋o !wXJ7?DgJ*(uN\u,dw <\.GG"9!K4K8_f2L[@1hET* +NƥUحJٵr$,@vWlu?TlL265Z5M^ IDAT4+{++"ɲޚ|Qrn|DoAdZu!TLgT&"񛵄UH:= h''kòqz5l0.>#9`]j 9tr8l(;DLcT:hUﲂXiHRu9 j6߻.Hޠsv݃!T<fvKxTͣ~Kߗ@pVwt>y\C]\ $y˛F9-6&*f,@VRJYU&?1(A'&ySzEy҉wiv"]ޟ78$A2l# ($(y8@7q3 uȦYx@6͐''ytfHб5KbҥM}VHP}Q<8)._og7]=)=m~y^Э{ABn]z_o urW]<򰋠z1[^is@}>!SBTR`_o;u;v|ͣ3dޭ[W/_Uow,"dM-~BHxl;bʣ7χ 9鄮5;򰨱m?[wn2Oqvx/΃cȪ_~fo_|={Vy4 Co^}y;|ZT0 y=|Z"խ۴ieƜ|pU)dDy4sRg-cb~n= ?Ҡ0ݱّU's>=}t0v膗:F\7s1W3W,Z=$J4O/zT}qݻxt/)- 顧WNR 5;`|{?n_֟f ^ػ{gGV%6v޽%xu>-@zɕ8'[ Z\Kf5 aE3"lp1tqakI>[hMVe5k^x.*^~{fõrH1f,vx//{5Þ$,(*2酝Ns~oUKg9 UצGږWe1oғū=bm$O<9_CFQR&zx*W/韵s+\YM[V9|W-퟽cƨ+|٫Z9JxdMFxb@++$|jř& ciѣkͻ5uŶުI pދP5ﺳS["Z K;<oP4 qrl'uo ۿ 5N)`v:] Wnc4[{v~l{O&qy~6vUG{k>54۬Nmj-ty0v$~Ml{N?7[>osɈ~dIj$]h߫ޭ3t绂j ̅|Ʋ<H:o -;|2GfٳGtljR?i$~o}ֳ#ʉsғaJl^"Qnf~;k ?xyy'(K2eP#"gU{ouf#w~o7A__SV~z2$\ռNmknf˂jR,D0b*W| B_S߸#Xz 䒨 KAՎ]qUwIX sxÞ'>9J3+.S0Y{sh^ʼڮ,`@ܝ(f3Fkʿ> Z8!&GZ8:G^ MKަLpE N3?HެM07W"0ip?Zb?GX/?O3q] o3ڍqJztzvt膸%(z*'2dR]<+TI @* 4 v( '@T?= *9S*1gP1l7Y6q~3q7-hY)`\+J [KIܳ ՛~(.RmօGԊrc#~7׭3Eޫ\X]J8\ KD~u yHؼ1F:?+Hؼ 0NiwKqF8po^ Ϭvegc#OokWjW/iü\ FY7N/ӝMi{KfѴ-=vkdWOi_xf5Kߧ;Zm8_,T~莃&=w0` i޳E 7)NsE]eq h[\;wd:\²md4هtaՋrN;Y溯9ߵS}T3v *R <9P̰uQP-X\'i[yp۩ ӵ ʒe{F}oTV, L7AjZJI?{GK b캳<$@P%AX;08Yd-VFj|l$maRTi{N%SxJݽ{rҪ1kfn6cNԫî& NÏoGG{L ft*p6l3ηITڹ'_^#f͌BCZVf?ط_8ŏS6o 3_(7}=[5ߊk<?:^ɏo%3i,4Ϊ9;n=9*5͝[_zxVy¢3cOahX.O~)/QuywPl<06-ѡ^=9Q;vuc̞^,MVg #P\{wwr:=ݱY9;cўjK۪kPvrE L1+ؽQAu f3<>& HpwZ/OԪ߮ (v1c#]2Ap !Yo8Ne P?M)$/咆V +vC|эZxu"Aw^>M0%N} {Y7.\~mqZH,EOnooi\Z۰acѻxd=G:bX]Ѭt-~;ĘǕ`YKGݱre9q*Gh vsl`̖Aiz\K뇧*֮O}kêsK@kѹRr4Ac"::]=ntt'(Rߐ* [$+ H .~!߼Mpőtgs ?Ob|JʢN&2]:9K\rb0i@c2 Ll'ҫU֭8)s6a@]w+zqvҪ1e'dJUktIE/=@u7U=Ib2'=])*^GH۾(=]%a)UӼ;Ss6P4 +Ź Rbl)U3`fUK7Yp /t]hVr} FdУtݿ{Z&4g8 R凇h'fޱT-*yqU3F]ܼA 7{E%$Ox,Q˨z;I䞥oxnz2=!'ӊE X<Q#cc/23stI*49&ٜQs)c#^8GKu0ʏ;HJcdYCtaC[@d*7@~yo5ʒ0ںAh_P>Ba0/ud)~~6ڶ_fNRŦCXzNø;QN4_x䏋={ƍ4ii/8A%A҇qo^@NƇʎJ`eFt&x6b {r)4WhVY<:5²Wo&A^G N4a9޼G+]"AAa8cW)]|=nL)`G^ -8i.Yn@EKR;):uA`L18<6'PRH5:FT•>LcVCL!D!>-PYm" xST-mPRBL-)N9Oq:R| #)(NPu¥+D,qOO$[<+n?'<`+QNI -R&Z$)LpK4V~mvjeXey%R&kr?@}>$ Aw|޷4C7ÓdE)Y_ o_6?2LOXUDY,]:*9:VDQş~ 2eOl6j264M{mfm)s no/FzVI w-ߒfb 䈀g) Y5>iߪBŅ^;yK[&wj66-Rjr W(b5ܴn7~Ѷ{q?GVSwvE|:Yg"x(d\?Y$; &J8`-czv=Q?KWW#}38xrzQ54RDe5QSkKw6+ l@b0J˜L\vsan]M=ᝓ31*d__5OJ ^P:35r fNXՎǮ"=Pn}{ @AzF? !5 .ƆU+Ab}+WP={ !$d4&Kbtӹ=0S @9b >zˆi' !Q9|^}59]eX`HwA2YM B&eY2@m~K+1@}L ,]ت#*AYjH`QJ݅OQBEZr* &xqO>/VLdVeR9eH<5k(%Un^O+=ʴTm$ЭZyr/9 )hmU]9>Gfqe>MTCتi^vmo_j*kE*-1ff~X$J7Gfqe$*!lX$NDUM H+ߧ-i֭<Uh-WL1J!$vf4]wW?XqmoxҋONB\[7碤" zm!/G0Q['Y <&P*=ɕV^/Q[$L:vX؁ I c G1@ZE'd_ɀ:A 1gq H @N.2bJqlݞ[W\i*K*YK.(,4rhJQ X]W"p+%cA e ~K,oExB,>z1E:u|ܚs\0($R qNbdxmizG}a 0GcHIANU Jt. \`R% ޙHu_{AGq˱s[.:FR"fNK;q=N^ mhcR8=1\qWOm}:ucݝWROO'~).&p|fU9R_ XXy)I]5=8J\ݴ{ݕۓ @Q%qm]p[@pbfd풏_}UTBd >~O>v-h,ªs =,N|/ڽ^1#[ӻ< x*N(xu.dyrrDd[r^T8K9g9`A󈿂r)@]&7gZoC8X2_ص۾wc]<~zfV] E^ǟ-ןf?4EWh=n@\"%Z6 Xֲ )OIq\Bi)hx/+*:'uFlG~2 v>73ʰt7:?JJ\`)dVL'l, ɼ:]YiJUIYjh4 "蠮N|7Yt5=)M|X InE"ūmY+óB\,}R .L8kI5V \\ 9}-͜X̫KvQJ^eY6P*3n[8*ܖt̡pʺyeh$=鲙C_/ʾyeSŗTQEӨo6ai_peڠ 2eEK+l=#QҊ4`0gSo<=$1fإ6<)mޚ!?4ٲYODSd=;dŭ4רo6e5Ҁ #;ߥ6|)oQ2%+l=1Y>H!S99>\9O*Ց)SSg#e֋˧m(G`J8ܧ_:f骳cTw_ImԎ00S[%)o['`ʴ,yIDḀ %)PTw6\aWV<#n1c澃2bq*ʔ W-~j*Q}qGjr6KbJ"eP5>[yCaO =p_v(# /*/\l/;NM# .1 3Nlu7L Egڮ<_rV(,;0ŎGPw7'NnA܊X}tP_~țZvS/*?.RF0>ϗ<^犿>LR3mW ɉ}|QrN37LՎwf3qu y~w0@n XP ~2?9ȟhK_c9-liG2H<¬m;$*/9FJ (d=,eK)1֔y [;`L8-R,{YYHYU YX-W2[:I De# uDctĹ%O&heE#yÅcYeJX 5&jм揟0󩈏tkVF&@BW_e QQ)np{˥#ߖk)2qdrt+j{kr U'9yڔQIO\Kd 2 ts3P,:7HCH+q%I=W͖z},}} s@EMZ6©ֿmv5ƧOwΛf(*W^>p*5Ҷ<^aaˤ!p!E Kδԭ;E}]?HDEE}"6 5YSl{IɌj=I~ˉ>܍c`o觑 qDO!Վ!_k()RV87M H;ƒOU'fyH7pהA&!43Eie-JZCs:%MbQV0\A_L>Wv;>}̉$ǀe Y1<٩+P[ejʼnxpdf~DZ*?GIJ5܀Ϯݚ5A볚UkɏKF`lUkUM:RA%3Us }#idj9+bH ~I1!#Ԩ:G/ft R)1xSDmŨڧl+\͞*I2@6]Nk9ULtPKUL469 Z1BbVV]j?DUo8ӱԻ+ii-VbptDj•0fdb9g2UQԪүI?EjSQ.DU1VϹ*B\Nk7>H?fc&%o*{i:$kWl+}Y*|`pL[^IXVcd(T]1NczEvPb1h0TdDctQ|Ux IP:4¯x ITL5:+7R6 1A";ACD4>'!(6 T HCLjYղcD?BFjU19!^Gmy/ek\\ȒJ&-7`rX\PD $U;\їf3@)*)L0l"`RPR`8@ITx"\!TJ4F !;"ly'jW~LiSYeCDžk>1R_?aկv3 q;ƨjW-j hC5Ęݚ3ZxL}FS_ (UG0А!//j(\ 9=Fcq?W Tc0>f.RGQE! Hudsy<â`8\q5Xe@_.e8LvnQU :a1 O#Ҧ0ƤBIA#*oŇ⨿`¯vkR"I"U #Z/ia`3(,+on'ǫoI\Te+=8TY8?V0wl~4UyD[~)4 պo~k}YpjWϚo:ɼ6͜ 2q qW7mӕ1c5 jmNHn424ba!OLpUv ] ~Lds$<(H_xn~0YÛ03 b{1o̴hРaĦHf>~t=n3LpxNt `Gig<~<($r (Ӯ= ~7 }3t{z=ϱAO? j3$'KOώWTbQha7ÞQEjM-g<Ϳ e´ہ!7˞Y}_  ytq/\m{9 2$,szE&0eՁB"C‚/^݁U*_=;pyHGa<{~^ 9S^<~?x;"4<ֱ%jTb;}_ʨ1jƗoWקc$ YԡC+"jQHzA:JkgJקmR(5)V Az ,6dRT_Z,ybwOB*Hr3mÔ\"ťM4>^pa3,vRB09,ThN'JEU^+RTEG+I\>&8bpx<g'`3pHJO7f`7&i/Mo)  T8.ݷqE kH[ }m*}O7kDFz=/ p-t'+WfFI$t6Iu>{lcFYѲ< ݲ:e)-pQ 3kø k(;h8c&MUf/DNZ tk-<짱?p?ױ%Bg;v̹MOkwԀwC~ǏsQ4` .&LQyd”f;N{(kF\\|F (Dgkʽo/3qu!rn5B2?`/NP?_e؏P卟}}g_(jDНl2hO|}nʵ7*>66oϬ L40|76wϬ󢁫P 4`p^n FkDYN۳le9Y{FC|9n\3Luu3ϗ0e wZ}|&2Oݸvܱf/Vm6v\FEܦ{u/YUNh窽EI`œfcھ:xƧXqϭ*Xљ4=OFaBARR)0)TƘ"*J~oma2L0luN)JPP11))@a!Lq*i(PQ"r1h\*\&Jerb`HAW%ק>j8̹ۙƫЃo) GU EEƠz"-eaIT_~|pyF0$l`eį!̆5`fv<8>!̆5d( S޽y.w6Mg,4'-5 K쮻ƒÃBO 10F ~˱8㷞>nxcqa ÃBT6YջWCnm~}=YgM>6>daA>vDcgY5Fx"(>1̦-{{cQNo^y VVyx,}Bȩ ҝ7`-m,+7mk G?=nߐ _8tl,vnRψ,ya-'< KtP˗ !7KwQ?֟#rNm8>>ci.^C>5nGek9h! ٦CXt4wQ>hC^@;, SG 17î;!ᑷq`T ߘ'<2ydH1/=0<2ѹ=lh궛FXdȓ˧r!g:f'7~!A 4sXsDiK@}7?5k BNNiEyihxd?C< gGEn6V,s] x_z6/:"P+fۭ#^"$:/:"h!GB#^?<7ԒT`0 !WM]q^XtD=/d~ѻ"<<9\׈GCj<7*: pJ:ŋZP^a7ݠE<{4ڑÚaթ^zn,;gw ࣇo==^<}|lR3.sϟ~tiO>ƀht0Um޶RE:A0Yo7֘G7}=zMs% $e@}Yn<_3uDH8_㯴XyDݗ֑KA o./`0 V_AUWh!#Cݦ9؃u1]. `m'Gԟx8 IDATqB67UZf/dű3(M TX |Ýg<\җ3&Ćg(od\v:C"[AcTyMz F@􋌹LˇpGn\\zu= H!NC:翈U7O΋ !p5x_n%UӦwuzv9՞,`FFMWFM{G3{Ĵr3:o>˯m8zQoYR%x+fz9Ϳ#=OR|pv.;'Ke&Y_9vԔŝiCd_qݯ[ߴ+W$pki#{V.XXQ\ۤ Z^P5⻵{hyC->2ߍct)=$VhyçEzvvų(QFp*| \[Hޅig=WW=D5}t}+2:_GSzOフYo˨ 4pJ^Vpoc~~;RdؿyϙNڹgc)j$UL-;{J-zɰ)?[ {/ےz߿5q;[.ܾZMGFfɱv`p TTwpfd| urLJ,BUPYg-qT{{;ZrE lӄ/`[8YB~R>0Bೠgv2 7Jɧ ΕY߲f:,WgS@>3'.fh h̑ {o{g_O}QT"iŽ>-IK/Ԟ1C^FSn&3i"m]V}ol6΋2Mھ77wl}՜_ E¢3cOahw@ٗ7 RH3^Q+o<065ѡ414ɉڱ`j3AʳF|Ĺ2ak-ϩ`§;=;{'=ӉK ڔk8ǛP#qe̝7`w(yO<=j@d6>S|| Z4j|h~8ЌתwrD ЪA3,"JkY> n6f}ġ+ViN~w./iH)I{Gjԃ_N*LBP}/65![E-: Kd7cqr>nw]K#⤔,э${Sk^[]{Û6szhmxd86uܫLI4~gӒ_زӀʷTu-qzxHtF^fkG(ErWW7rQ` s@) -"e%=X3hQ1@:[B2>=;~>CB4i7#bSb诋&cos雄Էn#y)Y~]KHK~yeî(= L<"$恩ieU”+ũuYui -kO ڦ}#u{Y8KsK'?91qXZtnEYtFz4W'(SeI*]B0UBx*c^z0\oa>{l{'knȒxRӔ1+N6cK;+I\Ws33AT<9akt[ߕPyq׃Wmeu;95gcH oJqnfFE *clɑY$?RL@;1I![LV0w~ҼNn.Z3!nr)^LP-UAȢ"D ,i sllQE˅8yoJ(,Kaq1'DQ7yM,Չ(?V#)}]Жȼ Gg;m߷9.DP )u>32MYٟ߰g:>f̕քZ~VIW)rG\y IC~ۼ2e̢Uݪ,=m:9k}R+KLϥMϴUR>T9YGxгnN$UTÿ7QL*;*Uљj}ϰTsT RV/5z 9:r"4.Ies1EPJcBTJUf0mr< )E Md m bIb/%\~o@7z)5Ҟ*FͤĈ qDc24@l6 Q ,L-4*gZ|PYL\C6B$V^xb}B^>}yV{%jPePt\*tK[]Էg+Nf`MMS#ƛRJe DR)e*`iɑ(hL&].M~΅O9P :J)јlahw1LD)Tzs3Q.D&I2X,`hpeK PąNL7z8JA*D856.\t; p';25Gr{E> x9YRb)B|Z0 K஑ = *~R8 JJeAUlwHƧp9y E0(QPn+.6I VH" N`+Q֎u8MHOU:Z W%1a+F,7ZIKE9!ioڹi&M?^}3#iLÓd%GY_b_6;♎>&(GDa /[MCYSsϸ Z2S'*Xv^lpJ0ML hgxSGýyqB>䗘+fEAFKϓOtTEm2/ u&JAb؞:t}2T:[莃'ɼURDHO/.GF90ٌ4%m4lFBE@I 1.:ޱsy{^5|45u}}/341" FT1E09\)\Udt Dɤr%PDL.L:ҷ@rNGGvۥgv0hϬiq-RQPdR&W0` R1<aM [^E6tҼB%;A.#1 mlM,T*J݀ú$tVc 18l6  [R*LGw~ʷő D)dr%f(tfg\IiDL6B* Ѐ@091 D6H6SbQx I[IW+>A~Z gkH>$i.BF.D4y.֯yCs] cJ&3R"{'I/B^b Ț'5G qݐeZ7g1ː^*ǕηWϚO/u_fqUWj!}[{X M~;AL~ľ PuhqGn蕶~ƺ]1g]V'eǎ;{eODrzĥB^ S}{@0y,P,n6 ױ",PÆئ] +[)RRe. rv*Ғu0Pa4 Ӭ4]<8PAݖiSeR4b<5S#JI[!T55b5U!95gWK.~Gتq~XY .!2а}\1E0Zi$:<÷g#Џ"ǘNj|>eG6kSA1QG$J90xL&PVxؖSf^5 w fpMLnlEzm!3.G贈A6ʵxR>,=\5qRwec¡$ I IIb}ʼw];k´Ky J&L!uEbDPJX,%R][ˆr}B&Q($I%RLX,+cD!SǞIbRЂ"g9~%qޮ,J}>D 1(s2I+WKB! s:tLJªi3N+fnuvߺ11ɔ̢I0`Q7vt\)JJ@(L"rXK7V=?xm*K* D#:R.+RA"XLnbE[-1*D"A(\*KnˋyMR8'o_5g%#>ϧj!pU3 #Z,jnJ(;9'X~;Ž1ZGKV.m^ jRL,f ['%vS_6x`ˑw=>k8fm,1z]m[WF\2ڭ{#纺byL/]=8ʕuu ~>}sum7zzk5own $z~@lְuN޾51a]-8oШGFnϦ˭.ͭ//]}e_LpBG:|n!U{U}Zh!D@X@AŊ`Di))bHQDZH BQ$!ʫJ߻˥aO^͛ٙIWgxfk: ZթRs̵åb}v%Fz_rlyF{?z[_XHuUw,Ýլg;C PwVk7 8-sp{OxujOrW_ywשZۖ8}٤nRN]z |3}uct{A.{?Cgfe̠U߱[Nw<:}n׻wXEY)59O- 9\]xynZw|j^eZeΐRzlK uYb>"%nn%HЌbHҵ-&L!ؽVS礬/Wk/]EJ)u !@N14oUj I[3vLJ!Wۇ,X^U׌ާ.$@\z*F^yz/ |CS3w]uߌ,+b1/?]q.7mxrܢ'qI5.n٫^nAx"RB[ffLǽ\DxC>hQ&u*W\1w[poXڷ}>c̘˾ yw9-(Agը>ywTX̃㖞3_ WnӶ /^U#}2rTu<%hptyge)"IK7|4h}yӎ8qu44^OKM=j. *亏YRU.e)DI E(>|.1&n[g׾|\L^9}1u?z8{FJ:myOZJ |3~Eϧ} ӓuɰM+^qʇ_H≾+tuoPyc*~k_> _}eS?%.VQMδqㆭl#9?3?c@|x4>kPb;5sHMf2cI9W߶ywoƀqϋӜێz}L>Nɲ嚌ܸ.,Ɩm[~zŔ1[QHL6jY>IGo'O<ɐЧ5HUklx Lb *@,=SE KB9bqaP@%@ ?RZ]u7u2Kph,hh*DH_4rB倿1v~&HSJtll Pn';?ZބZ]>Y.aʱbWT:&S[}}IFT_cxI)t{xOnb]]&_W=|+֌ ©)AN52F "0±}m39 Lwp{9bК1T–\/~1@Ϡ p$Ȕ F@NS( BAR"2ES-QƂ})Ǩ3$0=0/&ox)$ SD:smIޓ݃S=8x;c0tbˁX h4>5I81C"^cha4kwt!ghmRfD%]y=/F)+$B,!ZΨ@-VM3a FXepiQdj崛"Q.@ ˱53#Og[fFnh0zO"Xl.%F0 `#  @jE&֦ʲbr٭b3 at.2aDǂ-;JW!6r3l\\([2~@-rK\&JV,5M>&vj;T$vteA)dtmb@0r)w!`Cd5q== WP4UNK( Pq%RUt4TT=?A( PrvWB*VU*$ ,O23- Ψk/%AEU`( )UYuUC-gD( wB/&Y꧂ |/u@*blB*bGetFO$i`-@_-`5$5H4J0R.@ .dRx~0!AZrB$"׃kaI@Qd=Q2 r*]AY2?Gr˪#2mxӢ i^ѲbSh/ n%([lJhtdͳ9BFHV9!MTRMEֵ$7R,FwHA.P0(/hfF? U7B=< &1J"QXt_-Jè7 KS@dI(*)"P{䑨*T&QUP#*IE_KU)h.\[WD=AH,ky7(d >ɋ 4Q 'Lߔj&1"s[ւ0fmۤ-ٰaA3 t< ʅ$tÚϐ0*e-&ʒq<20!D̹@#.7xm #GgRċBb߫GG:/h,y'8Ic x0c*V$7RIǨx( IqdzDy{dhHĠ?˄ԁƺXR:j6Z*R,PlM"JTȺ"e-SL P.-*AXo!M*oG{Ѧ&0P(j5bXJn)XE|@mX"ܻל,s UbHF[Bs@dPNNVwȁca`쎁| rP[0"5`H(ïzvΣ"C AnDU3+ˠ\5@:c$X3ZP'f~QbЏ]2Dž92#$X=d,Z#x0[jgyE &2^^*yLQ-܋r; . @DBHK襯ֈO(ibS! ֒ åXQZYSC EMΐJ-q岲oOU$J"ax1!2srDɍD6TWw=l\1QW(P! E4-7b kK!%M2R?X 6\zDVo`eU1˪n70*q>ܤ$"e;MFF°C+0&/hFJMtc2Bhֶ55?OK,cjsaq + raCe/3"axch,+aGU rPڂ %ԥoBX<)6-::lS"J4,?Yj8exPE75t|n}e=qirG\AuݵLS?u<ֻkMM߻AhN1K@p QV,V<%T,FMA·F"򍐀3M ?pPj{QYFRd՚uzREMA AO*+MEDUrNVK< o| %|eUqqR,w68\UMnMFqih4FsVXGUUUUTUU M"+~)‘zh4 C<'4UUTDI*0h2zq&g}EœLFIϻRWB%QUUE,EbY %QUE)s0bu*On(UUTEQEuhlB:A+:% :;CРv=ȭt&Kb@K$`( (A06[,?l̅i$fO0︚wyK{ÉptʏO{mה"MXp=9pr*xCĿI)nλzTM" K?G QO[xhAH_ -bh)TFAc6VlUPl6@{YV(EZ,EGjs(BszjXEdx,8?aFdYrA#\P(DˠdXm:K 'axGdba&M@uPQAA M&^TfҚhhKVv)Lx0ߍaYA:\T/}є^ IfeÃPJF0N´0c&@O ȿ>>լnVQ}P8p`.Fy2 XIܘЪ a ~¨sV"ѕWms& +uW`qAw  3zq;V*}f)IH1akƢ-ǯe-朋Vh_ uxw͡Ky%#iMIσt9~=3eKRbd{b댮PlOzvEZ}b\=툎qr`y&ut'aC,y3{I]}R)<ˁo=kgg*뮛sLo ?HL7[rs6=^n0/%L~&˒kcmo1[.ier6l9iw Bnº24}GP;#:z&~vh&؂$bH~LÕcd#LKF#L7,GNE_mDqg%-3cYhQQUUEh2ktH6y,l(rnMF@ aX eyU۳ɭ"K("I69F]6k! V*H| :hgZ$]cjvgO)ol1^Qc#)$Ɋ(褏xVdYzH-)hC?YPvʷPkTQī)^ϷrµL^Nhkt^ڥSMxMRs^g@Jme;879ަS3ǽjd뿺v^w|=?ݺ~P#֍( }?l=/r\5SjC*c8 }گu˿ޖ8 뻗/[׸6/Yj+ȧ~\rŊ\@e+rݾrkVrٖ_,^|8\p-Ywn556hO!yƼ^t8nے'_ټdxWXK]+uzs?a(:q Lͺ6t6IeMۤ_QA|?t+{{Fx_mHEW m'|K+Wto>}&tjo%FruӒ#޳o]p4rW9Zx@"P*_Ch /f)dDj$|' )EH!_~CP]*<(VcM*Zyfbs{nx^CEp\#yG+tTsBhY%UUTYd`\BmEZflBUt=6ŦxN1yd2 3 }LeM H M~@&w ?xG &8&A}Vn3URT'5Z$킣[7=I 4K)lk8&\R.9ILv̠b{B|:?W_R./<ݣkԖAG5 \pԖsLw^oDu$ٝJ "QU|R5P߿`*֐}wc4iCVܪWW7}> K)e|ɸļ48z]k|bFrBMppS(:=?ۍ#0J԰M"yE(|Lh0j"U(CbzVh TUS@꺢KS@hP,KPϝ!;_"E)?M-/ ˧X8UTdfh Fh" bqax"I^.8Yf %G{gSUܼmɫV$[<:"fзgmYΞ>{RsbeEaK. ?u gC7D" f/|!Ӊ<˙-enИ[v5BmHژ,Ygdws.siO~R.gKʐؖNxdb*1T_c[ \s<;ҹGwT5&Mbn&[k1[v`k5̺a%y$$]zriȆLNqF$k׾>@ޟ$m5gKDvOo1\K%wgnHnaDTd{jZ\Xۍ|E#asS:?kѝd񌠿[DV$l"6Bt/QF™-(ɞRXA[8UYFY"q QatzȢȩR1!Y0pBM%yKShyWYG yeihXJj_= axE,TCsCQfy(`\H aXq0N,4E^Ǡ,7DUTr,C s%IEU5Ldy24M (Z1D`Msgs?g<^X98H^?qJ)I,?ZZ+(Ֆ ~%:~Įq$H<ճĥ:A_lKc & 9p En<R\K5lȶ4ctnsD.ww<15cZ1@_QOA6?pDES=WN x󉒶}RNM,•a,ifE뒎֩.q^uh3iIX:1-׽HS рc"I,CToG;"ZGYtEI:`UETu}VxNg>*k>(˄x@U !*MVdopphUو9;:rVD^U měpnD S H8?1ĉIv1ϹI8 ?[ď/"WOwnwz. BRJwlCW7*'欥C ӣ޲//H@kؐA-TGG YVdž܎pjwDRD7d/Uk7 q͖mJu*2p%hHbc[[ ŖeJu]p0\b*&^8ni]s3w!^V\9ѯ?Pէ{c7a9ԙz<ܰ_)@}73?61ߪ`3q_߃k~㔶coRG'Wl>c|5_0HIK,tQJ<.nV)V")/`c@*Ms+!kWk(|e* Ej m* VI {~ʢM]刺",~Ǥ*Œ[B{`;4' ^6M/~ԋI=5wc^?1IC?z17h qF5!s]@Nͫ^2`j/>ŷ{×5knOo~xc/ķWAZռkOɭƼSC,%I&U\ur.n2sgpSbr1z¹p$T}s\ɽÔ;W?k_GwnLm 5:S UJv%x+L::ŧZ󯻎]1ut=ez6՘)2bw,:%h{=,PG?][4.Ajpͯ-+}G3YEw"q-;eHw@MQZH$QB0iC8%-ke9Z]N P:3 6SKY-qb7:OXar'G٦f{_~"_{70tAi..aޚK{5纎p*=mX~S_#}vQ٪c;0qöˁSg KVR+^zj{ߞ?W16{vȀW{/5Zu| ϤMt73 #6#4Lv\'3Omk瓥Xddk<ȧڻvOqOkzop0Ko6ayDW oP 郞[8,9 -Mڭjٺe G>p@_\xvj?uyÑZ #+U *[W7%X"0@A7pCu[ah :hrB|+HdL a@ȁQzJEBZ Ơ00GR`ܖ5Fs:BE fD1-W!.ylvC5۩=t|}{NCXiȻeC56H-[@= _8F hjK#Zr63{RaA-mG ˱53#_a 11j5"zO"mz,Wnh<@.Kq,;(< .)|1CY#Bf| r^S\[AM"˿!=&(R$0WD_c_(z!NO(\H'a!FK0c~5E/4,MUI(D\ e :#MUe3fB+EsG*@nF %Y9"=SL=ie-$bvBWCbfO{U)%HضyY+kE#{:F&[*&$VOK[T >1XX ܲ6_k:"#t:t'@ah#m,ѤēRG#B~S K )$*2vM@+! ! !')BTBTB]M`4zqf$d4F[O(V7FѠ P,7&thBpz'hs@ӳBs:h4y3XX\E=X-n?+T['1Ua\KWJŘ Usa8O{~|ˮ#$~jqek>_$&l^5s-ֹմow$Hp䧥toޟa &ܴdc t`B▕.?Y#L2fɶnqo񁄿Gmj}pd]87WE[:ˊ1.~D{DFn>ៗZ_=ƬeC~X~Zk^`M?`$r@ǵ}mŸO`/?X6\WdK5(@ \'[#߿qkrD7jvU& E^o[\ŋV_0g-OVlzԫg՘eXP?쿺Gk}du}͔zp&ꞸW_o8 4AUumd*r^7bM!ßo`c`.(Xf 9b5'z=G)bXxZUTiN!P$ 1(ZfET 4lZ"2l~ߥt’odzԢҙ 4*k( hلn 5tt(fg8VӖIUv}gO<+[Oe/|륝}#gNkYNn^WawǧNvk-=) >foD>AD3ZݱӖNu}wܔJg& {esSoOf$85-'6/j[UmǤ|>(x!^ʌO,5yv~ӱן/?*՗uN'=>;dNFr)"x_wuKH~iEo<`.kwj{M0;3‹<ʖ]^|A (\ѝvʤTNa'}}v9_+W1ϒK-rygvVff]\ W'-ȃ <(tC81[{QꭝS# *^%T>$8{^E3ƱlMGHGU ,Eg?],8ttIJ|C>8kUJNoK;.ݙnkg 2azfrEq9c\3UwOfd]xه\3}bϬ%7Ofd$]"?U98G/.  aMA,(HJmwBc~ [^!oo,zi;N¹NFQ+q~:f1P*ͮ6B,QQ%TEV(j ٝ,QVQo,CAU@1 -(A $Er 4J~,J?!+@(_E9΄.t hI=C8C)hE!낽bɼii}J&3DP̹ie}YUs4Kkp6eך%a}YݝulW㋤A⯯yq"\h|IAkg׬kC㼏3.9}ƦIΩ$Nrww^`KJ{>} &pqʲ'6>ۣ'i||㯯~aX=uӈ$Ϝsk7Xkwn9Iƞ%dn}=-☓)6y.8||㯯~a"\ v-G 8✯$]>ؾI),]Tƒ0B>ww^P_q۪qAgz4Z6M?5ڰ*~-|\|9eYh|)}.Ϣe92U''Yc_Mx5/.{AKӖ?'{`.'mDKgwuZڱmΥH'/|196P=J6Y5X9[Gc//;kl1o<ְɹ≟?@WgkЫ۝͓MrURk hSYL޺@Wo|o.O'm]:={ߟ+O/oa7_U_4/|]0sy瓄] --0'#Рwy|jT IG/JN$$ϫni(OnfRyɔifOta5yϻ~p {n߭ʯ:;"Aʆ-Cn V~y&ݞiMUE4ck~᪹l\ 9'HyzD`Xt!tw2kea|.$DfTi:axG" H*!vAF PEߓ3D(mBQ|QUh*y\&]!Svt*Vx}7p៚e|OhErlj뛜{i/VmzOv~D򗭫6`$O|zO댌|35W}J;|*&j|~8|*ʝAA?q(qs owW o}0ϵrz3_ A ۡkt#tn\1(yfzF'K7w}̂=f6qU\Ygniyp3yt'AdtJ7Tk^HŦe}6'_ӝ#g?˓w3gd[GZ\ۿ4+Qoi*S^c *㳮]#gyDz{Hۖ:W?{{{zt[wygWiӼe.<HH 5 u-2l9D჎ "h[-5NiIMrչkڟiHL]U-9WZ霸 c\ƪѴ*mU(0>ω+!V@²C_"kiN"U) B;_q4tZՄQD4hEZfs5t2%fFzͬLJIMḪmqmx!VX^ MkhJ)% H+]3k1)M\~(>g⪂@9nzES'xՇéWY>IgDUBSNSՕO1BQD$EA@#gU^JxNf(dʸgS] 4Q DIڟ1n.*QsNݟ8%sڵk$pns=z"҆>`ռ$ wZ0~|wpO:|$nޚ8qmGϮ:r&6k3o~ R_jƮDJ^= =peHݸ*I%}%VWJuqAR^I}#Ϯ|sڟjfF~FϮpp['NVڸ*I/Gz7ՓnpUWg%P|h7QTٞ[T/t "Ȣʖ8cD@M5l2 x l APވ3$ $!tNoU]U=t_|ISsgܾi&g=,ͳ&mIშ[[lsnvLWVT]w6m;,]iԏ%Rg1̡eQTe㍙Or rWg札KlvݑPrvw۴s/=;--ݲj QImU[0cf5'Jߴ'Ҋ+N8J!@ޞ.vggajwyDR%;MЧj-&pk:Ai"Wu=Mъr`eҿj)cYʳ.oU؁['UYjޛԕofWC'l򃨜ofAAe?b0Y -i#I,T$oeys+I @![, 1lue%mZw,ˋ1FPHp ZA*&<Á@,=sD+c{K! d@H 0XIbH2 T0yV̾9G|ITBf(+$ʥ\a̚MPT^PU}/.Mr͈xcq'C:F]-_Nb`!{R6b||#W ً)#S:w?ąKO/@s Z vwx\~ۛ)Nk郜tѕ{vY~N,I~j0jmY6>샾N̰7M[V49/.r1,7kc+V1 B:C{X]Sޅ @,s3d&|VRLIw5c\nKnˑ:tSAtTiԥE͡ oΟxS\y9G# dڶi*FfOv$3o}td+xUҨ6W3%'|"Jz=mtO6a& TK)&-ß&XſNO 70}C~f;x,jwҜ\Pɫz7:jfzB}r~ %i/yakΥWjc[7|:ַU?,@ٮ9^[D-F~-%IJ:E`0ô/?7&<%mD74PY]ɫ^OGjFL7nM 'oрb}LNAJzƯyH6_; f J)&[S NKĭ|Lb;lrB4쎷^)b{J}=Of-nؒ{.V$o-;˴U5zOd0p|D9p47n"/./qYi6y47~浻|秸=g;'ܞ"@ S)Ϭ_E;6Uݞ**W U7OG YĽJuFBo$nD"\dOM4$#B(D<c2 4/e$\ -E0lU0ʣ~C=iV.-ڡesv@@vkK ɮѠ2trkrQxݭSgWĢ<3Q܊C;y/à2OL~iMI[r7Ws(jsbwm<|zi{.0ଥ?}}#ulq [d=XOR^ Ec+Nhׇ~xh,[p"hQg8]N8k.1ìo2'& .b-C'_qEogٵ pС^X"]vh^qnL=që3p(S^'Ra/?meMcb  ->9w=B\Ͼsp9u\ﬗaU pBn-F-/ <} Z;xho*s4sG?G³0ֽX2LAc 5(b=sssi #~=ǡҿWCSXx vj/nK-P+CIb:D~Xn5'd_ڧJ&Q4u 8G͟\F2$%!PP :fقQc&'􈽖@ߪC+w!Kby~ m!)A8;ҬCvBwrDy}~d| %|uj'aˊAFp}SQ#*+;=Q׺舃z̊W_W3|"I?xJ ֿBW;2AgE<)-WWlP=@]1:𸪯Ԣüo&+3'[zP I,րj9HBO *' :qN<73ÅvcV$&̞O=+"l.nj7 @1@ |,Pa6]X?u†64LƘW uu9uAk3rCRμF1b3a4 V[aANDb\n#o[+|!nMi"&jCBZ_CCgM{2? O :ݙ pž~kzғg;kn4K>A݇MIDs+B,mm QDWNhS Yq G90ˎN.n0Dqn~.]76Vu%yYIENDB`glances-2.11.1/docs/_static/sensors.png000066400000000000000000000373751315472316100200120ustar00rootroot00000000000000PNG  IHDRy sBITOtEXtSoftwareShutterc IDATx]w|K'@ !PB&A4H tD@AT@(HPb!RB yݻݻK<<zz 8ArAtp-A. [@2%ɮ Y=k~-[9"7dHvb3^{$2xbHY%ւ$%9a J(mfLPx?FoB&R!)M|@dy{%;_U.d>A[ÄȲI)ldھ)L\Ļs;F# cyo#j2 ۻxP<ؐT\X$Iڽ'EŅyAuY ^lmAQ#VxQT\PŃ5.Z곂¤k?NozQQ>v05|則EEY<(\mbyOʹ@8Z͸ɑ50MS}N62ew0 ^,B Ra<-}˄ěw_z73clOMϟ?OOך}sUYa?mvT!oo9|`@-}*)co< m5rٯZxy41mCěws63ZPؒVdPJ &dQW;99OlXni]2Q[[wF뮿<x|;6mi|Rd|tl-`S-ݻ~pߌWm ԮM*kiѻNbtPT ]PE\VŠhKpw``x{r%Wئ{Ecn"K44j*H"""ޫ#6VH5E+s D,ʽcfդ]CmiĬ{]j~;~H YνcDjWFImC0/! ^oR'??Xrcw4}WC*0#:DII'"WilDždhpe^VH،/CCklT{lp4shYwz׫_#$ .SGݩ}O G͝ҭE}FN4ȶJi ˅ny@Z)"iBzY:]($n/JLagEwj3ƒOtʾYJ~Tiɣb ť~K}qvR0,&r8!7D{ݣ6^.(F]ܲqNLO i6y ]SV7fl>lY6*$ G^^E4/D.Qi)@TBU~ul8,0?>h ysҼz3ǓumVYy~3;ܣm'l:h>۵yG᭽?|>K!c&C-J6%*s2tF @"B R qD>,>_lq-i #*IA+?vZ`k+8E IYw23ކSY ֓!a&ی8QzmvV͛~} ^ݒ?Nڷ I`'$5=8gͨ΄eDc:W6O7W_cʎL2]V~(a)GW&-y}6cKk/cu4b\J5(#V+P\H^EZ]J:$a0K[V;և]ŤO>_SV쿮5{1s)׮ܻ72^{/Hc$ql-N9K|٥6+9ѱK=|s@Ju/95lU4%Hʺ|:4Gx;k/|:"F+-68}Xw#J8gg0mjUTA'TBCeLUx F@r$5]ua'B(g5 GnFIk4oлA!{SK<’Ãoٛ*g|8LgQŚ U "T%畐ېP6$ $ԴuXUJ8|e(ǜnRiՌ~Iے4raA\@ѥIЅ81lpPOpZ2g\;T  ьD(zt2ٳUe/$VnrA`GG!0l会թⷮ(*KS]ʸl= zg=Mg"vWEM [/X4CF|5ydߘ>[v?{KгRdT:55Y'*ZF)ݘYА,rͱfe!.7{5jnj֦ǸxHHbk8 62d{U|:jYTsL,~bͶN?7k6 VMU4w]}4;zu݋}C6\j &$TT`ۀkN>+ dϐ}-%|5әrcl;h{tٔBV+y,F%ZI@)DS0C(^/ 0).l77̘HJDۆ8#lY!Q} [ht\4NVl9r'WxX,;Ȇ]3^QY/)b.l!9`JDv']!RKJ#f["9`> KVFֺ YD^TUոE[?yWAP7V \s 9:ɎeXG JOv; f#9rƥ.~54 T,E;,Ӯg#g^ymI|%LXP՛ƽQ/o^Ԅ/|+ EQ6ho~wǿ?mU_ kټ 6 28J%>3BƎ}O0GaqԶƻxV;AX%$B]6(L6qM=!B]Gw2 (H5h[ SB!A꩜{C]c bi*w4_Jy]utc{ڛ{V}mb̶8mA{|t~Ta~ѦY.qmo6 O&+'*  Ru\'r1h (P; 2hP`s ~uH ž~#W/ʚE6>a˻MZAX͚j:H:G oa!O^l#?;o;Oѫr-])b i΃M焰MgE֧Lmv3\vsn-7oyYk#6ϋFD8d IQ,M[ URCT3 R#2n*75@Gά_W컡{9SOF{zFa q+z~r|f?GE)|wRc3/esZ):+قDFY K;b‰`Apޕ*2E]kfGQbA?n$(PuK T'ײJEˀZQYIOB+L=ga߬쟴ls*jH"}Pª*̀Ja؈"Ga6'l[ɃVgu@poԲӼėR:.I:ӵkJ zn_h,xݻ[]U>[++/ a}Wxl7O}j։]γbN!Mj2ՠZAP}{Ѓ"-;V]zDX~T(۸`6!/ӓJ/W)JLSUid<”vbK>`n#\U1N|Wud{>4"/4 [{ ]/˃z.Q"brN !MGy 1wM[,BW= 伛 cXUUevS*.y32J\^twfG772^U蠽? mАR=eg9N>a1 Vv^ׇ1g:}OJ V{@q!;|V`>,7zs辸Rk?N`iʜJ>~Rjmϟvw&M)_5ufgr…#|<[Jy ͧQ?)jim=nCi_/,D3b$^8hF+hB'4"֭^A"yD4 NNV)S&$AB"v'}}wF \,>Wܼ@Ч:p5vKiԯ¬|CGt߯_^H*UA`):7d5wxF#f? ^ T".]^JY0rzs$ǾPـHq!("H W@Xm.GJ|a$sdzl*euMX.#:dEzĪHV^NGTbUwVlZ*Dй'O? XkdVsq^\9}>/倫8rRG=7,ݣqJUvA4df1_3W2Qe-Hd3a^\>RFL_柭3ϺO`!Z|py7" ~Ŀ݀0> IJvDKQY+l\/ytl K-joFU6v1y߽=jWA|8kδڴ[ל#_Nyq[[ݯ/_ӻ[l-j~6 ~;w%f^I>Jo;Ml82ov"S# I2dxhܜW!?X":`1F)dsHG@@FvCSdLHaVfnWv"I)Ǒ=$d}[uU WP0AAM1Wom!8(,گx'%E^$qhD$wH8W쫠eu?-Ӎە$8t2y`Xd# Y6;oLL^I#ڪkR moXZl٩vr¥cZZY7[ҡ$)6q`r! ,!"D8dzu##L(D lK.$`xE:b&a~8s=V|R!JY g|"dݿ'_xPx'PE$"lk3y֒I%<)| =kHgmނOtftlaSi "8"2$N Z%%d5-[r1勊ul_4k6MOc;nuc6lug#~!4UE? s':lĊ/6|}?_5 vA$S(p|MyO{hѻ`6~ƽ&l>*Ir8['DdK g !$rZ7tǗի[I_OS.+4Эfr Ra8"J%PWUID3&3*cFRЧ5ՆV w5Y6z7ِ'79è{&7V ȺĈΥ25-j2y2߿*O+5Teי^f .t+!o爖6Y-~ JRqYcWd,q&fb8>d2 1`$0pgҒȁGN`}YNwstL8X>]7T~y8_ߟC;>1@h=WaO`Ivz s20L޻|{a n|"CV&Iy#$:afu(: cG>?%D TcߌF6D#Wq@̱R>f8 Iǥ pEӺgqu~>{GA鑌wuZʺp:5C=!r[=[Z'%Q5tT42)$iZ׫&ϫ\~4Z+kAMd=V-h"!B#J,%15a943qQ~e#qJ#|P>V`u[˗31(ŻyFsmfr1Q`LM"5U&4§O2 ~ͺ}ѹizh!7սM wV9󣎴gK9݇ ޤ$R?2O*"iEIO:?y&n.{-UoRF.QV;HXVZGh "\}Ao}__S+6h:ת_E uFoHVO=}P{&۵AijGO?1_}Y9Gw|y2Qk4O4{Ϥ-KrWSnnŇ^0~.Lp~>IV; `5l@XfVs'u֘Zw6Ί9n'\z9c"܎5Tn!fƪw y㠝̨m/lSiCG`yCUt(C8 5e,BNU\"-| \ğ|'0*L`#㖿0:gZϨ~AX[ l%_A˛ONvʼiWgO$'˿qE`_ EAFef , !2 ˢi1<"n;K)G(DʶCɤd1IZ^4u[RMjb%_gu:TrTVӹ1ϋ k64ra4Z 5}.=xVALژq\P7DEMNvP&Vs؎9֜#r RmgR);dhgQ@Uf+Vl\l2_S8pWmytTj?&$NPN`azd @X}s@C[ᣮTn2%l3*|r5#7r]&ZoLaDt7FݺqldǪTsqA\OMksH3%wU=/SyS6E:x=GBeЕHntz,':]XƵ&MAy'((\In*2V2f eX'2Jd|iU_]p7@9V%u- K7<х_N'fn]a,@!uy9_L9(Λ'`¦4@D/ + ,>,ZS)"20ҨX'&M" ܜ~3 }!.h Oca'yB#x$CWy{%M//=+G ٺGWne{J qqAX]2VwFvb E997%3ˤ1#0B ~kuaUUB>GdžϸxFa҄Y&h3rF@7~W _ky$gQݕ1Nb(͊~d{ޮRכa{7v[x۟AnM O>qLȟ3R^bšۂh(,~o(ڢbk/9 2tJ! ˋPΗ6pSJvlj8}JNYI\Wjм!;A>E"֐g0-BKBH_T2@h]TsQ K1_G+=_ARl +(ϒy VOC9tXQ *iH 9=fNd-$IjښաoVtÝBNlu=}xMv~buf3"Vڜ_wT[qW 9hfaVh">8gRH͡ IJK6V-X_u`g>0sX_u`g>(3)l4/6OwQ h]?=uXYH[axsGyfFL U]~Q` wA:WIiꝒ"b ~jVt Ֆ66=1!!ĝ|0 z͘7/ ؎eT:4X"iK[{0]__#&ݔyyp֯k?YǃЫsh̨uc.޹Gl{iҠE}uET@d>&V*qʘN^Sh0TD)GfCelQŋ h7V x\ 7`IoT {JD' QЖ=빧_@WΎsܢYh$lpw'Hp ;Wu|&̅ܰݵS/4kw' 'WfV߲J_x[ݛ<i_#%DuF Xc6>Re?zمGW~ o2o)S&l4`:mEA~pTʓ}w@)n>Ud&qSMח[ F~O ꆱk@,[Dja. h_xo1z ~O),t1QLCT۱Χ~ K$e*R@J`Yfj~:4yo+- F/^ IzB%e(G6N!43W ?7pVQWzyҜ#9 U_6{o^u5n8hG;7f=Vu8I738K!+ @O@qz3@viCW߽.Qߖ|CEN9rqp4:;+Ө{~eɆbIXԖ3he4HE^-L0{[ oT=wgSRZ+¤MO|ƿ{wTsoj:of [uq, aX23J'U?ΰ-"4滟㏫bb+`W&XqO^M-;qשʘa/vu͸0UεJ1K\r;YH,=1R|}~=sh:t6RW (+֙P[eƝ4*.h / ekbN"e=9W UĪT!}v;ՏNj_*()Q xL'rBiU y̗H=`]jr۹W&SP9q],ZƨcF-J$*KcӐĜ|m'%u᫖M.]5-L])c w:?,Eqt޵-W!-eR\Pq@Bs!"IþR`/6W1Œb2-Nv6")du'TPU(&$Xy]7>IENDB`glances-2.11.1/docs/_static/trend.png000066400000000000000000000547551315472316100174330ustar00rootroot00000000000000PNG  IHDRDNAsBITOtEXtSoftwareShutterc IDATx]uX~gFEl^^z[,T%TBZ fs ,R߼>>2{vw{N 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0`Lu_ H 0` ȍ{O6<ĕcrH4MWWsL:و]ߞPh/J%֋|rYo=.t˕(5w,vCGvfztC\Nݭg׎嬷{m-JMfr;0RPts6n@rIBc>\]s:|*N!4M{*hYMtPC@%*vNJD-BѰ מ zqg]J5l;B}O.ZzQj,iZ,׳i}Wʶ?@S^Q4M 5~Fv\p3/0XYxv!I}m"ri}y{a^ů#|Uh+r=A=O4Wtv>+b?q7izs q{JW 'zŵ{מVN*Ku{ m5eem!}nL5dCM%k>M̀%nӀwnS0s1-h4eؔS"ZvM\bP鹒S2SndA(&j=# fys.)sHo#)Wݚmƭ i80/ߗ[*L-׸sYUKʛ ?ya%BV6M:sEDV2ftؚo7N-tQ@h|(3Ch:rS ^`?HV ii`>)J?7^|4zyzaYE\N/?4M:E=v~a@ ћfA6E{(,~7ЪųGHO8vQGB HР) DQe+r{N|5O.!~ߕY ѠN>q<6UaL*ʋ@Pڪ2M\uq]Cj9?(=, {^V+Wȓk:sׇ+k8Bs@*_F\J-_mȩ8y'`A^nw6!r")>Wl5jKH" @ID4_;MA"%%MH癰Z6%Lz`KESiuaIY,-8;wΟ^+k_aOm9u7aتFwG)qZ×JƊשzE/B*/;jV^Tx*>z43L(@Azy4F9| KPۉH oPR~7*+ջ/rFGi>5W:{(K{ǰuh Y{sUK,. O;^:\jz;5#7W>7XU◫9k2% 8|#ZT|%)٩XIΕ/>\;|y}Ip6ۻ-gC rͱ:W/P6:xwœWr[\E;l(F{Ү0@g.e)]Ls;ѢUw$m[^ZtxpsOonm+_ {Z#SOW,z*T˗0,xz{nݻp0\P>{^snjf ڃmv٭XQn޺r-۶l{z Oafu Fu܃2Ghh";}8qlE|s<$2$SPR:꺛k{k>KS8͝z,ad)Vą .\pnts^+0ZۊovOjC.aL6M!mZE斦'غMXkWo'_ݳ:+?99BA|h2ԌM;Xf_B{(J=}3*?WMJWxj<ͭ ϣ2|8ֆVZ}q',=zQ4 nwڭ2%nsxQa4D_ޤk4ש0h9ub)Z~Pn/;k/MRwks:>S\J͈aM8|ZFGV}ɿ|yV~عƞ_gT^jk>aVӗCdhAs;o޽s;bs_ ϞSMQRh4h*T^TӺv!.+;$%jn]'-05RA~Lt2i > KQ!DdߤGi+* ?#@gScbܔ\jrP//*ms9OΟ [u?zmr"ĕjD9zp-5mp+MeUe.'?Ƙyn𸽻=32g$žwP0*!|C'%ں瑨/R爠ۡ$4fU+Yښ쌨dAlUNn];&(f(A#=ȓ!9ORYq0L7Ƶ _[^O;&*nTU/ez[}|Uݡ Q6ƔAIv#/t37:<u':%yDTIZ<:EJ:E;g~qOV鮓{Qqs+m/Mlj]=<$IRKPꖯocٶSyh|A6=Hh|zRs95QԷUm76XJ#>CfcU@R!&l E΁owgm=JTjkrskziߤ?nAF>Y9)" ?=_R E)h*Kϯ kE~~"/5j&R*1B*5 z bh.G?IRQ_ q9fxZ=DX (j5SN9*:rfZz'Wl}CޜC&-"B1M?)^M?m{5j\D3a'GOHC12_$kϏ> ڞ..K7ؚc?ԙ}3"qFcť>y +X٭c̦*Ԏw ͩV 9cՄzG'ӊ.BX6tMH @oy18íw הgKfƴRpv*T/7GY훴(5RECnFg!J4D^iu5j}F47$r9$A.ew<~p_UB|X` GW a߳xl2A:9յgT/Й̵1#9Sf6Ms}\AA\ z?(ULӴ$#Ⱦ>si~_e5nPE4$saZ/ִ%j@O@Z,-Qi_A_א]rifs݄|S÷?bgҟta6 \^d_zv{鴪M.2&O?xĂլ-'/0k[}[7SBӉ{oyxdV}V/]ֵ꽷76偐m6E;pWɜÎ}Cs嵯@!'\y0Ǭg?=w~tyPS_`ߛ''4n^ zQ-9ՎN? K)i2>T T2M]Gi*BW7wt^K RkK?nhΓj;yZT ~ zc$%!z8XGȎ'Q4MKR]F^GoI2#=.WSU lnK>xa&V:5nJE~7L%<ΎgQ@0@`0` zscIFu@0p q0`P@;{T Re7K2RdÀc ruc[0ctn录 i]*eDV/a<̤7sό0\yI>@ #YDX_s  [ h\j4SNB &ov e"ʀ6 c]GR`N[t:#&Gwc@@vgg75E%=&B12!U15X$c /g/=L`%Ԁ@+njmE[^alGF14S RDIt ?%ݖ7yBvֶ _|_(G|dL Mo80Ҷ^VMayƃof!xg׺~YT_z]y n[kq>$<p!hMmZip%YOnX?Go3l5֐A'w}"d-?MJ~s!COG*,HOF_糪_ݍkΫ,Oi<_YcıgnRkzCd NJJIѷ`iJ>}ͧi_&++~GzNKvx606@S"P  Bێ[ropURXK@Grr4'MKNv# /0WU)G)I Ǩ\]R?+Թdp@$8, T.2 vY)z!C(ڦS"6r>h7ףk#iM_l`U]<~H"}JTty@eܽzYK<ݏ. G鱫lo̯UOI&ʬ2M;7ZHNys Xڶ{-0\;3dkzQ01nK̛5m&hАuOP?R`=08(Y BiUˇQmCІg]zC|4 (IDFDe@ ]8=6t^ Ngy4hd/9xlWe.U !('YjWI2>`Pɹ64#Z;â^t2J<Q7=1;n^]K³{C7Qa4M:\|*։^TD_\0Nìr^DhAsͪ;op1>Hcǧ܌/)ORԳy^u=b^Ѓ2pO@X1+j(p܇& aT#9"LPW_Ugy,K"wȗ]=ͫ8Z:hk4-]Y@D-/G|oYJDv|fӾU u>]Nl~naZxo)1K" "9,m}S[%}`N" )~> 6<+.^?Y'\OdT '{״~-1fYeZ&u㳵b +i'qe͆Tx7O_=nUJlZIW ﵒY12_$kϏ> ڞ.vPLq}ʠWjOmfډh%mMEH &|>;;x&)ڇ\i];FN2tu]:рNلp V'tbk ȕ@vV;{-:mu:}ʣߺ4-AkcQ%ukx/9KQPH._"hk4r9i tDp41}B;V _#%Q Io<2o~~O~K t [ ^Ԃk{`dž\%b~$ a&aہ6-T* ?vߣ'sT-k?BԦ˰yJwo>s=gTS_hGeٞ^ԳwmO|bjߎtؖx-s|0`f_#RfFE^Y*ecN#gj;ou$Ҟ4y9J\+sk%YIJ4,A3[i++u|~o|~-pR޴( $!RV9<ηfp͠Z[ 4XXZ2[J6ϙϱN_:~€6fr$Gz̦ipX.OqI1$!fPK$QV 5×Ty~iW sQE13#|+")/+R_VL}W%(Z9> ,!W"ɂˇr9J8[ Nyh6?i($x~ ^wKԮr{)\\F=l[n=$\Ȓ4WX-|t8*'%‚+s' 3%P4cϼj2?Y;|ri ƹT 9\ZY*c^Pez?5A lA@]RِV9OMI^nmwkd$v,XCp-mSRs}$ JX}܎ntI'\2t{~5U<~i<\`@na</%*Yz{zf/R*}Ud"D)A{[[zNj3 '3-?eoUOIᷲ~RS'@T u[e(1kwN` `[8̻#38A)nR) jlF V˪>*9h4+>LĔHݽ2BC t*o08NTKm~# 0=&c %W& X:M CeY ~gX/hhV- +?ɨWB tX2 {0ezZ%b&*ʟAO[.^ aXhZamHk@+Jwf(D&h:D.E F/h$d) RUi4K%.Z&.|NKEcN-w!AkY_^r51s aߎz)}zZlX))|Qѫ,?9eH"l' hf[Q% ,lѫT5l/ۇtAMjMeܟ0MX@ȦGOScit^|;}۝M6lۏ+wFnܚѐ#]13W7G y7bŽ+/C=OkBP~GGsEz& 8^;>gjGUSpE_ U!g ޻\<{yPrTf}B]/m!#.ʴLu{Z^@X |@&$"%G;5,?KG'<})3ͪjjyYZ;Ka0犭&YEYy;mX5'W7Wt +֗Zv)[JT'8:)=++%sr>GB D@ 0Z@ґ\LEG5Fr,Ij5_^42÷q{՝u6%<3Vnxt-pX, #>$M")ԋut"%[8s;8Cw8}Н4Y99}:3oW?ȥR?32؇304AC[];oYR0yj^_uZr7g$@$ʗTQ;{~?d Fc٢I䫴m̠qnvz}phHXd DTJ3~yDdB/ U aTf-? !gDXPPFk*W*Hs!k*3'c1oDsc,Et7W)>Mc31bp0p9F$})=ϗS6bi=P^S|s'*NhYIIA4d ;sN{EضJM2&sؿϪp4^5;YG"NԧH ° N3zB[ZT ߂TMs4%9jFL4>$x d` K"`b;AgI t{Yg]umv>`a-]3؜l\=eVWlfC}ȶP%qߖQ=nݷNVm"ϒTPi3MSD>|-go_x s%vN ghVw,)Oq'l+_5+,˦ +֜YJ\ٟBVE@DW=]}/?JOE}O_ޤ/iŇJ5eZ?tX;!,TV41ښhOs;,$??#~Ρ^3`zeqy ȗD 3$ Q۱X==|hW"ES뜯OO~|o.'GWyF둝E(p۳ +4?]Bq:NPBYRf#șh-/-6.pH{{g#O|TWaIyΤ+n_<(5D%;9zRP/ 7V5iqhA p'ovћ2WSEU߱Tה|SZ? |zblZI_ R:'7 WAW[.MUCn@Oy[:҅Et#խū\ Wv4<&{SWpuLASJekjR)i֞gV\Vd-,B\w_/~27j qvt\qvTDL-4$OG:@avPÍ d7B-k#PeQ S;k xc^$ -ɗuBj٩R5}Ge@Y ן4p^ހ.ju+]9|Uw[!9T'! rd.f˶g*| $jp5 i?B͞bĥY^udu<+u["$9tP&tw9Z!ÂXP?SB@H=,f\/=-+dA*s Z\Ǘy"5]~NخY;v/vd|FM|+=HY9BM%ömZTT] VfgZmc˽3i/)6ZSv1qæԝrSwF;r䧮mN.zj,8OItsmHM\GOcf<}J*; M@f} Iȣ@Y1TOjك;o(́A[Gq܁, p9JPY?BO̴7zs'I)޾/?Ks5;2RpڢiW>'3n}/0Vok$>zLW,O%a|ߍj`8Y$UIe@ V78r.Wl5-xV6(!82: fkqSZ{`ԱmI}t\̓.xxZ}{wA ^zgMXۀdqIDATa m/}%h`eڑ-Di3h@0|x+;jҰ$;*@׺ RО N't:!`kwg]z2z i|hd -Z;ESUceڏPEjy6g;0iG$-lunѸܕojZ*6TW[4Hd tluB6@\Y(X&tT&- t;2l2nH *,Jfo4x ƪZ`[ A.Y`38G >:ziaA̕ $wϗ]г5<ݞ~>%W cF=@4wN'9Fkp2 fX@I"iD2Zz P fSeNgO4Rv{Xl1*~^b_\ B.q*n3-":G@h 8$i9ݷ/#wT]j,^eqd~1gzDM04" >}Ai6e@xmmnQf[Pj` 5i0fƑf9mb<42eJb$tO/D:CDD1̜ST(\jʼ[ݫ%fOѮ 0`_lnފ3"fP_ϖ*LeҦ1Y,mSt6eaZ;nʏexCgiX&(JjS{3Hhyiu`PƕX:n >~ 0Ir0_jYV2( 8 Pg=zd4gd/7*3g2_e F}sS8^0- ƀ}Vė$11`"*ߕonjJa{L)zoe/_-& jҒR.LTn?ɖwMz /0܏y#{eb*>*gUlCo e&*dApOrK/v[L $d ]iM+ $+ /gQ<7M|kiè| '~*~SeĘ@i@ h0ڇ,Z6-Щ*8eYH9T,ʖJj\|8cߋ3 X*ȋ~`חqLrӤ#C}5smW;3^Ɍnˋ GwoJ:۸vLKgy)F+fشk!O6yE\y$U;_{gWcܭ}_fȒL4daB2`0c4DE$"*Q)E]GE{b_t9s~s-Kk#5ٝ=Fp ݇phV|u!Sr톾txH_&o?Wj,0jʥ]4 Y gMNz?>иbn۞:jBqԱ `%bQePں16SUmۿgikN~`[<%}9D7kiƄ/qlpm$XaY;s>T,mro, ڮg0 xV[ Num vR*=n>jHRg|z[wqƒ/2r}=fO5c[xfS|_cT?.+Zo~nzqvǞ6ܦ;t3hj;M#ӣK~ͷunSOG4-NG>u?ұ=zsvm<'FqYpSR)ΰ5߻y<*J&~Gܿ!D%u^k/ wZJm7 zr?05'n=~3:2Ii]J\;6 yGO"]?ej=*@@RLV>$iav_ZWRD^؅2[{}Xu.@.Ne-"Ꞝ^h f5 (bS`&S'2; POzyr#RnC 8Pcz:[RW;w'-(JY34T2Jc{fUNv&Y2 2N:JinEO]E?մ;C^${23Qj:)xtY}%ݽ}jWH#|?c=eK腎}?+L.)Yvrd\ VVVZe qԯj gftPnѽnwP=ZQwcgYC+uZzdͰߑg@͞9$"U7i/TW|x;wTӐ<94~#mik'jziӫ#7qKt!Kj]]ivRmTEY3EYҾ+[r}3[mw4yVVRh'00^)~k ˯X>lzWb3eb_U'cI/9{V i1_=I=tȌ hyt|Z3zA7SrEpa[ /x4 ċ뜮9Q >(e,OǬgz/`?}ėʌ8{)}Lw3HuxP01`SCwי/sڂn=Rʾ)x.ݲ@p4 {0V۬z IIȗ(J}pLj/!ZM8_8fHۢepZwJWn';?(aUԴْRPq9$lѐD.Z[یSϤ>!מyTj~f‹Bb5#M|/ $,:^|T:s ;GU`sQ @)+q(HĴ6-m_Id??ۏqen(vߢܟym7'yz F~?sZd0[35Q<pfgY d,x`c\Vƾwy0J$tpI2ʣ>ݲ=0T۱|)u (Z37us,j\xW~ iNbi+Yi^Vi^?Ŗg=g _8b?aʖc1aL5w_V' 5i cvM}kPR`Wdw8Z=`um8᧥ ,#I%22)C8ƊEXin ƍvݧXPx򴍶1^#wdi](\K3md]uUi ],+cAsi^Z؉'3a%LKO,ל>廱ϔ@C.x^€ֱnD+5j2]DL}Vg(nKC*vQygoQ^y噶a!=,~[@ {r1Y76P$~Zh1zX DS0:Z)\<7@[@@ǓP*g4|1=ǡ-4յzM^2ٸ If3Q?J=Mǜk3l%b^=[<`ѝx-۵R^ E ]G^~hgxP 9Hs>GS|.iC`"h{j3 #ܫvq&:;궕xqQ~!d?XPU{G G< O ?Xt{lS>OC]EҬ+n,Kx^QŅ/ŕTGz9r;ukPqnK¬O{[u1҈kC儭*CvҙwYjwqrYY0yOիg߭'[wMAy1 r;=x YznZkXqNm+ϾM8=;WCR;OD$eu琕]T+BJ٧vrR6;Pq}5ףT*>,+fxFcmCCHq{ APșXts%@M3-Vnab|k.d\ݹ^1ѫ!,]jGݡ4͜F m~1d.d1NGU7/?rrwH8J^!u'l0Nguc|(BJ5@~qa,8*C[՜zmg!wrv t=VkJoY%B} wQ9X|Y׵[ $WH5NHw^S8sBRVHU|5|;J'Y#r@ BQ u2o` I @hnl@pWKG@ c Z @ @ @ @ @ @ @  ?, F?~IENDB`glances-2.11.1/docs/_static/wifi.png000066400000000000000000000207641315472316100172460ustar00rootroot00000000000000PNG  IHDRGsBITOtEXtSoftwareShutterc IDATxw\^〣JDPXX{7lD5h]Q ,(.pT88$#ν}fv{@ @ @ z$jsJ|H~ƪPxJ6˄kU$5] kWh>I6ugpV Iw[*c@7}aGfR婹1RWv9I9㴉/>̛\6GIw~ۤ cOƔ~o Rb.WbF9)23GW eB. 'oԫ'&L&&ʼ[,(x[ҺY LyQ݀Pr:x(kie.d21qū(|˴ |VX5"|$%WgOܕFju]v?J\Y;-` ɲsŀn}Z@H2orkG$f{,>3XwZnm03$sڨY}Cdtד t`oiN$I(F{sy/$Wǝ4/i 7C7> 1St Ul mDsS 2,7{rFUg٩i#G5'^Kn@=gs\!H"w?LsV-! L,w"z/{Cl>H١/`L^h],wڕF= SHk)ZVN򘗕bT%_y݋2ٲ!yͷB;eւ̖o87K!Co_V?qa!gԧyL]>ꎘ1WW&z/H+K_|U1߾f/3f^9O^9 zc{6Ot=-<>.T:mj 9rBܶxS2ϭkqԹ tݥs~^[/HQcͼg)20HeGi}+\IQ^#W6qYk߇}&f+"`)8\) ;=@ZYQ]~Yݥb\ћ팤dgk|^YTij!Q~ȥhT)5ʍ^6¦q?؏;b z}yB+9㉤])j~כ0Y$IdҲCN$I` ͋f44݂Zoސ$RQ}uz g@|9`|C;Ak5P+8!QߙȨ7 7f>7',FMG} cf r>N~.95d})[< e~(=Y{:0Yorٝ m׀ @:m uyʲ+X[hF#=uUi)kȭc|ooٖgMN(]%I`W<$I[/@b $ N4O1IR*ާݗ&fe/)`P 5J  f]LZjJkV&pԔWCSUʉhWN忿W%r1@ ~[Bb)si%]qVG L;_%`޳\9)l"_Lfu}j?`x޽zIs:!To0I;#RI1[4)ZWzM95+at#OGpOĚ)r>'pY/?9c X\}1l0:F繸"~ͳTZLӉ-1eN=pBϭItR9qwG~Oe{ V:!>?jĦd (no`fe3zB㌧{ގ9?y t\XѮ՜3#ۇ7Y:jIb#Fx\=Le)Yi>;ڴ)?h!mf_&IN(r.+} reYGNDLpN a(UdEr@ s̲q e?KB^@u~p2d@pt1SnGH@$.}ۚ~O qC_nf ZgjcDK X:[ *uDkh -q}4\%;鵝XNL7 =Wc(]>椅)cu!ѩ\'wOa~+op~w_z&?zæ Sw̘b^aq\6'3kvV. Lܶ+1zv^2,r"@ _/J;C$&qsoM4l,>-@|QE +~rFfQ5cr(mE[z#׏&& 1VA㟠>GΦ/$)&4Qՠ} ~ RʏlRql(mh LfsI1r(͋ ? @ ? {ģT ؟܌pٜti/|g;}8\vR>t/ H4"hն\bi!IS1񷫡I\6'|~>=c.\s39=к/89_:wǁ&}_l6f4yׅ_,9PM cJ=*o(shK=ZYK~}llLϸ䓪:ʔӴ]03%?׏٣\M^*.n1L¶g .@[a[odD()hg+*һ9?aՐ=Ө\mSC(,23G俍mF~Rv|joC`lgS\SRNNQKN]5৓Z󬡎D k_R8mI6:ݐ:~'@T OBH\WȫZwtMM8Jpqm (Ѝ.}yKei}3R|?zdb&hFwW46{AD.KK]`L^Oop͂ßrnlL6ڿv[|/w-69iP5Q]؜WWn>n̨I CkZ38EAM=\L;V-Ir76C9mvG$f &fVkai[G|a0I;#RI1;7o觔f'8?/%r}?`=วQ?(-Df.rEΌ`hiؕNЎ4}=VE6j~wNm]X bQ[Ѭ S 8)LѽBtUEդt%mI J_&x۝q|o3BP2g{`{0X kQ~7(:Cg+p (tNFdQvGMQyV /y^7wB K]OY=!)=*W^`@jeV>W||qbZOd@ Q4ή` .o\1P oqwDt>hmũcpT70J6z.Y{{+ߥG{~ϗW-#=if\^ _Ef;H;~ td:lbWZ-h C˧ \{R`Lpk"NgX|ч) ѽlkpZ qf;Ngfq˹[-'<;IG/l`:X2T-Vm֫ aIl;p%e +HM~yH^F$?d?dG,yW#irJ^K4k# yl{ՕJn/Lͼ.Lcn8~e fsaHH+}\`|_a%LtyL-/N61i*:[>ƈIJ*t:<#23*情MBq)r2 zyצ ^VPyzu=Ro*3r铆tW& oa57L;;ϸzAa:PuL QjS_Ծ37D$8s8sg`뇌T`8o:@'7[MJJ2Jp-lY86usͫ:F\qo[qR᫻ѲzdZTқedض֥eh5~ m2viH^0YGSQ^ЙgfSM͈_# :ܬ< 9UB3Fb!Ni4*Ai4icJ+_dJW:(8XjbؕdӨaΚ9c|7]L(mionO>ԿK3}'3Gkhњ[]\wA'݌^hsOGTHS^PCulI@~wc>*-:ޓ43;mca`>kEWۏZ\R]P`/BnB/:T5))"zڸZ+Msy5rWm7@ @ @ @ @ ~e_r ylwM+ȷ zČxt>X@m&e=LA;b맚h#A9ε|b@R}dny[:6nTS$kyE-lj|ʹ6Tȩ_5܍@3v͹ST<YSu) *:AB+IEM l9yG֕EM'm *28TE&'n߄뢪Cu}ځ#rDƋs] ?N%E$aRG.ݑ%,MHRL$8@eTkTSϋKkћ8J~)|Tkȏ IhӕV$$$ZW*!U J$nȽTQ,R̆SQ-m$|}Y2ZJGHIkT+q$}K׻S0bh5v9K~-7nϷIDATի:=,pk寲6S;+ y*=n*+yvf͈'T*ГvFmNjhYɪK/\0ߧ_~=8J81f,p-1ABnYőq*ō>EN?/N~ӈme>% t7Ri5wFxnC_?a[4bѠW \^6OVXb*- ,N I ۊJ=K^6QWN 7y_~Dܛ2z.}G$'QI}+ۨG7Ka2DdECx7T=h)?qlS˳ $cgM~?6"Jφ@ @ ?V2:RFIENDB`glances-2.11.1/docs/_templates/000077500000000000000000000000001315472316100163005ustar00rootroot00000000000000glances-2.11.1/docs/_templates/links.html000066400000000000000000000005451315472316100203120ustar00rootroot00000000000000

Useful Links

glances-2.11.1/docs/aoa/000077500000000000000000000000001315472316100147035ustar00rootroot00000000000000glances-2.11.1/docs/aoa/actions.rst000066400000000000000000000022331315472316100170750ustar00rootroot00000000000000.. _actions: Actions ======= Glances can trigger actions on events. By ``action``, we mean all shell command line. For example, if you want to execute the ``foo.py`` script if the last 5 minutes load are critical then add the ``_action`` line to the Glances configuration file: .. code-block:: ini [load] critical=5.0 critical_action=python /path/to/foo.py All the stats are available in the command line through the use of the `{{mustache}}`_ syntax. Another example would be to create a log file containing used vs total disk space if a space trigger warning is reached: .. code-block:: ini [fs] warning=70 warning_action=echo {{mnt_point}} {{used}}/{{size}} > /tmp/fs.alert .. note:: You can use all the stats for the current plugin. See https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to for the stats list. It is also possible to repeat action until the end of the alert. Keep in mind that the command line is executed every refresh time so use with caution: .. code-block:: ini [load] critical=5.0 critical_action_repeat=/home/myhome/bin/bipper.sh .. _{{mustache}}: https://mustache.github.io/ glances-2.11.1/docs/aoa/amps.rst000066400000000000000000000055561315472316100164100ustar00rootroot00000000000000.. _amps: Applications Monitoring Process =============================== Thanks to Glances and its AMP module, you can add specific monitoring to running processes. AMPs are defined in the Glances configuration file. You can disable AMP using the ``--disable-amps`` option or pressing the ``A`` key. Simple AMP ---------- For example, a simple AMP that monitor the CPU/MEM of all Python processes can be defined as follows: .. code-block:: ini [amp_python] enable=true regex=.*python.* refresh=3 Every 3 seconds (``refresh``) and if the ``enable`` key is true, Glances will filter the running processes list thanks to the ``.*python.*`` regular expression (``regex``). The default behavior for an AMP is to display the number of matching processes, CPU and MEM: .. image:: ../_static/amp-python.png You can also define the minimum (``countmin``) and/or maximum (``countmax``) process number. For example: .. code-block:: ini [amp_python] enable=true regex=.*python.* refresh=3 countmin=1 countmax=2 With this configuration, if the number of running Python scripts is higher than 2, then the AMP is displayed with a purple color (red if less than countmin): .. image:: ../_static/amp-python-warning.png User defined AMP ---------------- If you need to execute a specific command line, you can use the ``command`` option. For example, if you want to display the Dropbox process status, you can define the following section in the Glances configuration file: .. code-block:: ini [amp_dropbox] # Use the default AMP (no dedicated AMP Python script) enable=true regex=.*dropbox.* refresh=3 one_line=false command=dropbox status countmin=1 The ``dropbox status`` command line will be executed and displayed in the Glances UI: .. image:: ../_static/amp-dropbox.png You can force Glances to display the result in one line setting ``one_line`` to true. Embedded AMP ------------ Glances provides some specific AMP scripts (replacing the ``command`` line). You can write your own AMP script to fill your needs. AMP scripts are located in the ``amps`` folder and should be named ``glances_*.py``. An AMP script define an Amp class (``GlancesAmp``) with a mandatory update method. The update method call the ``set_result`` method to set the AMP return string. The return string is a string with one or more line (\n between lines). To enable it, the configuration file section should be named ``[amp_*]``. For example, if you want to enable the Nginx AMP, the following definition should do the job (Nginx AMP is provided by the Glances team as an example): .. code-block:: ini [amp_nginx] enable=true regex=\/usr\/sbin\/nginx refresh=60 one_line=false status_url=http://localhost/nginx_status Here's the result: .. image:: ../_static/amps.png In client/server mode, the AMP list is defined on the server side. glances-2.11.1/docs/aoa/cpu.rst000066400000000000000000000057311315472316100162320ustar00rootroot00000000000000.. _cpu: CPU === The CPU stats are shown as a percentage or values and for the configured refresh time. The total CPU usage is displayed on the first line. .. image:: ../_static/cpu.png If enough horizontal space is available, extended CPU information are displayed. .. image:: ../_static/cpu-wide.png A character is also displayed just after the CPU header and shows the trend value: ======== ============================================================== Trend Status ======== ============================================================== ``-`` CPU value is equal to the mean of the six latests refreshes ``\`` CPU value is lower than the mean of the six latests refreshes ``/`` CPU value is higher than the mean of the six latests refreshes ======== ============================================================== CPU stats description: - **user**: percent time spent in user space. User CPU time is the time spent on the processor running your program's code (or code in libraries). - **system**: percent time spent in kernel space. System CPU time is the time spent running code in the Operating System kernel. - **idle**: percent of CPU used by any program. Every program or task that runs on a computer system occupies a certain amount of processing time on the CPU. If the CPU has completed all tasks it is idle. - **nice** *(\*nix)*: percent time occupied by user level processes with a positive nice value. The time the CPU has spent running users' processes that have been *niced*. - **irq** *(Linux, \*BSD)*: percent time spent servicing/handling hardware/software interrupts. Time servicing interrupts (hardware + software). - **iowait** *(Linux)*: percent time spent by the CPU waiting for I/O operations to complete. - **steal** *(Linux)*: percentage of time a virtual CPU waits for a real CPU while the hypervisor is servicing another virtual processor. - **ctx_sw**: number of context switches (voluntary + involuntary) per second. A context switch is a procedure that a computer's CPU (central processing unit) follows to change from one task (or process) to another while ensuring that the tasks do not conflict. - **inter**: number of interrupts per second. - **sw_inter**: number of software interrupts per second. Always set to 0 on Windows and SunOS. - **syscal**: number of system calls per second. Do not displayed on Linux (always 0). To switch to per-CPU stats, just hit the ``1`` key: .. image:: ../_static/per-cpu.png By default, ``steal`` CPU time alerts aren't logged. If you want that, just add to the configuration file: .. code-block:: ini [cpu] steal_log=True Legend: ================= ============ CPU (user/system) Status ================= ============ ``<50%`` ``OK`` ``>50%`` ``CAREFUL`` ``>70%`` ``WARNING`` ``>90%`` ``CRITICAL`` ================= ============ .. note:: Limit values can be overwritten in the configuration file under the ``[cpu]`` and/or ``[percpu]`` sections. glances-2.11.1/docs/aoa/disk.rst000066400000000000000000000007411315472316100163710ustar00rootroot00000000000000.. _disk: Disk I/O ======== .. image:: ../_static/diskio.png Glances displays the disk I/O throughput. The unit is adapted dynamically. There is no alert on this information. It's possible to define: - a list of disks to hide - aliases for disk name under the ``[diskio]`` section in the configuration file. For example, if you want to hide the loopback disks (loop0, loop1, ...) and the specific ``sda5`` partition: .. code-block:: ini [diskio] hide=sda5,loop.* glances-2.11.1/docs/aoa/docker.rst000066400000000000000000000015431315472316100167070ustar00rootroot00000000000000.. _docker: Docker ====== If you use ``Docker``, Glances can help you to monitor your containers. Glances uses the Docker API through the `docker-py`_ library. .. image:: ../_static/docker.png It is possible to define limits and actions from the configuration file under the ``[docker]`` section: .. code-block:: ini [docker] # Global containers' thresholds for CPU and MEM (in %) cpu_careful=50 cpu_warning=70 cpu_critical=90 mem_careful=20 mem_warning=50 mem_critical=70 # Per container thresholds containername_cpu_careful=10 containername_cpu_warning=20 containername_cpu_critical=30 containername_cpu_critical_action=echo {{Image}} {{Id}} {{cpu}} > /tmp/container_{{name}}.alert You can use all the variables ({{foo}}) available in the Docker plugin. .. _docker-py: https://github.com/docker/docker-py glances-2.11.1/docs/aoa/folders.rst000066400000000000000000000016601315472316100170760ustar00rootroot00000000000000.. _folders: Folders ======= The folders plugin allows user, through the configuration file, to monitor size of a predefined folders list. .. image:: ../_static/folders.png If the size cannot be computed, a ``'?'`` (non-existing folder) or a ``'!'`` (permission denied) is displayed. Each item is defined by: - ``path``: absolute path to monitor (mandatory) - ``careful``: optional careful threshold (in MB) - ``warning``: optional warning threshold (in MB) - ``critical``: optional critical threshold (in MB) Up to ``10`` items can be defined. For example, if you want to monitor the ``/tmp`` folder, the following definition should do the job: .. code-block:: ini [folders] folder_1_path=/tmp folder_1_careful=2500 folder_1_warning=3000 folder_1_critical=3500 In client/server mode, the list is defined on the ``server`` side. .. warning:: Do **NOT** define folders containing lot of files and subfolders. glances-2.11.1/docs/aoa/fs.rst000066400000000000000000000021611315472316100160450ustar00rootroot00000000000000.. _fs: File System =========== .. image:: ../_static/fs.png Glances displays the used and total file system disk space. The unit is adapted dynamically. Alerts are set for used disk space. Legend: =========== ============ Disk usage Status =========== ============ ``<50%`` ``OK`` ``>50%`` ``CAREFUL`` ``>70%`` ``WARNING`` ``>90%`` ``CRITICAL`` =========== ============ .. note:: Limit values can be overwritten in the configuration file under the ``[filesystem]`` section. By default, the plugin only displays physical devices (hard disks, USB keys). To allow other file system types, you have to enable them in the configuration file. For example, if you want to allow the ``zfs`` file system: .. code-block:: ini [fs] allow=zfs Also, you can hide mount points as well (in the following ``/boot``): .. code-block:: ini [fs] hide=/boot.* RAID ---- *Availability: Linux* Thanks to the `pymdstat`_ library, if a ``RAID`` controller is detected on you system, its status will be displayed as well: .. image:: ../_static/raid.png .. _pymdstat: https://github.com/nicolargo/pymdstat glances-2.11.1/docs/aoa/gpu.rst000066400000000000000000000022001315472316100162220ustar00rootroot00000000000000.. _gpu: GPU === .. note:: You need to install the `nvidia-ml-py3`_ library on your system. The GPU stats are shown as a percentage of value and for the configured refresh time. The total GPU usage is displayed on the first line, the memory consumption on the second one. .. image:: ../_static/gpu.png If you click on the ``6`` short key, the per-GPU view is displayed: .. image:: ../_static/pergpu.png .. note:: You can also start Glances with the ``--meangpu`` option to display the first view by default. You can change the threshold limits in the configuration file: .. code-block:: ini [gpu] # Default processor values if not defined: 50/70/90 proc_careful=50 proc_warning=70 proc_critical=90 # Default memory values if not defined: 50/70/90 mem_careful=50 mem_warning=70 mem_critical=90 Legend: ============== ============ GPU (PROC/MEM) Status ============== ============ ``<50%`` ``OK`` ``>50%`` ``CAREFUL`` ``>70%`` ``WARNING`` ``>90%`` ``CRITICAL`` ============== ============ .. _nvidia-ml-py3: https://pypi.python.org/pypi/nvidia-ml-py3 glances-2.11.1/docs/aoa/header.rst000066400000000000000000000010761315472316100166710ustar00rootroot00000000000000.. _header: Header ====== .. image:: ../_static/header.png The header shows the hostname, OS name, release version, platform architecture IP addresses (private and public) and system uptime. Additionally, on GNU/Linux, it also shows the kernel version. In client mode, the server connection status is also displayed. **Connected**: .. image:: ../_static/connected.png **Disconnected**: .. image:: ../_static/disconnected.png If you are hosted on an ``AWS EC2`` instance, some additional information can be displayed (AMI-ID, region). .. image:: ../_static/aws.png glances-2.11.1/docs/aoa/index.rst000066400000000000000000000011041315472316100165400ustar00rootroot00000000000000.. _aoa: Anatomy Of The Application ========================== This document is meant to give an overview of the Glances interface. Legend: =========== ============ ``GREEN`` ``OK`` ``BLUE`` ``CAREFUL`` ``MAGENTA`` ``WARNING`` ``RED`` ``CRITICAL`` =========== ============ .. note:: Only stats with colored background will be shown in the alert view. .. toctree:: :maxdepth: 2 header quicklook cpu gpu load memory network wifi ports disk fs folders irq sensors ps monitor amps logs docker actions glances-2.11.1/docs/aoa/irq.rst000066400000000000000000000010541315472316100162300ustar00rootroot00000000000000.. _irq: IRQ === *Availability: Linux* This plugin is disable by default, please use the --enable-irq option to enable it. .. image:: ../_static/irq.png Glances displays the top ``5`` interrupts rate. This plugin is only available on GNU/Linux (stats are grabbed from the ``/proc/interrupts`` file). .. note:: ``/proc/interrupts`` file doesn't exist inside OpenVZ containers. How to read the information: - The first column is the IRQ number / name - The second column says how many times the CPU has been interrupted during the last second glances-2.11.1/docs/aoa/load.rst000066400000000000000000000021131315472316100163510ustar00rootroot00000000000000.. _load: Load ==== *Availability: Unix* .. image:: ../_static/load.png On the *No Sheep* blog, Zachary Tirrell defines the `load average`_ on GNU/Linux operating system: "In short it is the average sum of the number of processes waiting in the run-queue plus the number currently executing over 1, 5, and 15 minutes time periods." Be aware that Load on Linux and BSD are different things, high S`load on BSD`_ does not means high CPU load. Glances gets the number of CPU core to adapt the alerts. Alerts on load average are only set on 15 minutes time period. The first line also displays the number of CPU core. Legend: ============= ============ Load avg Status ============= ============ ``<0.7*core`` ``OK`` ``>0.7*core`` ``CAREFUL`` ``>1*core`` ``WARNING`` ``>5*core`` ``CRITICAL`` ============= ============ .. note:: Limit values can be overwritten in the configuration file under the ``[load]`` section. .. _load average: http://nosheep.net/story/defining-unix-load-average/ .. _load on BSD: http://undeadly.org/cgi?action=article&sid=20090715034920 glances-2.11.1/docs/aoa/logs.rst000066400000000000000000000010111315472316100163720ustar00rootroot00000000000000.. _logs: Logs ==== .. image:: ../_static/logs.png A log messages list is displayed in the bottom of the screen if and only if: - at least one ``WARNING`` or ``CRITICAL`` alert was occurred - space is available in the bottom of the console/terminal Each alert message displays the following information: 1. start datetime 2. duration if alert is terminated or `ongoing` if the alert is still in progress 3. alert name 4. {min,avg,max} values or number of running processes for monitored processes list alerts glances-2.11.1/docs/aoa/memory.rst000066400000000000000000000021611315472316100167450ustar00rootroot00000000000000.. _memory: Memory ====== Glances uses two columns: one for the ``RAM`` and one for the ``SWAP``. .. image:: ../_static/mem.png If enough space is available, Glances displays extended information for the ``RAM``: .. image:: ../_static/mem-wide.png A character is also displayed just after the MEM header and shows the trend value: ======== ============================================================== Trend Status ======== ============================================================== ``-`` MEM value is equal to the mean of the six latests refreshes ``\`` MEM value is lower than the mean of the six latests refreshes ``/`` MEM value is higher than the mean of the six latests refreshes ======== ============================================================== Alerts are only set for used memory and used swap. Legend: ======== ============ RAM/Swap Status ======== ============ ``<50%`` ``OK`` ``>50%`` ``CAREFUL`` ``>70%`` ``WARNING`` ``>90%`` ``CRITICAL`` ======== ============ .. note:: Limit values can be overwritten in the configuration file under the ``[memory]`` and/or ``[memswap]`` sections. glances-2.11.1/docs/aoa/monitor.rst000066400000000000000000000003071315472316100171240ustar00rootroot00000000000000.. _monitor: Monitored Processes List ======================== .. warning:: The monitored processes list feature has been removed. Use the new Application Monitoring Process (AMP) instead. glances-2.11.1/docs/aoa/network.rst000066400000000000000000000031461315472316100171320ustar00rootroot00000000000000.. _network: Network ======= .. image:: ../_static/network.png Glances displays the network interface bit rate. The unit is adapted dynamically (bit/s, kbit/s, Mbit/s, etc). If the interface speed is detected (not on all systems), the defaults thresholds are applied (70% for careful, 80% warning and 90% critical). It is possible to define this percents thresholds from the configuration file. It is also possible to define per interface bit rate thresholds. In this case thresholds values are define in bps. Additionally, you can define: - a list of network interfaces to hide - per-interface limit values - aliases for interface name The configuration should be done in the ``[network]`` section of the Glances configuration file. For example, if you want to hide the loopback interface (lo) and all the virtual docker interface (docker0, docker1, ...): .. code-block:: ini [network] # Default bitrate thresholds in % of the network interface speed # Default values if not defined: 70/80/90 rx_careful=70 rx_warning=80 rx_critical=90 tx_careful=70 tx_warning=80 tx_critical=90 # Define the list of hidden network interfaces (comma-separated regexp) hide=docker.*,lo # WLAN 0 alias wlan0_alias=Wireless IF # It is possible to overwrite the bitrate thresholds per interface # WLAN 0 Default limits (in bits per second aka bps) for interface bitrate wlan0_rx_careful=4000000 wlan0_rx_warning=5000000 wlan0_rx_critical=6000000 wlan0_rx_log=True wlan0_tx_careful=700000 wlan0_tx_warning=900000 wlan0_tx_critical=1000000 wlan0_tx_log=True glances-2.11.1/docs/aoa/ports.rst000066400000000000000000000037111315472316100166060ustar00rootroot00000000000000.. _ports: Ports ===== *Availability: All* .. image:: ../_static/ports.png This plugin aims at providing a list of hosts/port and URL to scan. You can define ``ICMP`` or ``TCP`` ports scans and URL (head only) check. The list should be defined in the ``[ports]`` section of the Glances configuration file. .. code-block:: ini [ports] # Ports scanner plugin configuration # Interval in second between two scans refresh=30 # Set the default timeout (in second) for a scan (can be overwrite in the scan list) timeout=3 # If port_default_gateway is True, add the default gateway on top of the scan list port_default_gateway=True # # Define the scan list (1 < x < 255) # port_x_host (name or IP) is mandatory # port_x_port (TCP port number) is optional (if not set, use ICMP) # port_x_description is optional (if not set, define to host:port) # port_x_timeout is optional and overwrite the default timeout value # port_x_rtt_warning is optional and defines the warning threshold in ms # port_1_host=192.168.0.1 port_1_port=80 port_1_description=Home Box port_1_timeout=1 port_2_host=www.free.fr port_2_description=My ISP port_3_host=www.google.com port_3_description=Internet ICMP port_3_rtt_warning=1000 port_4_host=www.google.com port_4_description=Internet Web port_4_port=80 port_4_rtt_warning=1000 # # Define Web (URL) monitoring list (1 < x < 255) # web_x_url is the URL to monitor (example: http://my.site.com/folder) # web_x_description is optional (if not set, define to URL) # web_x_timeout is optional and overwrite the default timeout value # web_x_rtt_warning is optional and defines the warning respond time in ms (approximatively) # web_1_url=https://blog.nicolargo.com web_1_description=My Blog web_1_rtt_warning=3000 web_2_url=https://github.com web_3_url=http://www.google.fr web_3_description=Google Fr glances-2.11.1/docs/aoa/ps.rst000066400000000000000000000103211315472316100160540ustar00rootroot00000000000000.. _ps: Processes List ============== Compact view: .. image:: ../_static/processlist.png Full view: .. image:: ../_static/processlist-wide.png Filtered view: .. image:: ../_static/processlist-filter.png The process view consists of 3 parts: - Processes summary - Monitored processes list (optional) - Processes list The processes summary line displays: - Tasks number (total number of processes) - Threads number - Running tasks number - Sleeping tasks number - Other tasks number (not running or sleeping) - Sort key By default, or if you hit the ``a`` key, the processes list is automatically sorted by: - ``CPU``: if there is no alert (default behavior) - ``CPU``: if a CPU or LOAD alert is detected - ``MEM``: if a memory alert is detected - ``DISK I/O``: if a CPU iowait alert is detected The number of processes in the list is adapted to the screen size. Columns display --------------- ========================= ============================================== ``CPU%`` % of CPU used by the process If Irix/Solaris mode is off, the value is divided by logical core number ``MEM%`` % of MEM used by the process ``VIRT`` Virtual Memory Size The total amount of virtual memory used by the process. It includes all code, data and shared libraries plus pages that have been swapped out and pages that have been mapped but not used. ``RES`` Resident Memory Size The non-swapped physical memory a process is using (what's currently in the physical memory). ``PID`` Process ID ``USER`` User ID ``NI`` Nice level of the process ``S`` Process status The status of the process: - ``R``: running or runnable (on run queue) - ``S``: interruptible sleep (waiting for an event) - ``D``: uninterruptible sleep (usually I/O) - ``Z``: defunct ("zombie") process - ``T``: traced/stopped by job control signal - ``X``: dead (should never be seen) ``TIME+`` Cumulative CPU time used by the process ``R/s`` Per process I/O read rate in B/s ``W/s`` Per process I/O write rate in B/s ``COMMAND`` Process command line or command name User can switch to the process name by pressing on the ``'/'`` key ========================= ============================================== Process filtering ----------------- It's possible to filter the processes list using the ``ENTER`` key. Filter syntax is the following (examples): - ``python``: Filter processes name or command line starting with *python* (regexp) - ``.*python.*``: Filter processes name or command line containing *python* (regexp) - ``username:nicolargo``: Processes of nicolargo user (key:regexp) - ``cmdline:\/usr\/bin.*``: Processes starting by */usr/bin* Extended info ------------- .. image:: ../_static/processlist-top.png In standalone mode, additional information are provided for the top process: ========================= ============================================== ``CPU affinity`` Number of cores used by the process ``Memory info`` Extended memory information about the process For example, on Linux: swap, shared, text, lib, data and dirty ``Open`` The number of threads, files and network sessions (TCP and UDP) used by the process ``IO nice`` The process I/O niceness (priority) ========================= ============================================== The extended stats feature can be enabled using the ``--enable-process-extended`` option (command line) or the ``e`` key (curses interface). .. note:: Limit values can be overwritten in the configuration file under the ``[process]`` section. glances-2.11.1/docs/aoa/quicklook.rst000066400000000000000000000006311315472316100174360ustar00rootroot00000000000000.. _quicklook: Quick Look ========== The ``quicklook`` plugin is only displayed on wide screen and proposes a bar view for CPU and memory (virtual and swap). .. image:: ../_static/quicklook.png If the per CPU mode is on (by clicking the ``1`` key): .. image:: ../_static/quicklook-percpu.png .. note:: Limit values can be overwritten in the configuration file under the ``[quicklook]`` section. glances-2.11.1/docs/aoa/sensors.rst000066400000000000000000000005251315472316100171330ustar00rootroot00000000000000.. _sensors: Sensors ======= *Availability: Linux* .. image:: ../_static/sensors.png Glances can displays the sensors information using ``psutil`` and/or ``hddtemp``. There is no alert on this information. .. note:: Limit values and sensors alias names can be defined in the configuration file under the ``[sensors]`` section. glances-2.11.1/docs/aoa/wifi.rst000066400000000000000000000017421315472316100163770ustar00rootroot00000000000000.. _wifi: Wi-Fi ===== *Availability: Linux* .. image:: ../_static/wifi.png Glances displays the Wi-Fi hotspot names and signal quality. If Glances is ran as root, then all the available hotspots are displayed. .. note:: You need to install the ``wireless-tools`` package on your system. In the configuration file, you can define signal quality thresholds: - ``"Poor"`` quality is between -100 and -85dBm - ``"Good"`` quality between -85 and -60dBm - ``"Excellent"`` between -60 and -40dBm It's also possible to disable the scan on a specific interface from the configuration file (``[wifi]`` section). For example, if you want to hide the loopback interface (lo) and all the virtual docker interfaces: .. code-block:: ini [wifi] hide=lo,docker.* # Define SIGNAL thresholds in dBm (lower is better...) careful=-65 warning=-75 critical=-85 You can disable this plugin using the ``--disable-wifi`` option or by hitting the ``W`` key from the user interface. glances-2.11.1/docs/api.rst000066400000000000000000000007241315472316100154510ustar00rootroot00000000000000.. _api: API Documentation ================= Glances provides an `XML-RPC server`_ and a `RESTful-JSON`_ API which can be used by other clients. API documentation is available at: - XML-RPC: https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to - RESTful-JSON: https://github.com/nicolargo/glances/wiki/The-Glances-RESTFULL-JSON-API .. _XML-RPC server: http://docs.python.org/2/library/simplexmlrpcserver.html .. _RESTful-JSON: http://jsonapi.org/ glances-2.11.1/docs/cmds.rst000066400000000000000000000203221315472316100156220ustar00rootroot00000000000000.. _cmds: Command Reference ================= Command-Line Options -------------------- .. option:: -h, --help show this help message and exit .. option:: -V, --version show program's version number and exit .. option:: -d, --debug enable debug mode .. option:: -C CONF_FILE, --config CONF_FILE path to the configuration file .. option:: --disable-alert disable alert/log module .. option:: --disable-amps disable application monitoring process module .. option:: --disable-cpu disable CPU module .. option:: --disable-diskio disable disk I/O module .. option:: --disable-docker disable Docker module .. option:: --disable-folders disable folders module .. option:: --disable-fs disable file system module .. option:: --disable-hddtemp disable HD temperature module .. option:: --disable-ip disable IP module .. option:: --disable-irq disable IRQ module .. option:: --disable-load disable load module .. option:: --disable-mem disable memory module .. option:: --disable-memswap disable memory swap module .. option:: --disable-network disable network module .. option:: --disable-now disable current time module .. option:: --disable-ports disable Ports module .. option:: --disable-process disable process module .. option:: --disable-raid disable RAID module .. option:: --disable-sensors disable sensors module .. option:: --disable-wifi disable Wifi module .. option:: -0, --disable-irix task's CPU usage will be divided by the total number of CPUs .. option:: -1, --percpu start Glances in per CPU mode .. option:: -2, --disable-left-sidebar disable network, disk I/O, FS and sensors modules .. option:: -3, --disable-quicklook disable quick look module .. option:: -4, --full-quicklook disable all but quick look and load .. option:: -5, --disable-top disable top menu (QuickLook, CPU, MEM, SWAP and LOAD) .. option:: -6, --meangpu start Glances in mean GPU mode .. option:: --enable-history enable the history mode (matplotlib lib needed) .. option:: --disable-bold disable bold mode in the terminal .. option:: --disable-bg disable background colors in the terminal .. option:: --enable-process-extended enable extended stats on top process .. option:: --export-graph export stats to graph .. option:: --path-graph PATH_GRAPH set the export path for graph history .. option:: --export-csv EXPORT_CSV export stats to a CSV file .. option:: --export-cassandra export stats to a Cassandra/Scylla server (cassandra lib needed) .. option:: --export-couchdb export stats to a CouchDB server (couchdb lib needed) .. option:: --export-elasticsearch export stats to an Elasticsearch server (elasticsearch lib needed) .. option:: --export-influxdb export stats to an InfluxDB server (influxdb lib needed) .. option:: --export-opentsdb export stats to an OpenTSDB server (potsdb lib needed) .. option:: --export-rabbitmq export stats to RabbitMQ broker (pika lib needed) .. option:: --export-statsd export stats to a StatsD server (statsd lib needed) .. option:: --export-riemann export stats to Riemann server (bernhard lib needed) .. option:: --export-zeromq export stats to a ZeroMQ server (zmq lib needed) .. option:: -c CLIENT, --client CLIENT connect to a Glances server by IPv4/IPv6 address, hostname or hostname:port .. option:: -s, --server run Glances in server mode .. option:: --browser start the client browser (list of servers) .. option:: --disable-autodiscover disable autodiscover feature .. option:: -p PORT, --port PORT define the client/server TCP port [default: 61209] .. option:: -B BIND_ADDRESS, --bind BIND_ADDRESS bind server to the given IPv4/IPv6 address or hostname .. option:: --username define a client/server username .. option:: --password define a client/server password .. option:: --snmp-community SNMP_COMMUNITY SNMP community .. option:: --snmp-port SNMP_PORT SNMP port .. option:: --snmp-version SNMP_VERSION SNMP version (1, 2c or 3) .. option:: --snmp-user SNMP_USER SNMP username (only for SNMPv3) .. option:: --snmp-auth SNMP_AUTH SNMP authentication key (only for SNMPv3) .. option:: --snmp-force force SNMP mode .. option:: -t TIME, --time TIME set refresh time in seconds [default: 3 sec] .. option:: -w, --webserver run Glances in web server mode (bottle lib needed) .. option:: --cached-time CACHED_TIME set the server cache time [default: 1 sec] .. option:: open-web-browser try to open the Web UI in the default Web browser .. option:: -q, --quiet do not display the curses interface .. option:: -f PROCESS_FILTER, --process-filter PROCESS_FILTER set the process filter pattern (regular expression) .. option:: --process-short-name force short name for processes name .. option:: --hide-kernel-threads hide kernel threads in process list .. option:: --tree display processes as a tree .. option:: -b, --byte display network rate in byte per second .. option:: --diskio-show-ramfs show RAM FS in the DiskIO plugin .. option:: --diskio-iops show I/O per second in the DiskIO plugin .. option:: --fahrenheit display temperature in Fahrenheit (default is Celsius) .. option:: --fs-free-space display FS free space instead of used .. option:: --theme-white optimize display colors for white background .. option:: --disable-check-update disable online Glances version ckeck Interactive Commands -------------------- The following commands (key pressed) are supported while in Glances: ``ENTER`` Set the process filter .. note:: On macOS please use ``CTRL-H`` to delete filter. Filter is a regular expression pattern: - ``gnome``: matches all processes starting with the ``gnome`` string - ``.*gnome.*``: matches all processes containing the ``gnome`` string ``a`` Sort process list automatically - If CPU ``>70%``, sort processes by CPU usage - If MEM ``>70%``, sort processes by MEM usage - If CPU iowait ``>60%``, sort processes by I/O read and write ``A`` Enable/disable Application Monitoring Process ``b`` Switch between bit/s or Byte/s for network I/O ``B`` View disk I/O counters per second ``c`` Sort processes by CPU usage ``d`` Show/hide disk I/O stats ``D`` Enable/disable Docker stats ``e`` Enable/disable top extended stats ``E`` Erase current process filter ``f`` Show/hide file system and folder monitoring stats ``F`` Switch between file system used and free space ``g`` Generate graphs for current history ``h`` Show/hide the help screen ``i`` Sort processes by I/O rate ``I`` Show/hide IP module ``l`` Show/hide log messages ``m`` Sort processes by MEM usage ``M`` Reset processes summary min/max ``n`` Show/hide network stats ``N`` Show/hide current time ``p`` Sort processes by name ``q|ESC`` Quit the current Glances session ``Q`` Show/hide IRQ module ``r`` Reset history ``R`` Show/hide RAID plugin ``s`` Show/hide sensors stats ``t`` Sort process by CPU times (TIME+) ``T`` View network I/O as combination ``u`` Sort processes by USER ``U`` View cumulative network I/O ``w`` Delete finished warning log messages ``W`` Show/hide Wifi module ``x`` Delete finished warning and critical log messages ``z`` Show/hide processes stats ``0`` Enable/disable Irix/Solaris mode Task's CPU usage will be divided by the total number of CPUs ``1`` Switch between global CPU and per-CPU stats ``2`` Enable/disable left sidebar ``3`` Enable/disable the quick look module ``4`` Enable/disable all but quick look and load module ``5`` Enable/disable top menu (QuickLook, CPU, MEM, SWAP and LOAD) ``6`` Enable/disable mean GPU mode ``/`` Switch between process command line or command name In the Glances client browser (accessible through the ``--browser`` command line argument): ``ENTER`` Run the selected server ``UP`` Up in the servers list ``DOWN`` Down in the servers list ``q|ESC`` Quit Glances glances-2.11.1/docs/conf.py000066400000000000000000000224461315472316100154520ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Glances documentation build configuration file, created by # sphinx-quickstart on Tue Mar 1 10:53:59 2016. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os from datetime import datetime # 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('.')) # Insert Glances' path into the system. sys.path.insert(0, os.path.abspath('..')) from glances import __version__ # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. #extensions = ['sphinxcontrib.autohttp.bottle'] extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Glances' author = 'Nicolas Hennion' year = datetime.now().year copyright = '%d, %s' % (year, 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. # # The short X.Y version. version = __version__ # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = { } # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = { '**': [ 'about.html', 'navigation.html', 'links.html', 'searchbox.html' ] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' #html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value #html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'Glancesdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', # Latex figure (float) alignment #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'Glances.tex', 'Glances Documentation', 'Nicolas Hennion', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('glances', 'glances', 'An eye on your system', '', 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'Glances', 'Glances Documentation', author, 'Glances', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False glances-2.11.1/docs/config.rst000066400000000000000000000116071315472316100161470ustar00rootroot00000000000000.. _config: Configuration ============= No configuration file is mandatory to use Glances. Furthermore a configuration file is needed to access more settings. Location -------- .. note:: A template is available in the ``/usr{,/local}/share/doc/glances`` (Unix-like) directory or directly on `GitHub`_. You can put your own ``glances.conf`` file in the following locations: ==================== ============================================================= ``Linux``, ``SunOS`` ~/.config/glances, /etc/glances ``*BSD`` ~/.config/glances, /usr/local/etc/glances ``macOS`` ~/Library/Application Support/glances, /usr/local/etc/glances ``Windows`` %APPDATA%\\glances ==================== ============================================================= - On Windows XP, ``%APPDATA%`` is: ``C:\Documents and Settings\\Application Data``. - On Windows Vista and later: ``C:\Users\\AppData\Roaming``. User-specific options override system-wide options and options given on the command line override either. Syntax ------ Glances reads configuration files in the *ini* syntax. A first section (called global) is available: .. code-block:: ini [global] # Does Glances should check if a newer version is available on PyPI? check_update=true Each plugin, export module and application monitoring process (AMP) can have a section. Below an example for the CPU plugin: .. code-block:: ini [cpu] user_careful=50 user_warning=70 user_critical=90 iowait_careful=50 iowait_warning=70 iowait_critical=90 system_careful=50 system_warning=70 system_critical=90 steal_careful=50 steal_warning=70 steal_critical=90 an InfluxDB export module: .. code-block:: ini [influxdb] # Configuration for the --export-influxdb option # https://influxdb.com/ host=localhost port=8086 user=root password=root db=glances prefix=localhost #tags=foo:bar,spam:eggs or a Nginx AMP: .. code-block:: ini [amp_nginx] # Nginx status page should be enable (https://easyengine.io/tutorials/nginx/status-page/) enable=true regex=\/usr\/sbin\/nginx refresh=60 one_line=false status_url=http://localhost/nginx_status Logging ------- Glances logs all of its internal messages to a log file. ``DEBUG`` messages can been logged using the ``-d`` option on the command line. By default, the ``glances-USERNAME.log`` file is under the temporary directory: =========== ====== ``*nix`` /tmp ``Windows`` %TEMP% =========== ====== - On Windows XP, ``%TEMP%`` is: ``C:\Documents and Settings\\Local Settings\Temp``. - On Windows Vista and later: ``C:\Users\\AppData\Local\Temp``. If you want to use another system path or change the log message, you can use your own logger configuration. First of all, you have to create a ``glances.json`` file with, for example, the following content (JSON format): .. code-block:: json { "version": 1, "disable_existing_loggers": "False", "root": { "level": "INFO", "handlers": ["file", "console"] }, "formatters": { "standard": { "format": "%(asctime)s -- %(levelname)s -- %(message)s" }, "short": { "format": "%(levelname)s: %(message)s" }, "free": { "format": "%(message)s" } }, "handlers": { "file": { "level": "DEBUG", "class": "logging.handlers.RotatingFileHandler", "formatter": "standard", "filename": "/var/tmp/glances.log" }, "console": { "level": "CRITICAL", "class": "logging.StreamHandler", "formatter": "free" } }, "loggers": { "debug": { "handlers": ["file", "console"], "level": "DEBUG" }, "verbose": { "handlers": ["file", "console"], "level": "INFO" }, "standard": { "handlers": ["file"], "level": "INFO" }, "requests": { "handlers": ["file", "console"], "level": "ERROR" }, "elasticsearch": { "handlers": ["file", "console"], "level": "ERROR" }, "elasticsearch.trace": { "handlers": ["file", "console"], "level": "ERROR" } } } and start Glances using the following command line: .. code-block:: console LOG_CFG=/glances.json glances .. note:: Replace ```` by the folder where your ``glances.json`` file is hosted. .. _GitHub: https://raw.githubusercontent.com/nicolargo/glances/master/conf/glances.conf glances-2.11.1/docs/glances.rst000066400000000000000000000027711315472316100163200ustar00rootroot00000000000000:orphan: glances ======= SYNOPSIS -------- **glances** [OPTIONS] DESCRIPTION ----------- **glances** is a cross-platform curses-based monitoring tool which aims to present a maximum of information in a minimum of space, ideally to fit in a classical 80x24 terminal or higher to have additional information. It can adapt dynamically the displayed information depending on the terminal size. It can also work in client/server mode. Remote monitoring could be done via terminal or web interface. **glances** is written in Python and uses the *psutil* library to get information from your system. OPTIONS ------- .. include:: cmds.rst CONFIGURATION ------------- .. include:: config.rst EXAMPLES -------- Monitor local machine (standalone mode): $ glances Monitor local machine with the web interface (Web UI): $ glances -w Monitor local machine and export stats to a CSV file: $ glances --export-csv Monitor local machine and export stats to a InfluxDB server with 5s refresh time (also possible to export to OpenTSDB, Cassandra, Statsd, ElasticSearch, RabbitMQ and Riemann): $ glances -t 5 --export-influxdb Start a Glances server (server mode): $ glances -s Connect Glances to a Glances server (client mode): $ glances -c Connect to a Glances server and export stats to a StatsD server: $ glances -c --export-statsd Start the client browser (browser mode): $ glances --browser AUTHOR ------ Nicolas Hennion aka Nicolargo glances-2.11.1/docs/gw/000077500000000000000000000000001315472316100145605ustar00rootroot00000000000000glances-2.11.1/docs/gw/cassandra.rst000066400000000000000000000013641315472316100172550ustar00rootroot00000000000000.. _cassandra: Cassandra ========= You can export statistics to a ``Cassandra`` or ``Scylla`` server. The connection should be defined in the Glances configuration file as following: .. code-block:: ini [cassandra] host=localhost port=9042 protocol_version=3 keyspace=glances replication_factor=2 table=localhost and run Glances with: .. code-block:: console $ glances --export-cassandra The data model is the following: .. code-block:: ini CREATE TABLE (plugin text, time timeuuid, stat map, PRIMARY KEY (plugin, time)) Only numerical stats are stored in the Cassandra table. All the stats are converted to float. If a stat cannot be converted to float, it is not stored in the database. glances-2.11.1/docs/gw/couchdb.rst000066400000000000000000000021111315472316100167140ustar00rootroot00000000000000.. _couchdb: CouchDB ======= You can export statistics to a ``CouchDB`` server. The connection should be defined in the Glances configuration file as following: .. code-block:: ini [couchdb] host=localhost port=5984 user=root password=root db=glances and run Glances with: .. code-block:: console $ glances --export-couchdb Documents are stored in native ``JSON`` format. Glances adds ``"type"`` and ``"time"`` entries: - ``type``: plugin name - ``time``: timestamp (format: "2016-09-24T16:39:08.524828Z") Example of Couch Document for the load stats: .. code-block:: json { "_id": "36cbbad81453c53ef08804cb2612d5b6", "_rev": "1-382400899bec5615cabb99aa34df49fb", "min15": 0.33, "time": "2016-09-24T16:39:08.524828Z", "min5": 0.4, "cpucore": 4, "load_warning": 1, "min1": 0.5, "history_size": 28800, "load_critical": 5, "type": "load", "load_careful": 0.7 } You can view the result using the CouchDB utils URL: http://127.0.0.1:5984/_utils/database.html?glances. glances-2.11.1/docs/gw/csv.rst000066400000000000000000000003251315472316100161050ustar00rootroot00000000000000.. _csv: CSV === It's possible to export stats to a CSV file. .. code-block:: console $ glances --export-csv /tmp/glances.csv CSV file description: - Stats description (first line) - Stats (other lines) glances-2.11.1/docs/gw/elastic.rst000066400000000000000000000014241315472316100167370ustar00rootroot00000000000000.. _elastic: Elasticsearch ============= You can export statistics to an ``Elasticsearch`` server. The connection should be defined in the Glances configuration file as following: .. code-block:: ini [elasticsearch] host=localhost port=9200 index=glances and run Glances with: .. code-block:: console $ glances --export-elasticsearch The stats are available through the elasticsearch API. For example, to get the CPU system stats: .. code-block:: console $ curl http://172.17.0.2:9200/glances/cpu/system { "_index": "glances", "_type": "cpu", "_id": "system", "_version": 28, "found": true," _source": { "timestamp": "2016-02-04T14:11:02.362232", "value": "2.2" } } glances-2.11.1/docs/gw/index.rst000066400000000000000000000005751315472316100164300ustar00rootroot00000000000000.. _gw: Gateway To Other Services ========================= Glances can exports stats to a CSV file. Also, it can act as a gateway to providing stats to multiple services (see list below). .. toctree:: :maxdepth: 2 csv json cassandra couchdb elastic influxdb json kafka opentsdb prometheus rabbitmq restful riemann statsd zeromq glances-2.11.1/docs/gw/influxdb.rst000066400000000000000000000016321315472316100171270ustar00rootroot00000000000000.. _influxdb: InfluxDB ======== You can export statistics to an ``InfluxDB`` server (time series server). The connection should be defined in the Glances configuration file as following: .. code-block:: ini [influxdb] host=localhost port=8086 user=root password=root db=glances tags=foo:bar,spam:eggs and run Glances with: .. code-block:: console $ glances --export-influxdb Glances generates a lot of columns, e.g., if you have many running Docker containers, so you should use the ``tsm1`` engine in the InfluxDB configuration file (no limit on columns number). Grafana ------- For Grafana users, Glances provides a dedicated `dashboard`_. .. image:: ../_static/glances-influxdb.png To use it, just import the file in your ``Grafana`` web interface. .. image:: ../_static/grafana.png .. _dashboard: https://github.com/nicolargo/glances/blob/master/conf/glances-grafana.json glances-2.11.1/docs/gw/json.rst000066400000000000000000000002141315472316100162600ustar00rootroot00000000000000.. _json: JSON ==== It's possible to export stats to a JSON file. .. code-block:: console $ glances --export-json /tmp/glances.json glances-2.11.1/docs/gw/kafka.rst000066400000000000000000000024501315472316100163700ustar00rootroot00000000000000.. _kafka: Kafka ===== You can export statistics to a ``Kafka`` server. The connection should be defined in the Glances configuration file as following: .. code-block:: ini [kafka] host=localhost port=9092 topic=glances #compression=gzip Note: you can enable the compression but it consume CPU on your host. and run Glances with: .. code-block:: console $ glances --export-kafka Stats are sent in native ``JSON`` format to the topic: - ``key``: plugin name - ``value``: JSON dict Example of record for the memory plugin: .. code-block:: ini ConsumerRecord(topic=u'glances', partition=0, offset=1305, timestamp=1490460592248, timestamp_type=0, key='mem', value=u'{"available": 2094710784, "used": 5777428480, "cached": 2513543168, "mem_careful": 50.0, "percent": 73.4, "free": 2094710784, "mem_critical": 90.0, "inactive": 2361626624, "shared": 475504640, "history_size": 28800.0, "mem_warning": 70.0, "total": 7872139264, "active": 4834361344, "buffers": 160112640}', checksum=214895201, serialized_key_size=3, serialized_value_size=303) Python code example to consume Kafka Glances plugin: .. code-block:: python from kafka import KafkaConsumer import json consumer = KafkaConsumer('glances', value_deserializer=json.loads) for s in consumer: print s glances-2.11.1/docs/gw/opentsdb.rst000066400000000000000000000006021315472316100171260ustar00rootroot00000000000000.. _opentsdb: OpenTSDB ======== You can export statistics to an ``OpenTSDB`` server (time series server). The connection should be defined in the Glances configuration file as following: .. code-block:: ini [opentsdb] host=localhost port=4242 prefix=glances tags=foo:bar,spam:eggs and run Glances with: .. code-block:: console $ glances --export-opentsdb glances-2.11.1/docs/gw/prometheus.rst000066400000000000000000000017171315472316100175130ustar00rootroot00000000000000.. _prometheus: Prometheus ========== You can export statistics to a ``Prometheus`` server through an exporter. When the *--export-prometheus* is used, Glances creates a Prometheus exporter listening on (define in the Glances configuration file). .. code-block:: ini [prometheus] host=localhost port=9091 prefix=glances and run Glances with: .. code-block:: console $ glances --export-prometheus You can check that Glances exports the stats using this URL: http://localhost:9091 .. image:: ../_static/prometheus_exporter.png In order to store the metrics in a Prometheus server, you should add this exporter to your Prometheus server configuration with the following lines (in the prometheus.yml configuration file): .. code-block:: ini scrape_configs: - job_name: 'glances_exporter' scrape_interval: 5s static_configs: - targets: ['localhost:9091'] .. image:: ../_static/prometheus_server.png glances-2.11.1/docs/gw/rabbitmq.rst000066400000000000000000000006131315472316100171130ustar00rootroot00000000000000.. _rabbitmq: RabbitMQ ======== You can export statistics to an ``RabbitMQ`` server (AMQP Broker). The connection should be defined in the Glances configuration file as following: .. code-block:: ini [rabbitmq] host=localhost port=5672 user=glances password=glances queue=glances_queue and run Glances with: .. code-block:: console $ glances --export-rabbitmq glances-2.11.1/docs/gw/restful.rst000066400000000000000000000015151315472316100170000ustar00rootroot00000000000000.. _restful: Restful ======= You can export statistics to a ``Restful`` JSON server. All the available stats will be exported in one big (~15 KB) POST request to the Restful endpoint. The Restful endpoint should be defined in the Glances configuration file as following: .. code-block:: ini [restful] # Configuration for the --export-restful option # Example, export to http://localhost:6789/ host=localhost port=6789 protocol=http path=/ URL Syntax: .. code-block:: ini http://localhost:6789/ | | | | | | | path | | port | host protocol and run Glances with: .. code-block:: console $ glances --export-restful Glances will generate stats as a big JSON dictionary (see example `here`_). .. _here: https://pastebin.com/7U3vXqvF glances-2.11.1/docs/gw/riemann.rst000066400000000000000000000005151315472316100167440ustar00rootroot00000000000000.. _riemann: Riemann ======= You can export statistics to a ``Riemann`` server (using TCP protocol). The connection should be defined in the Glances configuration file as following: .. code-block:: ini [riemann] host=localhost port=5555 and run Glances with: .. code-block:: console $ glances --export-riemann glances-2.11.1/docs/gw/statsd.rst000066400000000000000000000011041315472316100166100ustar00rootroot00000000000000.. _statsd: StatsD ====== You can export statistics to a ``StatsD`` server (welcome to Graphite!). The connection should be defined in the Glances configuration file as following: .. code-block:: ini [statsd] host=localhost port=8125 prefix=glances .. note:: The ``prefix`` is optional (``glances`` by default) and run Glances with: .. code-block:: console $ glances --export-statsd Glances will generate stats as: :: 'glances.cpu.user': 12.5, 'glances.cpu.total': 14.9, 'glances.load.cpucore': 4, 'glances.load.min1': 0.19, ... glances-2.11.1/docs/gw/zeromq.rst000066400000000000000000000023031315472316100166250ustar00rootroot00000000000000.. _zeromq: ZeroMQ ====== You can export statistics to a ``ZeroMQ`` server. The connection should be defined in the Glances configuration file as following: .. code-block:: ini [zeromq] host=127.0.0.1 port=5678 prefix=G Glances `envelopes`_ the stats before publishing it. The message is composed of three frames: 1. the prefix configured in the [zeromq] section (as STRING) 2. the Glances plugin name (as STRING) 3. the Glances plugin stats (as JSON) Run Glances with: .. code-block:: console $ glances --export-zeromq -C /glances.conf Following is a simple Python client to subscribe to the Glances stats: .. code-block:: python # -*- coding: utf-8 -*- # # ZeroMQ subscriber for Glances # import json import zmq context = zmq.Context() subscriber = context.socket(zmq.SUB) subscriber.setsockopt(zmq.SUBSCRIBE, 'G') subscriber.connect("tcp://127.0.0.1:5678") while True: _, plugin, data_raw = subscriber.recv_multipart() data = json.loads(data_raw) print('{} => {}'.format(plugin, data)) subscriber.close() context.term() .. _envelopes: http://zguide.zeromq.org/page:all#Pub-Sub-Message-Envelopes glances-2.11.1/docs/index.rst000066400000000000000000000014231315472316100160040ustar00rootroot00000000000000Glances ======= .. image:: _static/screenshot-wide.png Glances is a cross-platform monitoring tool which aims to present a maximum of information in a minimum of space through a curses or Web based interface. It can adapt dynamically the displayed information depending on the terminal size. It can also work in client/server mode. Remote monitoring could be done via terminal, Web interface or API (XMLRPC and RESTful). Glances is written in Python and uses the `psutil`_ library to get information from your system. Stats can also be exported to external time/value databases. .. _psutil: https://github.com/giampaolo/psutil Table of Contents ================= .. toctree:: :maxdepth: 2 install quickstart cmds config aoa/index gw/index api support glances-2.11.1/docs/install.rst000066400000000000000000000021441315472316100163440ustar00rootroot00000000000000.. _install: Install ======= Glances is on ``PyPI``. By using PyPI, you are sure to have the latest stable version. To install, simply use ``pip``: .. code-block:: console pip install glances *Note*: Python headers are required to install `psutil`_. For example, on Debian/Ubuntu you need to install first the *python-dev* package. For Fedora/CentOS/RHEL install first *python-devel* package. For Windows, just install PsUtil from the binary installation file. You can also install the following libraries in order to use optional features (like the Web interface, export modules...): .. code-block:: console pip install glances[action,browser,cloud,cpuinfo,chart,docker,export,folders,gpu,ip,raid,snmp,web,wifi] To upgrade Glances and all its dependencies to the latest versions: .. code-block:: console pip install --upgrade glances pip install --upgrade psutil pip install --upgrade glances[...] For additional installation methods, read the official `README`_ file. .. _psutil: https://github.com/giampaolo/psutil .. _README: https://github.com/nicolargo/glances/blob/master/README.rst glances-2.11.1/docs/make.bat000066400000000000000000000161231315472316100155530ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) 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. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of 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 ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok 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\Glances.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Glances.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" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF 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" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 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 ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end glances-2.11.1/docs/man/000077500000000000000000000000001315472316100147165ustar00rootroot00000000000000glances-2.11.1/docs/man/glances.1000066400000000000000000000417361315472316100164270ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "GLANCES" "1" "Sep 09, 2017" "2.11.1_DEVELOP" "Glances" .SH NAME glances \- An eye on your system . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .sp \fBglances\fP [OPTIONS] .SH DESCRIPTION .sp \fBglances\fP is a cross\-platform curses\-based monitoring tool which aims to present a maximum of information in a minimum of space, ideally to fit in a classical 80x24 terminal or higher to have additional information. It can adapt dynamically the displayed information depending on the terminal size. It can also work in client/server mode. Remote monitoring could be done via terminal or web interface. .sp \fBglances\fP is written in Python and uses the \fIpsutil\fP library to get information from your system. .SH OPTIONS .SH COMMAND-LINE OPTIONS .INDENT 0.0 .TP .B \-h, \-\-help show this help message and exit .UNINDENT .INDENT 0.0 .TP .B \-V, \-\-version show program\(aqs version number and exit .UNINDENT .INDENT 0.0 .TP .B \-d, \-\-debug enable debug mode .UNINDENT .INDENT 0.0 .TP .B \-C CONF_FILE, \-\-config CONF_FILE path to the configuration file .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-alert disable alert/log module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-amps disable application monitoring process module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-cpu disable CPU module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-diskio disable disk I/O module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-docker disable Docker module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-folders disable folders module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-fs disable file system module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-hddtemp disable HD temperature module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-ip disable IP module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-irq disable IRQ module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-load disable load module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-mem disable memory module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-memswap disable memory swap module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-network disable network module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-now disable current time module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-ports disable Ports module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-process disable process module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-raid disable RAID module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-sensors disable sensors module .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-wifi disable Wifi module .UNINDENT .INDENT 0.0 .TP .B \-0, \-\-disable\-irix task\(aqs CPU usage will be divided by the total number of CPUs .UNINDENT .INDENT 0.0 .TP .B \-1, \-\-percpu start Glances in per CPU mode .UNINDENT .INDENT 0.0 .TP .B \-2, \-\-disable\-left\-sidebar disable network, disk I/O, FS and sensors modules .UNINDENT .INDENT 0.0 .TP .B \-3, \-\-disable\-quicklook disable quick look module .UNINDENT .INDENT 0.0 .TP .B \-4, \-\-full\-quicklook disable all but quick look and load .UNINDENT .INDENT 0.0 .TP .B \-5, \-\-disable\-top disable top menu (QuickLook, CPU, MEM, SWAP and LOAD) .UNINDENT .INDENT 0.0 .TP .B \-6, \-\-meangpu start Glances in mean GPU mode .UNINDENT .INDENT 0.0 .TP .B \-\-enable\-history enable the history mode (matplotlib lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-bold disable bold mode in the terminal .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-bg disable background colors in the terminal .UNINDENT .INDENT 0.0 .TP .B \-\-enable\-process\-extended enable extended stats on top process .UNINDENT .INDENT 0.0 .TP .B \-\-export\-graph export stats to graph .UNINDENT .INDENT 0.0 .TP .B \-\-path\-graph PATH_GRAPH set the export path for graph history .UNINDENT .INDENT 0.0 .TP .B \-\-export\-csv EXPORT_CSV export stats to a CSV file .UNINDENT .INDENT 0.0 .TP .B \-\-export\-cassandra export stats to a Cassandra/Scylla server (cassandra lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-couchdb export stats to a CouchDB server (couchdb lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-elasticsearch export stats to an Elasticsearch server (elasticsearch lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-influxdb export stats to an InfluxDB server (influxdb lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-opentsdb export stats to an OpenTSDB server (potsdb lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-rabbitmq export stats to RabbitMQ broker (pika lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-statsd export stats to a StatsD server (statsd lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-riemann export stats to Riemann server (bernhard lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-export\-zeromq export stats to a ZeroMQ server (zmq lib needed) .UNINDENT .INDENT 0.0 .TP .B \-c CLIENT, \-\-client CLIENT connect to a Glances server by IPv4/IPv6 address, hostname or hostname:port .UNINDENT .INDENT 0.0 .TP .B \-s, \-\-server run Glances in server mode .UNINDENT .INDENT 0.0 .TP .B \-\-browser start the client browser (list of servers) .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-autodiscover disable autodiscover feature .UNINDENT .INDENT 0.0 .TP .B \-p PORT, \-\-port PORT define the client/server TCP port [default: 61209] .UNINDENT .INDENT 0.0 .TP .B \-B BIND_ADDRESS, \-\-bind BIND_ADDRESS bind server to the given IPv4/IPv6 address or hostname .UNINDENT .INDENT 0.0 .TP .B \-\-username define a client/server username .UNINDENT .INDENT 0.0 .TP .B \-\-password define a client/server password .UNINDENT .INDENT 0.0 .TP .B \-\-snmp\-community SNMP_COMMUNITY SNMP community .UNINDENT .INDENT 0.0 .TP .B \-\-snmp\-port SNMP_PORT SNMP port .UNINDENT .INDENT 0.0 .TP .B \-\-snmp\-version SNMP_VERSION SNMP version (1, 2c or 3) .UNINDENT .INDENT 0.0 .TP .B \-\-snmp\-user SNMP_USER SNMP username (only for SNMPv3) .UNINDENT .INDENT 0.0 .TP .B \-\-snmp\-auth SNMP_AUTH SNMP authentication key (only for SNMPv3) .UNINDENT .INDENT 0.0 .TP .B \-\-snmp\-force force SNMP mode .UNINDENT .INDENT 0.0 .TP .B \-t TIME, \-\-time TIME set refresh time in seconds [default: 3 sec] .UNINDENT .INDENT 0.0 .TP .B \-w, \-\-webserver run Glances in web server mode (bottle lib needed) .UNINDENT .INDENT 0.0 .TP .B \-\-cached\-time CACHED_TIME set the server cache time [default: 1 sec] .UNINDENT .INDENT 0.0 .TP .B open\-web\-browser try to open the Web UI in the default Web browser .UNINDENT .INDENT 0.0 .TP .B \-q, \-\-quiet do not display the curses interface .UNINDENT .INDENT 0.0 .TP .B \-f PROCESS_FILTER, \-\-process\-filter PROCESS_FILTER set the process filter pattern (regular expression) .UNINDENT .INDENT 0.0 .TP .B \-\-process\-short\-name force short name for processes name .UNINDENT .INDENT 0.0 .TP .B \-\-hide\-kernel\-threads hide kernel threads in process list .UNINDENT .INDENT 0.0 .TP .B \-\-tree display processes as a tree .UNINDENT .INDENT 0.0 .TP .B \-b, \-\-byte display network rate in byte per second .UNINDENT .INDENT 0.0 .TP .B \-\-diskio\-show\-ramfs show RAM FS in the DiskIO plugin .UNINDENT .INDENT 0.0 .TP .B \-\-diskio\-iops show I/O per second in the DiskIO plugin .UNINDENT .INDENT 0.0 .TP .B \-\-fahrenheit display temperature in Fahrenheit (default is Celsius) .UNINDENT .INDENT 0.0 .TP .B \-\-fs\-free\-space display FS free space instead of used .UNINDENT .INDENT 0.0 .TP .B \-\-theme\-white optimize display colors for white background .UNINDENT .INDENT 0.0 .TP .B \-\-disable\-check\-update disable online Glances version ckeck .UNINDENT .SH INTERACTIVE COMMANDS .sp The following commands (key pressed) are supported while in Glances: .INDENT 0.0 .TP .B \fBENTER\fP Set the process filter .sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 On macOS please use \fBCTRL\-H\fP to delete filter. .UNINDENT .UNINDENT .sp Filter is a regular expression pattern: .INDENT 7.0 .IP \(bu 2 \fBgnome\fP: matches all processes starting with the \fBgnome\fP string .IP \(bu 2 \fB\&.*gnome.*\fP: matches all processes containing the \fBgnome\fP string .UNINDENT .TP .B \fBa\fP Sort process list automatically .INDENT 7.0 .IP \(bu 2 If CPU \fB>70%\fP, sort processes by CPU usage .IP \(bu 2 If MEM \fB>70%\fP, sort processes by MEM usage .IP \(bu 2 If CPU iowait \fB>60%\fP, sort processes by I/O read and write .UNINDENT .TP .B \fBA\fP Enable/disable Application Monitoring Process .TP .B \fBb\fP Switch between bit/s or Byte/s for network I/O .TP .B \fBB\fP View disk I/O counters per second .TP .B \fBc\fP Sort processes by CPU usage .TP .B \fBd\fP Show/hide disk I/O stats .TP .B \fBD\fP Enable/disable Docker stats .TP .B \fBe\fP Enable/disable top extended stats .TP .B \fBE\fP Erase current process filter .TP .B \fBf\fP Show/hide file system and folder monitoring stats .TP .B \fBF\fP Switch between file system used and free space .TP .B \fBg\fP Generate graphs for current history .TP .B \fBh\fP Show/hide the help screen .TP .B \fBi\fP Sort processes by I/O rate .TP .B \fBI\fP Show/hide IP module .TP .B \fBl\fP Show/hide log messages .TP .B \fBm\fP Sort processes by MEM usage .TP .B \fBM\fP Reset processes summary min/max .TP .B \fBn\fP Show/hide network stats .TP .B \fBN\fP Show/hide current time .TP .B \fBp\fP Sort processes by name .TP .B \fBq|ESC\fP Quit the current Glances session .TP .B \fBQ\fP Show/hide IRQ module .TP .B \fBr\fP Reset history .TP .B \fBR\fP Show/hide RAID plugin .TP .B \fBs\fP Show/hide sensors stats .TP .B \fBt\fP Sort process by CPU times (TIME+) .TP .B \fBT\fP View network I/O as combination .TP .B \fBu\fP Sort processes by USER .TP .B \fBU\fP View cumulative network I/O .TP .B \fBw\fP Delete finished warning log messages .TP .B \fBW\fP Show/hide Wifi module .TP .B \fBx\fP Delete finished warning and critical log messages .TP .B \fBz\fP Show/hide processes stats .TP .B \fB0\fP Enable/disable Irix/Solaris mode .sp Task\(aqs CPU usage will be divided by the total number of CPUs .TP .B \fB1\fP Switch between global CPU and per\-CPU stats .TP .B \fB2\fP Enable/disable left sidebar .TP .B \fB3\fP Enable/disable the quick look module .TP .B \fB4\fP Enable/disable all but quick look and load module .TP .B \fB5\fP Enable/disable top menu (QuickLook, CPU, MEM, SWAP and LOAD) .TP .B \fB6\fP Enable/disable mean GPU mode .TP .B \fB/\fP Switch between process command line or command name .UNINDENT .sp In the Glances client browser (accessible through the \fB\-\-browser\fP command line argument): .INDENT 0.0 .TP .B \fBENTER\fP Run the selected server .TP .B \fBUP\fP Up in the servers list .TP .B \fBDOWN\fP Down in the servers list .TP .B \fBq|ESC\fP Quit Glances .UNINDENT .SH CONFIGURATION .sp No configuration file is mandatory to use Glances. .sp Furthermore a configuration file is needed to access more settings. .SH LOCATION .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 A template is available in the \fB/usr{,/local}/share/doc/glances\fP (Unix\-like) directory or directly on \fI\%GitHub\fP\&. .UNINDENT .UNINDENT .sp You can put your own \fBglances.conf\fP file in the following locations: .TS center; |l|l|. _ T{ \fBLinux\fP, \fBSunOS\fP T} T{ ~/.config/glances, /etc/glances T} _ T{ \fB*BSD\fP T} T{ ~/.config/glances, /usr/local/etc/glances T} _ T{ \fBmacOS\fP T} T{ ~/Library/Application Support/glances, /usr/local/etc/glances T} _ T{ \fBWindows\fP T} T{ %APPDATA%\eglances T} _ .TE .INDENT 0.0 .IP \(bu 2 On Windows XP, \fB%APPDATA%\fP is: \fBC:\eDocuments and Settings\e\eApplication Data\fP\&. .IP \(bu 2 On Windows Vista and later: \fBC:\eUsers\e\eAppData\eRoaming\fP\&. .UNINDENT .sp User\-specific options override system\-wide options and options given on the command line override either. .SH SYNTAX .sp Glances reads configuration files in the \fIini\fP syntax. .sp A first section (called global) is available: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [global] # Does Glances should check if a newer version is available on PyPI? check_update=true .ft P .fi .UNINDENT .UNINDENT .sp Each plugin, export module and application monitoring process (AMP) can have a section. Below an example for the CPU plugin: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [cpu] user_careful=50 user_warning=70 user_critical=90 iowait_careful=50 iowait_warning=70 iowait_critical=90 system_careful=50 system_warning=70 system_critical=90 steal_careful=50 steal_warning=70 steal_critical=90 .ft P .fi .UNINDENT .UNINDENT .sp an InfluxDB export module: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [influxdb] # Configuration for the \-\-export\-influxdb option # https://influxdb.com/ host=localhost port=8086 user=root password=root db=glances prefix=localhost #tags=foo:bar,spam:eggs .ft P .fi .UNINDENT .UNINDENT .sp or a Nginx AMP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [amp_nginx] # Nginx status page should be enable (https://easyengine.io/tutorials/nginx/status\-page/) enable=true regex=\e/usr\e/sbin\e/nginx refresh=60 one_line=false status_url=http://localhost/nginx_status .ft P .fi .UNINDENT .UNINDENT .SH LOGGING .sp Glances logs all of its internal messages to a log file. .sp \fBDEBUG\fP messages can been logged using the \fB\-d\fP option on the command line. .sp By default, the \fBglances\-USERNAME.log\fP file is under the temporary directory: .TS center; |l|l|. _ T{ \fB*nix\fP T} T{ /tmp T} _ T{ \fBWindows\fP T} T{ %TEMP% T} _ .TE .INDENT 0.0 .IP \(bu 2 On Windows XP, \fB%TEMP%\fP is: \fBC:\eDocuments and Settings\e\eLocal Settings\eTemp\fP\&. .IP \(bu 2 On Windows Vista and later: \fBC:\eUsers\e\eAppData\eLocal\eTemp\fP\&. .UNINDENT .sp If you want to use another system path or change the log message, you can use your own logger configuration. First of all, you have to create a \fBglances.json\fP file with, for example, the following content (JSON format): .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C { "version": 1, "disable_existing_loggers": "False", "root": { "level": "INFO", "handlers": ["file", "console"] }, "formatters": { "standard": { "format": "%(asctime)s \-\- %(levelname)s \-\- %(message)s" }, "short": { "format": "%(levelname)s: %(message)s" }, "free": { "format": "%(message)s" } }, "handlers": { "file": { "level": "DEBUG", "class": "logging.handlers.RotatingFileHandler", "formatter": "standard", "filename": "/var/tmp/glances.log" }, "console": { "level": "CRITICAL", "class": "logging.StreamHandler", "formatter": "free" } }, "loggers": { "debug": { "handlers": ["file", "console"], "level": "DEBUG" }, "verbose": { "handlers": ["file", "console"], "level": "INFO" }, "standard": { "handlers": ["file"], "level": "INFO" }, "requests": { "handlers": ["file", "console"], "level": "ERROR" }, "elasticsearch": { "handlers": ["file", "console"], "level": "ERROR" }, "elasticsearch.trace": { "handlers": ["file", "console"], "level": "ERROR" } } } .ft P .fi .UNINDENT .UNINDENT .sp and start Glances using the following command line: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C LOG_CFG=/glances.json glances .ft P .fi .UNINDENT .UNINDENT .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 Replace \fB\fP by the folder where your \fBglances.json\fP file is hosted. .UNINDENT .UNINDENT .SH EXAMPLES .sp Monitor local machine (standalone mode): .INDENT 0.0 .INDENT 3.5 $ glances .UNINDENT .UNINDENT .sp Monitor local machine with the web interface (Web UI): .INDENT 0.0 .INDENT 3.5 $ glances \-w .UNINDENT .UNINDENT .sp Monitor local machine and export stats to a CSV file: .INDENT 0.0 .INDENT 3.5 $ glances \-\-export\-csv .UNINDENT .UNINDENT .sp Monitor local machine and export stats to a InfluxDB server with 5s refresh time (also possible to export to OpenTSDB, Cassandra, Statsd, ElasticSearch, RabbitMQ and Riemann): .INDENT 0.0 .INDENT 3.5 $ glances \-t 5 \-\-export\-influxdb .UNINDENT .UNINDENT .sp Start a Glances server (server mode): .INDENT 0.0 .INDENT 3.5 $ glances \-s .UNINDENT .UNINDENT .sp Connect Glances to a Glances server (client mode): .INDENT 0.0 .INDENT 3.5 $ glances \-c .UNINDENT .UNINDENT .sp Connect to a Glances server and export stats to a StatsD server: .INDENT 0.0 .INDENT 3.5 $ glances \-c \-\-export\-statsd .UNINDENT .UNINDENT .sp Start the client browser (browser mode): .INDENT 0.0 .INDENT 3.5 $ glances \-\-browser .UNINDENT .UNINDENT .SH AUTHOR .sp Nicolas Hennion aka Nicolargo <\fI\%contact@nicolargo.com\fP> .SH COPYRIGHT 2017, Nicolas Hennion .\" Generated by docutils manpage writer. . glances-2.11.1/docs/quickstart.rst000066400000000000000000000073621315472316100170770ustar00rootroot00000000000000.. _quickstart: Quickstart ========== This page gives a good introduction in how to get started with Glances. Glances offers 3 modes: - Standalone - Client/Server - Web server Standalone Mode --------------- If you want to monitor your local machine, open a console/terminal and simply run: .. code-block:: console $ glances Glances should start (press 'q' or 'ESC' to exit): .. image:: _static/screenshot-wide.png Client/Server Mode ------------------ If you want to remotely monitor a machine, called ``server``, from another one, called ``client``, just run on the server: .. code-block:: console server$ glances -s and on the client: .. code-block:: console client$ glances -c @server where ``@server`` is the IP address or hostname of the server. In server mode, you can set the bind address with ``-B ADDRESS`` and the listening TCP port with ``-p PORT``. In client mode, you can set the TCP port of the server with ``-p PORT``. Default binding address is ``0.0.0.0`` (Glances will listen on all the available network interfaces) and TCP port is ``61209``. In client/server mode, limits are set by the server side. You can set a password to access to the server ``--password``. By default, the username is ``glances`` but you can change it with ``--username``. It is also possible to set the password in the Glances configuration file: .. code-block:: ini [passwords] # Define the passwords list # Syntax: host=password # Where: host is the hostname # password is the clear password # Additionally (and optionally) a default password could be defined localhost=mylocalhostpassword default=mydefaultpassword If you ask it, the SHA password will be stored in ``username.pwd`` file. Next time your run the server/client, password will not be asked. Central client ^^^^^^^^^^^^^^ .. image:: _static/browser.png Glances can centralize available Glances servers using the ``--browser`` option. The server list can be statically defined via the configuration file (section ``[serverlist]``). Example: .. code-block:: ini [serverlist] # Define the static servers list server_1_name=xps server_1_alias=xps server_1_port=61209 server_2_name=win server_2_port=61235 Glances can also detect and display all Glances servers available on your network via the ``zeroconf`` protocol (not available on Windows): To start the central client, use the following option: .. code-block:: console client$ glances --browser .. note:: Use ``--disable-autodiscover`` to disable the auto discovery mode. SNMP ^^^^ As an experimental feature, if Glances server is not detected by the client, the latter will try to grab stats using the ``SNMP`` protocol: .. code-block:: console client$ glances -c @snmpserver .. note:: Stats grabbed by SNMP request are limited and OS dependent. A SNMP server should be installed and configured... IPv6 ^^^^ Glances is ``IPv6`` compatible. Just use the ``-B ::`` option to bind to all IPv6 addresses. Web Server Mode --------------- .. image:: _static/screenshot-web.png If you want to remotely monitor a machine, called ``server``, from any device with a web browser, just run the server with the ``-w`` option: .. code-block:: console server$ glances -w then on the client enter the following URL in your favorite web browser: :: http://@server:61208 where ``@server`` is the IP address or hostname of the server. To change the refresh rate of the page, just add the period in seconds at the end of the URL. For example, to refresh the page every ``10`` seconds: :: http://@server:61208/10 The Glances web interface follows responsive web design principles. Here's a screenshot from Chrome on Android: .. image:: _static/screenshot-web2.png glances-2.11.1/docs/support.rst000066400000000000000000000005051315472316100164110ustar00rootroot00000000000000.. _support: Support ======= To post a question about Glances use cases, please post it to the official Q&A `forum `_. To report a bug or a feature request use the GitHub `issue `_ tracker. Feel free to contribute! glances-2.11.1/glances/000077500000000000000000000000001315472316100146275ustar00rootroot00000000000000glances-2.11.1/glances/README.txt000066400000000000000000000041611315472316100163270ustar00rootroot00000000000000You are in the main Glances source folder. This page is **ONLY** for developers. If you are looking for the user manual, please follow this link: https://github.com/nicolargo/glances/blob/master/docs/glances-doc.rst === __init__.py Global module init __main__.py Entry point for Glances module config.py Manage the configuration file compat.py Python2/3 compatibility shims module globals.py Share variables upon modules main.py Main script to rule them up... client.py Glances client server.py Glances server webserver.py Glances web server (Bottle-based) autodiscover.py Glances autodiscover module (via zeroconf) standalone.py Glances standalone (curses interface) password.py Manage password for Glances client/server stats.py The stats manager timer.py The timer class actions.py Manage trigger actions (via mustache) snmp.py Glances SNMP client (via pysnmp) ... plugins => Glances data providers glances_plugins.py "Father class" for others plugins glances_cpu.py Manage CPU stats glances_load.py Manage load stats glances_mem.py Manage RAM stats glances_memswap.py Manage swap stats glances_network.py Manage network stats glances_fs.py Manage file system stats glances_diskio.py Manage disk I/O stats glances_docker.py Glances Docker plugin (via docker-py) glances_raid.py Glances RAID plugin (via pymdstat) ... outputs => Glances UI glances_curses.py The curses interface glances_bottle.py The web interface ... exports => Glances export interfaces glances_csv.py The CSV export module glances_influxdb.py The InfluxDB export module glances_opentsdb.py The OpenTSDB export module glances_rabbitmq.py The RabbitMQ export module glances_statsd.py The StatsD export module ... glances-2.11.1/glances/__init__.py000066400000000000000000000071461315472316100167500ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # """Init the Glances software.""" # Import system libs import locale import platform import signal import sys # Global name __version__ = '2.11.1' __author__ = 'Nicolas Hennion ' __license__ = 'LGPLv3' # Import psutil try: from psutil import __version__ as psutil_version except ImportError: print('PSutil library not found. Glances cannot start.') sys.exit(1) # Import Glances libs # Note: others Glances libs will be imported optionally from glances.logger import logger from glances.main import GlancesMain from glances.globals import WINDOWS # Check locale try: locale.setlocale(locale.LC_ALL, '') except locale.Error: print("Warning: Unable to set locale. Expect encoding problems.") # Check Python version if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 3): print('Glances requires at least Python 2.7 or 3.3 to run.') sys.exit(1) # Check PSutil version psutil_min_version = (2, 0, 0) psutil_version_info = tuple([int(num) for num in psutil_version.split('.')]) if psutil_version_info < psutil_min_version: print('PSutil 2.0 or higher is needed. Glances cannot start.') sys.exit(1) def __signal_handler(signal, frame): """Callback for CTRL-C.""" end() def end(): """Stop Glances.""" mode.end() logger.info("Glances stopped with CTRL-C") # The end... sys.exit(0) def start(config, args): """Start Glances""" # Load mode global mode if core.is_standalone(): from glances.standalone import GlancesStandalone as GlancesMode elif core.is_client(): if core.is_client_browser(): from glances.client_browser import GlancesClientBrowser as GlancesMode else: from glances.client import GlancesClient as GlancesMode elif core.is_server(): from glances.server import GlancesServer as GlancesMode elif core.is_webserver(): from glances.webserver import GlancesWebServer as GlancesMode # Init the mode logger.info("Start {} mode".format(GlancesMode.__name__)) mode = GlancesMode(config=config, args=args) # Start the main loop mode.serve_forever() # Shutdown mode.end() def main(): """Main entry point for Glances. Select the mode (standalone, client or server) Run it... """ # Log Glances and PSutil version logger.info('Start Glances {}'.format(__version__)) logger.info('{} {} and PSutil {} detected'.format( platform.python_implementation(), platform.python_version(), psutil_version)) # Share global var global core # Create the Glances main instance core = GlancesMain() config = core.get_config() args = core.get_args() # Catch the CTRL-C signal signal.signal(signal.SIGINT, __signal_handler) # Glances can be ran in standalone, client or server mode start(config=config, args=args) glances-2.11.1/glances/__main__.py000066400000000000000000000016531315472316100167260ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # Glances - An eye on your system # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Allow user to run Glances as a module.""" # Execute with: # $ python -m glances (2.7+) import glances if __name__ == '__main__': glances.main() glances-2.11.1/glances/actions.py000066400000000000000000000067221315472316100166500ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage on alert actions.""" from subprocess import Popen from glances.logger import logger from glances.timer import Timer try: import pystache except ImportError: logger.debug("Pystache library not found (action scripts won't work)") pystache_tag = False else: pystache_tag = True class GlancesActions(object): """This class manage action if an alert is reached.""" def __init__(self, args=None): """Init GlancesActions class.""" # Dict with the criticity status # - key: stat_name # - value: criticity # Goal: avoid to execute the same command twice self.status = {} # Add a timer to avoid any trigger when Glances is started (issue#732) # Action can be triggered after refresh * 2 seconds if hasattr(args, 'time'): self.start_timer = Timer(args.time * 2) else: self.start_timer = Timer(3) def get(self, stat_name): """Get the stat_name criticity.""" try: return self.status[stat_name] except KeyError: return None def set(self, stat_name, criticity): """Set the stat_name to criticity.""" self.status[stat_name] = criticity def run(self, stat_name, criticity, commands, repeat, mustache_dict=None): """Run the commands (in background). - stats_name: plugin_name (+ header) - criticity: criticity of the trigger - commands: a list of command line with optional {{mustache}} - If True, then repeat the action - mustache_dict: Plugin stats (can be use within {{mustache}}) Return True if the commands have been ran. """ if (self.get(stat_name) == criticity and not repeat) or \ not self.start_timer.finished(): # Action already executed => Exit return False logger.debug("{} action {} for {} ({}) with stats {}".format( "Repeat" if repeat else "Run", commands, stat_name, criticity, mustache_dict)) # Run all actions in background for cmd in commands: # Replace {{arg}} by the dict one (Thk to {Mustache}) if pystache_tag: cmd_full = pystache.render(cmd, mustache_dict) else: cmd_full = cmd # Execute the action logger.info("Action triggered for {} ({}): {}".format(stat_name, criticity, cmd_full)) logger.debug("Stats value for the trigger: {}".format(mustache_dict)) try: Popen(cmd_full, shell=True) except OSError as e: logger.error("Can't execute the action ({})".format(e)) self.set(stat_name, criticity) return True glances-2.11.1/glances/amps/000077500000000000000000000000001315472316100155675ustar00rootroot00000000000000glances-2.11.1/glances/amps/__init__.py000066400000000000000000000000001315472316100176660ustar00rootroot00000000000000glances-2.11.1/glances/amps/glances_amp.py000066400000000000000000000154571315472316100204260ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ I am your father... ...for all Glances Application Monitoring Processes (AMP). AMP (Application Monitoring Process) A Glances AMP is a Python script called (every *refresh* seconds) if: - the AMP is *enabled* in the Glances configuration file - a process is running (match the *regex* define in the configuration file) The script should define a Amp (GlancesAmp) class with, at least, an update method. The update method should call the set_result method to set the AMP return string. The return string is a string with one or more line (\n between lines). If the *one_line* var is true then the AMP will be displayed in one line. """ from glances.compat import u from glances.timer import Timer from glances.logger import logger class GlancesAmp(object): """Main class for Glances AMP.""" NAME = '?' VERSION = '?' DESCRIPTION = '?' AUTHOR = '?' EMAIL = '?' def __init__(self, name=None, args=None): """Init AMP classe.""" logger.debug("Init {} version {}".format(self.NAME, self.VERSION)) # AMP name (= module name without glances_) if name is None: self.amp_name = self.__class__.__module__[len('glances_'):] else: self.amp_name = name # Init the args self.args = args # Init the configs self.configs = {} # A timer is needed to only update every refresh seconds # Init to 0 in order to update the AMP on startup self.timer = Timer(0) def load_config(self, config): """Load AMP parameters from the configuration file.""" # Read AMP confifuration. # For ex, the AMP foo should have the following section: # # [foo] # enable=true # regex=\/usr\/bin\/nginx # refresh=60 # # and optionnaly: # # one_line=false # option1=opt1 # ... # amp_section = 'amp_' + self.amp_name if (hasattr(config, 'has_section') and config.has_section(amp_section)): logger.debug("{}: Load configuration".format(self.NAME)) for param, _ in config.items(amp_section): try: self.configs[param] = config.get_float_value(amp_section, param) except ValueError: self.configs[param] = config.get_value(amp_section, param).split(',') if len(self.configs[param]) == 1: self.configs[param] = self.configs[param][0] logger.debug("{}: Load parameter: {} = {}".format(self.NAME, param, self.configs[param])) else: logger.debug("{}: Can not find section {} in the configuration file".format(self.NAME, self.amp_name)) return False # enable, regex and refresh are mandatories # if not configured then AMP is disabled if self.enable(): for k in ['regex', 'refresh']: if k not in self.configs: logger.warning("{}: Can not find configuration key {} in section {}".format(self.NAME, k, self.amp_name)) self.configs['enable'] = 'false' else: logger.debug("{} is disabled".format(self.NAME)) # Init the count to 0 self.configs['count'] = 0 return self.enable() def get(self, key): """Generic method to get the item in the AMP configuration""" if key in self.configs: return self.configs[key] else: return None def enable(self): """Return True|False if the AMP is enabled in the configuration file (enable=true|false).""" ret = self.get('enable') if ret is None: return False else: return ret.lower().startswith('true') def regex(self): """Return regular expression used to identified the current application.""" return self.get('regex') def refresh(self): """Return refresh time in seconds for the current application monitoring process.""" return self.get('refresh') def one_line(self): """Return True|False if the AMP shoukd be displayed in oneline (one_lineline=true|false).""" ret = self.get('one_line') if ret is None: return False else: return ret.lower().startswith('true') def time_until_refresh(self): """Return time in seconds until refresh.""" return self.timer.get() def should_update(self): """Return True is the AMP should be updated: - AMP is enable - only update every 'refresh' seconds """ if self.timer.finished(): self.timer.set(self.refresh()) self.timer.reset() return self.enable() return False def set_count(self, count): """Set the number of processes matching the regex""" self.configs['count'] = count def count(self): """Get the number of processes matching the regex""" return self.get('count') def count_min(self): """Get the minimum number of processes""" return self.get('countmin') def count_max(self): """Get the maximum number of processes""" return self.get('countmax') def set_result(self, result, separator=''): """Store the result (string) into the result key of the AMP if one_line is true then replace \n by separator """ if self.one_line(): self.configs['result'] = str(result).replace('\n', separator) else: self.configs['result'] = str(result) def result(self): """ Return the result of the AMP (as a string)""" ret = self.get('result') if ret is not None: ret = u(ret) return ret def update_wrapper(self, process_list): """Wrapper for the children update""" # Set the number of running process self.set_count(len(process_list)) # Call the children update method if self.should_update(): return self.update(process_list) else: return self.result() glances-2.11.1/glances/amps/glances_default.py000066400000000000000000000051011315472316100212560ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ Default AMP ========= Monitor a process by executing a command line. This is the default AMP's behavor if no AMP script is found. Configuration file example -------------------------- [amp_foo] enable=true regex=\/usr\/bin\/foo refresh=10 one_line=false command=foo status """ from subprocess import check_output, STDOUT, CalledProcessError from glances.compat import u, to_ascii from glances.logger import logger from glances.amps.glances_amp import GlancesAmp class Amp(GlancesAmp): """Glances' Default AMP.""" NAME = '' VERSION = '1.0' DESCRIPTION = '' AUTHOR = 'Nicolargo' EMAIL = 'contact@nicolargo.com' def __init__(self, name=None, args=None): """Init the AMP.""" self.NAME = name.capitalize() super(Amp, self).__init__(name=name, args=args) def update(self, process_list): """Update the AMP""" # Get the systemctl status logger.debug('{}: Update stats using service {}'.format(self.NAME, self.get('service_cmd'))) try: res = self.get('command') except OSError as e: logger.debug('{}: Error while executing service ({})'.format(self.NAME, e)) else: if res is not None: try: msg = u(check_output(res.split(), stderr=STDOUT)) self.set_result(to_ascii(msg.rstrip())) except CalledProcessError as e: self.set_result(e.output) else: # Set the default message if command return None # Default sum of CPU and MEM for the matching regex self.set_result('CPU: {:.1f}% | MEM: {:.1f}%'.format( sum([p['cpu_percent'] for p in process_list]), sum([p['memory_percent'] for p in process_list]))) return self.result() glances-2.11.1/glances/amps/glances_nginx.py000066400000000000000000000061671315472316100207720ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ Nginx AMP ========= Monitor the Nginx process using the status page. How to read the stats --------------------- Active connections – Number of all open connections. This doesn’t mean number of users. A single user, for a single pageview can open many concurrent connections to your server. Server accepts handled requests – This shows three values. First is total accepted connections. Second is total handled connections. Usually first 2 values are same. Third value is number of and handles requests. This is usually greater than second value. Dividing third-value by second-one will give you number of requests per connection handled by Nginx. In above example, 10993/7368, 1.49 requests per connections. Reading – nginx reads request header Writing – nginx reads request body, processes request, or writes response to a client Waiting – keep-alive connections, actually it is active – (reading + writing). This value depends on keepalive-timeout. Do not confuse non-zero waiting value for poor performance. It can be ignored. Source reference: https://easyengine.io/tutorials/nginx/status-page/ Configuration file example -------------------------- [amp_nginx] # Nginx status page should be enable (https://easyengine.io/tutorials/nginx/status-page/) enable=true regex=\/usr\/sbin\/nginx refresh=60 one_line=false status_url=http://localhost/nginx_status """ import requests from glances.logger import logger from glances.amps.glances_amp import GlancesAmp class Amp(GlancesAmp): """Glances' Nginx AMP.""" NAME = 'Nginx' VERSION = '1.0' DESCRIPTION = 'Get Nginx stats from status-page' AUTHOR = 'Nicolargo' EMAIL = 'contact@nicolargo.com' # def __init__(self, args=None): # """Init the AMP.""" # super(Amp, self).__init__(args=args) def update(self, process_list): """Update the AMP""" # Get the Nginx status logger.debug('{}: Update stats using status URL {}'.format(self.NAME, self.get('status_url'))) res = requests.get(self.get('status_url')) if res.ok: # u'Active connections: 1 \nserver accepts handled requests\n 1 1 1 \nReading: 0 Writing: 1 Waiting: 0 \n' self.set_result(res.text.rstrip()) else: logger.debug('{}: Can not grab status URL {} ({})'.format(self.NAME, self.get('status_url'), res.reason)) return self.result() glances-2.11.1/glances/amps/glances_systemd.py000066400000000000000000000060371315472316100213330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ Systemd AMP =========== Monitor the state of the systemd system and service (unit) manager. How to read the stats --------------------- active: Number of active units. This is usually a fairly basic way to tell if the unit has started successfully or not. loaded: Number of loaded units (unit's configuration has been parsed by systemd). failed: Number of units with an active failed status. Source reference: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units Configuration file example -------------------------- [amp_systemd] # Systemd enable=true regex=\/usr\/lib\/systemd\/systemd refresh=60 one_line=true systemctl_cmd=/usr/bin/systemctl --plain """ from subprocess import check_output from glances.logger import logger from glances.compat import iteritems, to_ascii from glances.amps.glances_amp import GlancesAmp class Amp(GlancesAmp): """Glances' Systemd AMP.""" NAME = 'Systemd' VERSION = '1.0' DESCRIPTION = 'Get services list from systemctl (systemd)' AUTHOR = 'Nicolargo' EMAIL = 'contact@nicolargo.com' # def __init__(self, args=None): # """Init the AMP.""" # super(Amp, self).__init__(args=args) def update(self, process_list): """Update the AMP""" # Get the systemctl status logger.debug('{}: Update stats using systemctl {}'.format(self.NAME, self.get('systemctl_cmd'))) try: res = check_output(self.get('systemctl_cmd').split()) except OSError as e: logger.debug('{}: Error while executing systemctl ({})'.format(self.NAME, e)) else: status = {} # For each line for r in to_ascii(res).split('\n')[1:-8]: # Split per space .* l = r.split() if len(l) > 3: # load column for c in range(1, 3): try: status[l[c]] += 1 except KeyError: status[l[c]] = 1 # Build the output (string) message output = 'Services\n' for k, v in iteritems(status): output += '{}: {}\n'.format(k, v) self.set_result(output, separator=' ') return self.result() glances-2.11.1/glances/amps/glances_systemv.py000066400000000000000000000056371315472316100213620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ SystemV AMP =========== Monitor the state of the Syste V init system and service. How to read the stats --------------------- Running: Number of running services. Stopped: Number of stopped services. Upstart: Number of service managed by Upstart. Source reference: http://askubuntu.com/questions/407075/how-to-read-service-status-all-results Configuration file example -------------------------- [amp_systemv] # Systemv enable=true regex=\/sbin\/init refresh=60 one_line=true service_cmd=/usr/bin/service --status-all """ from subprocess import check_output, STDOUT from glances.logger import logger from glances.compat import iteritems from glances.amps.glances_amp import GlancesAmp class Amp(GlancesAmp): """Glances' Systemd AMP.""" NAME = 'SystemV' VERSION = '1.0' DESCRIPTION = 'Get services list from service (initd)' AUTHOR = 'Nicolargo' EMAIL = 'contact@nicolargo.com' # def __init__(self, args=None): # """Init the AMP.""" # super(Amp, self).__init__(args=args) def update(self, process_list): """Update the AMP""" # Get the systemctl status logger.debug('{}: Update stats using service {}'.format(self.NAME, self.get('service_cmd'))) try: res = check_output(self.get('service_cmd').split(), stderr=STDOUT).decode('utf-8') except OSError as e: logger.debug('{}: Error while executing service ({})'.format(self.NAME, e)) else: status = {'running': 0, 'stopped': 0, 'upstart': 0} # For each line for r in res.split('\n'): # Split per space .* l = r.split() if len(l) < 4: continue if l[1] == '+': status['running'] += 1 elif l[1] == '-': status['stopped'] += 1 elif l[1] == '?': status['upstart'] += 1 # Build the output (string) message output = 'Services\n' for k, v in iteritems(status): output += '{}: {}\n'.format(k, v) self.set_result(output, separator=' ') return self.result() glances-2.11.1/glances/amps_list.py000066400000000000000000000124671315472316100172060ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the AMPs list.""" import os import re import threading from glances.compat import listkeys, iteritems from glances.logger import logger from glances.globals import amps_path from glances.processes import glances_processes class AmpsList(object): """This class describes the optional application monitoring process list. The AMP list is a list of processes with a specific monitoring action. The list (Python list) is composed of items (Python dict). An item is defined (dict keys): *... """ # The dict __amps_dict = {} def __init__(self, args, config): """Init the AMPs list.""" self.args = args self.config = config # Load the AMP configurations / scripts self.load_configs() def load_configs(self): """Load the AMP configuration files.""" if self.config is None: return False # Display a warning (deprecated) message if the monitor section exist if "monitor" in self.config.sections(): logger.warning("A deprecated [monitor] section exists in the Glances configuration file. You should use the new Applications Monitoring Process module instead (http://glances.readthedocs.io/en/develop/aoa/amps.html).") header = "glances_" # For each AMP scrip, call the load_config method for s in self.config.sections(): if s.startswith("amp_"): # An AMP section exists in the configuration file # If an AMP script exist in the glances/amps folder, use it amp_conf_name = s[4:] amp_script = os.path.join(amps_path, header + s[4:] + ".py") if not os.path.exists(amp_script): # If not, use the default script amp_script = os.path.join(amps_path, "glances_default.py") try: amp = __import__(os.path.basename(amp_script)[:-3]) except ImportError as e: logger.warning("Cannot load {}, you need to install an external Python package ({})".format(os.path.basename(amp_script), e)) except Exception as e: logger.warning("Cannot load {} ({})".format(os.path.basename(amp_script), e)) else: # Add the AMP to the dictionary # The key is the AMP name # for example, the file glances_xxx.py # generate self._amps_list["xxx"] = ... self.__amps_dict[amp_conf_name] = amp.Amp(name=amp_conf_name, args=self.args) # Load the AMP configuration self.__amps_dict[amp_conf_name].load_config(self.config) # Log AMPs list logger.debug("AMPs list: {}".format(self.getList())) return True def __str__(self): return str(self.__amps_dict) def __repr__(self): return self.__amps_dict def __getitem__(self, item): return self.__amps_dict[item] def __len__(self): return len(self.__amps_dict) def update(self): """Update the command result attributed.""" # Search application monitored processes by a regular expression processlist = glances_processes.getalllist() # Iter upon the AMPs dict for k, v in iteritems(self.get()): if not v.enable(): # Do not update if the enable tag is set continue try: amps_list = [p for p in processlist for c in p['cmdline'] if re.search(v.regex(), c) is not None] except TypeError: continue if len(amps_list) > 0: # At least one process is matching the regex logger.debug("AMPS: {} process detected (PID={})".format(k, amps_list[0]['pid'])) # Call the AMP update method thread = threading.Thread(target=v.update_wrapper, args=[amps_list]) thread.start() else: # Set the process number to 0 v.set_count(0) if v.count_min() is not None and v.count_min() > 0: # Only display the "No running process message" is countmin is defined v.set_result("No running process") return self.__amps_dict def getList(self): """Return the AMPs list.""" return listkeys(self.__amps_dict) def get(self): """Return the AMPs dict.""" return self.__amps_dict def set(self, new_dict): """Set the AMPs dict.""" self.__amps_dict = new_dict glances-2.11.1/glances/attribute.py000066400000000000000000000077541315472316100172210ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Attribute class.""" from datetime import datetime class GlancesAttribute(object): def __init__(self, name, description='', history_max_size=None): """Init the attribute name: Attribute name (string) description: Attribute human reading description (string) history_max_size: Maximum size of the history list (default is no limit) History is stored as a list for tuple: [(date, value), ...] """ self._name = name self._description = description self._value = None self._history_max_size = history_max_size self._history = [] def __repr__(self): return self.value def __str__(self): return str(self.value) """ Properties for the attribute name """ @property def name(self): return self._name @name.setter def name(self, new_name): self._name = new_name """ Properties for the attribute description """ @property def description(self): return self._description @description.setter def description(self, new_description): self._description = new_description """ Properties for the attribute value """ @property def value(self): if self.history_len() > 0: return (self._value[1] - self.history_value()[1]) / (self._value[0] - self.history_value()[0]) else: return None @value.setter def value(self, new_value): """Set a value. Value is a tuple: (, ) """ self._value = (datetime.now(), new_value) self.history_add(self._value) """ Properties for the attribute history """ @property def history(self): return self._history @history.setter def history(self, new_history): self._history = new_history @history.deleter def history(self): del self._history def history_reset(self): self._history = [] def history_add(self, value): """Add a value in the history """ if self._history_max_size is None or self.history_len() < self._history_max_size: self._history.append(value) else: self._history = self._history[1:] + [value] def history_size(self): """Return the history size (maximum nuber of value in the history) """ return len(self._history) def history_len(self): """Return the current history lenght """ return len(self._history) def history_value(self, pos=1): """Return the value in position pos in the history. Default is to return the latest value added to the history. """ return self._history[-pos] def history_raw(self, nb=0): """Return the history of last nb items (0 for all) In ISO JSON format""" return self._history[-nb:] def history_json(self, nb=0): """Return the history of last nb items (0 for all) In ISO JSON format""" return [(i[0].isoformat(), i[1]) for i in self._history[-nb:]] def history_mean(self, nb=5): """Return the mean on the values in the history. """ _, v = zip(*self._history) return sum(v[-nb:]) / float(v[-1] - v[-nb]) glances-2.11.1/glances/autodiscover.py000066400000000000000000000221321315472316100177100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage autodiscover Glances server (thk to the ZeroConf protocol).""" import socket import sys from glances.globals import BSD from glances.logger import logger try: from zeroconf import ( __version__ as __zeroconf_version, ServiceBrowser, ServiceInfo, Zeroconf ) zeroconf_tag = True except ImportError: zeroconf_tag = False # Zeroconf 0.17 or higher is needed if zeroconf_tag: zeroconf_min_version = (0, 17, 0) zeroconf_version = tuple([int(num) for num in __zeroconf_version.split('.')]) logger.debug("Zeroconf version {} detected.".format(__zeroconf_version)) if zeroconf_version < zeroconf_min_version: logger.critical("Please install zeroconf 0.17 or higher.") sys.exit(1) # Global var # Recent versions of the zeroconf python package doesnt like a zeroconf type that ends with '._tcp.'. # Correct issue: zeroconf problem with zeroconf_type = "_%s._tcp." % 'glances' #888 zeroconf_type = "_%s._tcp.local." % 'glances' class AutoDiscovered(object): """Class to manage the auto discovered servers dict.""" def __init__(self): # server_dict is a list of dict (JSON compliant) # [ {'key': 'zeroconf name', ip': '172.1.2.3', 'port': 61209, 'cpu': 3, 'mem': 34 ...} ... ] self._server_list = [] def get_servers_list(self): """Return the current server list (list of dict).""" return self._server_list def set_server(self, server_pos, key, value): """Set the key to the value for the server_pos (position in the list).""" self._server_list[server_pos][key] = value def add_server(self, name, ip, port): """Add a new server to the list.""" new_server = { 'key': name, # Zeroconf name with both hostname and port 'name': name.split(':')[0], # Short name 'ip': ip, # IP address seen by the client 'port': port, # TCP port 'username': 'glances', # Default username 'password': '', # Default password 'status': 'UNKNOWN', # Server status: 'UNKNOWN', 'OFFLINE', 'ONLINE', 'PROTECTED' 'type': 'DYNAMIC'} # Server type: 'STATIC' or 'DYNAMIC' self._server_list.append(new_server) logger.debug("Updated servers list (%s servers): %s" % (len(self._server_list), self._server_list)) def remove_server(self, name): """Remove a server from the dict.""" for i in self._server_list: if i['key'] == name: try: self._server_list.remove(i) logger.debug("Remove server %s from the list" % name) logger.debug("Updated servers list (%s servers): %s" % ( len(self._server_list), self._server_list)) except ValueError: logger.error( "Cannot remove server %s from the list" % name) class GlancesAutoDiscoverListener(object): """Zeroconf listener for Glances server.""" def __init__(self): # Create an instance of the servers list self.servers = AutoDiscovered() def get_servers_list(self): """Return the current server list (list of dict).""" return self.servers.get_servers_list() def set_server(self, server_pos, key, value): """Set the key to the value for the server_pos (position in the list).""" self.servers.set_server(server_pos, key, value) def add_service(self, zeroconf, srv_type, srv_name): """Method called when a new Zeroconf client is detected. Return True if the zeroconf client is a Glances server Note: the return code will never be used """ if srv_type != zeroconf_type: return False logger.debug("Check new Zeroconf server: %s / %s" % (srv_type, srv_name)) info = zeroconf.get_service_info(srv_type, srv_name) if info: new_server_ip = socket.inet_ntoa(info.address) new_server_port = info.port # Add server to the global dict self.servers.add_server(srv_name, new_server_ip, new_server_port) logger.info("New Glances server detected (%s from %s:%s)" % (srv_name, new_server_ip, new_server_port)) else: logger.warning( "New Glances server detected, but Zeroconf info failed to be grabbed") return True def remove_service(self, zeroconf, srv_type, srv_name): """Remove the server from the list.""" self.servers.remove_server(srv_name) logger.info( "Glances server %s removed from the autodetect list" % srv_name) class GlancesAutoDiscoverServer(object): """Implementation of the Zeroconf protocol (server side for the Glances client).""" def __init__(self, args=None): if zeroconf_tag: logger.info("Init autodiscover mode (Zeroconf protocol)") try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start Zeroconf (%s)" % e) self.zeroconf_enable_tag = False else: self.listener = GlancesAutoDiscoverListener() self.browser = ServiceBrowser( self.zeroconf, zeroconf_type, self.listener) self.zeroconf_enable_tag = True else: logger.error("Cannot start autodiscover mode (Zeroconf lib is not installed)") self.zeroconf_enable_tag = False def get_servers_list(self): """Return the current server list (dict of dict).""" if zeroconf_tag and self.zeroconf_enable_tag: return self.listener.get_servers_list() else: return [] def set_server(self, server_pos, key, value): """Set the key to the value for the server_pos (position in the list).""" if zeroconf_tag and self.zeroconf_enable_tag: self.listener.set_server(server_pos, key, value) def close(self): if zeroconf_tag and self.zeroconf_enable_tag: self.zeroconf.close() class GlancesAutoDiscoverClient(object): """Implementation of the zeroconf protocol (client side for the Glances server).""" def __init__(self, hostname, args=None): if zeroconf_tag: zeroconf_bind_address = args.bind_address try: self.zeroconf = Zeroconf() except socket.error as e: logger.error("Cannot start zeroconf: {}".format(e)) # XXX *BSDs: Segmentation fault (core dumped) # -- https://bitbucket.org/al45tair/netifaces/issues/15 if not BSD: try: # -B @ overwrite the dynamic IPv4 choice if zeroconf_bind_address == '0.0.0.0': zeroconf_bind_address = self.find_active_ip_address() except KeyError: # Issue #528 (no network interface available) pass # Check IP v4/v6 address_family = socket.getaddrinfo(zeroconf_bind_address, args.port)[0][0] # Start the zeroconf service self.info = ServiceInfo( zeroconf_type, '{}:{}.{}'.format(hostname, args.port, zeroconf_type), address=socket.inet_pton(address_family, zeroconf_bind_address), port=args.port, weight=0, priority=0, properties={}, server=hostname) try: self.zeroconf.register_service(self.info) except socket.error as e: logger.error("Error while announcing Glances server: {}".format(e)) else: print("Announce the Glances server on the LAN (using {} IP address)".format(zeroconf_bind_address)) else: logger.error("Cannot announce Glances server on the network: zeroconf library not found.") @staticmethod def find_active_ip_address(): """Try to find the active IP addresses.""" import netifaces # Interface of the default gateway gateway_itf = netifaces.gateways()['default'][netifaces.AF_INET][1] # IP address for the interface return netifaces.ifaddresses(gateway_itf)[netifaces.AF_INET][0]['addr'] def close(self): if zeroconf_tag: self.zeroconf.unregister_service(self.info) self.zeroconf.close() glances-2.11.1/glances/client.py000066400000000000000000000211621315472316100164610ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances client.""" import json import socket import sys from glances import __version__ from glances.compat import Fault, ProtocolError, ServerProxy, Transport from glances.logger import logger from glances.stats_client import GlancesStatsClient from glances.outputs.glances_curses import GlancesCursesClient class GlancesClientTransport(Transport): """This class overwrite the default XML-RPC transport and manage timeout.""" def set_timeout(self, timeout): self.timeout = timeout class GlancesClient(object): """This class creates and manages the TCP client.""" def __init__(self, config=None, args=None, timeout=7, return_to_browser=False): # Store the arg/config self.args = args self.config = config # Quiet mode self._quiet = args.quiet # Default client mode self._client_mode = 'glances' # Return to browser or exit self.return_to_browser = return_to_browser # Build the URI if args.password != "": self.uri = 'http://{}:{}@{}:{}'.format(args.username, args.password, args.client, args.port) else: self.uri = 'http://{}:{}'.format(args.client, args.port) logger.debug("Try to connect to {}".format(self.uri)) # Try to connect to the URI transport = GlancesClientTransport() # Configure the server timeout transport.set_timeout(timeout) try: self.client = ServerProxy(self.uri, transport=transport) except Exception as e: self.log_and_exit("Client couldn't create socket {}: {}".format(self.uri, e)) @property def quiet(self): return self._quiet def log_and_exit(self, msg=''): """Log and exit.""" if not self.return_to_browser: logger.critical(msg) sys.exit(2) else: logger.error(msg) @property def client_mode(self): """Get the client mode.""" return self._client_mode @client_mode.setter def client_mode(self, mode): """Set the client mode. - 'glances' = Glances server (default) - 'snmp' = SNMP (fallback) """ self._client_mode = mode def _login_glances(self): """Login to a Glances server""" client_version = None try: client_version = self.client.init() except socket.error as err: # Fallback to SNMP self.client_mode = 'snmp' logger.error("Connection to Glances server failed ({} {})".format(err.errno, err.strerror)) fallbackmsg = 'No Glances server found on {}. Trying fallback to SNMP...'.format(self.uri) if not self.return_to_browser: print(fallbackmsg) else: logger.info(fallbackmsg) except ProtocolError as err: # Other errors msg = "Connection to server {} failed".format(self.uri) if err.errcode == 401: msg += " (Bad username/password)" else: msg += " ({} {})".format(err.errcode, err.errmsg) self.log_and_exit(msg) return False if self.client_mode == 'glances': # Check that both client and server are in the same major version if __version__.split('.')[0] == client_version.split('.')[0]: # Init stats self.stats = GlancesStatsClient(config=self.config, args=self.args) self.stats.set_plugins(json.loads(self.client.getAllPlugins())) logger.debug("Client version: {} / Server version: {}".format(__version__, client_version)) else: self.log_and_exit(('Client and server not compatible: ' 'Client version: {} / Server version: {}'.format(__version__, client_version))) return False return True def _login_snmp(self): """Login to a SNMP server""" logger.info("Trying to grab stats by SNMP...") from glances.stats_client_snmp import GlancesStatsClientSNMP # Init stats self.stats = GlancesStatsClientSNMP(config=self.config, args=self.args) if not self.stats.check_snmp(): self.log_and_exit("Connection to SNMP server failed") return False return True def login(self): """Logon to the server.""" if self.args.snmp_force: # Force SNMP instead of Glances server self.client_mode = 'snmp' else: # First of all, trying to connect to a Glances server if not self._login_glances(): return False # Try SNMP mode if self.client_mode == 'snmp': if not self._login_snmp(): return False # Load limits from the configuration file # Each client can choose its owns limits logger.debug("Load limits from the client configuration file") self.stats.load_limits(self.config) # Init screen if self.quiet: # In quiet mode, nothing is displayed logger.info("Quiet mode is ON: Nothing will be displayed") else: self.screen = GlancesCursesClient(config=self.config, args=self.args) # Return True: OK return True def update(self): """Update stats from Glances/SNMP server.""" if self.client_mode == 'glances': return self.update_glances() elif self.client_mode == 'snmp': return self.update_snmp() else: self.end() logger.critical("Unknown server mode: {}".format(self.client_mode)) sys.exit(2) def update_glances(self): """Get stats from Glances server. Return the client/server connection status: - Connected: Connection OK - Disconnected: Connection NOK """ # Update the stats try: server_stats = json.loads(self.client.getAll()) except socket.error: # Client cannot get server stats return "Disconnected" except Fault: # Client cannot get server stats (issue #375) return "Disconnected" else: # Put it in the internal dict self.stats.update(server_stats) return "Connected" def update_snmp(self): """Get stats from SNMP server. Return the client/server connection status: - SNMP: Connection with SNMP server OK - Disconnected: Connection NOK """ # Update the stats try: self.stats.update() except Exception: # Client cannot get SNMP server stats return "Disconnected" else: # Grab success return "SNMP" def serve_forever(self): """Main client loop.""" # Test if client and server are in the same major version if not self.login(): logger.critical("The server version is not compatible with the client") self.end() return self.client_mode exitkey = False try: while True and not exitkey: # Update the stats cs_status = self.update() # Update the screen if not self.quiet: exitkey = self.screen.update(self.stats, cs_status=cs_status, return_to_browser=self.return_to_browser) # Export stats using export modules self.stats.export(self.stats) except Exception as e: logger.critical(e) self.end() return self.client_mode def end(self): """End of the client session.""" if not self.quiet: self.screen.end() glances-2.11.1/glances/client_browser.py000066400000000000000000000244031315472316100202250ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances client browser (list of Glances server).""" import json import socket import threading from glances.compat import Fault, ProtocolError, ServerProxy from glances.autodiscover import GlancesAutoDiscoverServer from glances.client import GlancesClient, GlancesClientTransport from glances.logger import logger, LOG_FILENAME from glances.password_list import GlancesPasswordList as GlancesPassword from glances.static_list import GlancesStaticServer from glances.outputs.glances_curses_browser import GlancesCursesBrowser class GlancesClientBrowser(object): """This class creates and manages the TCP client browser (servers list).""" def __init__(self, config=None, args=None): # Store the arg/config self.args = args self.config = config self.static_server = None self.password = None # Load the configuration file self.load() # Start the autodiscover mode (Zeroconf listener) if not self.args.disable_autodiscover: self.autodiscover_server = GlancesAutoDiscoverServer() else: self.autodiscover_server = None # Init screen self.screen = GlancesCursesBrowser(args=self.args) def load(self): """Load server and password list from the confiuration file.""" # Init the static server list (if defined) self.static_server = GlancesStaticServer(config=self.config) # Init the password list (if defined) self.password = GlancesPassword(config=self.config) def get_servers_list(self): """Return the current server list (list of dict). Merge of static + autodiscover servers list. """ ret = [] if self.args.browser: ret = self.static_server.get_servers_list() if self.autodiscover_server is not None: ret = self.static_server.get_servers_list() + self.autodiscover_server.get_servers_list() return ret def __get_uri(self, server): """Return the URI for the given server dict.""" # Select the connection mode (with or without password) if server['password'] != "": if server['status'] == 'PROTECTED': # Try with the preconfigure password (only if status is PROTECTED) clear_password = self.password.get_password(server['name']) if clear_password is not None: server['password'] = self.password.sha256_hash(clear_password) return 'http://{}:{}@{}:{}'.format(server['username'], server['password'], server['ip'], server['port']) else: return 'http://{}:{}'.format(server['ip'], server['port']) def __update_stats(self, server): """ Update stats for the given server (picked from the server list) """ # Get the server URI uri = self.__get_uri(server) # Try to connect to the server t = GlancesClientTransport() t.set_timeout(3) # Get common stats try: s = ServerProxy(uri, transport=t) except Exception as e: logger.warning( "Client browser couldn't create socket {}: {}".format(uri, e)) else: # Mandatory stats try: # CPU% cpu_percent = 100 - json.loads(s.getCpu())['idle'] server['cpu_percent'] = '{:.1f}'.format(cpu_percent) # MEM% server['mem_percent'] = json.loads(s.getMem())['percent'] # OS (Human Readable name) server['hr_name'] = json.loads(s.getSystem())['hr_name'] except (socket.error, Fault, KeyError) as e: logger.debug( "Error while grabbing stats form {}: {}".format(uri, e)) server['status'] = 'OFFLINE' except ProtocolError as e: if e.errcode == 401: # Error 401 (Authentication failed) # Password is not the good one... server['password'] = None server['status'] = 'PROTECTED' else: server['status'] = 'OFFLINE' logger.debug("Cannot grab stats from {} ({} {})".format(uri, e.errcode, e.errmsg)) else: # Status server['status'] = 'ONLINE' # Optional stats (load is not available on Windows OS) try: # LOAD load_min5 = json.loads(s.getLoad())['min5'] server['load_min5'] = '{:.2f}'.format(load_min5) except Exception as e: logger.warning( "Error while grabbing stats form {}: {}".format(uri, e)) return server def __display_server(self, server): """ Connect and display the given server """ # Display the Glances client for the selected server logger.debug("Selected server: {}".format(server)) # Connection can take time # Display a popup self.screen.display_popup( 'Connect to {}:{}'.format(server['name'], server['port']), duration=1) # A password is needed to access to the server's stats if server['password'] is None: # First of all, check if a password is available in the [passwords] section clear_password = self.password.get_password(server['name']) if (clear_password is None or self.get_servers_list() [self.screen.active_server]['status'] == 'PROTECTED'): # Else, the password should be enter by the user # Display a popup to enter password clear_password = self.screen.display_popup( 'Password needed for {}: '.format(server['name']), is_input=True) # Store the password for the selected server if clear_password is not None: self.set_in_selected('password', self.password.sha256_hash(clear_password)) # Display the Glance client on the selected server logger.info("Connect Glances client to the {} server".format(server['key'])) # Init the client args_server = self.args # Overwrite connection setting args_server.client = server['ip'] args_server.port = server['port'] args_server.username = server['username'] args_server.password = server['password'] client = GlancesClient(config=self.config, args=args_server, return_to_browser=True) # Test if client and server are in the same major version if not client.login(): self.screen.display_popup( "Sorry, cannot connect to '{}'\n" "See '{}' for more details".format(server['name'], LOG_FILENAME)) # Set the ONLINE status for the selected server self.set_in_selected('status', 'OFFLINE') else: # Start the client loop # Return connection type: 'glances' or 'snmp' connection_type = client.serve_forever() try: logger.debug("Disconnect Glances client from the {} server".format(server['key'])) except IndexError: # Server did not exist anymore pass else: # Set the ONLINE status for the selected server if connection_type == 'snmp': self.set_in_selected('status', 'SNMP') else: self.set_in_selected('status', 'ONLINE') # Return to the browser (no server selected) self.screen.active_server = None def __serve_forever(self): """Main client loop.""" # No need to update the server list # It's done by the GlancesAutoDiscoverListener class (autodiscover.py) # Or define staticaly in the configuration file (module static_list.py) # For each server in the list, grab elementary stats (CPU, LOAD, MEM, OS...) while True: logger.debug("Iter through the following server list: {}".format(self.get_servers_list())) for v in self.get_servers_list(): thread = threading.Thread(target=self.__update_stats, args=[v]) thread.start() # Update the screen (list or Glances client) if self.screen.active_server is None: # Display the Glances browser self.screen.update(self.get_servers_list()) else: # Display the active server self.__display_server(self.get_servers_list()[self.screen.active_server]) def serve_forever(self): """Wrapper to the serve_forever function. This function will restore the terminal to a sane state before re-raising the exception and generating a traceback. """ try: return self.__serve_forever() finally: self.end() def set_in_selected(self, key, value): """Set the (key, value) for the selected server in the list.""" # Static list then dynamic one if self.screen.active_server >= len(self.static_server.get_servers_list()): self.autodiscover_server.set_server( self.screen.active_server - len(self.static_server.get_servers_list()), key, value) else: self.static_server.set_server(self.screen.active_server, key, value) def end(self): """End of the client browser session.""" self.screen.end() glances-2.11.1/glances/compat.py000066400000000000000000000106131315472316100164650ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # flake8: noqa # pylint: skip-file """Python 2/3 compatibility shims.""" import operator import sys import unicodedata import types import platform PY_CYTHON = platform.python_implementation() == 'CPython' PY_PYPY = platform.python_implementation() == 'PyPy' PY_JYTHON = platform.python_implementation() == 'Jython' PY_IRON = platform.python_implementation() == 'IronPython' PY3 = sys.version_info[0] == 3 try: from statistics import mean except ImportError: # Statistics is only available for Python 3.4 or higher def mean(numbers): return float(sum(numbers)) / max(len(numbers), 1) if PY3: import queue from configparser import ConfigParser, NoOptionError, NoSectionError from xmlrpc.client import Fault, ProtocolError, ServerProxy, Transport, Server from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from urllib.request import urlopen from urllib.error import HTTPError, URLError from urllib.parse import urlparse input = input range = range map = map text_type = str binary_type = bytes bool_type = bool viewkeys = operator.methodcaller('keys') viewvalues = operator.methodcaller('values') viewitems = operator.methodcaller('items') def to_ascii(s): """Convert the bytes string to a ASCII string Usefull to remove accent (diacritics)""" return str(s, 'utf-8') def listitems(d): return list(d.items()) def listkeys(d): return list(d.keys()) def listvalues(d): return list(d.values()) def iteritems(d): return iter(d.items()) def iterkeys(d): return iter(d.keys()) def itervalues(d): return iter(d.values()) def u(s): if isinstance(s, text_type): return s return s.decode('utf-8', 'replace') def b(s): if isinstance(s, binary_type): return s return s.encode('latin-1') def nativestr(s): if isinstance(s, text_type): return s return s.decode('utf-8', 'replace') else: import Queue as queue from itertools import imap as map from ConfigParser import SafeConfigParser as ConfigParser, NoOptionError, NoSectionError from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from xmlrpclib import Fault, ProtocolError, ServerProxy, Transport, Server from urllib2 import urlopen, HTTPError, URLError from urlparse import urlparse input = raw_input range = xrange ConfigParser.read_file = ConfigParser.readfp text_type = unicode binary_type = str bool_type = types.BooleanType viewkeys = operator.methodcaller('viewkeys') viewvalues = operator.methodcaller('viewvalues') viewitems = operator.methodcaller('viewitems') def to_ascii(s): """Convert the unicode 's' to a ASCII string Usefull to remove accent (diacritics)""" if isinstance(s, binary_type): return s return unicodedata.normalize('NFKD', s).encode('ASCII', 'ignore') def listitems(d): return d.items() def listkeys(d): return d.keys() def listvalues(d): return d.values() def iteritems(d): return d.iteritems() def iterkeys(d): return d.iterkeys() def itervalues(d): return d.itervalues() def u(s): if isinstance(s, text_type): return s return s.decode('utf-8') def b(s): if isinstance(s, binary_type): return s return s.encode('utf-8', 'replace') def nativestr(s): if isinstance(s, binary_type): return s return s.encode('utf-8', 'replace') glances-2.11.1/glances/config.py000066400000000000000000000234761315472316100164620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the configuration file.""" import os import sys import multiprocessing from io import open from glances.compat import ConfigParser, NoOptionError from glances.globals import BSD, LINUX, MACOS, SUNOS, WINDOWS from glances.logger import logger def user_config_dir(): r"""Return the per-user config dir (full path). - Linux, *BSD, SunOS: ~/.config/glances - macOS: ~/Library/Application Support/glances - Windows: %APPDATA%\glances """ if WINDOWS: path = os.environ.get('APPDATA') elif MACOS: path = os.path.expanduser('~/Library/Application Support') else: path = os.environ.get('XDG_CONFIG_HOME') or os.path.expanduser('~/.config') if path is None: path = '' else: path = os.path.join(path, 'glances') return path def user_cache_dir(): r"""Return the per-user cache dir (full path). - Linux, *BSD, SunOS: ~/.cache/glances - macOS: ~/Library/Caches/glances - Windows: {%LOCALAPPDATA%,%APPDATA%}\glances\cache """ if WINDOWS: path = os.path.join(os.environ.get('LOCALAPPDATA') or os.environ.get('APPDATA'), 'glances', 'cache') elif MACOS: path = os.path.expanduser('~/Library/Caches/glances') else: path = os.path.join(os.environ.get('XDG_CACHE_HOME') or os.path.expanduser('~/.cache'), 'glances') return path def system_config_dir(): r"""Return the system-wide config dir (full path). - Linux, SunOS: /etc/glances - *BSD, macOS: /usr/local/etc/glances - Windows: %APPDATA%\glances """ if LINUX or SUNOS: path = '/etc' elif BSD or MACOS: path = '/usr/local/etc' else: path = os.environ.get('APPDATA') if path is None: path = '' else: path = os.path.join(path, 'glances') return path class Config(object): """This class is used to access/read config file, if it exists. :param config_dir: the path to search for config file :type config_dir: str or None """ def __init__(self, config_dir=None): self.config_dir = config_dir self.config_filename = 'glances.conf' self._loaded_config_file = None self.parser = ConfigParser() self.read() def config_file_paths(self): r"""Get a list of config file paths. The list is built taking into account of the OS, priority and location. * custom path: /path/to/glances * Linux, SunOS: ~/.config/glances, /etc/glances * *BSD: ~/.config/glances, /usr/local/etc/glances * macOS: ~/Library/Application Support/glances, /usr/local/etc/glances * Windows: %APPDATA%\glances The config file will be searched in the following order of priority: * /path/to/file (via -C flag) * user's home directory (per-user settings) * system-wide directory (system-wide settings) """ paths = [] if self.config_dir: paths.append(self.config_dir) paths.append(os.path.join(user_config_dir(), self.config_filename)) paths.append(os.path.join(system_config_dir(), self.config_filename)) return paths def read(self): """Read the config file, if it exists. Using defaults otherwise.""" for config_file in self.config_file_paths(): if os.path.exists(config_file): try: with open(config_file, encoding='utf-8') as f: self.parser.read_file(f) self.parser.read(f) logger.info("Read configuration file '{}'".format(config_file)) except UnicodeDecodeError as err: logger.error("Cannot decode configuration file '{}': {}".format(config_file, err)) sys.exit(1) # Save the loaded configuration file path (issue #374) self._loaded_config_file = config_file break # Quicklook if not self.parser.has_section('quicklook'): self.parser.add_section('quicklook') self.set_default_cwc('quicklook', 'cpu') self.set_default_cwc('quicklook', 'mem') self.set_default_cwc('quicklook', 'swap') # CPU if not self.parser.has_section('cpu'): self.parser.add_section('cpu') self.set_default_cwc('cpu', 'user') self.set_default_cwc('cpu', 'system') self.set_default_cwc('cpu', 'steal') # By default I/O wait should be lower than 1/number of CPU cores iowait_bottleneck = (1.0 / multiprocessing.cpu_count()) * 100.0 self.set_default_cwc('cpu', 'iowait', [str(iowait_bottleneck - (iowait_bottleneck * 0.20)), str(iowait_bottleneck - (iowait_bottleneck * 0.10)), str(iowait_bottleneck)]) ctx_switches_bottleneck = 56000 / multiprocessing.cpu_count() self.set_default_cwc('cpu', 'ctx_switches', [str(ctx_switches_bottleneck - (ctx_switches_bottleneck * 0.20)), str(ctx_switches_bottleneck - (ctx_switches_bottleneck * 0.10)), str(ctx_switches_bottleneck)]) # Per-CPU if not self.parser.has_section('percpu'): self.parser.add_section('percpu') self.set_default_cwc('percpu', 'user') self.set_default_cwc('percpu', 'system') # Load if not self.parser.has_section('load'): self.parser.add_section('load') self.set_default_cwc('load', cwc=['0.7', '1.0', '5.0']) # Mem if not self.parser.has_section('mem'): self.parser.add_section('mem') self.set_default_cwc('mem') # Swap if not self.parser.has_section('memswap'): self.parser.add_section('memswap') self.set_default_cwc('memswap') # NETWORK if not self.parser.has_section('network'): self.parser.add_section('network') self.set_default_cwc('network', 'rx') self.set_default_cwc('network', 'tx') # FS if not self.parser.has_section('fs'): self.parser.add_section('fs') self.set_default_cwc('fs') # Sensors if not self.parser.has_section('sensors'): self.parser.add_section('sensors') self.set_default_cwc('sensors', 'temperature_core', cwc=['60', '70', '80']) self.set_default_cwc('sensors', 'temperature_hdd', cwc=['45', '52', '60']) self.set_default_cwc('sensors', 'battery', cwc=['80', '90', '95']) # Process list if not self.parser.has_section('processlist'): self.parser.add_section('processlist') self.set_default_cwc('processlist', 'cpu') self.set_default_cwc('processlist', 'mem') @property def loaded_config_file(self): """Return the loaded configuration file.""" return self._loaded_config_file def as_dict(self): """Return the configuration as a dict""" dictionary = {} for section in self.parser.sections(): dictionary[section] = {} for option in self.parser.options(section): dictionary[section][option] = self.parser.get(section, option) return dictionary def sections(self): """Return a list of all sections.""" return self.parser.sections() def items(self, section): """Return the items list of a section.""" return self.parser.items(section) def has_section(self, section): """Return info about the existence of a section.""" return self.parser.has_section(section) def set_default_cwc(self, section, option_header=None, cwc=['50', '70', '90']): """Set default values for careful, warning and critical.""" if option_header is None: header = '' else: header = option_header + '_' self.set_default(section, header + 'careful', cwc[0]) self.set_default(section, header + 'warning', cwc[1]) self.set_default(section, header + 'critical', cwc[2]) def set_default(self, section, option, default): """If the option did not exist, create a default value.""" if not self.parser.has_option(section, option): self.parser.set(section, option, default) def get_value(self, section, option, default=None): """Get the value of an option, if it exists.""" try: return self.parser.get(section, option) except NoOptionError: return default def get_int_value(self, section, option, default=0): """Get the int value of an option, if it exists.""" try: return self.parser.getint(section, option) except NoOptionError: return int(default) def get_float_value(self, section, option, default=0.0): """Get the float value of an option, if it exists.""" try: return self.parser.getfloat(section, option) except NoOptionError: return float(default) glances-2.11.1/glances/cpu_percent.py000066400000000000000000000072401315472316100175130ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """CPU percent stats shared between CPU and Quicklook plugins.""" from glances.timer import Timer import psutil class CpuPercent(object): """Get and store the CPU percent.""" def __init__(self, cached_time=1): self.cpu_percent = 0 self.percpu_percent = [] # cached_time is the minimum time interval between stats updates # since last update is passed (will retrieve old cached info instead) self.timer_cpu = Timer(0) self.timer_percpu = Timer(0) self.cached_time = cached_time def get_key(self): """Return the key of the per CPU list.""" return 'cpu_number' def get(self, percpu=False): """Update and/or return the CPU using the psutil library. If percpu, return the percpu stats""" if percpu: return self.__get_percpu() else: return self.__get_cpu() def __get_cpu(self): """Update and/or return the CPU using the psutil library.""" # Never update more than 1 time per cached_time if self.timer_cpu.finished(): self.cpu_percent = psutil.cpu_percent(interval=0.0) # Reset timer for cache self.timer_cpu = Timer(self.cached_time) return self.cpu_percent def __get_percpu(self): """Update and/or return the per CPU list using the psutil library.""" # Never update more than 1 time per cached_time if self.timer_percpu.finished(): self.percpu_percent = [] for cpu_number, cputimes in enumerate(psutil.cpu_times_percent(interval=0.0, percpu=True)): cpu = {'key': self.get_key(), 'cpu_number': cpu_number, 'total': round(100 - cputimes.idle, 1), 'user': cputimes.user, 'system': cputimes.system, 'idle': cputimes.idle} # The following stats are for API purposes only if hasattr(cputimes, 'nice'): cpu['nice'] = cputimes.nice if hasattr(cputimes, 'iowait'): cpu['iowait'] = cputimes.iowait if hasattr(cputimes, 'irq'): cpu['irq'] = cputimes.irq if hasattr(cputimes, 'softirq'): cpu['softirq'] = cputimes.softirq if hasattr(cputimes, 'steal'): cpu['steal'] = cputimes.steal if hasattr(cputimes, 'guest'): cpu['guest'] = cputimes.guest if hasattr(cputimes, 'guest_nice'): cpu['guest_nice'] = cputimes.guest_nice # Append new CPU to the list self.percpu_percent.append(cpu) # Reset timer for cache self.timer_percpu = Timer(self.cached_time) return self.percpu_percent # CpuPercent instance shared between plugins cpu_percent = CpuPercent() glances-2.11.1/glances/exports/000077500000000000000000000000001315472316100163335ustar00rootroot00000000000000glances-2.11.1/glances/exports/__init__.py000066400000000000000000000000001315472316100204320ustar00rootroot00000000000000glances-2.11.1/glances/exports/glances_cassandra.py000066400000000000000000000111621315472316100223410ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Cassandra/Scylla interface class.""" import sys from datetime import datetime from numbers import Number from glances.logger import logger from glances.exports.glances_export import GlancesExport from glances.compat import iteritems from cassandra.cluster import Cluster from cassandra.util import uuid_from_time from cassandra import InvalidRequest class Export(GlancesExport): """This class manages the Cassandra/Scylla export module.""" def __init__(self, config=None, args=None): """Init the Cassandra export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.keyspace = None # Optionals configuration keys self.protocol_version = 3 self.replication_factor = 2 self.table = None # Load the Cassandra configuration file section self.export_enable = self.load_conf('cassandra', mandatories=['host', 'port', 'keyspace'], options=['protocol_version', 'replication_factor', 'table']) if not self.export_enable: sys.exit(2) # Init the Cassandra client self.cluster, self.session = self.init() def init(self): """Init the connection to the InfluxDB server.""" if not self.export_enable: return None # Cluster try: cluster = Cluster([self.host], port=int(self.port), protocol_version=int(self.protocol_version)) session = cluster.connect() except Exception as e: logger.critical("Cannot connect to Cassandra cluster '%s:%s' (%s)" % (self.host, self.port, e)) sys.exit(2) # Keyspace try: session.set_keyspace(self.keyspace) except InvalidRequest as e: logger.info("Create keyspace {} on the Cassandra cluster".format(self.keyspace)) c = "CREATE KEYSPACE %s WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': '%s' }" % (self.keyspace, self.replication_factor) session.execute(c) session.set_keyspace(self.keyspace) logger.info( "Stats will be exported to Cassandra cluster {} ({}) in keyspace {}".format( cluster.metadata.cluster_name, cluster.metadata.all_hosts(), self.keyspace)) # Table try: session.execute("CREATE TABLE %s (plugin text, time timeuuid, stat map, PRIMARY KEY (plugin, time)) WITH CLUSTERING ORDER BY (time DESC)" % self.table) except Exception: logger.debug("Cassandra table %s already exist" % self.table) return cluster, session def export(self, name, columns, points): """Write the points to the Cassandra cluster.""" logger.debug("Export {} stats to Cassandra".format(name)) # Remove non number stats and convert all to float (for Boolean) data = {k: float(v) for (k, v) in dict(zip(columns, points)).iteritems() if isinstance(v, Number)} # Write input to the Cassandra table try: self.session.execute( """ INSERT INTO localhost (plugin, time, stat) VALUES (%s, %s, %s) """, (name, uuid_from_time(datetime.now()), data) ) except Exception as e: logger.error("Cannot export {} stats to Cassandra ({})".format(name, e)) def exit(self): """Close the Cassandra export module.""" # To ensure all connections are properly closed self.session.shutdown() self.cluster.shutdown() # Call the father method super(Export, self).exit() glances-2.11.1/glances/exports/glances_couchdb.py000066400000000000000000000071441315472316100220160ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """CouchDB interface class.""" import sys from datetime import datetime from glances.logger import logger from glances.exports.glances_export import GlancesExport import couchdb import couchdb.mapping class Export(GlancesExport): """This class manages the CouchDB export module.""" def __init__(self, config=None, args=None): """Init the CouchDB export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.db = None # Optionals configuration keys self.user = None self.password = None # Load the Cassandra configuration file section self.export_enable = self.load_conf('couchdb', mandatories=['host', 'port', 'db'], options=['user', 'password']) if not self.export_enable: sys.exit(2) # Init the CouchDB client self.client = self.init() def init(self): """Init the connection to the CouchDB server.""" if not self.export_enable: return None if self.user is None: server_uri = 'http://{}:{}/'.format(self.host, self.port) else: server_uri = 'http://{}:{}@{}:{}/'.format(self.user, self.password, self.host, self.port) try: s = couchdb.Server(server_uri) except Exception as e: logger.critical("Cannot connect to CouchDB server %s (%s)" % (server_uri, e)) sys.exit(2) else: logger.info("Connected to the CouchDB server %s" % server_uri) try: s[self.db] except Exception as e: # Database did not exist # Create it... s.create(self.db) else: logger.info("There is already a %s database" % self.db) return s def database(self): """Return the CouchDB database object""" return self.client[self.db] def export(self, name, columns, points): """Write the points to the CouchDB server.""" logger.debug("Export {} stats to CouchDB".format(name)) # Create DB input data = dict(zip(columns, points)) # Set the type to the current stat name data['type'] = name data['time'] = couchdb.mapping.DateTimeField()._to_json(datetime.now()) # Write input to the CouchDB database # Result can be view: http://127.0.0.1:5984/_utils try: self.client[self.db].save(data) except Exception as e: logger.error("Cannot export {} stats to CouchDB ({})".format(name, e)) glances-2.11.1/glances/exports/glances_csv.py000066400000000000000000000067231315472316100212040ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """CSV interface class.""" import csv import sys import time from glances.compat import PY3, iterkeys, itervalues from glances.logger import logger from glances.exports.glances_export import GlancesExport class Export(GlancesExport): """This class manages the CSV export module.""" def __init__(self, config=None, args=None): """Init the CSV export IF.""" super(Export, self).__init__(config=config, args=args) # CSV file name self.csv_filename = args.export_csv # Set the CSV output file try: if PY3: self.csv_file = open(self.csv_filename, 'w', newline='') else: self.csv_file = open(self.csv_filename, 'wb') self.writer = csv.writer(self.csv_file) except IOError as e: logger.critical("Cannot create the CSV file: {}".format(e)) sys.exit(2) logger.info("Stats exported to CSV file: {}".format(self.csv_filename)) self.export_enable = True self.first_line = True def exit(self): """Close the CSV file.""" logger.debug("Finalise export interface %s" % self.export_name) self.csv_file.close() def update(self, stats): """Update stats in the CSV output file.""" # Get the stats all_stats = stats.getAllExports() plugins = stats.getAllPlugins() # Init data with timestamp (issue#708) if self.first_line: csv_header = ['timestamp'] csv_data = [time.strftime('%Y-%m-%d %H:%M:%S')] # Loop over available plugin for i, plugin in enumerate(plugins): if plugin in self.plugins_to_export(): if isinstance(all_stats[i], list): for stat in all_stats[i]: # First line: header if self.first_line: csv_header += ('{}_{}_{}'.format( plugin, self.get_item_key(stat), item) for item in stat) # Others lines: stats csv_data += itervalues(stat) elif isinstance(all_stats[i], dict): # First line: header if self.first_line: fieldnames = iterkeys(all_stats[i]) csv_header += ('{}_{}'.format(plugin, fieldname) for fieldname in fieldnames) # Others lines: stats csv_data += itervalues(all_stats[i]) # Export to CSV if self.first_line: self.writer.writerow(csv_header) self.first_line = False self.writer.writerow(csv_data) self.csv_file.flush() glances-2.11.1/glances/exports/glances_elasticsearch.py000066400000000000000000000066351315472316100232250ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ElasticSearch interface class.""" import sys from datetime import datetime from glances.logger import logger from glances.exports.glances_export import GlancesExport from elasticsearch import Elasticsearch, helpers class Export(GlancesExport): """This class manages the ElasticSearch (ES) export module.""" def __init__(self, config=None, args=None): """Init the ES export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.index = None # Optionals configuration keys # N/A # Load the ES configuration file self.export_enable = self.load_conf('elasticsearch', mandatories=['host', 'port', 'index'], options=[]) if not self.export_enable: sys.exit(2) # Init the ES client self.client = self.init() def init(self): """Init the connection to the ES server.""" if not self.export_enable: return None try: es = Elasticsearch(hosts=['{}:{}'.format(self.host, self.port)]) except Exception as e: logger.critical("Cannot connect to ElasticSearch server %s:%s (%s)" % (self.host, self.port, e)) sys.exit(2) else: logger.info("Connected to the ElasticSearch server %s:%s" % (self.host, self.port)) try: index_count = es.count(index=self.index)['count'] except Exception as e: # Index did not exist, it will be created at the first write # Create it... es.indices.create(self.index) else: logger.info("There is already %s entries in the ElasticSearch %s index" % (index_count, self.index)) return es def export(self, name, columns, points): """Write the points to the ES server.""" logger.debug("Export {} stats to ElasticSearch".format(name)) # Create DB input # https://elasticsearch-py.readthedocs.io/en/master/helpers.html actions = [] for c, p in zip(columns, points): action = { "_index": self.index, "_type": name, "_id": c, "_source": { "value": str(p), "timestamp": datetime.now() } } actions.append(action) # Write input to the ES index try: helpers.bulk(self.client, actions) except Exception as e: logger.error("Cannot export {} stats to ElasticSearch ({})".format(name, e)) glances-2.11.1/glances/exports/glances_export.py000066400000000000000000000161411315472316100217250ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ I am your father... ...for all Glances exports IF. """ import json from glances.compat import NoOptionError, NoSectionError, iteritems, iterkeys from glances.logger import logger class GlancesExport(object): """Main class for Glances export IF.""" def __init__(self, config=None, args=None): """Init the export class.""" # Export name (= module name without glances_) self.export_name = self.__class__.__module__[len('glances_'):] logger.debug("Init export module %s" % self.export_name) # Init the config & args self.config = config self.args = args # By default export is disable # Had to be set to True in the __init__ class of child self.export_enable = False # Mandatory for (most of) the export module self.host = None self.port = None def exit(self): """Close the export module.""" logger.debug("Finalise export interface %s" % self.export_name) def plugins_to_export(self): """Return the list of plugins to export.""" return ['cpu', 'percpu', 'load', 'mem', 'memswap', 'network', 'diskio', 'fs', 'processcount', 'ip', 'system', 'uptime', 'sensors', 'docker', 'uptime'] def load_conf(self, section, mandatories=['host', 'port'], options=None): """Load the export
configuration in the Glances configuration file. :param section: name of the export section to load :param mandatories: a list of mandatories parameters to load :param options: a list of optionnals parameters to load :returns: Boolean -- True if section is found """ options = options or [] if self.config is None: return False # By default read the mandatory host:port items try: for opt in mandatories: setattr(self, opt, self.config.get_value(section, opt)) except NoSectionError: logger.critical("No {} configuration found".format(section)) return False except NoOptionError as e: logger.critical("Error in the {} configuration ({})".format(section, e)) return False # Load options for opt in options: try: setattr(self, opt, self.config.get_value(section, opt)) except NoOptionError: pass logger.debug("Load {} from the Glances configuration file".format(section)) logger.debug("{} parameters: {}".format(section, {opt: getattr(self, opt) for opt in mandatories + options})) return True def get_item_key(self, item): """Return the value of the item 'key'.""" try: ret = item[item['key']] except KeyError: logger.error("No 'key' available in {}".format(item)) if isinstance(ret, list): return ret[0] else: return ret def parse_tags(self, tags): """Parse tags into a dict. input tags: a comma separated list of 'key:value' pairs. Example: foo:bar,spam:eggs output dtags: a dict of tags. Example: {'foo': 'bar', 'spam': 'eggs'} """ dtags = {} if tags: try: dtags = dict([x.split(':') for x in tags.split(',')]) except ValueError: # one of the 'key:value' pairs was missing logger.info('Invalid tags passed: %s', tags) dtags = {} return dtags def update(self, stats): """Update stats to a server. The method builds two lists: names and values and calls the export method to export the stats. Be aware that CSV export overwrite this class and use a specific one. """ if not self.export_enable: return False # Get all the stats & limits all_stats = stats.getAllExportsAsDict(plugin_list=self.plugins_to_export()) all_limits = stats.getAllLimitsAsDict(plugin_list=self.plugins_to_export()) # Loop over plugins to export for plugin in self.plugins_to_export(): if isinstance(all_stats[plugin], dict): all_stats[plugin].update(all_limits[plugin]) elif isinstance(all_stats[plugin], list): # TypeError: string indices must be integers (Network plugin) #1054 for i in all_stats[plugin]: i.update(all_limits[plugin]) else: continue export_names, export_values = self.__build_export(all_stats[plugin]) self.export(plugin, export_names, export_values) return True def __build_export(self, stats): """Build the export lists.""" export_names = [] export_values = [] if isinstance(stats, dict): # Stats is a dict # Is there a key ? if 'key' in iterkeys(stats) and stats['key'] in iterkeys(stats): pre_key = '{}.'.format(stats[stats['key']]) else: pre_key = '' # Walk through the dict for key, value in iteritems(stats): if isinstance(value, bool): value = json.dumps(value) if isinstance(value, list): try: value = value[0] except IndexError: value = '' if isinstance(value, dict): item_names, item_values = self.__build_export(value) item_names = [pre_key + key.lower() + str(i) for i in item_names] export_names += item_names export_values += item_values else: export_names.append(pre_key + key.lower()) export_values.append(value) elif isinstance(stats, list): # Stats is a list (of dict) # Recursive loop through the list for item in stats: item_names, item_values = self.__build_export(item) export_names += item_names export_values += item_values return export_names, export_values glances-2.11.1/glances/exports/glances_influxdb.py000066400000000000000000000115121315472316100222140ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """InfluxDB interface class.""" import sys from glances.logger import logger from glances.exports.glances_export import GlancesExport from influxdb import InfluxDBClient from influxdb.client import InfluxDBClientError from influxdb.influxdb08 import InfluxDBClient as InfluxDBClient08 from influxdb.influxdb08.client import InfluxDBClientError as InfluxDBClientError08 # Constants for tracking specific behavior INFLUXDB_08 = '0.8' INFLUXDB_09PLUS = '0.9+' class Export(GlancesExport): """This class manages the InfluxDB export module.""" def __init__(self, config=None, args=None): """Init the InfluxDB export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.user = None self.password = None self.db = None # Optionals configuration keys self.prefix = None self.tags = None # Load the InfluxDB configuration file self.export_enable = self.load_conf('influxdb', mandatories=['host', 'port', 'user', 'password', 'db'], options=['prefix', 'tags']) if not self.export_enable: sys.exit(2) # Init the InfluxDB client self.client = self.init() def init(self): """Init the connection to the InfluxDB server.""" if not self.export_enable: return None try: db = InfluxDBClient(host=self.host, port=self.port, username=self.user, password=self.password, database=self.db) get_all_db = [i['name'] for i in db.get_list_database()] self.version = INFLUXDB_09PLUS except InfluxDBClientError: # https://github.com/influxdb/influxdb-python/issues/138 logger.info("Trying fallback to InfluxDB v0.8") db = InfluxDBClient08(host=self.host, port=self.port, username=self.user, password=self.password, database=self.db) get_all_db = [i['name'] for i in db.get_list_database()] self.version = INFLUXDB_08 except InfluxDBClientError08 as e: logger.critical("Cannot connect to InfluxDB database '%s' (%s)" % (self.db, e)) sys.exit(2) if self.db in get_all_db: logger.info( "Stats will be exported to InfluxDB server: {}".format(db._baseurl)) else: logger.critical("InfluxDB database '%s' did not exist. Please create it" % self.db) sys.exit(2) return db def export(self, name, columns, points): """Write the points to the InfluxDB server.""" logger.debug("Export {} stats to InfluxDB".format(name)) # Manage prefix if self.prefix is not None: name = self.prefix + '.' + name # Create DB input if self.version == INFLUXDB_08: data = [{'name': name, 'columns': columns, 'points': [points]}] else: # Convert all int to float (mandatory for InfluxDB>0.9.2) # Correct issue#750 and issue#749 for i, _ in enumerate(points): try: points[i] = float(points[i]) except (TypeError, ValueError) as e: logger.debug("InfluxDB error during stat convertion %s=%s (%s)" % (columns[i], points[i], e)) data = [{'measurement': name, 'tags': self.parse_tags(self.tags), 'fields': dict(zip(columns, points))}] # Write input to the InfluxDB database try: self.client.write_points(data) except Exception as e: logger.error("Cannot export {} stats to InfluxDB ({})".format(name, e)) glances-2.11.1/glances/exports/glances_json.py000066400000000000000000000036171315472316100213610ustar00rootroot00000000000000"""JSON interface class.""" import sys import json from glances.compat import PY3, listkeys from glances.logger import logger from glances.exports.glances_export import GlancesExport class Export(GlancesExport): """This class manages the JSON export module.""" def __init__(self, config=None, args=None): """Init the JSON export IF.""" super(Export, self).__init__(config=config, args=args) # JSON file name self.json_filename = args.export_json # Set the JSON output file try: if PY3: self.json_file = open(self.json_filename, 'w') else: self.json_file = open(self.json_filename, 'wb') except IOError as e: logger.critical("Cannot create the JSON file: {}".format(e)) sys.exit(2) logger.info("Exporting stats to file: {}".format(self.json_filename)) self.export_enable = True # Buffer for dict of stats self.buffer = {} def exit(self): """Close the JSON file.""" logger.debug("Finalise export interface %s" % self.export_name) self.json_file.close() def export(self, name, columns, points): """Export the stats to the JSON file.""" # Check for completion of loop for all exports if name == self.plugins_to_export()[0] and self.buffer != {}: # One whole loop has been completed # Flush stats to file logger.debug("Exporting stats ({}) to JSON file ({})".format( listkeys(self.buffer), self.json_filename) ) # Export stats to JSON file data_json = json.dumps(self.buffer) self.json_file.write("{}\n".format(data_json)) # Reset buffer self.buffer = {} # Add current stat to the buffer self.buffer[name] = dict(zip(columns, points)) glances-2.11.1/glances/exports/glances_kafka.py000066400000000000000000000063531315472316100214650ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Kafka interface class.""" import sys from glances.logger import logger from glances.compat import iteritems from glances.exports.glances_export import GlancesExport from kafka import KafkaProducer import json class Export(GlancesExport): """This class manages the Kafka export module.""" def __init__(self, config=None, args=None): """Init the Kafka export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.topic = None # Optionals configuration keys self.compression = None # Load the Cassandra configuration file section self.export_enable = self.load_conf('kafka', mandatories=['host', 'port', 'topic'], options=['compression']) if not self.export_enable: sys.exit(2) # Init the kafka client self.client = self.init() def init(self): """Init the connection to the Kafka server.""" if not self.export_enable: return None # Build the server URI with host and port server_uri = '{}:{}'.format(self.host, self.port) try: s = KafkaProducer(bootstrap_servers=server_uri, value_serializer=lambda v: json.dumps(v).encode('utf-8'), compression_type=self.compression) except Exception as e: logger.critical("Cannot connect to Kafka server %s (%s)" % (server_uri, e)) sys.exit(2) else: logger.info("Connected to the Kafka server %s" % server_uri) return s def export(self, name, columns, points): """Write the points to the kafka server.""" logger.debug("Export {} stats to Kafka".format(name)) # Create DB input data = dict(zip(columns, points)) # Send stats to the kafka topic # key= # value=JSON dict try: self.client.send(self.topic, key=name, value=data) except Exception as e: logger.error("Cannot export {} stats to Kafka ({})".format(name, e)) def exit(self): """Close the Kafka export module.""" # To ensure all connections are properly closed self.client.flush() self.client.close() # Call the father method super(Export, self).exit() glances-2.11.1/glances/exports/glances_opentsdb.py000066400000000000000000000062521315472316100222240ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """OpenTSDB interface class.""" import sys from numbers import Number from glances.compat import range from glances.logger import logger from glances.exports.glances_export import GlancesExport import potsdb class Export(GlancesExport): """This class manages the OpenTSDB export module.""" def __init__(self, config=None, args=None): """Init the OpenTSDB export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) # N/A # Optionals configuration keys self.prefix = None self.tags = None # Load the InfluxDB configuration file self.export_enable = self.load_conf('opentsdb', mandatories=['host', 'port'], options=['prefix', 'tags']) if not self.export_enable: sys.exit(2) # Default prefix for stats is 'glances' if self.prefix is None: self.prefix = 'glances' # Init the OpenTSDB client self.client = self.init() def init(self): """Init the connection to the OpenTSDB server.""" if not self.export_enable: return None try: db = potsdb.Client(self.host, port=int(self.port), check_host=True) except Exception as e: logger.critical("Cannot connect to OpenTSDB server %s:%s (%s)" % (self.host, self.port, e)) sys.exit(2) return db def export(self, name, columns, points): """Export the stats to the Statsd server.""" for i in range(len(columns)): if not isinstance(points[i], Number): continue stat_name = '{}.{}.{}'.format(self.prefix, name, columns[i]) stat_value = points[i] tags = self.parse_tags(self.tags) try: self.client.send(stat_name, stat_value, **tags) except Exception as e: logger.error("Can not export stats %s to OpenTSDB (%s)" % (name, e)) logger.debug("Export {} stats to OpenTSDB".format(name)) def exit(self): """Close the OpenTSDB export module.""" # Waits for all outstanding metrics to be sent and background thread closes self.client.wait() # Call the father method super(Export, self).exit() glances-2.11.1/glances/exports/glances_prometheus.py000066400000000000000000000065561315472316100226100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Prometheus interface class.""" import sys from datetime import datetime from numbers import Number from glances.logger import logger from glances.exports.glances_export import GlancesExport from glances.compat import iteritems from prometheus_client import start_http_server, Gauge class Export(GlancesExport): """This class manages the Prometheus export module.""" METRIC_SEPARATOR = '_' def __init__(self, config=None, args=None): """Init the Prometheus export IF.""" super(Export, self).__init__(config=config, args=args) # Optionals configuration keys self.prefix = 'glances' # Load the Prometheus configuration file section self.export_enable = self.load_conf('prometheus', mandatories=['host', 'port'], options=['prefix']) if not self.export_enable: sys.exit(2) # Init the metric dict # Perhaps a better method is possible... self._metric_dict = {} # Init the Prometheus Exporter self.init() def init(self): """Init the Prometheus Exporter""" try: start_http_server(port=int(self.port), addr=self.host) except Exception as e: logger.critical("Can not start Prometheus exporter on {}:{} ({})".format(self.host, self.port, e)) sys.exit(2) else: logger.info("Start Prometheus exporter on {}:{}".format(self.host, self.port)) def export(self, name, columns, points): """Write the points to the Prometheus exporter using Gauge.""" logger.debug("Export {} stats to Prometheus exporter".format(name)) # Remove non number stats and convert all to float (for Boolean) data = {k: float(v) for (k, v) in iteritems(dict(zip(columns, points))) if isinstance(v, Number)} # Write metrics to the Prometheus exporter for k, v in iteritems(data): # Prometheus metric name: prefix_ metric_name = self.prefix + self.METRIC_SEPARATOR + name + self.METRIC_SEPARATOR + k # Prometheus is very sensible to the metric name # See: https://prometheus.io/docs/practices/naming/ for c in ['.', '-', '/', ' ']: metric_name = metric_name.replace(c, self.METRIC_SEPARATOR) # Manage an internal dict between metric name and Gauge if metric_name not in self._metric_dict: self._metric_dict[metric_name] = Gauge(metric_name, k) # Write the value self._metric_dict[metric_name].set(v) glances-2.11.1/glances/exports/glances_rabbitmq.py000066400000000000000000000063611315472316100222100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """JMS interface class.""" import datetime import socket import sys from numbers import Number from glances.compat import range from glances.logger import logger from glances.exports.glances_export import GlancesExport # Import pika for RabbitMQ import pika class Export(GlancesExport): """This class manages the rabbitMQ export module.""" def __init__(self, config=None, args=None): """Init the RabbitMQ export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.user = None self.password = None self.queue = None # Optionals configuration keys # N/A # Load the rabbitMQ configuration file self.export_enable = self.load_conf('rabbitmq', mandatories=['host', 'port', 'user', 'password', 'queue'], options=[]) if not self.export_enable: sys.exit(2) # Get the current hostname self.hostname = socket.gethostname() # Init the rabbitmq client self.client = self.init() def init(self): """Init the connection to the rabbitmq server.""" if not self.export_enable: return None try: parameters = pika.URLParameters( 'amqp://' + self.user + ':' + self.password + '@' + self.host + ':' + self.port + '/') connection = pika.BlockingConnection(parameters) channel = connection.channel() return channel except Exception as e: logger.critical("Connection to rabbitMQ failed : %s " % e) return None def export(self, name, columns, points): """Write the points in RabbitMQ.""" data = ('hostname=' + self.hostname + ', name=' + name + ', dateinfo=' + datetime.datetime.utcnow().isoformat()) for i in range(len(columns)): if not isinstance(points[i], Number): continue else: data += ", " + columns[i] + "=" + str(points[i]) logger.debug(data) try: self.client.basic_publish(exchange='', routing_key=self.queue, body=data) except Exception as e: logger.error("Can not export stats to RabbitMQ (%s)" % e) glances-2.11.1/glances/exports/glances_restful.py000066400000000000000000000056511315472316100220740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Restful interface class.""" import sys from glances.compat import listkeys from glances.logger import logger from glances.exports.glances_export import GlancesExport from requests import post class Export(GlancesExport): """This class manages the Restful export module. Be aware that stats will be exported in one big POST request""" def __init__(self, config=None, args=None): """Init the Restful export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.protocol = None self.path = None # Load the Restful section in the configuration file self.export_enable = self.load_conf('restful', mandatories=['host', 'port', 'protocol', 'path']) if not self.export_enable: sys.exit(2) # Init the stats buffer # It's a dict of stats self.buffer = {} # Init the Statsd client self.client = self.init() def init(self): """Init the connection to the restful server.""" if not self.export_enable: return None # Build the Restful URL where the stats will be posted url = '{}://{}:{}{}'.format(self.protocol, self.host, self.port, self.path) logger.info( "Stats will be exported to the restful endpoint {}".format(url)) return url def export(self, name, columns, points): """Export the stats to the Statsd server.""" if name == self.plugins_to_export()[0] and self.buffer != {}: # One complete loop have been done logger.debug("Export stats ({}) to Restful endpoint ({})".format(listkeys(self.buffer), self.client)) # Export stats post(self.client, json=self.buffer, allow_redirects=True) # Reset buffer self.buffer = {} # Add current stat to the buffer self.buffer[name] = dict(zip(columns, points)) glances-2.11.1/glances/exports/glances_riemann.py000066400000000000000000000052671315472316100220440ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Riemann interface class.""" import socket import sys from numbers import Number from glances.compat import range from glances.logger import logger from glances.exports.glances_export import GlancesExport # Import bernhard for Riemann import bernhard class Export(GlancesExport): """This class manages the Riemann export module.""" def __init__(self, config=None, args=None): """Init the Riemann export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) # N/A # Optionals configuration keys # N/A # Load the Riemann configuration self.export_enable = self.load_conf('riemann', mandatories=['host', 'port'], options=[]) if not self.export_enable: sys.exit(2) # Get the current hostname self.hostname = socket.gethostname() # Init the Riemann client self.client = self.init() def init(self): """Init the connection to the Riemann server.""" if not self.export_enable: return None try: client = bernhard.Client(host=self.host, port=self.port) return client except Exception as e: logger.critical("Connection to Riemann failed : %s " % e) return None def export(self, name, columns, points): """Write the points in Riemann.""" for i in range(len(columns)): if not isinstance(points[i], Number): continue else: data = {'host': self.hostname, 'service': name + " " + columns[i], 'metric': points[i]} logger.debug(data) try: self.client.send(data) except Exception as e: logger.error("Cannot export stats to Riemann (%s)" % e) glances-2.11.1/glances/exports/glances_statsd.py000066400000000000000000000061171315472316100217100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Statsd interface class.""" import sys from numbers import Number from glances.compat import range from glances.logger import logger from glances.exports.glances_export import GlancesExport from statsd import StatsClient class Export(GlancesExport): """This class manages the Statsd export module.""" def __init__(self, config=None, args=None): """Init the Statsd export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) # N/A # Optionals configuration keys self.prefix = None # Load the InfluxDB configuration file self.export_enable = self.load_conf('statsd', mandatories=['host', 'port'], options=['prefix']) if not self.export_enable: sys.exit(2) # Default prefix for stats is 'glances' if self.prefix is None: self.prefix = 'glances' # Init the Statsd client self.client = self.init() def init(self): """Init the connection to the Statsd server.""" if not self.export_enable: return None logger.info( "Stats will be exported to StatsD server: {}:{}".format(self.host, self.port)) return StatsClient(self.host, int(self.port), prefix=self.prefix) def export(self, name, columns, points): """Export the stats to the Statsd server.""" for i in range(len(columns)): if not isinstance(points[i], Number): continue stat_name = '{}.{}'.format(name, columns[i]) stat_value = points[i] try: self.client.gauge(normalize(stat_name), stat_value) except Exception as e: logger.error("Can not export stats to Statsd (%s)" % e) logger.debug("Export {} stats to Statsd".format(name)) def normalize(name): """Normalize name for the Statsd convention""" # Name should not contain some specials chars (issue #1068) ret = name.replace(':', '') ret = ret.replace('%', '') ret = ret.replace(' ', '_') return ret glances-2.11.1/glances/exports/glances_zeromq.py000066400000000000000000000070021315472316100217150ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ZeroMQ interface class.""" import sys import json from glances.compat import b from glances.logger import logger from glances.exports.glances_export import GlancesExport import zmq from zmq.utils.strtypes import asbytes class Export(GlancesExport): """This class manages the ZeroMQ export module.""" def __init__(self, config=None, args=None): """Init the ZeroMQ export IF.""" super(Export, self).__init__(config=config, args=args) # Mandatories configuration keys (additional to host and port) self.prefix = None # Optionals configuration keys # N/A # Load the ZeroMQ configuration file section ([export_zeromq]) self.export_enable = self.load_conf('zeromq', mandatories=['host', 'port', 'prefix'], options=[]) if not self.export_enable: sys.exit(2) # Init the ZeroMQ context self.context = None self.client = self.init() def init(self): """Init the connection to the CouchDB server.""" if not self.export_enable: return None server_uri = 'tcp://{}:{}'.format(self.host, self.port) try: self.context = zmq.Context() publisher = self.context.socket(zmq.PUB) publisher.bind(server_uri) except Exception as e: logger.critical("Cannot connect to ZeroMQ server %s (%s)" % (server_uri, e)) sys.exit(2) else: logger.info("Connected to the ZeroMQ server %s" % server_uri) return publisher def exit(self): """Close the socket and context""" if self.client is not None: self.client.close() if self.context is not None: self.context.destroy() def export(self, name, columns, points): """Write the points to the ZeroMQ server.""" logger.debug("Export {} stats to ZeroMQ".format(name)) # Create DB input data = dict(zip(columns, points)) # Do not publish empty stats if data == {}: return False # Glances envelopes the stats in a publish message with two frames: # - First frame containing the following prefix (STRING) # - Second frame with the Glances plugin name (STRING) # - Third frame with the Glances plugin stats (JSON) message = [b(self.prefix), b(name), asbytes(json.dumps(data))] # Write data to the ZeroMQ bus # Result can be view: tcp://host:port try: self.client.send_multipart(message) except Exception as e: logger.error("Cannot export {} stats to ZeroMQ ({})".format(name, e)) return True glances-2.11.1/glances/exports/graph.py000066400000000000000000000157251315472316100200200ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Graph generation class.""" import os from glances.compat import iterkeys from glances.logger import logger try: from matplotlib import __version__ as matplotlib_version import matplotlib.pyplot as plt except ImportError: matplotlib_check = False logger.warning('Cannot load Matplotlib library. Please install it using "pip install matplotlib"') else: matplotlib_check = True logger.info('Load Matplotlib version %s' % matplotlib_version) class GlancesGraph(object): """Thanks to this class, Glances can export history to graphs.""" def __init__(self, output_folder): self.output_folder = output_folder def get_output_folder(self): """Return the output folder where the graph are generated.""" return self.output_folder def graph_enabled(self): """Return True if Glances can generate history graphs.""" return matplotlib_check def reset(self, stats): """Reset all the history.""" if not self.graph_enabled(): return False for p in stats.getAllPlugins(): h = stats.get_plugin(p).get_stats_history() if h is not None: stats.get_plugin(p).reset_stats_history() return True def get_graph_color(self, item): """Get the item's color.""" try: ret = item['color'] except KeyError: return '#FFFFFF' else: return ret def get_graph_legend(self, item): """Get the item's legend.""" return item['description'] def get_graph_yunit(self, item, pre_label=''): """Get the item's Y unit.""" try: unit = " (%s)" % item['y_unit'] except KeyError: unit = '' if pre_label == '': label = '' else: label = pre_label.split('_')[0] return "%s%s" % (label, unit) def generate_graph(self, stats): """Generate graphs from plugins history. Return the number of output files generated by the function. """ if not self.graph_enabled(): return 0 index_all = 0 for p in stats.getAllPlugins(): # History h = stats.get_plugin(p).get_export_history() # Current plugin item history list ih = stats.get_plugin(p).get_items_history_list() # Check if we must process history if h is None or ih is None: # History (h) not available for plugin (p) continue # Init graph plt.clf() index_graph = 0 handles = [] labels = [] for i in ih: if i['name'] in iterkeys(h): # The key exist # Add the curves in the current chart logger.debug("Generate graph: %s %s" % (p, i['name'])) index_graph += 1 # Labels handles.append(plt.Rectangle((0, 0), 1, 1, fc=self.get_graph_color(i), ec=self.get_graph_color(i), linewidth=2)) labels.append(self.get_graph_legend(i)) # Legend plt.ylabel(self.get_graph_yunit(i, pre_label='')) # Curves plt.grid(True) # Points are stored as tuple (date, value) x, y = zip(*h[i['name']]) plt.plot_date(x, y, fmt='', drawstyle='default', linestyle='-', color=self.get_graph_color(i), xdate=True, ydate=False) if index_graph == 1: # Title only on top of the first graph plt.title(p.capitalize()) else: # The key did not exist # Find if anothers key ends with the key # Ex: key='tx' => 'ethernet_tx' # Add one curve per chart stats_history_filtered = sorted([key for key in iterkeys(h) if key.endswith('_' + i['name'])]) logger.debug("Generate graphs: %s %s" % (p, stats_history_filtered)) if len(stats_history_filtered) > 0: # Create 'n' graph # Each graph iter through the stats plt.clf() index_item = 0 for k in stats_history_filtered: index_item += 1 plt.subplot( len(stats_history_filtered), 1, index_item) # Legend plt.ylabel(self.get_graph_yunit(i, pre_label=k)) # Curves plt.grid(True) # Points are stored as tuple (date, value) x, y = zip(*h[k]) plt.plot_date(x, y, fmt='', drawstyle='default', linestyle='-', color=self.get_graph_color(i), xdate=True, ydate=False) if index_item == 1: # Title only on top of the first graph plt.title(p.capitalize() + ' ' + i['name']) # Save the graph to output file fig = plt.gcf() fig.set_size_inches(20, 5 * index_item) plt.xlabel('Date') plt.savefig( os.path.join(self.output_folder, 'glances_%s_%s.png' % (p, i['name'])), dpi=72) index_all += 1 if index_graph > 0: # Save the graph to output file fig = plt.gcf() fig.set_size_inches(20, 10) plt.legend(handles, labels, loc=1, prop={'size': 9}) plt.xlabel('Date') plt.savefig(os.path.join(self.output_folder, 'glances_%s.png' % p), dpi=72) index_all += 1 plt.close() return index_all glances-2.11.1/glances/filter.py000066400000000000000000000113671315472316100164760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . import re from glances.logger import logger class GlancesFilter(object): """Allow Glances to filter processes >>> f = GlancesFilter() >>> f.filter = '.*python.*' >>> f.filter '.*python.*' >>> f.key None >>> f.filter = 'user:nicolargo' >>> f.filter 'nicolargo' >>> f.key 'user' >>> f.filter = 'username:.*nico.*' >>> f.filter '.*nico.*' >>> f.key 'username' """ def __init__(self): # Filter entered by the user (string) self._filter_input = None # Filter to apply self._filter = None # Filter regular expression self._filter_re = None # Dict key where the filter should be applied # Default is None: search on command line and process name self._filter_key = None @property def filter_input(self): """Return the filter given by the user (as a sting)""" return self._filter_input @property def filter(self): """Return the current filter to be applied""" return self._filter @filter.setter def filter(self, value): """Set the filter (as a sting) and compute the regular expression A filter could be one of the following: - python > Process name of cmd start with python - .*python.* > Process name of cmd contain python - username:nicolargo > Process of nicolargo user """ self._filter_input = value if value is None: self._filter = None self._filter_key = None else: new_filter = value.split(':') if len(new_filter) == 1: self._filter = new_filter[0] self._filter_key = None else: self._filter = new_filter[1] self._filter_key = new_filter[0] self._filter_re = None if self.filter is not None: logger.info("Set filter to {} on key {}".format(self.filter, self.filter_key)) # Compute the regular expression try: self._filter_re = re.compile(self.filter) logger.debug("Filter regex compilation OK: {}".format(self.filter)) except Exception as e: logger.error("Cannot compile filter regex: {} ({})".format(self.filter, e)) self._filter = None self._filter_re = None self._filter_key = None @property def filter_re(self): """Return the filter regular expression""" return self._filter_re @property def filter_key(self): """key where the filter should be applied""" return self._filter_key def is_filtered(self, process): """Return True if the process item match the current filter The proces item is a dict. """ if self.filter is None: # No filter => Not filtered return False if self.filter_key is None: # Apply filter on command line and process name return self._is_process_filtered(process, key='cmdline') and self._is_process_filtered(process, key='name') else: # Apply filter on return self._is_process_filtered(process) def _is_process_filtered(self, process, key=None): """Return True if the process[key] should be filtered according to the current filter""" if key is None: key = self.filter_key try: # If the item process[key] is a list, convert it to a string # in order to match it with the current regular expression if isinstance(process[key], list): value = ' '.join(process[key]) else: value = process[key] except KeyError: # If the key did not exist return False try: return self._filter_re.match(value) is None except AttributeError: # Filter processes crashs with a bad regular expression pattern (issue #665) return False glances-2.11.1/glances/folder_list.py000066400000000000000000000135571315472316100175220ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the folder list.""" import os from glances.compat import range from glances.logger import logger # Use the built-in version of scandir/walk if possible, otherwise # use the scandir module version scandir_tag = True try: # For Python 3.5 or higher from os import scandir except ImportError: # For others... try: from scandir import scandir except ImportError: scandir_tag = False class FolderList(object): """This class describes the optional monitored folder list. The folder list is a list of 'important' folder to monitor. The list (Python list) is composed of items (Python dict). An item is defined (dict keys): * path: Path to the folder * careful: optional careful threshold (in MB) * warning: optional warning threshold (in MB) * critical: optional critical threshold (in MB) """ # Maximum number of items in the list __folder_list_max_size = 10 # The folder list __folder_list = [] def __init__(self, config): """Init the folder list from the configuration file, if it exists.""" self.config = config if self.config is not None and self.config.has_section('folders'): if scandir_tag: # Process monitoring list logger.debug("Folder list configuration detected") self.__set_folder_list('folders') else: logger.error('Scandir not found. Please use Python 3.5+ or install the scandir lib') else: self.__folder_list = [] def __set_folder_list(self, section): """Init the monitored folder list. The list is defined in the Glances configuration file. """ for l in range(1, self.__folder_list_max_size + 1): value = {} key = 'folder_' + str(l) + '_' # Path is mandatory value['path'] = self.config.get_value(section, key + 'path') if value['path'] is None: continue # Optional conf keys for i in ['careful', 'warning', 'critical']: value[i] = self.config.get_value(section, key + i) if value[i] is None: logger.debug("No {} threshold for folder {}".format(i, value["path"])) # Add the item to the list self.__folder_list.append(value) def __str__(self): return str(self.__folder_list) def __repr__(self): return self.__folder_list def __getitem__(self, item): return self.__folder_list[item] def __len__(self): return len(self.__folder_list) def __get__(self, item, key): """Meta function to return key value of item. Return None if not defined or item > len(list) """ if item < len(self.__folder_list): try: return self.__folder_list[item][key] except Exception: return None else: return None def __folder_size(self, path): """Return the size of the directory given by path path: """ ret = 0 for f in scandir(path): if f.is_dir() and (f.name != '.' or f.name != '..'): ret += self.__folder_size(os.path.join(path, f.name)) else: try: ret += f.stat().st_size except OSError: pass return ret def update(self): """Update the command result attributed.""" # Only continue if monitor list is not empty if len(self.__folder_list) == 0: return self.__folder_list # Iter upon the folder list for i in range(len(self.get())): # Update folder size try: self.__folder_list[i]['size'] = self.__folder_size(self.path(i)) except OSError as e: logger.debug('Cannot get folder size ({}). Error: {}'.format(self.path(i), e)) if e.errno == 13: # Permission denied self.__folder_list[i]['size'] = '!' else: self.__folder_list[i]['size'] = '?' return self.__folder_list def get(self): """Return the monitored list (list of dict).""" return self.__folder_list def set(self, newlist): """Set the monitored list (list of dict).""" self.__folder_list = newlist def getAll(self): # Deprecated: use get() return self.get() def setAll(self, newlist): # Deprecated: use set() self.set(newlist) def path(self, item): """Return the path of the item number (item).""" return self.__get__(item, "path") def careful(self, item): """Return the careful threshold of the item number (item).""" return self.__get__(item, "careful") def warning(self, item): """Return the warning threshold of the item number (item).""" return self.__get__(item, "warning") def critical(self, item): """Return the critical threshold of the item number (item).""" return self.__get__(item, "critical") glances-2.11.1/glances/globals.py000066400000000000000000000034201315472316100166230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Common objects shared by all Glances modules.""" import errno import os import sys # Operating system flag # Note: Somes libs depends of OS BSD = sys.platform.find('bsd') != -1 LINUX = sys.platform.startswith('linux') MACOS = sys.platform.startswith('darwin') SUNOS = sys.platform.startswith('sunos') WINDOWS = sys.platform.startswith('win') # Set the AMPs, plugins and export modules path work_path = os.path.realpath(os.path.dirname(__file__)) amps_path = os.path.realpath(os.path.join(work_path, 'amps')) plugins_path = os.path.realpath(os.path.join(work_path, 'plugins')) exports_path = os.path.realpath(os.path.join(work_path, 'exports')) sys_path = sys.path[:] sys.path.insert(1, exports_path) sys.path.insert(1, plugins_path) sys.path.insert(1, amps_path) def safe_makedirs(path): """A safe function for creating a directory tree.""" try: os.makedirs(path) except OSError as err: if err.errno == errno.EEXIST: if not os.path.isdir(path): raise else: raise glances-2.11.1/glances/history.py000066400000000000000000000041171315472316100167050ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage stats history""" from glances.attribute import GlancesAttribute class GlancesHistory(object): """This class manage a dict of GlancesAttribute - key: stats name - value: GlancesAttribute""" def __init__(self): """ items_history_list: list of stats to historized (define inside plugins) """ self.stats_history = {} def add(self, key, value, description='', history_max_size=None): """Add an new item (key, value) to the current history.""" if key not in self.stats_history: self.stats_history[key] = GlancesAttribute(key, description=description, history_max_size=history_max_size) self.stats_history[key].value = value def reset(self): """Reset all the stats history""" for a in self.stats_history: self.stats_history[a].history_reset() def get(self, nb=0): """Get the history as a dict of list""" return {i: self.stats_history[i].history_raw(nb=nb) for i in self.stats_history} def get_json(self, nb=0): """Get the history as a dict of list (with list JSON compliant)""" return {i: self.stats_history[i].history_json(nb=nb) for i in self.stats_history} glances-2.11.1/glances/logger.py000066400000000000000000000061771315472316100164730ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Custom logger class.""" import os import json import getpass import tempfile import logging import logging.config LOG_FILENAME = os.path.join(tempfile.gettempdir(), 'glances-{}.log'.format(getpass.getuser())) # Define the logging configuration LOGGING_CFG = { "version": 1, "disable_existing_loggers": "False", "root": { "level": "INFO", "handlers": ["file", "console"] }, "formatters": { "standard": { "format": "%(asctime)s -- %(levelname)s -- %(message)s" }, "short": { "format": "%(levelname)s: %(message)s" }, "free": { "format": "%(message)s" } }, "handlers": { "file": { "level": "DEBUG", "class": "logging.handlers.RotatingFileHandler", "formatter": "standard", "filename": LOG_FILENAME }, "console": { "level": "CRITICAL", "class": "logging.StreamHandler", "formatter": "free" } }, "loggers": { "debug": { "handlers": ["file", "console"], "level": "DEBUG" }, "verbose": { "handlers": ["file", "console"], "level": "INFO" }, "standard": { "handlers": ["file"], "level": "INFO" }, "requests": { "handlers": ["file", "console"], "level": "ERROR" }, "elasticsearch": { "handlers": ["file", "console"], "level": "ERROR" }, "elasticsearch.trace": { "handlers": ["file", "console"], "level": "ERROR" } } } def glances_logger(env_key='LOG_CFG'): """Build and return the logger. env_key define the env var where a path to a specific JSON logger could be defined :return: logger -- Logger instance """ _logger = logging.getLogger() # By default, use the LOGGING_CFG logger configuration config = LOGGING_CFG # Check if a specific configuration is available user_file = os.getenv(env_key, None) if user_file and os.path.exists(user_file): # A user file as been defined. Use it... with open(user_file, 'rt') as f: config = json.load(f) # Load the configuration logging.config.dictConfig(config) return _logger logger = glances_logger() glances-2.11.1/glances/logs.py000066400000000000000000000173561315472316100161610ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage logs.""" import time from datetime import datetime from glances.compat import range from glances.processes import glances_processes, sort_stats class GlancesLogs(object): """This class manages logs inside the Glances software. Logs is a list of list (stored in the self.logs_list var) item_state = "OK|CAREFUL|WARNING|CRITICAL" item_type = "CPU*|LOAD|MEM|MON" item_value = value Item is defined by: ["begin", "end", "WARNING|CRITICAL", "CPU|LOAD|MEM", MAX, AVG, MIN, SUM, COUNT, [top3 process list], "Processes description", "top sort key"] """ def __init__(self): """Init the logs class.""" # Maximum size of the logs list self.logs_max = 10 # Init the logs list self.logs_list = [] def get(self): """Return the raw logs list.""" return self.logs_list def len(self): """Return the number of item in the logs list.""" return self.logs_list.__len__() def __itemexist__(self, item_type): """Return the item position, if it exists. An item exist in the list if: * end is < 0 * item_type is matching Return -1 if the item is not found. """ for i in range(self.len()): if self.logs_list[i][1] < 0 and self.logs_list[i][3] == item_type: return i return -1 def get_process_sort_key(self, item_type): """Return the process sort key""" # Process sort depending on alert type if item_type.startswith("MEM"): # Sort TOP process by memory_percent ret = 'memory_percent' elif item_type.startswith("CPU_IOWAIT"): # Sort TOP process by io_counters (only for Linux OS) ret = 'io_counters' else: # Default sort is... ret = 'cpu_percent' return ret def set_process_sort(self, item_type): """Define the process auto sort key from the alert type.""" glances_processes.auto_sort = True glances_processes.sort_key = self.get_process_sort_key(item_type) def reset_process_sort(self): """Reset the process auto sort key.""" # Default sort is... glances_processes.auto_sort = True glances_processes.sort_key = 'cpu_percent' def add(self, item_state, item_type, item_value, proc_list=None, proc_desc="", peak_time=6): """Add a new item to the logs list. If 'item' is a 'new one', add the new item at the beginning of the logs list. If 'item' is not a 'new one', update the existing item. If event < peak_time the the alert is not setoff. """ proc_list = proc_list or glances_processes.getalllist() # Add or update the log item_index = self.__itemexist__(item_type) if item_index < 0: # Item did not exist, add if WARNING or CRITICAL self._create_item(item_state, item_type, item_value, proc_list, proc_desc, peak_time) else: # Item exist, update self._update_item(item_index, item_state, item_type, item_value, proc_list, proc_desc, peak_time) return self.len() def _create_item(self, item_state, item_type, item_value, proc_list, proc_desc, peak_time): """Create a new item in the log list""" if item_state == "WARNING" or item_state == "CRITICAL": # Define the automatic process sort key self.set_process_sort(item_type) # Create the new log item # Time is stored in Epoch format # Epoch -> DMYHMS = datetime.fromtimestamp(epoch) item = [ time.mktime(datetime.now().timetuple()), # START DATE -1, # END DATE item_state, # STATE: WARNING|CRITICAL item_type, # TYPE: CPU, LOAD, MEM... item_value, # MAX item_value, # AVG item_value, # MIN item_value, # SUM 1, # COUNT [], # TOP 3 PROCESS LIST proc_desc, # MONITORED PROCESSES DESC glances_processes.sort_key] # TOP PROCESS SORTKEY # Add the item to the list self.logs_list.insert(0, item) if self.len() > self.logs_max: self.logs_list.pop() return True else: return False def _update_item(self, item_index, item_state, item_type, item_value, proc_list, proc_desc, peak_time): """Update a item in the log list""" if item_state == "OK" or item_state == "CAREFUL": # Reset the automatic process sort key self.reset_process_sort() endtime = time.mktime(datetime.now().timetuple()) if endtime - self.logs_list[item_index][0] > peak_time: # If event is > peak_time seconds self.logs_list[item_index][1] = endtime else: # If event <= peak_time seconds, ignore self.logs_list.remove(self.logs_list[item_index]) else: # Update the item # State if item_state == "CRITICAL": self.logs_list[item_index][2] = item_state # Value if item_value > self.logs_list[item_index][4]: # MAX self.logs_list[item_index][4] = item_value elif item_value < self.logs_list[item_index][6]: # MIN self.logs_list[item_index][6] = item_value # AVG (compute average value) self.logs_list[item_index][7] += item_value self.logs_list[item_index][8] += 1 self.logs_list[item_index][5] = (self.logs_list[item_index][7] / self.logs_list[item_index][8]) # TOP PROCESS LIST (only for CRITICAL ALERT) if item_state == "CRITICAL": # Sort the current process list to retreive the TOP 3 processes self.logs_list[item_index][9] = sort_stats(proc_list, glances_processes.sort_key)[0:3] self.logs_list[item_index][11] = glances_processes.sort_key # MONITORED PROCESSES DESC self.logs_list[item_index][10] = proc_desc return True def clean(self, critical=False): """Clean the logs list by deleting finished items. By default, only delete WARNING message. If critical = True, also delete CRITICAL message. """ # Create a new clean list clean_logs_list = [] while self.len() > 0: item = self.logs_list.pop() if item[1] < 0 or (not critical and item[2].startswith("CRITICAL")): clean_logs_list.insert(0, item) # The list is now the clean one self.logs_list = clean_logs_list return self.len() glances_logs = GlancesLogs() glances-2.11.1/glances/main.py000066400000000000000000000604151315472316100161330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Glances main class.""" import argparse import os import sys import tempfile from glances import __version__, psutil_version from glances.compat import input from glances.config import Config from glances.globals import LINUX, WINDOWS from glances.logger import logger class GlancesMain(object): """Main class to manage Glances instance.""" # Default stats' refresh time is 3 seconds refresh_time = 3 # Set the default cache lifetime to 1 second (only for server) cached_time = 1 # By default, Glances is ran in standalone mode (no client/server) client_tag = False # Server TCP port number (default is 61209) server_port = 61209 # Web Server TCP port number (default is 61208) web_server_port = 61208 # Default username/password for client/server mode username = "glances" password = "" # Examples of use example_of_use = """ Examples of use: Monitor local machine (standalone mode): $ glances Monitor local machine with the Web interface (Web UI): $ glances -w Glances web server started on http://0.0.0.0:61208/ Monitor local machine and export stats to a CSV file (standalone mode): $ glances --export-csv /tmp/glances.csv Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode): $ glances -t 5 --export-influxdb Start a Glances server (server mode): $ glances -s Connect Glances to a Glances server (client mode): $ glances -c Connect Glances to a Glances server and export stats to a StatsD server (client mode): $ glances -c --export-statsd Start the client browser (browser mode): $ glances --browser """ def __init__(self): """Manage the command line arguments.""" # Read the command line arguments self.args = self.parse_args() def init_args(self): """Init all the command line arguments.""" version = "Glances v" + __version__ + " with psutil v" + psutil_version parser = argparse.ArgumentParser( prog='glances', conflict_handler='resolve', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=self.example_of_use) parser.add_argument( '-V', '--version', action='version', version=version) parser.add_argument('-d', '--debug', action='store_true', default=False, dest='debug', help='enable debug mode') parser.add_argument('-C', '--config', dest='conf_file', help='path to the configuration file') # Enable or disable option on startup parser.add_argument('--disable-alert', action='store_true', default=False, dest='disable_alert', help='disable alert module') parser.add_argument('--disable-amps', action='store_true', default=False, dest='disable_amps', help='disable applications monitoring process (AMP) module') parser.add_argument('--disable-cloud', action='store_true', default=False, dest='disable_cloud', help='disable Cloud module') parser.add_argument('--disable-cpu', action='store_true', default=False, dest='disable_cpu', help='disable CPU module') parser.add_argument('--disable-diskio', action='store_true', default=False, dest='disable_diskio', help='disable disk I/O module') parser.add_argument('--disable-docker', action='store_true', default=False, dest='disable_docker', help='disable Docker module') parser.add_argument('--disable-folders', action='store_true', default=False, dest='disable_folders', help='disable folder module') parser.add_argument('--disable-fs', action='store_true', default=False, dest='disable_fs', help='disable filesystem module') parser.add_argument('--disable-gpu', action='store_true', default=False, dest='disable_gpu', help='disable GPU module') parser.add_argument('--disable-hddtemp', action='store_true', default=False, dest='disable_hddtemp', help='disable HD temperature module') parser.add_argument('--disable-ip', action='store_true', default=False, dest='disable_ip', help='disable IP module') parser.add_argument('--disable-load', action='store_true', default=False, dest='disable_load', help='disable load module') parser.add_argument('--disable-mem', action='store_true', default=False, dest='disable_mem', help='disable memory module') parser.add_argument('--disable-memswap', action='store_true', default=False, dest='disable_memswap', help='disable memory swap module') parser.add_argument('--disable-network', action='store_true', default=False, dest='disable_network', help='disable network module') parser.add_argument('--disable-now', action='store_true', default=False, dest='disable_now', help='disable current time module') parser.add_argument('--disable-ports', action='store_true', default=False, dest='disable_ports', help='disable ports scanner module') parser.add_argument('--disable-process', action='store_true', default=False, dest='disable_process', help='disable process module') parser.add_argument('--disable-raid', action='store_true', default=False, dest='disable_raid', help='disable RAID module') parser.add_argument('--disable-sensors', action='store_true', default=False, dest='disable_sensors', help='disable sensors module') parser.add_argument('--disable-wifi', action='store_true', default=False, dest='disable_wifi', help='disable wifi module') parser.add_argument('-0', '--disable-irix', action='store_true', default=False, dest='disable_irix', help='task\'s cpu usage will be divided by the total number of CPUs') parser.add_argument('-1', '--percpu', action='store_true', default=False, dest='percpu', help='start Glances in per CPU mode') parser.add_argument('-2', '--disable-left-sidebar', action='store_true', default=False, dest='disable_left_sidebar', help='disable network, disk I/O, FS and sensors modules') parser.add_argument('-3', '--disable-quicklook', action='store_true', default=False, dest='disable_quicklook', help='disable quick look module') parser.add_argument('-4', '--full-quicklook', action='store_true', default=False, dest='full_quicklook', help='disable all but quick look and load') parser.add_argument('-5', '--disable-top', action='store_true', default=False, dest='disable_top', help='disable top menu (QL, CPU, MEM, SWAP and LOAD)') parser.add_argument('-6', '--meangpu', action='store_true', default=False, dest='meangpu', help='start Glances in mean GPU mode') parser.add_argument('--disable-history', action='store_true', default=False, dest='disable_history', help='disable stats history') parser.add_argument('--disable-bold', action='store_true', default=False, dest='disable_bold', help='disable bold mode in the terminal') parser.add_argument('--disable-bg', action='store_true', default=False, dest='disable_bg', help='disable background colors in the terminal') parser.add_argument('--enable-irq', action='store_true', default=False, dest='enable_irq', help='enable IRQ module'), parser.add_argument('--enable-process-extended', action='store_true', default=False, dest='enable_process_extended', help='enable extended stats on top process') # Export modules feature parser.add_argument('--export-graph', action='store_true', default=None, dest='export_graph', help='export stats to graphs') parser.add_argument('--path-graph', default=tempfile.gettempdir(), dest='path_graph', help='set the export path for graphs (default is {})'.format(tempfile.gettempdir())) parser.add_argument('--export-csv', default=None, dest='export_csv', help='export stats to a CSV file') parser.add_argument('--export-json', default=None, dest='export_json', help='export stats to a JSON file') parser.add_argument('--export-cassandra', action='store_true', default=False, dest='export_cassandra', help='export stats to a Cassandra or Scylla server (cassandra lib needed)') parser.add_argument('--export-couchdb', action='store_true', default=False, dest='export_couchdb', help='export stats to a CouchDB server (couch lib needed)') parser.add_argument('--export-elasticsearch', action='store_true', default=False, dest='export_elasticsearch', help='export stats to an ElasticSearch server (elasticsearch lib needed)') parser.add_argument('--export-influxdb', action='store_true', default=False, dest='export_influxdb', help='export stats to an InfluxDB server (influxdb lib needed)') parser.add_argument('--export-kafka', action='store_true', default=False, dest='export_kafka', help='export stats to a Kafka server (kafka-python lib needed)') parser.add_argument('--export-opentsdb', action='store_true', default=False, dest='export_opentsdb', help='export stats to an OpenTSDB server (potsdb lib needed)') parser.add_argument('--export-prometheus', action='store_true', default=False, dest='export_prometheus', help='export stats to a Prometheus exporter (prometheus_client lib needed)') parser.add_argument('--export-rabbitmq', action='store_true', default=False, dest='export_rabbitmq', help='export stats to rabbitmq broker (pika lib needed)') parser.add_argument('--export-restful', action='store_true', default=False, dest='export_restful', help='export stats to a Restful endpoint (requests lib needed)') parser.add_argument('--export-riemann', action='store_true', default=False, dest='export_riemann', help='export stats to riemann broker (bernhard lib needed)') parser.add_argument('--export-statsd', action='store_true', default=False, dest='export_statsd', help='export stats to a StatsD server (statsd lib needed)') parser.add_argument('--export-zeromq', action='store_true', default=False, dest='export_zeromq', help='export stats to a ZeroMQ server (pyzmq lib needed)') # Client/Server option parser.add_argument('-c', '--client', dest='client', help='connect to a Glances server by IPv4/IPv6 address or hostname') parser.add_argument('-s', '--server', action='store_true', default=False, dest='server', help='run Glances in server mode') parser.add_argument('--browser', action='store_true', default=False, dest='browser', help='start the client browser (list of servers)') parser.add_argument('--disable-autodiscover', action='store_true', default=False, dest='disable_autodiscover', help='disable autodiscover feature') parser.add_argument('-p', '--port', default=None, type=int, dest='port', help='define the client/server TCP port [default: {}]'.format(self.server_port)) parser.add_argument('-B', '--bind', default='0.0.0.0', dest='bind_address', help='bind server to the given IPv4/IPv6 address or hostname') parser.add_argument('--username', action='store_true', default=False, dest='username_prompt', help='define a client/server username') parser.add_argument('--password', action='store_true', default=False, dest='password_prompt', help='define a client/server password') parser.add_argument('--snmp-community', default='public', dest='snmp_community', help='SNMP community') parser.add_argument('--snmp-port', default=161, type=int, dest='snmp_port', help='SNMP port') parser.add_argument('--snmp-version', default='2c', dest='snmp_version', help='SNMP version (1, 2c or 3)') parser.add_argument('--snmp-user', default='private', dest='snmp_user', help='SNMP username (only for SNMPv3)') parser.add_argument('--snmp-auth', default='password', dest='snmp_auth', help='SNMP authentication key (only for SNMPv3)') parser.add_argument('--snmp-force', action='store_true', default=False, dest='snmp_force', help='force SNMP mode') parser.add_argument('-t', '--time', default=self.refresh_time, type=float, dest='time', help='set refresh time in seconds [default: {} sec]'.format(self.refresh_time)) parser.add_argument('-w', '--webserver', action='store_true', default=False, dest='webserver', help='run Glances in web server mode (bottle needed)') parser.add_argument('--cached-time', default=self.cached_time, type=int, dest='cached_time', help='set the server cache time [default: {} sec]'.format(self.cached_time)) parser.add_argument('--open-web-browser', action='store_true', default=False, dest='open_web_browser', help='try to open the Web UI in the default Web browser') # Display options parser.add_argument('-q', '--quiet', default=False, action='store_true', dest='quiet', help='do not display the curses interface') parser.add_argument('-f', '--process-filter', default=None, type=str, dest='process_filter', help='set the process filter pattern (regular expression)') parser.add_argument('--process-short-name', action='store_true', default=False, dest='process_short_name', help='force short name for processes name') if not WINDOWS: parser.add_argument('--hide-kernel-threads', action='store_true', default=False, dest='no_kernel_threads', help='hide kernel threads in process list') if LINUX: parser.add_argument('--tree', action='store_true', default=False, dest='process_tree', help='display processes as a tree') parser.add_argument('-b', '--byte', action='store_true', default=False, dest='byte', help='display network rate in byte per second') parser.add_argument('--diskio-show-ramfs', action='store_true', default=False, dest='diskio_show_ramfs', help='show RAM Fs in the DiskIO plugin') parser.add_argument('--diskio-iops', action='store_true', default=False, dest='diskio_iops', help='show IO per second in the DiskIO plugin') parser.add_argument('--fahrenheit', action='store_true', default=False, dest='fahrenheit', help='display temperature in Fahrenheit (default is Celsius)') parser.add_argument('--fs-free-space', action='store_true', default=False, dest='fs_free_space', help='display FS free space instead of used') parser.add_argument('--theme-white', action='store_true', default=False, dest='theme_white', help='optimize display colors for white background') # Globals options parser.add_argument('--disable-check-update', action='store_true', default=False, dest='disable_check_update', help='disable online Glances version ckeck') return parser def parse_args(self): """Parse command line arguments.""" args = self.init_args().parse_args() # Load the configuration file, if it exists self.config = Config(args.conf_file) # Debug mode if args.debug: from logging import DEBUG logger.setLevel(DEBUG) # Client/server Port if args.port is None: if args.webserver: args.port = self.web_server_port else: args.port = self.server_port # Port in the -c URI #996 if args.client is not None: args.client, args.port = (x if x else y for (x, y) in zip(args.client.partition(':')[::2], (args.client, args.port))) # Autodiscover if args.disable_autodiscover: logger.info("Auto discover mode is disabled") # By default Windows is started in Web mode if WINDOWS: args.webserver = True # In web server mode, defaul refresh time: 5 sec if args.webserver: args.time = 5 args.process_short_name = True # Server or client login/password if args.username_prompt: # Every username needs a password args.password_prompt = True # Prompt username if args.server: args.username = self.__get_username( description='Define the Glances server username: ') elif args.webserver: args.username = self.__get_username( description='Define the Glances webserver username: ') elif args.client: args.username = self.__get_username( description='Enter the Glances server username: ') else: # Default user name is 'glances' args.username = self.username if args.password_prompt: # Interactive or file password if args.server: args.password = self.__get_password( description='Define the Glances server password ({} username): '.format( args.username), confirm=True, username=args.username) elif args.webserver: args.password = self.__get_password( description='Define the Glances webserver password ({} username): '.format( args.username), confirm=True, username=args.username) elif args.client: args.password = self.__get_password( description='Enter the Glances server password ({} username): '.format( args.username), clear=True, username=args.username) else: # Default is no password args.password = self.password # By default help is hidden args.help_tag = False # Display Rx and Tx, not the sum for the network args.network_sum = False args.network_cumul = False # Manage full quicklook option if args.full_quicklook: logger.info("Disable QuickLook menu") args.disable_quicklook = False args.disable_cpu = True args.disable_mem = True args.disable_memswap = True args.disable_load = False # Manage disable_top option if args.disable_top: logger.info("Disable top menu") args.disable_quicklook = True args.disable_cpu = True args.disable_mem = True args.disable_memswap = True args.disable_load = True # Control parameter and exit if it is not OK self.args = args # Export is only available in standalone or client mode (issue #614) export_tag = any([getattr(args, a) for a in args.__dict__ if a.startswith('export_')]) if WINDOWS and export_tag: # On Windows, export is possible but only in quiet mode # See issue #1038 logger.info("On Windows OS, export disable the Web interface") self.args.quiet = True self.args.webserver = False elif not (self.is_standalone() or self.is_client()) and export_tag: logger.critical("Export is only available in standalone or client mode") sys.exit(2) # Filter is only available in standalone mode if args.process_filter is not None and not self.is_standalone(): logger.critical( "Process filter is only available in standalone mode") sys.exit(2) # Check graph output path if args.export_graph and args.path_graph is not None: if not os.access(args.path_graph, os.W_OK): logger.critical("Graphs output path {} doesn't exist or is not writable".format(args.path_graph)) sys.exit(2) logger.debug( "Graphs output path is set to {}".format(args.path_graph)) # For export graph, history is mandatory if args.export_graph and args.disable_history: logger.critical("Can not export graph if history is disabled") sys.exit(2) # Disable HDDTemp if sensors are disabled if args.disable_sensors: args.disable_hddtemp = True logger.debug("Sensors and HDDTemp are disabled") return args def is_standalone(self): """Return True if Glances is running in standalone mode.""" return (not self.args.client and not self.args.browser and not self.args.server and not self.args.webserver) def is_client(self): """Return True if Glances is running in client mode.""" return (self.args.client or self.args.browser) and not self.args.server def is_client_browser(self): """Return True if Glances is running in client browser mode.""" return self.args.browser and not self.args.server def is_server(self): """Return True if Glances is running in server mode.""" return not self.args.client and self.args.server def is_webserver(self): """Return True if Glances is running in Web server mode.""" return not self.args.client and self.args.webserver def get_config(self): """Return configuration file object.""" return self.config def get_args(self): """Return the arguments.""" return self.args def get_mode(self): """Return the mode.""" return self.mode def __get_username(self, description=''): """Read an username from the command line. """ return input(description) def __get_password(self, description='', confirm=False, clear=False, username='glances'): """Read a password from the command line. - if confirm = True, with confirmation - if clear = True, plain (clear password) """ from glances.password import GlancesPassword password = GlancesPassword(username=username) return password.get_password(description, confirm, clear) glances-2.11.1/glances/outdated.py000066400000000000000000000140041315472316100170110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage Glances update.""" from datetime import datetime, timedelta from distutils.version import LooseVersion import threading import json import pickle import os from glances import __version__ from glances.compat import nativestr, urlopen, HTTPError, URLError from glances.config import user_cache_dir from glances.globals import safe_makedirs from glances.logger import logger PYPI_API_URL = 'https://pypi.python.org/pypi/Glances/json' class Outdated(object): """ This class aims at providing methods to warn the user when a new Glances version is available on the PyPI repository (https://pypi.python.org/pypi/Glances/). """ def __init__(self, args, config): """Init the Outdated class""" self.args = args self.config = config self.cache_dir = user_cache_dir() self.cache_file = os.path.join(self.cache_dir, 'glances-version.db') # Set default value... self.data = { u'installed_version': __version__, u'latest_version': '0.0', u'refresh_date': datetime.now() } # Read the configuration file self.load_config(config) logger.debug("Check Glances version up-to-date: {}".format(not self.args.disable_check_update)) # And update ! self.get_pypi_version() def load_config(self, config): """Load outdated parameter in the global section of the configuration file.""" global_section = 'global' if (hasattr(config, 'has_section') and config.has_section(global_section)): self.args.disable_check_update = config.get_value(global_section, 'check_update').lower() == 'false' else: logger.debug("Cannot find section {} in the configuration file".format(global_section)) return False return True def installed_version(self): return self.data['installed_version'] def latest_version(self): return self.data['latest_version'] def refresh_date(self): return self.data['refresh_date'] def get_pypi_version(self): """Wrapper to get the latest PyPI version (async) The data are stored in a cached file Only update online once a week """ if self.args.disable_check_update: return # If the cached file exist, read-it cached_data = self._load_cache() if cached_data == {}: # Update needed # Update and save the cache thread = threading.Thread(target=self._update_pypi_version) thread.start() else: # Update not needed self.data['latest_version'] = cached_data['latest_version'] logger.debug("Get Glances version from cache file") def is_outdated(self): """Return True if a new version is available""" if self.args.disable_check_update: # Check is disabled by configuration return False logger.debug("Check Glances version (installed: {} / latest: {})".format(self.installed_version(), self.latest_version())) return LooseVersion(self.latest_version()) > LooseVersion(self.installed_version()) def _load_cache(self): """Load cache file and return cached data""" # If the cached file exist, read-it max_refresh_date = timedelta(days=7) cached_data = {} try: with open(self.cache_file, 'rb') as f: cached_data = pickle.load(f) except Exception as e: logger.debug("Cannot read version from cache file: {} ({})".format(self.cache_file, e)) else: logger.debug("Read version from cache file") if (cached_data['installed_version'] != self.installed_version() or datetime.now() - cached_data['refresh_date'] > max_refresh_date): # Reset the cache if: # - the installed version is different # - the refresh_date is > max_refresh_date cached_data = {} return cached_data def _save_cache(self): """Save data to the cache file.""" # Create the cache directory safe_makedirs(self.cache_dir) # Create/overwrite the cache file try: with open(self.cache_file, 'wb') as f: pickle.dump(self.data, f) except Exception as e: logger.error("Cannot write version to cache file {} ({})".format(self.cache_file, e)) def _update_pypi_version(self): """Get the latest PyPI version (as a string) via the RESTful JSON API""" logger.debug("Get latest Glances version from the PyPI RESTful API ({})".format(PYPI_API_URL)) # Update the current time self.data[u'refresh_date'] = datetime.now() try: res = urlopen(PYPI_API_URL, timeout=3).read() except (HTTPError, URLError) as e: logger.debug("Cannot get Glances version from the PyPI RESTful API ({})".format(e)) else: self.data[u'latest_version'] = json.loads(nativestr(res))['info']['version'] logger.debug("Save Glances version to the cache file") # Save result to the cache file # Note: also saved if the Glances PyPI version cannot be grabbed self._save_cache() return self.data glances-2.11.1/glances/outputs/000077500000000000000000000000001315472316100163525ustar00rootroot00000000000000glances-2.11.1/glances/outputs/__init__.py000066400000000000000000000000001315472316100204510ustar00rootroot00000000000000glances-2.11.1/glances/outputs/glances_bars.py000066400000000000000000000053531315472316100213550ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage bars for Glances output.""" from __future__ import division from math import modf curses_bars = [' ', ' ', ' ', ' ', '|', '|', '|', '|', '|'] class Bar(object): r"""Manage bar (progression or status). import sys import time b = Bar(10) for p in range(0, 100): b.percent = p print("\r%s" % b), time.sleep(0.1) sys.stdout.flush() """ def __init__(self, size, pre_char='[', post_char=']', empty_char=' ', with_text=True): # Bar size self.__size = size # Bar current percent self.__percent = 0 # Min and max value self.min_value = 0 self.max_value = 100 # Char used for the decoration self.__pre_char = pre_char self.__post_char = post_char self.__empty_char = empty_char self.__with_text = with_text @property def size(self, with_decoration=False): # Return the bar size, with or without decoration if with_decoration: return self.__size if self.__with_text: return self.__size - 6 # @size.setter # def size(self, value): # self.__size = value @property def percent(self): return self.__percent @percent.setter def percent(self, value): if value <= self.min_value: value = self.min_value if value >= self.max_value: value = self.max_value self.__percent = value @property def pre_char(self): return self.__pre_char @property def post_char(self): return self.__post_char def __str__(self): """Return the bars.""" frac, whole = modf(self.size * self.percent / 100.0) ret = curses_bars[8] * int(whole) if frac > 0: ret += curses_bars[int(frac * 8)] whole += 1 ret += self.__empty_char * int(self.size - whole) if self.__with_text: ret = '{}{:5.1f}%'.format(ret, self.percent) return ret glances-2.11.1/glances/outputs/glances_bottle.py000066400000000000000000000443301315472316100217150ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Web interface class.""" import json import os import sys import tempfile from io import open import webbrowser from glances.timer import Timer from glances.logger import logger try: from bottle import Bottle, static_file, abort, response, request, auth_basic, template, TEMPLATE_PATH except ImportError: logger.critical('Bottle module not found. Glances cannot start in web server mode.') sys.exit(2) class GlancesBottle(object): """This class manages the Bottle Web server.""" def __init__(self, config=None, args=None): # Init config self.config = config # Init args self.args = args # Init stats # Will be updated within Bottle route self.stats = None # cached_time is the minimum time interval between stats updates # i.e. HTTP/Restful calls will not retrieve updated info until the time # since last update is passed (will retrieve old cached info instead) self.timer = Timer(0) # Load configuration file self.load_config(config) # Init Bottle self._app = Bottle() # Enable CORS (issue #479) self._app.install(EnableCors()) # Password if args.password != '': self._app.install(auth_basic(self.check_auth)) # Define routes self._route() # Path where the statics files are stored self.STATIC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/public') # Paths for templates TEMPLATE_PATH.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/templates')) def load_config(self, config): """Load the outputs section of the configuration file.""" # Limit the number of processes to display in the WebUI if config is not None and config.has_section('outputs'): logger.debug('Read number of processes to display in the WebUI') n = config.get_value('outputs', 'max_processes_display', default=None) logger.debug('Number of processes to display in the WebUI: {}'.format(n)) def __update__(self): # Never update more than 1 time per cached_time if self.timer.finished(): self.stats.update() self.timer = Timer(self.args.cached_time) def app(self): return self._app() def check_auth(self, username, password): """Check if a username/password combination is valid.""" if username == self.args.username: from glances.password import GlancesPassword pwd = GlancesPassword() return pwd.check_password(self.args.password, pwd.sha256_hash(password)) else: return False def _route(self): """Define route.""" self._app.route('/', method="GET", callback=self._index) self._app.route('/', method=["GET"], callback=self._index) # REST API self._app.route('/api/2/config', method="GET", callback=self._api_config) self._app.route('/api/2/config/', method="GET", callback=self._api_config_item) self._app.route('/api/2/args', method="GET", callback=self._api_args) self._app.route('/api/2/args/', method="GET", callback=self._api_args_item) self._app.route('/api/2/help', method="GET", callback=self._api_help) self._app.route('/api/2/pluginslist', method="GET", callback=self._api_plugins) self._app.route('/api/2/all', method="GET", callback=self._api_all) self._app.route('/api/2/all/limits', method="GET", callback=self._api_all_limits) self._app.route('/api/2/all/views', method="GET", callback=self._api_all_views) self._app.route('/api/2/', method="GET", callback=self._api) self._app.route('/api/2//history', method="GET", callback=self._api_history) self._app.route('/api/2//history/', method="GET", callback=self._api_history) self._app.route('/api/2//limits', method="GET", callback=self._api_limits) self._app.route('/api/2//views', method="GET", callback=self._api_views) self._app.route('/api/2//', method="GET", callback=self._api_item) self._app.route('/api/2///history', method="GET", callback=self._api_item_history) self._app.route('/api/2///history/', method="GET", callback=self._api_item_history) self._app.route('/api/2///', method="GET", callback=self._api_value) self._app.route('/', method="GET", callback=self._resource) def start(self, stats): """Start the bottle.""" # Init stats self.stats = stats # Init plugin list self.plugins_list = self.stats.getAllPlugins() # Bind the Bottle TCP address/port bindurl = 'http://{}:{}/'.format(self.args.bind_address, self.args.port) bindmsg = 'Glances web server started on {}'.format(bindurl) logger.info(bindmsg) print(bindmsg) if self.args.open_web_browser: # Implementation of the issue #946 # Try to open the Glances Web UI in the default Web browser if: # 1) --open-web-browser option is used # 2) Glances standalone mode is running on Windows OS webbrowser.open(bindurl, new=2, autoraise=1) self._app.run(host=self.args.bind_address, port=self.args.port, quiet=not self.args.debug) def end(self): """End the bottle.""" pass def _index(self, refresh_time=None): """Bottle callback for index.html (/) file.""" if refresh_time is None: refresh_time = self.args.time # Update the stat self.__update__() # Display return template("index.html", refresh_time=refresh_time) def _resource(self, filepath): """Bottle callback for resources files.""" # Return the static file return static_file(filepath, root=self.STATIC_PATH) def _api_help(self): """Glances API RESTFul implementation. Return the help data or 404 error. """ response.content_type = 'application/json' # Update the stat view_data = self.stats.get_plugin("help").get_view_data() try: plist = json.dumps(view_data, sort_keys=True) except Exception as e: abort(404, "Cannot get help view data (%s)" % str(e)) return plist def _api_plugins(self): """ @api {get} /api/2/pluginslist Get plugins list @apiVersion 2.0 @apiName pluginslist @apiGroup plugin @apiSuccess {String[]} Plugins list. @apiSuccessExample Success-Response: HTTP/1.1 200 OK [ "load", "help", "ip", "memswap", "processlist", ... ] @apiError Cannot get plugin list. @apiErrorExample Error-Response: HTTP/1.1 404 Not Found """ response.content_type = 'application/json' # Update the stat self.__update__() try: plist = json.dumps(self.plugins_list) except Exception as e: abort(404, "Cannot get plugin list (%s)" % str(e)) return plist def _api_all(self): """Glances API RESTFul implementation. Return the JSON representation of all the plugins HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ response.content_type = 'application/json' if self.args.debug: fname = os.path.join(tempfile.gettempdir(), 'glances-debug.json') try: with open(fname) as f: return f.read() except IOError: logger.debug("Debug file (%s) not found" % fname) # Update the stat self.__update__() try: # Get the JSON value of the stat ID statval = json.dumps(self.stats.getAllAsDict()) except Exception as e: abort(404, "Cannot get stats (%s)" % str(e)) return statval def _api_all_limits(self): """Glances API RESTFul implementation. Return the JSON representation of all the plugins limits HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ response.content_type = 'application/json' try: # Get the JSON value of the stat limits limits = json.dumps(self.stats.getAllLimitsAsDict()) except Exception as e: abort(404, "Cannot get limits (%s)" % (str(e))) return limits def _api_all_views(self): """Glances API RESTFul implementation. Return the JSON representation of all the plugins views HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ response.content_type = 'application/json' try: # Get the JSON value of the stat view limits = json.dumps(self.stats.getAllViewsAsDict()) except Exception as e: abort(404, "Cannot get views (%s)" % (str(e))) return limits def _api(self, plugin): """Glances API RESTFul implementation. Return the JSON representation of a given plugin HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ response.content_type = 'application/json' if plugin not in self.plugins_list: abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) # Update the stat self.__update__() try: # Get the JSON value of the stat ID statval = self.stats.get_plugin(plugin).get_stats() except Exception as e: abort(404, "Cannot get plugin %s (%s)" % (plugin, str(e))) return statval def _api_history(self, plugin, nb=0): """Glances API RESTFul implementation. Return the JSON representation of a given plugin history Limit to the last nb items (all if nb=0) HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ response.content_type = 'application/json' if plugin not in self.plugins_list: abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) # Update the stat self.__update__() try: # Get the JSON value of the stat ID statval = self.stats.get_plugin(plugin).get_stats_history(nb=int(nb)) except Exception as e: abort(404, "Cannot get plugin history %s (%s)" % (plugin, str(e))) return statval def _api_limits(self, plugin): """Glances API RESTFul implementation. Return the JSON limits of a given plugin HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ response.content_type = 'application/json' if plugin not in self.plugins_list: abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) # Update the stat # self.__update__() try: # Get the JSON value of the stat limits ret = self.stats.get_plugin(plugin).limits except Exception as e: abort(404, "Cannot get limits for plugin %s (%s)" % (plugin, str(e))) return ret def _api_views(self, plugin): """Glances API RESTFul implementation. Return the JSON views of a given plugin HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ response.content_type = 'application/json' if plugin not in self.plugins_list: abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) # Update the stat # self.__update__() try: # Get the JSON value of the stat views ret = self.stats.get_plugin(plugin).get_views() except Exception as e: abort(404, "Cannot get views for plugin %s (%s)" % (plugin, str(e))) return ret def _api_itemvalue(self, plugin, item, value=None, history=False, nb=0): """Father method for _api_item and _api_value""" response.content_type = 'application/json' if plugin not in self.plugins_list: abort(400, "Unknown plugin %s (available plugins: %s)" % (plugin, self.plugins_list)) # Update the stat self.__update__() if value is None: if history: ret = self.stats.get_plugin(plugin).get_stats_history(item, nb=int(nb)) else: ret = self.stats.get_plugin(plugin).get_stats_item(item) if ret is None: abort(404, "Cannot get item %s%s in plugin %s" % (item, 'history ' if history else '', plugin)) else: if history: # Not available ret = None else: ret = self.stats.get_plugin(plugin).get_stats_value(item, value) if ret is None: abort(404, "Cannot get item %s(%s=%s) in plugin %s" % ('history ' if history else '', item, value, plugin)) return ret def _api_item(self, plugin, item): """Glances API RESTFul implementation. Return the JSON representation of the couple plugin/item HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ return self._api_itemvalue(plugin, item) def _api_item_history(self, plugin, item, nb=0): """Glances API RESTFul implementation. Return the JSON representation of the couple plugin/history of item HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ return self._api_itemvalue(plugin, item, history=True, nb=int(nb)) def _api_value(self, plugin, item, value): """Glances API RESTFul implementation. Return the process stats (dict) for the given item=value HTTP/200 if OK HTTP/400 if plugin is not found HTTP/404 if others error """ return self._api_itemvalue(plugin, item, value) def _api_config(self): """Glances API RESTFul implementation. Return the JSON representation of the Glances configuration file HTTP/200 if OK HTTP/404 if others error """ response.content_type = 'application/json' try: # Get the JSON value of the config' dict args_json = json.dumps(self.config.as_dict()) except Exception as e: abort(404, "Cannot get config (%s)" % str(e)) return args_json def _api_config_item(self, item): """Glances API RESTFul implementation. Return the JSON representation of the Glances configuration item HTTP/200 if OK HTTP/400 if item is not found HTTP/404 if others error """ response.content_type = 'application/json' config_dict = self.config.as_dict() if item not in config_dict: abort(400, "Unknown configuration item %s" % item) try: # Get the JSON value of the config' dict args_json = json.dumps(config_dict[item]) except Exception as e: abort(404, "Cannot get config item (%s)" % str(e)) return args_json def _api_args(self): """Glances API RESTFul implementation. Return the JSON representation of the Glances command line arguments HTTP/200 if OK HTTP/404 if others error """ response.content_type = 'application/json' try: # Get the JSON value of the args' dict # Use vars to convert namespace to dict # Source: https://docs.python.org/2/library/functions.html#vars args_json = json.dumps(vars(self.args)) except Exception as e: abort(404, "Cannot get args (%s)" % str(e)) return args_json def _api_args_item(self, item): """Glances API RESTFul implementation. Return the JSON representation of the Glances command line arguments item HTTP/200 if OK HTTP/400 if item is not found HTTP/404 if others error """ response.content_type = 'application/json' if item not in self.args: abort(400, "Unknown argument item %s" % item) try: # Get the JSON value of the args' dict # Use vars to convert namespace to dict # Source: https://docs.python.org/2/library/functions.html#vars args_json = json.dumps(vars(self.args)[item]) except Exception as e: abort(404, "Cannot get args item (%s)" % str(e)) return args_json class EnableCors(object): name = 'enable_cors' api = 2 def apply(self, fn, context): def _enable_cors(*args, **kwargs): # set CORS headers response.headers['Access-Control-Allow-Origin'] = '*' response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS' response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token' if request.method != 'OPTIONS': # actual request; reply with the actual response return fn(*args, **kwargs) return _enable_cors glances-2.11.1/glances/outputs/glances_curses.py000066400000000000000000001177401315472316100217360ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Curses interface class.""" import re import sys from glances.compat import u, itervalues from glances.globals import MACOS, WINDOWS from glances.logger import logger from glances.logs import glances_logs from glances.processes import glances_processes from glances.timer import Timer # Import curses library for "normal" operating system if not WINDOWS: try: import curses import curses.panel from curses.textpad import Textbox except ImportError: logger.critical("Curses module not found. Glances cannot start in standalone mode.") sys.exit(1) class _GlancesCurses(object): """This class manages the curses display (and key pressed). Note: It is a private class, use GlancesCursesClient or GlancesCursesBrowser. """ _hotkeys = { '0': {'switch': 'disable_irix'}, '1': {'switch': 'percpu'}, '2': {'switch': 'disable_left_sidebar'}, '3': {'switch': 'disable_quicklook'}, '6': {'switch': 'meangpu'}, '/': {'switch': 'process_short_name'}, 'A': {'switch': 'disable_amps'}, 'b': {'switch': 'byte'}, 'B': {'switch': 'diskio_iops'}, 'C': {'switch': 'disable_cloud'}, 'D': {'switch': 'disable_docker'}, 'd': {'switch': 'disable_diskio'}, 'F': {'switch': 'fs_free_space'}, 'G': {'switch': 'disable_gpu'}, 'h': {'switch': 'help_tag'}, 'I': {'switch': 'disable_ip'}, 'l': {'switch': 'disable_alert'}, 'M': {'switch': 'reset_minmax_tag'}, 'n': {'switch': 'disable_network'}, 'N': {'switch': 'disable_now'}, 'P': {'switch': 'disable_ports'}, 'Q': {'switch': 'enable_irq'}, 'R': {'switch': 'disable_raid'}, 's': {'switch': 'disable_sensors'}, 'T': {'switch': 'network_sum'}, 'U': {'switch': 'network_cumul'}, 'W': {'switch': 'disable_wifi'}, # Processes sort hotkeys 'a': {'auto_sort': True, 'sort_key': 'cpu_percent'}, 'c': {'auto_sort': False, 'sort_key': 'cpu_percent'}, 'i': {'auto_sort': False, 'sort_key': 'io_counters'}, 'm': {'auto_sort': False, 'sort_key': 'memory_percent'}, 'p': {'auto_sort': False, 'sort_key': 'name'}, 't': {'auto_sort': False, 'sort_key': 'cpu_times'}, 'u': {'auto_sort': False, 'sort_key': 'username'}, } _sort_loop = ['cpu_percent', 'memory_percent', 'username', 'cpu_times', 'io_counters', 'name'] def __init__(self, config=None, args=None): # Init self.config = config self.args = args # Init windows positions self.term_w = 80 self.term_h = 24 # Space between stats self.space_between_column = 3 self.space_between_line = 2 # Init the curses screen self.screen = curses.initscr() if not self.screen: logger.critical("Cannot init the curses library.\n") sys.exit(1) # Load the 'outputs' section of the configuration file # - Init the theme (default is black) self.theme = {'name': 'black'} # Load configuration file self.load_config(config) # Init cursor self._init_cursor() # Init the colors self._init_colors() # Init main window self.term_window = self.screen.subwin(0, 0) # Init refresh time self.__refresh_time = args.time # Init edit filter tag self.edit_filter = False # Init the process min/max reset self.args.reset_minmax_tag = False # Catch key pressed with non blocking mode self.term_window.keypad(1) self.term_window.nodelay(1) self.pressedkey = -1 # History tag self._init_history() def load_config(self, config): """Load the outputs section of the configuration file.""" # Load the theme if config is not None and config.has_section('outputs'): logger.debug('Read the outputs section in the configuration file') self.theme['name'] = config.get_value('outputs', 'curse_theme', default='black') logger.debug('Theme for the curse interface: {}'.format(self.theme['name'])) def is_theme(self, name): """Return True if the theme *name* should be used.""" return getattr(self.args, 'theme_' + name) or self.theme['name'] == name def _init_history(self): """Init the history option.""" self.reset_history_tag = False self.graph_tag = False if self.args.export_graph: logger.info('Export graphs function enabled with output path %s' % self.args.path_graph) from glances.exports.graph import GlancesGraph self.glances_graph = GlancesGraph(self.args.path_graph) if not self.glances_graph.graph_enabled(): self.args.export_graph = False logger.error('Export graphs disabled') def _init_cursor(self): """Init cursors.""" if hasattr(curses, 'noecho'): curses.noecho() if hasattr(curses, 'cbreak'): curses.cbreak() self.set_cursor(0) def _init_colors(self): """Init the Curses color layout.""" # Set curses options if hasattr(curses, 'start_color'): curses.start_color() if hasattr(curses, 'use_default_colors'): curses.use_default_colors() # Init colors if self.args.disable_bold: A_BOLD = 0 self.args.disable_bg = True else: A_BOLD = curses.A_BOLD self.title_color = A_BOLD self.title_underline_color = A_BOLD | curses.A_UNDERLINE self.help_color = A_BOLD if curses.has_colors(): # The screen is compatible with a colored design if self.is_theme('white'): # White theme: black ==> white curses.init_pair(1, curses.COLOR_BLACK, -1) else: curses.init_pair(1, curses.COLOR_WHITE, -1) if self.args.disable_bg: curses.init_pair(2, curses.COLOR_RED, -1) curses.init_pair(3, curses.COLOR_GREEN, -1) curses.init_pair(4, curses.COLOR_BLUE, -1) curses.init_pair(5, curses.COLOR_MAGENTA, -1) else: curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_RED) curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_GREEN) curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_BLUE) curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_MAGENTA) curses.init_pair(6, curses.COLOR_RED, -1) curses.init_pair(7, curses.COLOR_GREEN, -1) curses.init_pair(8, curses.COLOR_BLUE, -1) # Colors text styles if curses.COLOR_PAIRS > 8: try: curses.init_pair(9, curses.COLOR_MAGENTA, -1) except Exception: if self.is_theme('white'): curses.init_pair(9, curses.COLOR_BLACK, -1) else: curses.init_pair(9, curses.COLOR_WHITE, -1) try: curses.init_pair(10, curses.COLOR_CYAN, -1) except Exception: if self.is_theme('white'): curses.init_pair(10, curses.COLOR_BLACK, -1) else: curses.init_pair(10, curses.COLOR_WHITE, -1) self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD self.filter_color = curses.color_pair(10) | A_BOLD self.no_color = curses.color_pair(1) self.default_color = curses.color_pair(3) | A_BOLD self.nice_color = curses.color_pair(9) self.cpu_time_color = curses.color_pair(9) self.ifCAREFUL_color = curses.color_pair(4) | A_BOLD self.ifWARNING_color = curses.color_pair(5) | A_BOLD self.ifCRITICAL_color = curses.color_pair(2) | A_BOLD self.default_color2 = curses.color_pair(7) self.ifCAREFUL_color2 = curses.color_pair(8) | A_BOLD else: # The screen is NOT compatible with a colored design # switch to B&W text styles self.no_color = curses.A_NORMAL self.default_color = curses.A_NORMAL self.nice_color = A_BOLD self.cpu_time_color = A_BOLD self.ifCAREFUL_color = curses.A_UNDERLINE self.ifWARNING_color = A_BOLD self.ifCRITICAL_color = curses.A_REVERSE self.default_color2 = curses.A_NORMAL self.ifCAREFUL_color2 = curses.A_UNDERLINE self.ifWARNING_color2 = A_BOLD self.ifCRITICAL_color2 = curses.A_REVERSE self.filter_color = A_BOLD # Define the colors list (hash table) for stats self.colors_list = { 'DEFAULT': self.no_color, 'UNDERLINE': curses.A_UNDERLINE, 'BOLD': A_BOLD, 'SORT': A_BOLD, 'OK': self.default_color2, 'MAX': self.default_color2 | curses.A_BOLD, 'FILTER': self.filter_color, 'TITLE': self.title_color, 'PROCESS': self.default_color2, 'STATUS': self.default_color2, 'NICE': self.nice_color, 'CPU_TIME': self.cpu_time_color, 'CAREFUL': self.ifCAREFUL_color2, 'WARNING': self.ifWARNING_color2, 'CRITICAL': self.ifCRITICAL_color2, 'OK_LOG': self.default_color, 'CAREFUL_LOG': self.ifCAREFUL_color, 'WARNING_LOG': self.ifWARNING_color, 'CRITICAL_LOG': self.ifCRITICAL_color, 'PASSWORD': curses.A_PROTECT } def set_cursor(self, value): """Configure the curse cursor apparence. 0: invisible 1: visible 2: very visible """ if hasattr(curses, 'curs_set'): try: curses.curs_set(value) except Exception: pass def get_key(self, window): # Catch ESC key AND numlock key (issue #163) keycode = [0, 0] keycode[0] = window.getch() keycode[1] = window.getch() if keycode != [-1, -1]: logger.debug("Keypressed (code: %s)" % keycode) if keycode[0] == 27 and keycode[1] != -1: # Do not escape on specials keys return -1 else: return keycode[0] def __catch_key(self, return_to_browser=False): # Catch the pressed key self.pressedkey = self.get_key(self.term_window) # Actions (available in the global hotkey dict)... for hotkey in self._hotkeys: if self.pressedkey == ord(hotkey) and 'switch' in self._hotkeys[hotkey]: setattr(self.args, self._hotkeys[hotkey]['switch'], not getattr(self.args, self._hotkeys[hotkey]['switch'])) if self.pressedkey == ord(hotkey) and 'auto_sort' in self._hotkeys[hotkey]: setattr(glances_processes, 'auto_sort', self._hotkeys[hotkey]['auto_sort']) if self.pressedkey == ord(hotkey) and 'sort_key' in self._hotkeys[hotkey]: setattr(glances_processes, 'sort_key', self._hotkeys[hotkey]['sort_key']) # Other actions... if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'): # 'ESC'|'q' > Quit if return_to_browser: logger.info("Stop Glances client and return to the browser") else: self.end() logger.info("Stop Glances") sys.exit(0) elif self.pressedkey == ord('\n'): # 'ENTER' > Edit the process filter self.edit_filter = not self.edit_filter elif self.pressedkey == ord('4'): self.args.full_quicklook = not self.args.full_quicklook if self.args.full_quicklook: self.enable_fullquicklook() else: self.disable_fullquicklook() elif self.pressedkey == ord('5'): self.args.disable_top = not self.args.disable_top if self.args.disable_top: self.disable_top() else: self.enable_top() elif self.pressedkey == ord('e'): # 'e' > Enable/Disable process extended self.args.enable_process_extended = not self.args.enable_process_extended if not self.args.enable_process_extended: glances_processes.disable_extended() else: glances_processes.enable_extended() elif self.pressedkey == ord('E'): # 'E' > Erase the process filter glances_processes.process_filter = None elif self.pressedkey == ord('f'): # 'f' > Show/hide fs / folder stats self.args.disable_fs = not self.args.disable_fs self.args.disable_folders = not self.args.disable_folders elif self.pressedkey == ord('g'): # 'g' > Generate graph from history self.graph_tag = not self.graph_tag elif self.pressedkey == ord('r'): # 'r' > Reset graph history self.reset_history_tag = not self.reset_history_tag elif self.pressedkey == ord('w'): # 'w' > Delete finished warning logs glances_logs.clean() elif self.pressedkey == ord('x'): # 'x' > Delete finished warning and critical logs glances_logs.clean(critical=True) elif self.pressedkey == ord('z'): # 'z' > Enable or disable processes self.args.disable_process = not self.args.disable_process if self.args.disable_process: glances_processes.disable() else: glances_processes.enable() elif self.pressedkey == curses.KEY_LEFT: # "<" (left arrow) navigation through process sort setattr(glances_processes, 'auto_sort', False) next_sort = (self.loop_position() - 1) % len(self._sort_loop) glances_processes.sort_key = self._sort_loop[next_sort] elif self.pressedkey == curses.KEY_RIGHT: # ">" (right arrow) navigation through process sort setattr(glances_processes, 'auto_sort', False) next_sort = (self.loop_position() + 1) % len(self._sort_loop) glances_processes.sort_key = self._sort_loop[next_sort] # Return the key code return self.pressedkey def loop_position(self): """Return the current sort in the loop""" for i, v in enumerate(self._sort_loop): if v == glances_processes.sort_key: return i return 0 def disable_top(self): """Disable the top panel""" for p in ['quicklook', 'cpu', 'gpu', 'mem', 'memswap', 'load']: setattr(self.args, 'disable_' + p, True) def enable_top(self): """Enable the top panel""" for p in ['quicklook', 'cpu', 'gpu', 'mem', 'memswap', 'load']: setattr(self.args, 'disable_' + p, False) def disable_fullquicklook(self): """Disable the full quicklook mode""" for p in ['quicklook', 'cpu', 'gpu', 'mem', 'memswap']: setattr(self.args, 'disable_' + p, False) def enable_fullquicklook(self): """Disable the full quicklook mode""" self.args.disable_quicklook = False for p in ['cpu', 'gpu', 'mem', 'memswap']: setattr(self.args, 'disable_' + p, True) def end(self): """Shutdown the curses window.""" if hasattr(curses, 'echo'): curses.echo() if hasattr(curses, 'nocbreak'): curses.nocbreak() if hasattr(curses, 'curs_set'): try: curses.curs_set(1) except Exception: pass curses.endwin() def init_line_column(self): """Init the line and column position for the curses interface.""" self.init_line() self.init_column() def init_line(self): """Init the line position for the curses interface.""" self.line = 0 self.next_line = 0 def init_column(self): """Init the column position for the curses interface.""" self.column = 0 self.next_column = 0 def new_line(self): """New line in the curses interface.""" self.line = self.next_line def new_column(self): """New column in the curses interface.""" self.column = self.next_column def __get_stat_display(self, stats, plugin_max_width): """Return a dict of dict with all the stats display * key: plugin name * value: dict returned by the get_stats_display Plugin method :returns: dict of dict """ ret = {} for p in stats.getAllPlugins(enable=False): if p in ['network', 'wifi', 'irq', 'fs', 'folders']: ret[p] = stats.get_plugin(p).get_stats_display( args=self.args, max_width=plugin_max_width) elif p in ['quicklook']: # Grab later because we need plugin size continue else: # system, uptime, cpu, percpu, gpu, load, mem, memswap, ip, # ... diskio, raid, sensors, ports, now, docker, processcount, # ... amps, alert try: ret[p] = stats.get_plugin(p).get_stats_display(args=self.args) except AttributeError: ret[p] = None if self.args.percpu: ret['cpu'] = ret['percpu'] return ret def display(self, stats, cs_status=None): """Display stats on the screen. stats: Stats database to display cs_status: "None": standalone or server mode "Connected": Client is connected to a Glances server "SNMP": Client is connected to a SNMP server "Disconnected": Client is disconnected from the server Return: True if the stats have been displayed False if the help have been displayed """ # Init the internal line/column for Glances Curses self.init_line_column() # No processes list in SNMP mode if cs_status == 'SNMP': # so... more space for others plugins plugin_max_width = 43 else: plugin_max_width = None # Update the stats messages ########################### # Update the client server status self.args.cs_status = cs_status __stat_display = self.__get_stat_display(stats, plugin_max_width) # Adapt number of processes to the available space max_processes_displayed = ( self.screen.getmaxyx()[0] - 11 - self.get_stats_display_height(__stat_display["alert"]) - self.get_stats_display_height(__stat_display["docker"]) ) try: if self.args.enable_process_extended and not self.args.process_tree: max_processes_displayed -= 4 except AttributeError: pass if max_processes_displayed < 0: max_processes_displayed = 0 if (glances_processes.max_processes is None or glances_processes.max_processes != max_processes_displayed): logger.debug("Set number of displayed processes to {}".format(max_processes_displayed)) glances_processes.max_processes = max_processes_displayed __stat_display["processlist"] = stats.get_plugin( 'processlist').get_stats_display(args=self.args) # Display the stats on the curses interface ########################################### # Help screen (on top of the other stats) if self.args.help_tag: # Display the stats... self.display_plugin( stats.get_plugin('help').get_stats_display(args=self.args)) # ... and exit return False # ===================================== # Display first line (system+ip+uptime) # Optionnaly: Cloud on second line # ===================================== self.__display_firstline(__stat_display) # ============================================================== # Display second line (+CPU|PERCPU++LOAD+MEM+SWAP) # ============================================================== self.__display_secondline(__stat_display, stats) # ================================================================== # Display left sidebar (NETWORK+PORTS+DISKIO+FS+SENSORS+Current time) # ================================================================== self.__display_left(__stat_display) # ==================================== # Display right stats (process and co) # ==================================== self.__display_right(__stat_display) # History option # Generate history graph if self.graph_tag and self.args.export_graph: self.display_popup( 'Generate graphs history in {}\nPlease wait...'.format( self.glances_graph.get_output_folder())) self.display_popup( 'Generate graphs history in {}\nDone: {} graphs generated'.format( self.glances_graph.get_output_folder(), self.glances_graph.generate_graph(stats))) elif self.reset_history_tag and self.args.export_graph: self.display_popup('Reset graph history') self.glances_graph.reset(stats) elif (self.graph_tag or self.reset_history_tag) and not self.args.export_graph: try: self.glances_graph.graph_enabled() except Exception: self.display_popup('Graph disabled\nEnable it using --export-graph') else: self.display_popup('Graph disabled') self.graph_tag = False self.reset_history_tag = False # Display edit filter popup # Only in standalone mode (cs_status is None) if self.edit_filter and cs_status is None: new_filter = self.display_popup( 'Process filter pattern: \n\n' + 'Examples:\n' + '- python\n' + '- .*python.*\n' + '- \/usr\/lib.*\n' + '- name:.*nautilus.*\n' + '- cmdline:.*glances.*\n' + '- username:nicolargo\n' + '- username:^root ', is_input=True, input_value=glances_processes.process_filter_input) glances_processes.process_filter = new_filter elif self.edit_filter and cs_status is not None: self.display_popup('Process filter only available in standalone mode') self.edit_filter = False return True def __display_firstline(self, stat_display): """Display the first line in the Curses interface. system + ip + uptime """ # Space between column self.space_between_column = 0 self.new_line() l_uptime = (self.get_stats_display_width(stat_display["system"]) + self.space_between_column + self.get_stats_display_width(stat_display["ip"]) + 3 + self.get_stats_display_width(stat_display["uptime"])) self.display_plugin( stat_display["system"], display_optional=(self.screen.getmaxyx()[1] >= l_uptime)) self.new_column() self.display_plugin(stat_display["ip"]) # Space between column self.space_between_column = 3 self.new_column() self.display_plugin(stat_display["uptime"], add_space=self.get_stats_display_width(stat_display["cloud"]) == 0) self.init_column() self.new_line() self.display_plugin(stat_display["cloud"]) def __display_secondline(self, stat_display, stats): """Display the second line in the Curses interface. + CPU|PERCPU + + MEM + SWAP + LOAD """ self.init_column() self.new_line() # Init quicklook stat_display['quicklook'] = {'msgdict': []} # Dict for plugins width plugin_widths = {'quicklook': 0} for p in ['cpu', 'gpu', 'mem', 'memswap', 'load']: plugin_widths[p] = self.get_stats_display_width(stat_display[p]) if hasattr(self.args, 'disable_' + p) and p in stat_display else 0 # Width of all plugins stats_width = sum(itervalues(plugin_widths)) # Number of plugin but quicklook stats_number = ( int(not self.args.disable_cpu and stat_display["cpu"]['msgdict'] != []) + int(not self.args.disable_gpu and stat_display["gpu"]['msgdict'] != []) + int(not self.args.disable_mem and stat_display["mem"]['msgdict'] != []) + int(not self.args.disable_memswap and stat_display["memswap"]['msgdict'] != []) + int(not self.args.disable_load and stat_display["load"]['msgdict'] != [])) if not self.args.disable_quicklook: # Quick look is in the place ! if self.args.full_quicklook: quicklook_width = self.screen.getmaxyx()[1] - (stats_width + 8 + stats_number * self.space_between_column) else: quicklook_width = min(self.screen.getmaxyx()[1] - (stats_width + 8 + stats_number * self.space_between_column), 79) try: stat_display["quicklook"] = stats.get_plugin( 'quicklook').get_stats_display(max_width=quicklook_width, args=self.args) except AttributeError as e: logger.debug("Quicklook plugin not available (%s)" % e) else: plugin_widths['quicklook'] = self.get_stats_display_width(stat_display["quicklook"]) stats_width = sum(itervalues(plugin_widths)) + 1 self.space_between_column = 1 self.display_plugin(stat_display["quicklook"]) self.new_column() # Compute spaces between plugins # Note: Only one space between Quicklook and others plugin_display_optional = {} for p in ['cpu', 'gpu', 'mem', 'memswap', 'load']: plugin_display_optional[p] = True if stats_number > 1: self.space_between_column = max(1, int((self.screen.getmaxyx()[1] - stats_width) / (stats_number - 1))) for p in ['mem', 'cpu']: # No space ? Remove optional stats if self.space_between_column < 3: plugin_display_optional[p] = False plugin_widths[p] = self.get_stats_display_width(stat_display[p], without_option=True) if hasattr(self.args, 'disable_' + p) else 0 stats_width = sum(itervalues(plugin_widths)) + 1 self.space_between_column = max(1, int((self.screen.getmaxyx()[1] - stats_width) / (stats_number - 1))) else: self.space_between_column = 0 # Display CPU, MEM, SWAP and LOAD for p in ['cpu', 'gpu', 'mem', 'memswap', 'load']: if p in stat_display: self.display_plugin(stat_display[p], display_optional=plugin_display_optional[p]) if p is not 'load': # Skip last column self.new_column() # Space between column self.space_between_column = 3 # Backup line position self.saved_line = self.next_line def __display_left(self, stat_display): """Display the left sidebar in the Curses interface. network+wifi+ports+diskio+fs+irq+folders+raid+sensors+now """ self.init_column() if not self.args.disable_left_sidebar: for s in ['network', 'wifi', 'ports', 'diskio', 'fs', 'irq', 'folders', 'raid', 'sensors', 'now']: if ((hasattr(self.args, 'enable_' + s) or hasattr(self.args, 'disable_' + s)) and s in stat_display): self.new_line() self.display_plugin(stat_display[s]) def __display_right(self, stat_display): """Display the right sidebar in the Curses interface. docker + processcount + amps + processlist + alert """ # If space available... if self.screen.getmaxyx()[1] > 52: # Restore line position self.next_line = self.saved_line # Display right sidebar # DOCKER+PROCESS_COUNT+AMPS+PROCESS_LIST+ALERT self.new_column() self.new_line() self.display_plugin(stat_display["docker"]) self.new_line() self.display_plugin(stat_display["processcount"]) self.new_line() self.display_plugin(stat_display["amps"]) self.new_line() self.display_plugin(stat_display["processlist"], display_optional=(self.screen.getmaxyx()[1] > 102), display_additional=(not MACOS), max_y=(self.screen.getmaxyx()[0] - self.get_stats_display_height(stat_display["alert"]) - 2)) self.new_line() self.display_plugin(stat_display["alert"]) def display_popup(self, message, size_x=None, size_y=None, duration=3, is_input=False, input_size=30, input_value=None): """ Display a centered popup. If is_input is False: Display a centered popup with the given message during duration seconds If size_x and size_y: set the popup size else set it automatically Return True if the popup could be displayed If is_input is True: Display a centered popup with the given message and a input field If size_x and size_y: set the popup size else set it automatically Return the input string or None if the field is empty """ # Center the popup sentence_list = message.split('\n') if size_x is None: size_x = len(max(sentence_list, key=len)) + 4 # Add space for the input field if is_input: size_x += input_size if size_y is None: size_y = len(sentence_list) + 4 screen_x = self.screen.getmaxyx()[1] screen_y = self.screen.getmaxyx()[0] if size_x > screen_x or size_y > screen_y: # No size to display the popup => abord return False pos_x = int((screen_x - size_x) / 2) pos_y = int((screen_y - size_y) / 2) # Create the popup popup = curses.newwin(size_y, size_x, pos_y, pos_x) # Fill the popup popup.border() # Add the message for y, m in enumerate(message.split('\n')): popup.addnstr(2 + y, 2, m, len(m)) if is_input and not WINDOWS: # Create a subwindow for the text field subpop = popup.derwin(1, input_size, 2, 2 + len(m)) subpop.attron(self.colors_list['FILTER']) # Init the field with the current value if input_value is not None: subpop.addnstr(0, 0, input_value, len(input_value)) # Display the popup popup.refresh() subpop.refresh() # Create the textbox inside the subwindows self.set_cursor(2) self.term_window.keypad(1) textbox = GlancesTextbox(subpop, insert_mode=False) textbox.edit() self.set_cursor(0) self.term_window.keypad(0) if textbox.gather() != '': logger.debug( "User enters the following string: %s" % textbox.gather()) return textbox.gather()[:-1] else: logger.debug("User centers an empty string") return None else: # Display the popup popup.refresh() self.wait(duration * 1000) return True def display_plugin(self, plugin_stats, display_optional=True, display_additional=True, max_y=65535, add_space=True): """Display the plugin_stats on the screen. If display_optional=True display the optional stats If display_additional=True display additionnal stats max_y do not display line > max_y """ # Exit if: # - the plugin_stats message is empty # - the display tag = False if plugin_stats is None or not plugin_stats['msgdict'] or not plugin_stats['display']: # Exit return 0 # Get the screen size screen_x = self.screen.getmaxyx()[1] screen_y = self.screen.getmaxyx()[0] # Set the upper/left position of the message if plugin_stats['align'] == 'right': # Right align (last column) display_x = screen_x - self.get_stats_display_width(plugin_stats) else: display_x = self.column if plugin_stats['align'] == 'bottom': # Bottom (last line) display_y = screen_y - self.get_stats_display_height(plugin_stats) else: display_y = self.line # Display x = display_x x_max = x y = display_y for m in plugin_stats['msgdict']: # New line if m['msg'].startswith('\n'): # Go to the next line y += 1 # Return to the first column x = display_x continue # Do not display outside the screen if x < 0: continue if not m['splittable'] and (x + len(m['msg']) > screen_x): continue if y < 0 or (y + 1 > screen_y) or (y > max_y): break # If display_optional = False do not display optional stats if not display_optional and m['optional']: continue # If display_additional = False do not display additional stats if not display_additional and m['additional']: continue # Is it possible to display the stat with the current screen size # !!! Crach if not try/except... Why ??? try: self.term_window.addnstr(y, x, m['msg'], # Do not disply outside the screen screen_x - x, self.colors_list[m['decoration']]) except Exception: pass else: # New column # Python 2: we need to decode to get real screen size because # UTF-8 special tree chars occupy several bytes. # Python 3: strings are strings and bytes are bytes, all is # good. try: x += len(u(m['msg'])) except UnicodeDecodeError: # Quick and dirty hack for issue #745 pass if x > x_max: x_max = x # Compute the next Glances column/line position self.next_column = max( self.next_column, x_max + self.space_between_column) self.next_line = max(self.next_line, y + self.space_between_line) if not add_space and self.next_line > 0: # Do not have empty line after self.next_line -= 1 def erase(self): """Erase the content of the screen.""" self.term_window.erase() def flush(self, stats, cs_status=None): """Clear and update the screen. stats: Stats database to display cs_status: "None": standalone or server mode "Connected": Client is connected to the server "Disconnected": Client is disconnected from the server """ self.erase() self.display(stats, cs_status=cs_status) def update(self, stats, cs_status=None, return_to_browser=False): """Update the screen. Wait for __refresh_time sec / catch key every 100 ms. INPUT stats: Stats database to display cs_status: "None": standalone or server mode "Connected": Client is connected to the server "Disconnected": Client is disconnected from the server return_to_browser: True: Do not exist, return to the browser list False: Exit and return to the shell OUPUT True: Exit key has been pressed False: Others cases... """ # Flush display self.flush(stats, cs_status=cs_status) # Wait exitkey = False countdown = Timer(self.__refresh_time) while not countdown.finished() and not exitkey: # Getkey pressedkey = self.__catch_key(return_to_browser=return_to_browser) # Is it an exit key ? exitkey = (pressedkey == ord('\x1b') or pressedkey == ord('q')) if not exitkey and pressedkey > -1: # Redraw display self.flush(stats, cs_status=cs_status) # Wait 100ms... self.wait() return exitkey def wait(self, delay=100): """Wait delay in ms""" curses.napms(100) def get_stats_display_width(self, curse_msg, without_option=False): """Return the width of the formatted curses message. The height is defined by the maximum line. """ try: if without_option: # Size without options c = len(max(''.join([(re.sub(r'[^\x00-\x7F]+', ' ', i['msg']) if not i['optional'] else "") for i in curse_msg['msgdict']]).split('\n'), key=len)) else: # Size with all options c = len(max(''.join([re.sub(r'[^\x00-\x7F]+', ' ', i['msg']) for i in curse_msg['msgdict']]).split('\n'), key=len)) except Exception: return 0 else: return c def get_stats_display_height(self, curse_msg): r"""Return the height of the formatted curses message. The height is defined by the number of '\n' (new line). """ try: c = [i['msg'] for i in curse_msg['msgdict']].count('\n') except Exception: return 0 else: return c + 1 class GlancesCursesStandalone(_GlancesCurses): """Class for the Glances curse standalone.""" pass class GlancesCursesClient(_GlancesCurses): """Class for the Glances curse client.""" pass if not WINDOWS: class GlancesTextbox(Textbox, object): def __init__(self, *args, **kwargs): super(GlancesTextbox, self).__init__(*args, **kwargs) def do_command(self, ch): if ch == 10: # Enter return 0 if ch == 127: # Back return 8 return super(GlancesTextbox, self).do_command(ch) glances-2.11.1/glances/outputs/glances_curses_browser.py000066400000000000000000000217331315472316100234750ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Curses browser interface class .""" import sys import curses from glances.outputs.glances_curses import _GlancesCurses from glances.logger import logger from glances.timer import Timer class GlancesCursesBrowser(_GlancesCurses): """Class for the Glances curse client browser.""" def __init__(self, args=None): # Init the father class super(GlancesCursesBrowser, self).__init__(args=args) _colors_list = { 'UNKNOWN': self.no_color, 'SNMP': self.default_color2, 'ONLINE': self.default_color2, 'OFFLINE': self.ifCRITICAL_color2, 'PROTECTED': self.ifWARNING_color2, } self.colors_list.update(_colors_list) # First time scan tag # Used to display a specific message when the browser is started self.first_scan = True # Init refresh time self.__refresh_time = args.time # Init the cursor position for the client browser self.cursor_position = 0 # Active Glances server number self._active_server = None @property def active_server(self): """Return the active server or None if it's the browser list.""" return self._active_server @active_server.setter def active_server(self, index): """Set the active server or None if no server selected.""" self._active_server = index @property def cursor(self): """Get the cursor position.""" return self.cursor_position @cursor.setter def cursor(self, position): """Set the cursor position.""" self.cursor_position = position def cursor_up(self, servers_list): """Set the cursor to position N-1 in the list.""" if self.cursor_position > 0: self.cursor_position -= 1 else: self.cursor_position = len(servers_list) - 1 def cursor_down(self, servers_list): """Set the cursor to position N-1 in the list.""" if self.cursor_position < len(servers_list) - 1: self.cursor_position += 1 else: self.cursor_position = 0 def __catch_key(self, servers_list): # Catch the browser pressed key self.pressedkey = self.get_key(self.term_window) if self.pressedkey != -1: logger.debug("Key pressed. Code=%s" % self.pressedkey) # Actions... if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'): # 'ESC'|'q' > Quit self.end() logger.info("Stop Glances client browser") sys.exit(0) elif self.pressedkey == 10: # 'ENTER' > Run Glances on the selected server logger.debug("Server number {} selected".format(self.cursor + 1)) self.active_server = self.cursor elif self.pressedkey == curses.KEY_UP: # 'UP' > Up in the server list self.cursor_up(servers_list) elif self.pressedkey == curses.KEY_DOWN: # 'DOWN' > Down in the server list self.cursor_down(servers_list) # Return the key code return self.pressedkey def update(self, servers_list): """Update the servers' list screen. Wait for __refresh_time sec / catch key every 100 ms. servers_list: Dict of dict with servers stats """ # Flush display logger.debug('Servers list: {}'.format(servers_list)) self.flush(servers_list) # Wait exitkey = False countdown = Timer(self.__refresh_time) while not countdown.finished() and not exitkey: # Getkey pressedkey = self.__catch_key(servers_list) # Is it an exit or select server key ? exitkey = ( pressedkey == ord('\x1b') or pressedkey == ord('q') or pressedkey == 10) if not exitkey and pressedkey > -1: # Redraw display self.flush(servers_list) # Wait 100ms... self.wait() return self.active_server def flush(self, servers_list): """Update the servers' list screen. servers_list: List of dict with servers stats """ self.erase() self.display(servers_list) def display(self, servers_list): """Display the servers list. Return: True if the stats have been displayed False if the stats have not been displayed (no server available) """ # Init the internal line/column for Glances Curses self.init_line_column() # Get the current screen size screen_x = self.screen.getmaxyx()[1] screen_y = self.screen.getmaxyx()[0] # Init position x = 0 y = 0 # Display top header if len(servers_list) == 0: if self.first_scan and not self.args.disable_autodiscover: msg = 'Glances is scanning your network. Please wait...' self.first_scan = False else: msg = 'No Glances server available' elif len(servers_list) == 1: msg = 'One Glances server available' else: msg = '{} Glances servers available'.format(len(servers_list)) if self.args.disable_autodiscover: msg += ' ' + '(auto discover is disabled)' self.term_window.addnstr(y, x, msg, screen_x - x, self.colors_list['TITLE']) if len(servers_list) == 0: return False # Display the Glances server list # ================================ # Table of table # Item description: [stats_id, column name, column size] column_def = [ ['name', 'Name', 16], ['alias', None, None], ['load_min5', 'LOAD', 6], ['cpu_percent', 'CPU%', 5], ['mem_percent', 'MEM%', 5], ['status', 'STATUS', 9], ['ip', 'IP', 15], # ['port', 'PORT', 5], ['hr_name', 'OS', 16], ] y = 2 # Display table header xc = x + 2 for cpt, c in enumerate(column_def): if xc < screen_x and y < screen_y and c[1] is not None: self.term_window.addnstr(y, xc, c[1], screen_x - x, self.colors_list['BOLD']) xc += c[2] + self.space_between_column y += 1 # If a servers has been deleted from the list... # ... and if the cursor is in the latest position if self.cursor > len(servers_list) - 1: # Set the cursor position to the latest item self.cursor = len(servers_list) - 1 # Display table line = 0 for v in servers_list: # Get server stats server_stat = {} for c in column_def: try: server_stat[c[0]] = v[c[0]] except KeyError as e: logger.debug( "Cannot grab stats {} from server (KeyError: {})".format(c[0], e)) server_stat[c[0]] = '?' # Display alias instead of name try: if c[0] == 'alias' and v[c[0]] is not None: server_stat['name'] = v[c[0]] except KeyError: pass # Display line for server stats cpt = 0 xc = x # Is the line selected ? if line == self.cursor: # Display cursor self.term_window.addnstr( y, xc, ">", screen_x - xc, self.colors_list['BOLD']) # Display the line xc += 2 for c in column_def: if xc < screen_x and y < screen_y and c[1] is not None: # Display server stats self.term_window.addnstr( y, xc, format(server_stat[c[0]]), c[2], self.colors_list[v['status']]) xc += c[2] + self.space_between_column cpt += 1 # Next line, next server... y += 1 line += 1 return True glances-2.11.1/glances/outputs/static/000077500000000000000000000000001315472316100176415ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/README.md000066400000000000000000000013011315472316100211130ustar00rootroot00000000000000# How to contribute? In order to build the assets of the Web UI, you'll need [npm](https://docs.npmjs.com/getting-started/what-is-npm). You must run the following command from the `glances/outputs/static/` directory. ## Install dependencies ```bash $ npm install ``` ## Build assets Run the build command to build assets once : ```bash $ npm run build ``` or use the watch command to rebuild only modified files : ```bash $ npm run watch ``` # Anatomy ```bash static | |--- css | |--- images | |--- js | |--- public # path where builds are put | |--- templates (bottle) ``` ## Data Each plugin receives the data in the following format: * stats * views * isBsd * isLinux * isMac * isWindows glances-2.11.1/glances/outputs/static/bower.json000066400000000000000000000004721315472316100216550ustar00rootroot00000000000000{ "name": "glances", "private": true, "dependencies": { "angular": "^1.5.8", "lodash": "^4.13.1", "favico.js": "^0.3.10", "angular-hotkeys": "chieffancypants/angular-hotkeys#^1.7.0" }, "overrides": { "angular-hotkeys": { "main": [ "build/hotkeys.js" ] } } } glances-2.11.1/glances/outputs/static/css/000077500000000000000000000000001315472316100204315ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/css/bootstrap.css000066400000000000000000000661741315472316100231760ustar00rootroot00000000000000/*! * Bootstrap v3.3.5 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ /*! * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=5319fed74136f5128183) * Config saved to config.json and https://gist.github.com/5319fed74136f5128183 *//*! * Bootstrap v3.3.5 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12, .col-xs-13, .col-sm-13, .col-md-13, .col-lg-13, .col-xs-14, .col-sm-14, .col-md-14, .col-lg-14, .col-xs-15, .col-sm-15, .col-md-15, .col-lg-15, .col-xs-16, .col-sm-16, .col-md-16, .col-lg-16, .col-xs-17, .col-sm-17, .col-md-17, .col-lg-17, .col-xs-18, .col-sm-18, .col-md-18, .col-lg-18, .col-xs-19, .col-sm-19, .col-md-19, .col-lg-19, .col-xs-20, .col-sm-20, .col-md-20, .col-lg-20, .col-xs-21, .col-sm-21, .col-md-21, .col-lg-21, .col-xs-22, .col-sm-22, .col-md-22, .col-lg-22, .col-xs-23, .col-sm-23, .col-md-23, .col-lg-23, .col-xs-24, .col-sm-24, .col-md-24, .col-lg-24{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-13, .col-xs-14, .col-xs-15, .col-xs-16, .col-xs-17, .col-xs-18, .col-xs-19, .col-xs-20, .col-xs-21, .col-xs-22, .col-xs-23, .col-xs-24{float:left}.col-xs-24{width:100%}.col-xs-23{width:95.83333333%}.col-xs-22{width:91.66666667%}.col-xs-21{width:87.5%}.col-xs-20{width:83.33333333%}.col-xs-19{width:79.16666667%}.col-xs-18{width:75%}.col-xs-17{width:70.83333333%}.col-xs-16{width:66.66666667%}.col-xs-15{width:62.5%}.col-xs-14{width:58.33333333%}.col-xs-13{width:54.16666667%}.col-xs-12{width:50%}.col-xs-11{width:45.83333333%}.col-xs-10{width:41.66666667%}.col-xs-9{width:37.5%}.col-xs-8{width:33.33333333%}.col-xs-7{width:29.16666667%}.col-xs-6{width:25%}.col-xs-5{width:20.83333333%}.col-xs-4{width:16.66666667%}.col-xs-3{width:12.5%}.col-xs-2{width:8.33333333%}.col-xs-1{width:4.16666667%}.col-xs-pull-24{right:100%}.col-xs-pull-23{right:95.83333333%}.col-xs-pull-22{right:91.66666667%}.col-xs-pull-21{right:87.5%}.col-xs-pull-20{right:83.33333333%}.col-xs-pull-19{right:79.16666667%}.col-xs-pull-18{right:75%}.col-xs-pull-17{right:70.83333333%}.col-xs-pull-16{right:66.66666667%}.col-xs-pull-15{right:62.5%}.col-xs-pull-14{right:58.33333333%}.col-xs-pull-13{right:54.16666667%}.col-xs-pull-12{right:50%}.col-xs-pull-11{right:45.83333333%}.col-xs-pull-10{right:41.66666667%}.col-xs-pull-9{right:37.5%}.col-xs-pull-8{right:33.33333333%}.col-xs-pull-7{right:29.16666667%}.col-xs-pull-6{right:25%}.col-xs-pull-5{right:20.83333333%}.col-xs-pull-4{right:16.66666667%}.col-xs-pull-3{right:12.5%}.col-xs-pull-2{right:8.33333333%}.col-xs-pull-1{right:4.16666667%}.col-xs-pull-0{right:auto}.col-xs-push-24{left:100%}.col-xs-push-23{left:95.83333333%}.col-xs-push-22{left:91.66666667%}.col-xs-push-21{left:87.5%}.col-xs-push-20{left:83.33333333%}.col-xs-push-19{left:79.16666667%}.col-xs-push-18{left:75%}.col-xs-push-17{left:70.83333333%}.col-xs-push-16{left:66.66666667%}.col-xs-push-15{left:62.5%}.col-xs-push-14{left:58.33333333%}.col-xs-push-13{left:54.16666667%}.col-xs-push-12{left:50%}.col-xs-push-11{left:45.83333333%}.col-xs-push-10{left:41.66666667%}.col-xs-push-9{left:37.5%}.col-xs-push-8{left:33.33333333%}.col-xs-push-7{left:29.16666667%}.col-xs-push-6{left:25%}.col-xs-push-5{left:20.83333333%}.col-xs-push-4{left:16.66666667%}.col-xs-push-3{left:12.5%}.col-xs-push-2{left:8.33333333%}.col-xs-push-1{left:4.16666667%}.col-xs-push-0{left:auto}.col-xs-offset-24{margin-left:100%}.col-xs-offset-23{margin-left:95.83333333%}.col-xs-offset-22{margin-left:91.66666667%}.col-xs-offset-21{margin-left:87.5%}.col-xs-offset-20{margin-left:83.33333333%}.col-xs-offset-19{margin-left:79.16666667%}.col-xs-offset-18{margin-left:75%}.col-xs-offset-17{margin-left:70.83333333%}.col-xs-offset-16{margin-left:66.66666667%}.col-xs-offset-15{margin-left:62.5%}.col-xs-offset-14{margin-left:58.33333333%}.col-xs-offset-13{margin-left:54.16666667%}.col-xs-offset-12{margin-left:50%}.col-xs-offset-11{margin-left:45.83333333%}.col-xs-offset-10{margin-left:41.66666667%}.col-xs-offset-9{margin-left:37.5%}.col-xs-offset-8{margin-left:33.33333333%}.col-xs-offset-7{margin-left:29.16666667%}.col-xs-offset-6{margin-left:25%}.col-xs-offset-5{margin-left:20.83333333%}.col-xs-offset-4{margin-left:16.66666667%}.col-xs-offset-3{margin-left:12.5%}.col-xs-offset-2{margin-left:8.33333333%}.col-xs-offset-1{margin-left:4.16666667%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-13, .col-sm-14, .col-sm-15, .col-sm-16, .col-sm-17, .col-sm-18, .col-sm-19, .col-sm-20, .col-sm-21, .col-sm-22, .col-sm-23, .col-sm-24{float:left}.col-sm-24{width:100%}.col-sm-23{width:95.83333333%}.col-sm-22{width:91.66666667%}.col-sm-21{width:87.5%}.col-sm-20{width:83.33333333%}.col-sm-19{width:79.16666667%}.col-sm-18{width:75%}.col-sm-17{width:70.83333333%}.col-sm-16{width:66.66666667%}.col-sm-15{width:62.5%}.col-sm-14{width:58.33333333%}.col-sm-13{width:54.16666667%}.col-sm-12{width:50%}.col-sm-11{width:45.83333333%}.col-sm-10{width:41.66666667%}.col-sm-9{width:37.5%}.col-sm-8{width:33.33333333%}.col-sm-7{width:29.16666667%}.col-sm-6{width:25%}.col-sm-5{width:20.83333333%}.col-sm-4{width:16.66666667%}.col-sm-3{width:12.5%}.col-sm-2{width:8.33333333%}.col-sm-1{width:4.16666667%}.col-sm-pull-24{right:100%}.col-sm-pull-23{right:95.83333333%}.col-sm-pull-22{right:91.66666667%}.col-sm-pull-21{right:87.5%}.col-sm-pull-20{right:83.33333333%}.col-sm-pull-19{right:79.16666667%}.col-sm-pull-18{right:75%}.col-sm-pull-17{right:70.83333333%}.col-sm-pull-16{right:66.66666667%}.col-sm-pull-15{right:62.5%}.col-sm-pull-14{right:58.33333333%}.col-sm-pull-13{right:54.16666667%}.col-sm-pull-12{right:50%}.col-sm-pull-11{right:45.83333333%}.col-sm-pull-10{right:41.66666667%}.col-sm-pull-9{right:37.5%}.col-sm-pull-8{right:33.33333333%}.col-sm-pull-7{right:29.16666667%}.col-sm-pull-6{right:25%}.col-sm-pull-5{right:20.83333333%}.col-sm-pull-4{right:16.66666667%}.col-sm-pull-3{right:12.5%}.col-sm-pull-2{right:8.33333333%}.col-sm-pull-1{right:4.16666667%}.col-sm-pull-0{right:auto}.col-sm-push-24{left:100%}.col-sm-push-23{left:95.83333333%}.col-sm-push-22{left:91.66666667%}.col-sm-push-21{left:87.5%}.col-sm-push-20{left:83.33333333%}.col-sm-push-19{left:79.16666667%}.col-sm-push-18{left:75%}.col-sm-push-17{left:70.83333333%}.col-sm-push-16{left:66.66666667%}.col-sm-push-15{left:62.5%}.col-sm-push-14{left:58.33333333%}.col-sm-push-13{left:54.16666667%}.col-sm-push-12{left:50%}.col-sm-push-11{left:45.83333333%}.col-sm-push-10{left:41.66666667%}.col-sm-push-9{left:37.5%}.col-sm-push-8{left:33.33333333%}.col-sm-push-7{left:29.16666667%}.col-sm-push-6{left:25%}.col-sm-push-5{left:20.83333333%}.col-sm-push-4{left:16.66666667%}.col-sm-push-3{left:12.5%}.col-sm-push-2{left:8.33333333%}.col-sm-push-1{left:4.16666667%}.col-sm-push-0{left:auto}.col-sm-offset-24{margin-left:100%}.col-sm-offset-23{margin-left:95.83333333%}.col-sm-offset-22{margin-left:91.66666667%}.col-sm-offset-21{margin-left:87.5%}.col-sm-offset-20{margin-left:83.33333333%}.col-sm-offset-19{margin-left:79.16666667%}.col-sm-offset-18{margin-left:75%}.col-sm-offset-17{margin-left:70.83333333%}.col-sm-offset-16{margin-left:66.66666667%}.col-sm-offset-15{margin-left:62.5%}.col-sm-offset-14{margin-left:58.33333333%}.col-sm-offset-13{margin-left:54.16666667%}.col-sm-offset-12{margin-left:50%}.col-sm-offset-11{margin-left:45.83333333%}.col-sm-offset-10{margin-left:41.66666667%}.col-sm-offset-9{margin-left:37.5%}.col-sm-offset-8{margin-left:33.33333333%}.col-sm-offset-7{margin-left:29.16666667%}.col-sm-offset-6{margin-left:25%}.col-sm-offset-5{margin-left:20.83333333%}.col-sm-offset-4{margin-left:16.66666667%}.col-sm-offset-3{margin-left:12.5%}.col-sm-offset-2{margin-left:8.33333333%}.col-sm-offset-1{margin-left:4.16666667%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md-13, .col-md-14, .col-md-15, .col-md-16, .col-md-17, .col-md-18, .col-md-19, .col-md-20, .col-md-21, .col-md-22, .col-md-23, .col-md-24{float:left}.col-md-24{width:100%}.col-md-23{width:95.83333333%}.col-md-22{width:91.66666667%}.col-md-21{width:87.5%}.col-md-20{width:83.33333333%}.col-md-19{width:79.16666667%}.col-md-18{width:75%}.col-md-17{width:70.83333333%}.col-md-16{width:66.66666667%}.col-md-15{width:62.5%}.col-md-14{width:58.33333333%}.col-md-13{width:54.16666667%}.col-md-12{width:50%}.col-md-11{width:45.83333333%}.col-md-10{width:41.66666667%}.col-md-9{width:37.5%}.col-md-8{width:33.33333333%}.col-md-7{width:29.16666667%}.col-md-6{width:25%}.col-md-5{width:20.83333333%}.col-md-4{width:16.66666667%}.col-md-3{width:12.5%}.col-md-2{width:8.33333333%}.col-md-1{width:4.16666667%}.col-md-pull-24{right:100%}.col-md-pull-23{right:95.83333333%}.col-md-pull-22{right:91.66666667%}.col-md-pull-21{right:87.5%}.col-md-pull-20{right:83.33333333%}.col-md-pull-19{right:79.16666667%}.col-md-pull-18{right:75%}.col-md-pull-17{right:70.83333333%}.col-md-pull-16{right:66.66666667%}.col-md-pull-15{right:62.5%}.col-md-pull-14{right:58.33333333%}.col-md-pull-13{right:54.16666667%}.col-md-pull-12{right:50%}.col-md-pull-11{right:45.83333333%}.col-md-pull-10{right:41.66666667%}.col-md-pull-9{right:37.5%}.col-md-pull-8{right:33.33333333%}.col-md-pull-7{right:29.16666667%}.col-md-pull-6{right:25%}.col-md-pull-5{right:20.83333333%}.col-md-pull-4{right:16.66666667%}.col-md-pull-3{right:12.5%}.col-md-pull-2{right:8.33333333%}.col-md-pull-1{right:4.16666667%}.col-md-pull-0{right:auto}.col-md-push-24{left:100%}.col-md-push-23{left:95.83333333%}.col-md-push-22{left:91.66666667%}.col-md-push-21{left:87.5%}.col-md-push-20{left:83.33333333%}.col-md-push-19{left:79.16666667%}.col-md-push-18{left:75%}.col-md-push-17{left:70.83333333%}.col-md-push-16{left:66.66666667%}.col-md-push-15{left:62.5%}.col-md-push-14{left:58.33333333%}.col-md-push-13{left:54.16666667%}.col-md-push-12{left:50%}.col-md-push-11{left:45.83333333%}.col-md-push-10{left:41.66666667%}.col-md-push-9{left:37.5%}.col-md-push-8{left:33.33333333%}.col-md-push-7{left:29.16666667%}.col-md-push-6{left:25%}.col-md-push-5{left:20.83333333%}.col-md-push-4{left:16.66666667%}.col-md-push-3{left:12.5%}.col-md-push-2{left:8.33333333%}.col-md-push-1{left:4.16666667%}.col-md-push-0{left:auto}.col-md-offset-24{margin-left:100%}.col-md-offset-23{margin-left:95.83333333%}.col-md-offset-22{margin-left:91.66666667%}.col-md-offset-21{margin-left:87.5%}.col-md-offset-20{margin-left:83.33333333%}.col-md-offset-19{margin-left:79.16666667%}.col-md-offset-18{margin-left:75%}.col-md-offset-17{margin-left:70.83333333%}.col-md-offset-16{margin-left:66.66666667%}.col-md-offset-15{margin-left:62.5%}.col-md-offset-14{margin-left:58.33333333%}.col-md-offset-13{margin-left:54.16666667%}.col-md-offset-12{margin-left:50%}.col-md-offset-11{margin-left:45.83333333%}.col-md-offset-10{margin-left:41.66666667%}.col-md-offset-9{margin-left:37.5%}.col-md-offset-8{margin-left:33.33333333%}.col-md-offset-7{margin-left:29.16666667%}.col-md-offset-6{margin-left:25%}.col-md-offset-5{margin-left:20.83333333%}.col-md-offset-4{margin-left:16.66666667%}.col-md-offset-3{margin-left:12.5%}.col-md-offset-2{margin-left:8.33333333%}.col-md-offset-1{margin-left:4.16666667%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-13, .col-lg-14, .col-lg-15, .col-lg-16, .col-lg-17, .col-lg-18, .col-lg-19, .col-lg-20, .col-lg-21, .col-lg-22, .col-lg-23, .col-lg-24{float:left}.col-lg-24{width:100%}.col-lg-23{width:95.83333333%}.col-lg-22{width:91.66666667%}.col-lg-21{width:87.5%}.col-lg-20{width:83.33333333%}.col-lg-19{width:79.16666667%}.col-lg-18{width:75%}.col-lg-17{width:70.83333333%}.col-lg-16{width:66.66666667%}.col-lg-15{width:62.5%}.col-lg-14{width:58.33333333%}.col-lg-13{width:54.16666667%}.col-lg-12{width:50%}.col-lg-11{width:45.83333333%}.col-lg-10{width:41.66666667%}.col-lg-9{width:37.5%}.col-lg-8{width:33.33333333%}.col-lg-7{width:29.16666667%}.col-lg-6{width:25%}.col-lg-5{width:20.83333333%}.col-lg-4{width:16.66666667%}.col-lg-3{width:12.5%}.col-lg-2{width:8.33333333%}.col-lg-1{width:4.16666667%}.col-lg-pull-24{right:100%}.col-lg-pull-23{right:95.83333333%}.col-lg-pull-22{right:91.66666667%}.col-lg-pull-21{right:87.5%}.col-lg-pull-20{right:83.33333333%}.col-lg-pull-19{right:79.16666667%}.col-lg-pull-18{right:75%}.col-lg-pull-17{right:70.83333333%}.col-lg-pull-16{right:66.66666667%}.col-lg-pull-15{right:62.5%}.col-lg-pull-14{right:58.33333333%}.col-lg-pull-13{right:54.16666667%}.col-lg-pull-12{right:50%}.col-lg-pull-11{right:45.83333333%}.col-lg-pull-10{right:41.66666667%}.col-lg-pull-9{right:37.5%}.col-lg-pull-8{right:33.33333333%}.col-lg-pull-7{right:29.16666667%}.col-lg-pull-6{right:25%}.col-lg-pull-5{right:20.83333333%}.col-lg-pull-4{right:16.66666667%}.col-lg-pull-3{right:12.5%}.col-lg-pull-2{right:8.33333333%}.col-lg-pull-1{right:4.16666667%}.col-lg-pull-0{right:auto}.col-lg-push-24{left:100%}.col-lg-push-23{left:95.83333333%}.col-lg-push-22{left:91.66666667%}.col-lg-push-21{left:87.5%}.col-lg-push-20{left:83.33333333%}.col-lg-push-19{left:79.16666667%}.col-lg-push-18{left:75%}.col-lg-push-17{left:70.83333333%}.col-lg-push-16{left:66.66666667%}.col-lg-push-15{left:62.5%}.col-lg-push-14{left:58.33333333%}.col-lg-push-13{left:54.16666667%}.col-lg-push-12{left:50%}.col-lg-push-11{left:45.83333333%}.col-lg-push-10{left:41.66666667%}.col-lg-push-9{left:37.5%}.col-lg-push-8{left:33.33333333%}.col-lg-push-7{left:29.16666667%}.col-lg-push-6{left:25%}.col-lg-push-5{left:20.83333333%}.col-lg-push-4{left:16.66666667%}.col-lg-push-3{left:12.5%}.col-lg-push-2{left:8.33333333%}.col-lg-push-1{left:4.16666667%}.col-lg-push-0{left:auto}.col-lg-offset-24{margin-left:100%}.col-lg-offset-23{margin-left:95.83333333%}.col-lg-offset-22{margin-left:91.66666667%}.col-lg-offset-21{margin-left:87.5%}.col-lg-offset-20{margin-left:83.33333333%}.col-lg-offset-19{margin-left:79.16666667%}.col-lg-offset-18{margin-left:75%}.col-lg-offset-17{margin-left:70.83333333%}.col-lg-offset-16{margin-left:66.66666667%}.col-lg-offset-15{margin-left:62.5%}.col-lg-offset-14{margin-left:58.33333333%}.col-lg-offset-13{margin-left:54.16666667%}.col-lg-offset-12{margin-left:50%}.col-lg-offset-11{margin-left:45.83333333%}.col-lg-offset-10{margin-left:41.66666667%}.col-lg-offset-9{margin-left:37.5%}.col-lg-offset-8{margin-left:33.33333333%}.col-lg-offset-7{margin-left:29.16666667%}.col-lg-offset-6{margin-left:25%}.col-lg-offset-5{margin-left:20.83333333%}.col-lg-offset-4{margin-left:16.66666667%}.col-lg-offset-3{margin-left:12.5%}.col-lg-offset-2{margin-left:8.33333333%}.col-lg-offset-1{margin-left:4.16666667%}.col-lg-offset-0{margin-left:0}}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}glances-2.11.1/glances/outputs/static/css/normalize.css000066400000000000000000000034411315472316100231450ustar00rootroot00000000000000article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;}glances-2.11.1/glances/outputs/static/css/style.css000066400000000000000000000101551315472316100223050ustar00rootroot00000000000000body { background: black; color: #BBB; font-family: "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace; } .table { display: table; width: 100%; max-width:100%; } .table-row-group { display: table-row-group } .table-row { display: table-row; } .table-cell { display: table-cell; text-align: right; } .top-plugin { margin-bottom: 20px; } .plugin { margin-bottom: 20px; } .plugin.table-row-group .table-row:last-child .table-cell { padding-bottom: 20px; } .underline { text-decoration: underline } .bold { font-weight: bold; } .sort { font-weight: bold; color: white; } .sortable { cursor: pointer; } .text-right { text-align: right; } .text-left { text-align: left; } .sidebar .table-cell:not(.text-left) { padding-left: 10px; } /* Theme */ .title { font-weight: bold; color: white; } .highlight { font-weight: bold; color: #5D4062; } .ok, .status, .process { color: #3E7B04; /*font-weight: bold;*/ } .ok_log { background-color: #3E7B04; color: white; /*font-weight: bold;*/ } .max { color: #3E7B04; font-weight: bold; } .careful { color: #295183; font-weight: bold; } .careful_log { background-color: #295183; color: white; font-weight: bold; } .warning, .nice { color: #5D4062; font-weight: bold; } .warning_log { background-color: #5D4062; color: white; font-weight: bold; } .critical { color: #A30000; font-weight: bold; } .critical_log { background-color: #A30000; color: white; font-weight: bold; } /* Plugins */ #processlist-plugin .table-cell { padding: 0px 5px 0px 5px; white-space: nowrap; } #containers-plugin .table-cell { padding: 0px 10px 0px 10px; white-space: nowrap; } #quicklook-plugin .progress { margin-bottom: 0px; min-width: 100px; background-color: #000; height: 12px; border-radius: 0px; text-align: right; } #quicklook-plugin .progress-bar-ok { background-color: #3E7B04; } #quicklook-plugin .progress-bar-careful { background-color: #295183; } #quicklook-plugin .progress-bar-warning { background-color: #5D4062; } #quicklook-plugin .progress-bar-critical { background-color: #A30000; } #quicklook-plugin .cpu-name { white-space: nowrap; overflow: hidden; width: 100%; text-overflow: ellipsis; } #amps-plugin .process-result { max-width: 300px; overflow: hidden; white-space: pre-wrap; padding-left: 10px; text-overflow: ellipsis; } #gpu-plugin .gpu-name { white-space: nowrap; overflow: hidden; width: 100%; text-overflow: ellipsis; } /* Loading page */ #loading-page .glances-logo { background: url('../images/glances.png') no-repeat center center; background-size: contain; } @media (max-width: 750px) { #loading-page .glances-logo { height: 400px; } } @media (min-width: 750px) { #loading-page .glances-logo { height: 500px; } } /* Loading animation source : https://github.com/lukehaas/css-loaders */ #loading-page .loader:before, #loading-page .loader:after, #loading-page .loader { border-radius: 50%; width: 1em; height: 1em; -webkit-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation: loader 1.8s infinite ease-in-out; animation: loader 1.8s infinite ease-in-out; } #loading-page .loader { margin: auto; font-size: 10px; position: relative; text-indent: -9999em; -webkit-animation-delay: 0.16s; animation-delay: 0.16s; } #loading-page .loader:before { left: -3.5em; } #loading-page .loader:after { left: 3.5em; -webkit-animation-delay: 0.32s; animation-delay: 0.32s; } #loading-page .loader:before, #loading-page .loader:after { content: ''; position: absolute; top: 0; } @-webkit-keyframes loader { 0%, 80%, 100% { box-shadow: 0 2.5em 0 -1.3em #56CA69; } 40% { box-shadow: 0 2.5em 0 0 #56CA69; } } @keyframes loader { 0%, 80%, 100% { box-shadow: 0 2.5em 0 -1.3em #56CA69; } 40% { box-shadow: 0 2.5em 0 0 #56CA69; } } glances-2.11.1/glances/outputs/static/gulpfile.js000066400000000000000000000031751315472316100220140ustar00rootroot00000000000000var gulp = require('gulp'); var concat = require('gulp-concat'); var mainBowerFiles = require('main-bower-files'); var ngAnnotate = require('gulp-ng-annotate'); var templateCache = require('gulp-angular-templatecache'); var del = require('del'); var rename = require('gulp-rename'); gulp.task('clean', function() { del('./public/*') }); gulp.task('copy', function() { gulp.src('./html/*.html') .pipe(gulp.dest('./public')); gulp.src('./css/*.css') .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('./public/css')); gulp.src('./images/*.png') .pipe(gulp.dest('./public/images')); gulp.src('./images/favicon.ico') .pipe(gulp.dest('./public')); }); gulp.task('bower', function() { return gulp.src(mainBowerFiles()) .pipe(concat('vendor.js')) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('./public/js')) }); gulp.task('build-js', function() { return gulp.src('./js/**/*.js') .pipe(ngAnnotate()) .pipe(concat('main.js')) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('./public/js')) }); gulp.task('template', function () { return gulp.src('./js/components/**/*.html') .pipe(templateCache('templates.js', {'root': 'components/', 'module': 'glancesApp'})) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('./public/js')); }); gulp.task('watch', function () { gulp.watch(['./html/*.html','./css/*.css', './images/*.png'], ['copy']); gulp.watch('bower.json', ['bower']); gulp.watch('./js/**/*.js', ['build-js']); gulp.watch('./html/plugins/*.html', ['template']); }); gulp.task('build', ['clean', 'bower', 'build-js', 'template', 'copy']); gulp.task('default', ['build']); glances-2.11.1/glances/outputs/static/images/000077500000000000000000000000001315472316100211065ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/images/favicon.ico000066400000000000000000000102761315472316100232350ustar00rootroot00000000000000  ( @   !*  u/$( W\-!XO *  TKTX5# TK:x+31SK=s:7 ]\]KbG8-7qCVK269) ,N(392869+yX97)92$-77"-:6  $6768*4896*&).59877775, -:98888897%    ?glances-2.11.1/glances/outputs/static/images/glances.png000066400000000000000000001251041315472316100232330ustar00rootroot00000000000000PNG  IHDRzzS;xsRGBbKGD pHYs\F\FCAtIME+;Y IDATx{}sqF4xMU4I9ј8B4!{huu|zBGllU^ ' ^Zv/4$cƬnil@k@`J++ŭK^b<p.< A^RZY9h`Y: ng@k&LXG`lUw[o%@`  no޺Z=vrмU[h y8\0fx{'y_ r1حziTV=sM)Z=@P G6$}G?[i Y8\c0f zS GL9 wsT,^p -KVTTYl)-/\JK8fFHAN+6Z=@9w_=q" ᄾAwu.Z={6yrmf pBzVVf„y 쁠+N&W=bxZ@AwBzTZQQfٲ= p9i3g:U3> ]ia=\ie5h uuͯOIzF@#p(CI7ǟ|K$V7ׯk-Aa=K䂧W`^WSjw_ZY9Y3j$ ?T0@0P`%\֭=vItzgl#@AlܶNz-hp?o~k$=J++` I&u%\PKk縢/|a)cG_Y|@@@ 5j?<ǐdR|EA8zbUW~b= p$B8VU# XwAȱ 쁠=mH2ÇBN?8!YYWW~]wNK +.;2){֥j<)dUUlil-AJ++]3a  'B# ,+[Gpz= 4U2<VTT_sKAnڵN+tUU5-7fبQA=>,p,#聠Ǭ8\")Smjh%tfz {P5@O 5$= y55U5ׯ5p#QaO׺l;n-Jot<>N9@vzr%t f8\i zvܹ~ĉ4qXYWﺋ9\ } 聠w~r&<{o0ӗeUWS֮%ʹw;Ea GH6n>6f #i `cA@6sSM،iil?ƙC zk38P p\ћWS \cA=݈=GuXMBA/^3$Թ^JYjDA@aay&{R>zI$噈&p9M|ǘ1c~1clܔ)$pVZQQfٲD#@׮A@ਦ9㪫)=A@ޢjY#聠 1wx+t]wVV^S[  xEMM#,6A/7!AYsv^j3s7o7i<%(8dy8\vZBޘ1cUU5BU@Y?x;46$ e3z@؋GW]=<4bF3xO~=-y55!= 5j#!7f# A@v(^v?#-:jҌh@Jت7l)23z@ȄouA<@L2'3z@`^&46NntÇ[= p|鬬S !d,մBbFX[YWﺋJh'%YAkjk%B3AqKq2 C^Yx r^D+ ۱tH>xw4oz/wq.+B@ 4C~-tEvWw#T{~-}?KJd*+-S\Uj}d%v-ARCa]xR+N&CI>gS^X;4Z BIgTAxߢm,ƒ rGιs z q8LgoϑtAFUo׭rY^?b+5]kjk@)dlUUMKcM|v[/؏^xp?uUOTIŒv+T=YzRAŽ?wvbApJoj{xI [=-#T<^+Qi2d?s.(-xs@"6_tR>c^v2]&rf-LrVԒoq0kqqAӲN7qA_cS ~^aKD?Yr/0l<^y55Zp!Ϝ,Qز8Nҧ$!)Ad~ef F}{M.'聠d|9eRҼc'<>A &Ud\x&䪧WOA٨]s˯9*%*cI{Ze=Tط4 mVG>f[gvcfv73Iiy{Ғ^٣fY2z> VO>`Y]rLer9MF/M|"ت-u7}T൶٧د(\~\&ۉ?zμ4 s,qՃyrcfnLOZ$OXJ>yg>Lxw)VCosNؿ,d>@=闒}?E z=<Ypn-J7$UJ*d&b_.=O#UZY9zMm:_<5nK+$Ep}\-rg ecr<S͹JpIE:wُ%A]/חoRq3 t\\Y9Yt=aq*DidOXO]?KF1 hDEE a`t;'N̩iܔ)654һuK:GR -~₯?zv0@=m[YWﺋC-'Ss%}BR-.OzKؽK.S`L@,xxc9WSHD\A#RO׭ Ͽouuʵ>8Fk-[+?{(={s>Q_tez]MrArmvJ i_PZ>T(y(R\e/iS~LuL%)/>f l4/*/?IͰQ6>#r5IJ⇠dr+VϕYqof.4"o~L7$=cfkez)*~nM7>vM%ͩ2;SKLJڃP>=I{l yO%pc-Q;4,R.]᛹,kip ^Kl{aߢ ^ ]4UҶ<=šq*!]&2x]n~)5>щj$d#io\uEM0iK_- 7K%7R+V,>N}v@u?%r͹پL뗖yK.$P  F!sri?޼-^~nݜJ~\s$ ̹3G> As듊}?%#r/2{"[r=z\Zk,^v/ Zv5wuc]ޔגoAi=w\^Rq95YwFr%r/7Zd7G_,:{T4Eqxأƴ3YgN?NIO.~jEBp$Wfvn.&r MreZfQ4dP|ɮqd*)}|#Iɴç8\X&r3 I&5f#e^RIu\흢k$}" ezk$-[ttKdz}01(!/Wn?H5Mi-+1={lO>9(ݒ\_T&s̾%l)c48#L!' ByWyߔ)g8601x`3>ގDa gO_ Ӟ5!/VU9|8!/M]7g~aA%ϿGEWȢ?DI_KՁ`νar},N~@ɓāK%?|y!Y0W[޾ZO\3sm'ew?rwwң]sT3u{\gI*0O-U ?/\!_C=!^;K51[NܷegSe\{va/ߒY")Sx{2_`Tz:uGӛ@z\q2 Ԑ7Si.M xӫ2͉ G9fO&ɢVIK_$SYr}rǐdFK77ګk\YL}s=O`JXZjj'^z,=Eү[7\t\%P%"Ie̾珞3o K.V Y5˖77$x8t\T"0*7-o{t[3D`n i&k OĩxOA?҇erܚ(xakjhM!.פfxflr.tAIEA]Uݟ(M>[/ƥZs IDATfuȄjϫ{ݛK-lzs=rItѩl]2z<1/ޤ36ы=wVUnil@Lqoix02[I\uW3Sm3$}vג 绤ݟtaT KZsӧ= #E@;,q:.i\'2#3{Rv5[]\eWTgTدh]۾zG2O .LC>zD uu2ϕt\&IKFr}:k>;?5 k\F}gogdA|qusӓ@UC6no66fu^6y[K8O sPA35H'![.xmOokIgUr (=2yn$yu@U8OwSZ_w|ZZi3g=7mZ/Aιƹdr ˄2OӞC,5$z@*)/+tB^򔗻J:m̞K޺.>-2!wl˻~o--jR$G<у@v:V,DZlqՃwS9܇?$ f=dgh~?|GCZZɒ.:>Ͽ~9t\aA7\ rYiEEuN-Ы&xm $- y~鱿Á[ZoijMRLYN?aWzZaY(Iç=wĩz&nkE+ t$rR&z/tA(N&We1 nNq2!ļr\:OжNJҩ>nKOwLws6JӲ~ilg2KZO/@`FYrtV${@RICɓ\$AuU/5 ҩRVlw(wB^*gsŮ}g猤7j5{C[S[c.EgrMTcas';9r?*iheG}"лZ' =Gecq5׳(xOvzjil{xڸhַΖ4#N?.Leܿ} Ig03.CKbzr4pf̺! xy4\ 'j%5Se;n\V8F &w~ 2#IA?['uLL7E䂁eeKCfmUR^~{U"E{Zvי0m^gzrwq2%,vÛd}Y!{ ;6Jҫ:94;HM/"4䪐^}聐ύ5nif6#xJ4QfгwfULR Ii['EV/WCH\=ZF/"4_={|(:,=L9ִ}_HTET`Y`̧M+fgY$]ܑǤ? hoIgx:O!4RT3~j`z,?t=8\Uy8h޴Rg{rD 3gfrwlqTCm0SgJ28ND(J++GtM;55h~k$BR8eL*(3z&Ir7w͏;DzC`Ey5\Ad`YY0獭ZM.כ6VUp^ :+5BPL1Div/t1sE_ҷ>=`~yofo9=eLE}A$[ꌖ ARY|Y<ּ)3J! IElse=jhr$tb_iM= !wΝKCPw6Y 3!*N(ʞL.o\KD (߳WT&SYudrA(zwcުDEñ<7aQtLAd&$Uݠgf22g}d+z?"I{ثm'][X@^ZvV(ڼuX~aFݦ/+<]8.$qPEQD$=R\VϞ)a-'? NO"urvARO-_~! X+Jzn쟣(Zx WGc,LYx\\K.)ب7J"!kt [Wy8>\Ȍ^5F*sdfk3[Xܧן)F[5"6IMĥZLVA}E;CQrBYsSm, fv Yup\jip\J++GƷ[)q ǝsfaҌ!{pD5GdDqBT`e%k[N/`(S31,sĉY{mo0AYCif ,].TqY AїZ[ҙ\c$S3zp@:(z!(QԾG/Ȕ$fJ=<] gg=HFθ =#![޻G/;ۃ^ھf%ʆK={&{; Kdm=IX{2՘C/))/=ۮ&z=t;BrM5ݱG/TMy=.={3A]W<|=t=cV+ Sg6\%Gph #Y@3z7L,B t z8dr!xMeTb3X7g V%1He'A+NyzŊ<-wnr$yoJ5f2K7)Ƃ^mn^AGtK6 yuepW$tK(*NʼnK7={:3G1lڟǹy S͜I5&)L1d*,,+sC۩03"caFs@C:k!8TKZz^({Bo&i/5`u2^QZY9([<)Dzd|RPZrPB$տuw37qPq*};0=5;ZAGTZQQM/QpKji/ʀ=E_ʬ,6$۫Pxظz85˖-%nM픴D(B1{ ព6ޒDO9㧺ҐdRM;pXGd|c[8K/?Nsh:'klsQsOuÇ3A]|V6_,2 :aE7Jtg +O$%Ayee]hfywqkʹKހf,4d* fifiL;<-t z͛q]w1Aw4g]6y]۾V}^X";K7qGSfd,DxׯaҌ pDGsf^֭bwgy^$z8=sY@EdQا #ipX,^_0d{ǡ(ԟpdڣMWEDCVتz8) Lec=za/k^|L7eʵz8.= d6̀tD! j?™3.PJ++G5454 #1co8q؆ԟM{AUh1ٮ%N]כpX#$[UHR{;~C/Ri*SI0{N3w55Vթ~=- g[j I:yt b'* ^R7JUf[͙݁Auf6YN&D\I yC++tKDB=f$qLC:3_.M(ƙmf%5t$pJ* ձyEz>ս<z8#|(Fo9\}香NnrJb-.1],[UU5z8dr!Zݖh b4><6;Oq 3EV"\Ȍ^j,W:=tG]Zo@a=b,Bе65+sA+4t\E6%7#:ܷQƁnZ~xSzxϭ zK* "e*nn6\DpDwΝ{f98>m{Z\R@.!*!If,Ā΃/il͛{m~, ሮ8KWا( zq۞ozb~(]!*g-= ˛X[UAu%IDnb^ G恠#8!$W.@]dfUH/2z1M{fSnj;!*o[^xzk6o…恠;ÇwqW_s숂 hWZiW$MS˵_˯j}3ӄʭ[Zj^* ppc#B9̹_tJg|3>u"e:Qϛ6Au}$lJJuKOho>I қ =Rɹ3}$DJuJvvn߻>&UyF"}KmA:Lh1j/V!O*_24}W++$I'mee} IDAT v=zu4JBuxx|GmSS+R+j:H52'YڣW3&igij낖/Y ,6J*^#F8 zZ}X8sTuܖ-HsC ۤ).(imJʀ O^S~9͞}UAOoiEBy+T[i's$t.sQ1/e^au]IX"n$IfxuT|F=!UD:Iy)o\6esBBQoC;5MW eH&\[PU׈YR eȓu&I2*3Enڙ:j ؊ӟ&$llU4antoyVTz<\4{V^=~VAW&cL/L;\Vl~$$;Q0)]buWO9Zrz-T a;opҒ&&/T*N l\&%e0T5bmVA=IjbIIM$̪)K-@M+.Lߙv *4B'I%Tj16͞ՖAO;lVkn,wKZ_loA{𚃲T]'#omOn;tsr|sAO˶?NJx:t|'6jN}$ܐLPN2IR- ~#RAf=Mޕ[$IrYݝ;Or,9VB=IBm̃)$\9z%IC8qoy;RE|vW.=d) lmIL^]xbK(g)$uEILZRfVgoiܹg{X p+ ̇NLi+(=n-{N/IkfzeiۑQNϷ#9רI'ӫ}=HrZROZ[lKHw7sʪ:{$i :3D}1Uz^/eC;n'[۩9 >GHHIy6iIv?iC(e}ƌ z$ )7չ=-aR"a9/MߑH9P$ [QU-2Iнo[H?V*ezC2~-XFM:a{XT&%,}$I.ٿAO)7ϐf3zTnW{?u*^@:.kmOJKR6}; %ICG?fk(e޲iSGO fM.!aqe>.s\y Y .h?"ep{$q-v晆yf߹#}͑8kZms+ $ޖ!O2IR;tz7_GOo ֹRv^BR.;t[Sΐ'$ifs:$GoIyR7gso }iL8~g[xzGM<Rv!g6"eRҒNZlQߒEKGʉo|W?eI\^<mv'Rڀ^-dIKٱCGk ː'56oݔl0=zK/A:<}s.5=?Wzw6>\/}) yIrGҒ|Gc*چ[o=Ր'-IQgڙ^i+>U^v1mIڙ~CHٶ)R:$-w=#We(7ϐ'$y^yH9Ugow%ɘzyڎBO`HڑlAZ޻{:iIN2vy2I=I*8vo³̓\O&<|Q*?p˩y->ig4dafH/ާǍN!CdГ$O=|%/)lڄgN`BҒ;tԪmʨI'C~(MO!_eyɻ镻#Te83ϐ'$$6g⟾Jʩu$} O7H^7L&ߖn 4}3ЫiN6U"z yAO* Kig36o[ I IKTKٗx²W~ԬS`ݎK$-6ig 7%лz*%ɏIHy1Ώ(CdГ$ӓg?Q] N̼o SIyx9iIig{kiGz.3ޱhIŝ}$%I} linI– "a=IacH!O2IJp}}8ؓ]6ֻYp|ˡ\!O2IR博p|[ &M?FF=|0^ۘ-ʶy<ɠ'IM Ǎ"!m@T3,`\>ݿyȐ'$Iup'nܹ$gY?e!DҒ|{ѿ(2I=IR8*0Ϥ7̀VE%-ɩc~Ȑ'$I OܬI؏VD+xmz;ӒtCdГ.O9O9䴱~rVzzq yAO6tiG5>NʖVDIm̟-jnο{|3F z$Qߞ#RQ {Y=%%Ꮴva\hoTͽ1Egk%$i%wˮiG私cI `ky$9=qdaTwٳAO&k=m&LAG>~7|1)ӀuvJ˂^O)|4 t:+ "IrcKu/bKfyN $I3j ;KJ:ؑ́]4/'I2IIKPڙ>5vE5<3=`ֿ뭚AOOu֖Haig+ ;5ЛɦrXH~`RҚߧm.#Tu>'$IzS>pb%[%I1)i:l@B`;0dF'I2dz”+v>-fӳ;Ǎnȓ z$m=tRK>{/hΎIlv$Y/MӾdHzHIJ ,wvt ɂ^%Mg%- dFK8wtӗBJ֤AW$$IH~ȑڧOh%%$I⁷jJ=I$5M3I=I$5QodГ$IR^#F\hcԸZ,$IRFu!Oj|I$5"Ґg5jGO$^! yRxJ$5ރk*bY{tЩ gU z$InoՔ z$Ijgȓ z$Ij AO$IM^<8$IR—k/dГ$IRыw|3 z$Immsܸ»œ z$I2z>~Oz-dГ$IR؋'$I45%$I$xAO$I5uڙg_)guۧOk%$Ij<[dГ$Iރk*sަ)ɠ'ITydz1ǔ$$IR y{R9}V[AO$$e,KdГ$I*Q϶_9n1Xu3MAO$ n_zZˑ4%$IJTU?>cV]AO$\=SAO$)^#Fܶh}$$IR#hJ2I$U=܁I2I$5E3I2I$5QN]8s$$IRAj9ݲdГ$I*X=z9rXmI=I$$$I=hۯZI%$I V޻Ə看.OAO$niOAO$ydz1m?g=$$IgR{qۢٳ5$$Iަ<3=`{:ɹ$$I{ࡷ_}z|uۧOkH2I$ n_zzs/+.k"I=I?>cն$$IRÝw z$IoS$$I]BAF]OGYpwE$$Ij~6S[.Wg$ɠ'IRS=hŋf[FmdГ$y3o7<ݲ>SΜC[_ z$UZ6:+{ݹ$ɠ'IRlk*so[2%ɠ'IR%~Oz-$$IjXyf[U.'.$$I׳;Ǎn%VvdГ$tvt O;:>)68B$$I*ՖcJAOHᝋwnxιOϘqՐ$$>}ރ#M$OC;/ҽmig琤ٷwri:|vt HZ[Я1{|M9`o65FGOO>jH zTD4hd}*us1)I2IR,V6޻Oϝ7'&$$˽v!ouj {(EdГZ?`E|n*T?R$I=I-v7^Kg{9c{l^p$$6)bY=-ճK^]y砓$$#v;AOoGvC=uҞ=.|ca$$zߟ[XI zAϠ'IXI$I2I$I z$I$$I$ɠ'I$I2I$IRf T1^`% X 蛿 h_pυ^$I2IŇ݀Yy_gB/:$IjFN2]wyl:-}?BK$ 詨ђQ'u+7_mB۲$I"ך݁O6h͛\ \Bx=I$F"F lcX $I zj 5`.Z%B3I$ɠ ׁ &!\gГ$IR#qt,@|x!? '?d9$IdS1ƫF֊41^i)$I^AVAV "H$ɠF yWMrw%$IR#M- y޶?YI$5{ xQXįC޺)I$~je$IAOyY5v{ IF3z]3m ݐWa$IRCG논w c _/}߯/}hgWI$ɠ7aޞ~ !xVe{7}W`シB{$I zGG^&. w!e,<p{$I5wE]!ԮT$I2 b_>Rj6$IAO"5L !͊K$I=O ?p$I z*Y@`W`xa-I$T~U>BxjK$Iy+C |ڐ'I$T#1nҒ$IAO `= 8K$I3z"$ IDATc\8ŧQ!׬i6MF]߽F} [=)0jKolE8נ]xkt+!̵Q eސ䗁9dy !Lk %;50&^dS^ ׫ I `F!]Kb *p?:pU̾Pؗw!izvKݦ@|ǀ?;B/|Gnr^+ߖz @{Z_=<`Jפ}7>쓿Wtzw>/xSC ߲=6v˃<ܕa0%~K_}gS}9/JJX4`|+mЫ'6&hX&\lL[}ʝ@ !lkÀy??6 pOzޏ7w&u{=> >ҫ@\G~ ̳ zJXtJ6V٠01#%Q91!.v/lv\ |<_.:m QƆ&V݁#zNc0 8' !wPV!^?eAO5xةE{˦A/im| X6 >paaQ}]nI%m6-n~B~t_|8 peH[آA?to#h޻h=c_$U65N6k曞_*;n݃$Խ850o'z'T|s@̿KvH]Bs[ߍUPa'T9NPM'k yfq&y4x~_YOb7k5x `<Ƞ|'{6 [af0>8b{.?&z*xD~VW=?cG6 RAcdUGb?1Vx@Ng,&xaSm@9?BU<dW xȟ}drXӚH6Z>MRVGq< m=j;Ҫ"}ޫQ|`UˮU m^Hvi[viQVc#Oc\be@&l%1.J"|EͿ$^86@ղpcM~Nz/s5f@c=ɞ["Ad3uk0>FvkW.JyMBH6w~M+Aoiz|?1n`l}K#Áh5@,= 7 )VLb{nq^I=n=IE_'J[h?:\w\sM;b8\D95{ zadK zm:%]y\cܣ!GhÖ5\FO3f@,=H(i)]p Syb?ڴԱ޽kig Wgcnca+]'uݠTaU zte^Ӏy^ \}0a`ncCS*i'܊C/aՋs,Wɦ藿͏mmY !<[Dzv7 v<0sdwlkWkxAqb4eIQgm-y~S~L.o4F]2 ]U[7_$Lnɟ !,y{.-+@#{D_X{_&/_y8_b`@~^%0x[c2BEBަkʙxQJzHgv_C_go15XՒ|;/BXpr' ,6>Pj^&!{V_ }<휇?b8Ɖv\dCYGҢBH*: c]!x|ռlBxba_S E1 §*pw+yU=5ܾ-6?oi!\_F9S)-{}BxJ6wzʲo:*)uClK<Y/ . V)lʠ58G [CAjA/~m{>%! ߖV@[ɫ'pGc[*g1GGmnL'Hy|C/V*vS@w=VGw>M6uTx6?;X/Za^^ڤppr +^iԏ/ͅW! F6Yx|-Xmw+[!BF2<BK io@BRs?R9!X8xoᣞ z*"B5Jo_-aۆw+u6!pXI8"pi}r(sQ'N)F_ !,vm N|]ԲW/x=PuӘ*+Tf%,.*/58v-'{^ 4覟[R{7pjI~zM6Jd1EDبmˠڐkY ki]dXbקStEv/;وw`wg?u/wJ;^d1ƭk [{Bˠ'('CV\/v+[{lDlб;ނ{ +E+t4EI' x M&zH+W2̠eBy z {wF}/o:pJ&ẙ{87~FJ=tZV.A8ݠWiE_Dw>cH |ddp˻+y@GAhq`2i%,=)pY޾YٳPEl]MBc|-u+}/ݷ*tܻemQ S2ѓk<4'Er֭ ]BG oi>N\ ?/pYe z*3٣'Qa!0ŭkEfza{[wڷJyLHЛ]ಆ{Ƞ'fu,e] (rڀmE4gw^?\Q"_ZvPcL< dSYA[7%"upGy^bm=Ky_=.Ua"AoTVгGO2iy1n5;EM]bzq}7mz ^b==dГ=zAϠט-pY݁w!tLw*CUO2+z z*W-d{ͽ \EoI=z1~CBmq \˲J=.fs罿ŽҚoHӡ4Kл֣Bxl"1~ΣCef ^;8 @ hZe[RG!1>lS"X !RE$uylc\' R-1-o{Lma oYUrzXʺVs]&"{BAQ$d 嚒w0Aki/a%Y*4g \V-o7 \#MT" ؠG(ncz.2.{$'k~nҚ6*p7Qyq | x:xz1F|Fq=zҿ. k}Z칷~ɫ˽fSS|+-pY[в\KeyG˳Go~f"H o_1^ !yVh]WdUSt uރ1/pZkZRR8A^*a詙]+2n_2-Vn %ijC[a7c5puaͯB|Z>1SȞͭ*jգWdpNV^#ɼ!yd?ͬ&dcc]@jQ2S31Ɠ(#A=z=^ zy؛F67?dL1c<;eA a5Ccs˾v6eeг*U% !kqhX`=_Bt2詼/%=B^+py. ;= x(:l@`7`O`0֖A˰G6*58P;1#F@}zIOt2\Jz1 !̳j _/a__޳!< BonsàWpnD򩴮1nRyqBYT^u[2XZ5|.J=BNBޛàWoa9:=B8V/4~3AO(cbYZ5})9kmCy: z5VdAkB!\EoIgdS  G9(a1pXlK,ٻT;L׻K`Su݁:AO幡iiUo1/T +,:v=fA6) 5 &&Jǒ|C%ҹ(BW[Z.5A7/#`3Igpߏ1 z*D[6>lyUgE߶o,6t,o(K`+4j3f8݂AO)UȖVY>An.E'VVZd 0Ezk>GA0ƸU2W{dRdˠ+ic|U=y!UzSENﱋ\%wƚT[^̧fx/dZf z*ލsfwS9KdhJzs/pY6|r-OK\Vڠ%%-1 * !fIc/KRE~rj%׋!/=OW<̎`SI.,]{BT \T)D`QAGS4 7,V!Ec\ TA; caUcEMJ#Q#JkkIWBqsKUY/XGk7詤v1w/1`U# \*H[ҕ*GlliUD6ϬAϠ [%Ƙa/mEiB/ \V1=[9"uqS+U z~raE`1&VY|N?UIw'Kݰuj9b'S^cYWZ"}>fZ,pYZNJ?\{| VuvV!-pY[٣mҪC7boZ󇀿|=wEq3(YӠڜ4~c<Ŋ7u{W>=zKH%,g>;[][l3詚\5.!Ÿ ^_c[Y mқ gS5O/_cuѡu/7XY&P3BtVKz.y3ypAϠ8ckÁc8oRS~5o_)p_[Hr}^v;bB`~ =+18`A{fZUjk]D1b楂:?rאVM>]ω%-~p[q+o5'ce8':j[~ ~"xPS+aߩ!'K'Ϗ1)UvdIF6ДWc=⸭F=b1^cܾb%)?1x1!gs ^!v. z_pzVpYqJbzj  M1Ɠj)e}2pO#-JO=zY109(ccCX5'٭e81ȓwCcmM;1cm X˵cн_e 1^NXYE;I] O(=JsEaAd쟿hR!> \peϪc=_^n_.<`B zɺWkp=b{a j6Cڑl݀G$cߚ'_wC W`7=8>Z j|Πgkࠗ719_B]݁w{nW !lV$x{ ُlww)9mk7`*\.X@w|?x$\%??#dw§6qN=ɺ`ل/ҿ_"sll$. IDATUu z;pcK_!p;v&=S m%e^ nyo] ߗmd3?4 Akߎ+ay ,>/?"ndm-W% !̫Qͷ&zy!#d^_k൴=Z&حɾc:lй5 Y/di y1?.Zz~~kiyװ$ڠ:aw.>i5/m|7sBg_qo2bH==!XÚphal =-?>oX07Vi\r AR7 pvq/"9uC]7j zjvpphJ'G O_vHZ1y$P'y= e7cCXB84لj%^&-א 1_!dJTہ PA/siF`SuNڗS$ժߐ $RE~(O iSmud^?ȐcӠ %`SNړ/+FӴ"io+ds*iJ "mfc|Gk>l[neZ,؇l֮!o!6詢'B&|Ɋ4ENj=*֋!Gjvtޱ5|~]ݕ=U>gSs/"kbyTrrN601!ɞ~ l P%!Ueʷm%$b>?<@38Fz}s g@M+5y2 OGܡj pr!7IOU;C' K^lIda K ]0#` s83 C-Xؽ E!2 ;B!cVe^jжY.q5p{ !|q˘TK!]As=Yּ=pVϦ)tfov !Bxo2։{qWd/k p/} ܎݆c`A \m0Qjgoᆪ%ʄ? 4ɨDAiQxEP$G0300|#8 (ID2HAH#4%݋PUu> :wījsڈ|t<Z?ہo/6C߈7KùFИeh22s[+gW8rLkk7ћHD{Qf3ڡ?t޳'61uiUm YcooGĽ#k:z?ʢ룔~aJ܄2K)C;G-f/+lѓ:xK;ՊejcL{ڹ;7"k]BgFCV<}ޏrx$wWWP*]\6:;9AӷYρ"1K'P.se]1L ֠<]gCuQʛsk{X/b)Nߋ~Nxgn^D,Y˛5x.#} ?.:Gf6Q;*Q.WPF }]6"niefԍ)O;W<Cy#~?|@vꮈѲ*fSf\!Z,\}# ;ySG >I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$-fI I42s9`;``3`#``U``6pOn..LMIv4kh*0K\x`w`)~|x舸TIv$IL8 xQ`>>q>k$GaI I4w(4i)`o`<6"^lfԭdjȎ$I=ej|<1]CY䈘?Fyw,, BΚWgkrZF̐xʼB/31q'8YfM{[WԴ0"~?|c\oDuLc*Ė)cc:xO(ODÛ7g汙>L+#1F%<03kzɃUߣf^]Lօڨ>x\o}}:2ᙹ¢otٓrGK<Ы[۹H!^@Z} 3?0Jw^ +ZFx3ћӻ>6k,OO#ѳ}4aKu D}>3yG}V)eVNf7Μgl0Tf<,<}evA>A2bͼ6^~fS;/16Pf F1s>*RQ]^ao݊KmQ=2=슔 xaXx>~P&\^&4 ka e*gPfڷW'(wk\u'"d|kfLPk(gKea-ΥL@gx(C^XYK_ͦcpezn\Y47.;=nﴌxymNlʲ mA-OeFwMd)2ڦdYobجKkt^؃3\뾫j~2nZn<2N5@Y>u_OޟW;(3΢<}2(KMƕ{@Yno67,up˫2;;zmPaDo?LJ=pGd5=jDf\ Z;E[6*MCpְ{(t_jc(~:"n|Rf~>ЁT?]g#MEֲFA܏2fR{{fYFw{^qu@-wZ&k?FYc*e ?.ڰ'o+;tphbIS.0.Dj_ n?qF}n?ei%jga$nFļJj_umbowrLLuJk8/khG`x⏕F(r]Es`ubM;4+OF,zxon<0ɿ7s2J뫭Cf/Ь8سC'c~3#-wRfm3[D=V~$p`;4wzqo}]~xpEcp~JtC4Γ)A:9}a:OM}mD=|+ʰ;efpNNlMyS9Zԋ|8 7~ܔe f 1`Ӥ5mqb߁ ؎^(S)tNGG7Ϣ<-mhUóNt@]맘. wdi9$nw'/{x)Ӎ)#F%kelL$|Z\ fhl&˻x&/{m:KT>#7>q7{9Tfdؾo7@DD ? Nl^qg*Z.=ʈQ7zxW1~egXlگ+esx[cNRv"_'֣U ^sJ273=oztKv'e^} rIC2^k1f^S?SYjf^ЋF$6[z3AmM)!쿝l`GoZ/2K;z=.Н\guɼ#К$bf`n_á[q>Ʃx3 k#Y(GnIYbcSӵ@t}Е^ԉ7\m+VA!~wb #eJ^Tnkl?iҚlН;lq4e͞dz"÷~尗o5 rfD<#)KBL 2_0i˰fk)o=탶K۟؃c&B{ qn5sJyw% (/_AY3\wG5DrMfS+dzeГ; hYu7>$KkL&L%ON7 qngXFM4x8ط>z5e=gN> l3Sl~vY6yK< >hk?׋74/oGob(?ḫ(75&{ ʂԽN㺻ztz=㵆$eeXśyMố2{eisD6.Wgjg}=-G1 탶{- |^fM6?3=W[wVDμ3IgnD8wox׷x3i;}FĻ(32wO7{b]"o2|m}op\>hk5hlGQXOg; w SfuW}w`&pzk a \}2Fhݘ =oN3s1XezpֲFsG*S׻Fߦ~$nfTn?O༆̀Zl>{2bͼa﫝C3s1Eiq+=oN29^ &{G)탶^0}Q{1kͤSo~yI) ל!LAOl|/g1Vf^0nPf[?YИ "󦐤dF !LZkP(p|cUsz\ 1x1`L̕16#Ĉؚ(ՀQצ4=+txeLӁ(cOEGimbNCVZCUn 'xN 0ZiJ oז2 tgz`wڳ ΩQNiqrDKeShm&=H,ŮvRR}"3r<':OOf.Lr;zFpɼ0bl+^V_X8嵻Уwg#bɿ42 Eot~vۀ'q>W4ϝx4{imO229߃u=-#ӷf'pf}z4M?T*ˁ7v;39$5Tzt~ؾ ,5oc>BfmZk)Ḿc#WEyxeyֺK/ǷM 4֐nl_G/޵7rNc_sw̞\qъqkW5on!|s 6{;2rƮ{Mcll__FZf/}[ i(NB%- ~̯t^i-`>EE1k7덍{ 6{nYj[FךFڗ /4v#3Pc#b*S~,3WqprcáӈXhČOY^Mc#fڍI]k45jM>}>vn*gZd*O\kl_Rfњl`7eީF3%}Ѭ7~fn8Ϻ!w}-xRW4v{]}f,LHvZ/!3}@m:5ze'_=yD+auQQs]Zj."0D/,ؾ-? IDAT"p\pj%ovffFf{cUۗ>ۧl0͎ ]|f}ZDrV#{=|]_\:5UxgVIwSiС98z2 ׺1;16Fy'xpFfneimQT+u폴ȍBlܐ'egjSH2۴GMdnjH\#3ߓ}n< q}MPf2Lf^dzey8'S̔\= {:5Sz7ehƍ> |<32tZ ,+ؔrwv9< 4_{2ʹo \z%`.vLjxePt%pnf6Qf\\2{I?b]o|!3vJD ~=w 67Bg՟~8'"ΜW=e@?3W4[06^2A3"fMd7O2{\L¹ClF3۲1p`Ӏw}ӡqkqcf9l ۲i=;ae晵q[Zh7RKyBm?xz͇^k9 2.<4 33 # lF=ݮWz4_LS;xi0wʆ}_ g/(VK^؏ZkR}8?k'. ,e8_7"1Av^;s es=ƪW3)/iL`~>唱Оl6k2~OpEa۸䵈iC沾i>|`8jbsP=#)џ)Ο-1j'\ (w%4ȴ@l,wRx{pˆ^wU19ʽi; o"sشu ͻdL)әTB``nDԃ8;2Բ ֳ}-a?J~e^240|GMw .S [P>OyCz]OQe`t/g۸䵈82MozQfx ͻgFn .'"vk-6#bg?H`yS"⽽,GS͒fק{f)3T+QfU~JYOtuDdP2qצ)>>DYrdcP&XX,ɲȝw . 8?"nR`ܺV/⽏Z~)"~iv75w|-37beJEZ^Nv#+jyqCƿޖL'ergS kcDD{lFeƢm|e9j{/q+Ί_]j)zWsyW=ɹDBW&)3 N7LZCqv kefmP+y/3kc~Y2n ()kXC{v wcS_mHC1uiF f^ ]U66%&4i/ml>϶)oƛdlJ'H}'്ݎ}OxMcS')NteI2$cS=idۀ74v;6"N1$M26%ѓ_Q͙OÀ/6vH$M26%M gLwtf. Gr4s(k0>x&eͣ]eOTג&ؔdGO3֔EUw}?">oJƛdlJNԌ׊WhJƛdlJ'M{Y;Œ%o)Ɏ4Mӣ6GD,0I%M26% L6ջ9"N0)%M26%ѓ*sߋ&dIƦa3$LϠ250XR,󁛁 )/Wr&$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$i[9Y.IENDB`glances-2.11.1/glances/outputs/static/js/000077500000000000000000000000001315472316100202555ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/app.js000066400000000000000000000007701315472316100213770ustar00rootroot00000000000000var glancesApp = angular.module('glancesApp', ['glances.config', 'cfp.hotkeys']) .value('CONFIG', {}) .value('ARGUMENTS', {}) .config(function (hotkeysProvider) { hotkeysProvider.useNgRoute = false; hotkeysProvider.includeCheatSheet = false; }) .run(function ($rootScope, GlancesStats) { $rootScope.title = "Glances"; $rootScope.$on('data_refreshed', function (event, data) { $rootScope.title = data.stats.system.hostname + ' - Glances'; }); GlancesStats.init(); }); glances-2.11.1/glances/outputs/static/js/components/000077500000000000000000000000001315472316100224425ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/glances/000077500000000000000000000000001315472316100240565ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/glances/component.js000066400000000000000000000002401315472316100264120ustar00rootroot00000000000000'use strict'; glancesApp.component('glances', { controller: GlancesController, controllerAs: 'vm', templateUrl: 'components/glances/view.html' }); glances-2.11.1/glances/outputs/static/js/components/glances/controller.js000066400000000000000000000123401315472316100265770ustar00rootroot00000000000000'use strict'; function GlancesController($scope, GlancesStats, hotkeys, ARGUMENTS) { var vm = this; vm.dataLoaded = false; vm.arguments = ARGUMENTS; $scope.$on('data_refreshed', function (event, data) { vm.hasGpu = data.stats.gpu.length > 0; vm.dataLoaded = true; }); // A => Enable/disable AMPs hotkeys.add({ combo: 'A', callback: function () { ARGUMENTS.disable_amps = !ARGUMENTS.disable_amps; } }); // d => Show/hide disk I/O stats hotkeys.add({ combo: 'd', callback: function () { ARGUMENTS.disable_diskio = !ARGUMENTS.disable_diskio; } }); // Q => Show/hide IRQ hotkeys.add({ combo: 'Q', callback: function () { ARGUMENTS.enable_irq = !ARGUMENTS.enable_irq; } }); // f => Show/hide filesystem stats hotkeys.add({ combo: 'f', callback: function () { ARGUMENTS.disable_fs = !ARGUMENTS.disable_fs; } }); // n => Show/hide network stats hotkeys.add({ combo: 'n', callback: function () { ARGUMENTS.disable_network = !ARGUMENTS.disable_network; } }); // s => Show/hide sensors stats hotkeys.add({ combo: 's', callback: function () { ARGUMENTS.disable_sensors = !ARGUMENTS.disable_sensors; } }); // 2 => Show/hide left sidebar hotkeys.add({ combo: '2', callback: function () { ARGUMENTS.disable_left_sidebar = !ARGUMENTS.disable_left_sidebar; } }); // z => Enable/disable processes stats hotkeys.add({ combo: 'z', callback: function () { ARGUMENTS.disable_process = !ARGUMENTS.disable_process; } }); // SLASH => Enable/disable short processes name hotkeys.add({ combo: '/', callback: function () { ARGUMENTS.process_short_name = !ARGUMENTS.process_short_name; } }); // D => Enable/disable Docker stats hotkeys.add({ combo: 'D', callback: function () { ARGUMENTS.disable_docker = !ARGUMENTS.disable_docker; } }); // b => Bytes or bits for network I/O hotkeys.add({ combo: 'b', callback: function () { ARGUMENTS.byte = !ARGUMENTS.byte; } }); // 'B' => Switch between bit/s and IO/s for Disk IO hotkeys.add({ combo: 'B', callback: function () { ARGUMENTS.diskio_iops = !ARGUMENTS.diskio_iops; } }); // l => Show/hide alert logs hotkeys.add({ combo: 'l', callback: function () { ARGUMENTS.disable_alert = !ARGUMENTS.disable_alert; } }); // 1 => Global CPU or per-CPU stats hotkeys.add({ combo: '1', callback: function () { ARGUMENTS.percpu = !ARGUMENTS.percpu; } }); // h => Show/hide this help screen hotkeys.add({ combo: 'h', callback: function () { ARGUMENTS.help_tag = !ARGUMENTS.help_tag; } }); // T => View network I/O as combination hotkeys.add({ combo: 'T', callback: function () { ARGUMENTS.network_sum = !ARGUMENTS.network_sum; } }); // U => View cumulative network I/O hotkeys.add({ combo: 'U', callback: function () { ARGUMENTS.network_cumul = !ARGUMENTS.network_cumul; } }); // F => Show filesystem free space hotkeys.add({ combo: 'F', callback: function () { ARGUMENTS.fs_free_space = !ARGUMENTS.fs_free_space; } }); // 3 => Enable/disable quick look plugin hotkeys.add({ combo: '3', callback: function () { ARGUMENTS.disable_quicklook = !ARGUMENTS.disable_quicklook; } }); // 6 => Enable/disable mean gpu hotkeys.add({ combo: '6', callback: function () { ARGUMENTS.meangpu = !ARGUMENTS.meangpu; } }); // G => Enable/disable gpu hotkeys.add({ combo: 'G', callback: function () { ARGUMENTS.disable_gpu = !ARGUMENTS.disable_gpu; } }); hotkeys.add({ combo: '5', callback: function () { ARGUMENTS.disable_quicklook = !ARGUMENTS.disable_quicklook; ARGUMENTS.disable_cpu = !ARGUMENTS.disable_cpu; ARGUMENTS.disable_mem = !ARGUMENTS.disable_mem; ARGUMENTS.disable_memswap = !ARGUMENTS.disable_memswap; ARGUMENTS.disable_load = !ARGUMENTS.disable_load; ARGUMENTS.disable_gpu = !ARGUMENTS.disable_gpu; } }); // I => Show/hide IP module hotkeys.add({ combo: 'I', callback: function () { ARGUMENTS.disable_ip = !ARGUMENTS.disable_ip; } }); // P => Enable/disable ports module hotkeys.add({ combo: 'P', callback: function () { ARGUMENTS.disable_ports = !ARGUMENTS.disable_ports; } }); // 'W' > Enable/Disable Wifi plugin hotkeys.add({ combo: 'W', callback: function () { ARGUMENTS.disable_wifi = !ARGUMENTS.disable_wifi; } }); } glances-2.11.1/glances/outputs/static/js/components/glances/view.html000066400000000000000000000110471315472316100257210ustar00rootroot00000000000000
Loading...
glances-2.11.1/glances/outputs/static/js/components/help/000077500000000000000000000000001315472316100233725ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/help/component.js000066400000000000000000000002451315472316100257330ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesHelp', { controller: GlancesHelpController, controllerAs: 'vm', templateUrl: 'components/help/view.html' }); glances-2.11.1/glances/outputs/static/js/components/help/controller.js000066400000000000000000000002551315472316100261150ustar00rootroot00000000000000'use strict'; function GlancesHelpController($http) { var vm = this; $http.get('api/2/help').then(function (response) { vm.help = response.data; }); } glances-2.11.1/glances/outputs/static/js/components/help/view.html000066400000000000000000000065021315472316100252350ustar00rootroot00000000000000
{{vm.help.version}} {{vm.help.psutil_version}}
 
{{vm.help.configuration_file}}
 
{{vm.help.sort_auto}}
{{vm.help.sort_network}}
{{vm.help.sort_cpu}}
{{vm.help.show_hide_alert}}
{{vm.help.sort_mem}}
{{vm.help.percpu}}
{{vm.help.sort_user}}
{{vm.help.show_hide_ip}}
{{vm.help.sort_proc}}
{{vm.help.enable_disable_docker}}
{{vm.help.sort_io}}
{{vm.help.view_network_io_combination}}
{{vm.help.sort_cpu_times}}
{{vm.help.view_cumulative_network}}
{{vm.help.show_hide_diskio}}
{{vm.help.show_hide_filesytem_freespace}}
{{vm.help.show_hide_filesystem}}
{{vm.help.show_hide_vm.help}}
{{vm.help.show_hide_network}}
{{vm.help.diskio_iops}}
{{vm.help.show_hide_sensors}}
{{vm.help.show_hide_top_menu}}
{{vm.help.show_hide_left_sidebar}}
{{vm.help.show_hide_amp}}
{{vm.help.enable_disable_process_stats}}
{{vm.help.show_hide_irq}}
{{vm.help.enable_disable_gpu}}
{{vm.help.enable_disable_mean_gpu}}
{{vm.help.enable_disable_quick_look}}
{{vm.help.enable_disable_short_processname}}
{{vm.help.enable_disable_ports}}
glances-2.11.1/glances/outputs/static/js/components/plugin-alert/000077500000000000000000000000001315472316100250455ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-alert/component.js000066400000000000000000000002731315472316100274070ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginAlert', { controller: GlancesPluginAlertController, controllerAs: 'vm', templateUrl: 'components/plugin-alert/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-alert/controller.js000066400000000000000000000036111315472316100275670ustar00rootroot00000000000000'use strict'; function GlancesPluginAlertController($scope, favicoService) { var vm = this; var _alerts = []; $scope.$on('data_refreshed', function (event, data) { var alertStats = data.stats['alert']; if (!_.isArray(alertStats)) { alertStats = []; } _alerts = []; for (var i = 0; i < alertStats.length; i++) { var alertalertStats = alertStats[i]; var alert = {}; alert.name = alertalertStats[3]; alert.level = alertalertStats[2]; alert.begin = alertalertStats[0] * 1000; alert.end = alertalertStats[1] * 1000; alert.ongoing = alertalertStats[1] == -1; alert.min = alertalertStats[6]; alert.mean = alertalertStats[5]; alert.max = alertalertStats[4]; if (!alert.ongoing) { var duration = alert.end - alert.begin; var seconds = parseInt((duration / 1000) % 60) , minutes = parseInt((duration / (1000 * 60)) % 60) , hours = parseInt((duration / (1000 * 60 * 60)) % 24); alert.duration = _.padStart(hours, 2, '0') + ":" + _.padStart(minutes, 2, '0') + ":" + _.padStart(seconds, 2, '0'); } _alerts.push(alert); } if (vm.hasOngoingAlerts()) { favicoService.badge(vm.countOngoingAlerts()); } else { favicoService.reset(); } }); vm.hasAlerts = function () { return _alerts.length > 0; }; vm.getAlerts = function () { return _alerts; }; vm.count = function () { return _alerts.length; }; vm.hasOngoingAlerts = function () { return _.filter(_alerts, {'ongoing': true}).length > 0; }; vm.countOngoingAlerts = function () { return _.filter(_alerts, {'ongoing': true}).length; } } glances-2.11.1/glances/outputs/static/js/components/plugin-alert/view.html000066400000000000000000000013661315472316100267130ustar00rootroot00000000000000
No warning or critical alert detected Warning or critical alerts (lasts {{vm.count()}} entries)
{{alert.begin | date : 'yyyy-MM-dd H:mm:ss'}} ({{ alert.ongoing ? 'ongoing' : alert.duration }}) - {{alert.level}} on {{alert.name}} ({{alert.max}})
glances-2.11.1/glances/outputs/static/js/components/plugin-amps/000077500000000000000000000000001315472316100246765ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-amps/component.js000066400000000000000000000002701315472316100272350ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginAmps', { controller: GlancesPluginAmpsController, controllerAs: 'vm', templateUrl: 'components/plugin-amps/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-amps/controller.js000066400000000000000000000022201315472316100274130ustar00rootroot00000000000000'use strict'; function GlancesPluginAmpsController($scope, GlancesStats, favicoService) { var vm = this; vm.processes = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var processes = data.stats['amps']; vm.processes = []; angular.forEach(processes, function (process) { if (process.result !== null) { vm.processes.push(process); } }, this); }; vm.getDescriptionDecoration = function (process) { var count = process.count; var countMin = process.countmin; var countMax = process.countmax; var decoration = "ok"; if (count > 0) { if ((countMin === null || count >= countMin) && (countMax === null || count <= countMax)) { decoration = 'ok'; } else { decoration = 'careful'; } } else { decoration = countMin === null ? 'ok' : 'critical'; } return decoration; } } glances-2.11.1/glances/outputs/static/js/components/plugin-amps/view.html000066400000000000000000000006731315472316100265440ustar00rootroot00000000000000
{{ process.name }}
{{ process.count }}
{{ process.result }}
glances-2.11.1/glances/outputs/static/js/components/plugin-cloud/000077500000000000000000000000001315472316100250445ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-cloud/component.js000066400000000000000000000002731315472316100274060ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginCloud', { controller: GlancesPluginCloudController, controllerAs: 'vm', templateUrl: 'components/plugin-cloud/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-cloud/controller.js000066400000000000000000000011501315472316100275620ustar00rootroot00000000000000'use strict'; function GlancesPluginCloudController($scope, GlancesStats) { var vm = this; vm.provider = null; vm.instance = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['cloud']; if (stats['ami-id'] !== undefined) { vm.provider = 'AWS EC2'; vm.instance = stats['instance-type'] + ' instance ' + stats['instance-id'] + ' (' + stats['region'] + ')'; } } } glances-2.11.1/glances/outputs/static/js/components/plugin-cloud/view.html000066400000000000000000000001431315472316100267020ustar00rootroot00000000000000
{{ vm.provider }} {{ vm.instance }}
glances-2.11.1/glances/outputs/static/js/components/plugin-cpu/000077500000000000000000000000001315472316100245255ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-cpu/component.js000066400000000000000000000002651315472316100270700ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginCpu', { controller: GlancesPluginCpuController, controllerAs: 'vm', templateUrl: 'components/plugin-cpu/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-cpu/controller.js000066400000000000000000000031401315472316100272440ustar00rootroot00000000000000'use strict'; function GlancesPluginCpuController($scope, GlancesStats) { var vm = this; var _view = {}; vm.total = null; vm.user = null; vm.system = null; vm.idle = null; vm.nice = null; vm.irq = null; vm.iowait = null; vm.steal = null; vm.ctx_switches = null; vm.interrupts = null; vm.soft_interrupts = null; vm.syscalls = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['cpu']; _view = data.views['cpu']; vm.total = stats.total; vm.user = stats.user; vm.system = stats.system; vm.idle = stats.idle; vm.nice = stats.nice; vm.irq = stats.irq; vm.iowait = stats.iowait; vm.steal = stats.steal; if (stats.ctx_switches) { vm.ctx_switches = Math.floor(stats.ctx_switches / stats.time_since_update); } if (stats.interrupts) { vm.interrupts = Math.floor(stats.interrupts / stats.time_since_update); } if (stats.soft_interrupts) { vm.soft_interrupts = Math.floor(stats.soft_interrupts / stats.time_since_update); } if (stats.syscalls) { vm.syscalls = Math.floor(stats.syscalls / stats.time_since_update); } } vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-cpu/view.html000066400000000000000000000072101315472316100263650ustar00rootroot00000000000000
CPU
{{ vm.total }}%
user:
{{ vm.user }}%
system:
{{ vm.system }}%
idle:
{{ vm.idle }}%
glances-2.11.1/glances/outputs/static/js/components/plugin-diskio/000077500000000000000000000000001315472316100252205ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-diskio/component.js000066400000000000000000000002761315472316100275650ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginDiskio', { controller: GlancesPluginDiskioController, controllerAs: 'vm', templateUrl: 'components/plugin-diskio/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-diskio/controller.js000066400000000000000000000023401315472316100277400ustar00rootroot00000000000000'use strict'; function GlancesPluginDiskioController($scope, $filter, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.disks = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['diskio'] || []; stats = $filter('orderBy')(stats, 'disk_name'); vm.disks = stats.map(function(diskioData) { var timeSinceUpdate = diskioData['time_since_update']; return { 'name': diskioData['disk_name'], 'bitrate': { 'txps': $filter('bytes')(diskioData['read_bytes'] / timeSinceUpdate), 'rxps': $filter('bytes')(diskioData['write_bytes'] / timeSinceUpdate) }, 'count': { 'txps': $filter('bytes')(diskioData['read_count'] / timeSinceUpdate), 'rxps': $filter('bytes')(diskioData['write_count'] / timeSinceUpdate) }, 'alias': diskioData['alias'] !== undefined ? diskioData['alias'] : null }; }); } } glances-2.11.1/glances/outputs/static/js/components/plugin-diskio/view.html000066400000000000000000000016571315472316100270710ustar00rootroot00000000000000
DISK I/O
R/s
W/s
IOR/s
IOW/s
{{(disk.alias ? disk.alias : disk.name) | min_size:9}}
{{disk.bitrate.txps }}
{{disk.bitrate.rxps }}
{{disk.count.txps }}
{{disk.count.rxps }}
glances-2.11.1/glances/outputs/static/js/components/plugin-docker/000077500000000000000000000000001315472316100252055ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-docker/component.js000066400000000000000000000002761315472316100275520ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginDocker', { controller: GlancesPluginDockerController, controllerAs: 'vm', templateUrl: 'components/plugin-docker/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-docker/controller.js000066400000000000000000000030731315472316100277310ustar00rootroot00000000000000'use strict'; function GlancesPluginDockerController($scope, GlancesStats) { var vm = this; vm.containers = []; vm.version = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['docker']; vm.containers = []; if (_.isEmpty(stats)) { return; } vm.containers = stats['containers'].map(function(containerData) { return { 'id': containerData.Id, 'name': containerData.Names[0].split('/').splice(-1)[0], 'status': containerData.Status, 'cpu': containerData.cpu.total, 'memory': containerData.memory.usage != undefined ? containerData.memory.usage : '?', 'ior': containerData.io.ior != undefined ? containerData.io.ior : '?', 'iow': containerData.io.iow != undefined ? containerData.io.iow : '?', 'io_time_since_update': containerData.io.time_since_update, 'rx': containerData.network.rx != undefined ? containerData.network.rx : '?', 'tx': containerData.network.tx != undefined ? containerData.network.tx : '?', 'net_time_since_update': containerData.network.time_since_update, 'command': containerData.Command, 'image': containerData.Image }; }); vm.version = stats['version']['Version']; } } glances-2.11.1/glances/outputs/static/js/components/plugin-docker/view.html000066400000000000000000000032111315472316100270420ustar00rootroot00000000000000
CONTAINERS {{ vm.containers.length }} (served by Docker {{ vm.version }})
Name
Status
CPU%
MEM
IOR/s
IOW/s
RX/s
TX/s
Command
{{ container.name }}
{{ container.status }}
{{ container.cpu | number:1 }}
{{ container.memory | bytes }}
{{ container.ior / container.io_time_since_update | bits }}
{{ container.iow / container.io_time_since_update | bits }}
{{ container.rx / container.net_time_since_update | bits }}
{{ container.tx / container.net_time_since_update | bits }}
{{ container.command }}
glances-2.11.1/glances/outputs/static/js/components/plugin-folders/000077500000000000000000000000001315472316100253745ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-folders/component.js000066400000000000000000000002741315472316100277370ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginFolders', { controller: GlancesPluginFsController, controllerAs: 'vm', templateUrl: 'components/plugin-folders/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-folders/controller.js000066400000000000000000000024751315472316100301250ustar00rootroot00000000000000'use strict'; function GlancesPluginFoldersController($scope, GlancesStats) { var vm = this; vm.folders = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['folders']; vm.folders = []; for (var i = 0; i < stats.length; i++) { var folderData = stats[i]; var folder = { 'path': folderData['path'], 'size': folderData['size'], 'careful': folderData['careful'], 'warning': folderData['warning'], 'critical': folderData['critical'] }; vm.folders.push(folder); } } vm.getDecoration = function (folder) { if (!Number.isInteger(folder.size)) { return; } if (folder.critical !== null && folder.size > (folder.critical * 1000000)) { return 'critical'; } else if (folder.warning !== null && folder.size > (folder.warning * 1000000)) { return 'warning'; } else if (folder.careful !== null && folder.size > (folder.careful * 1000000)) { return 'careful'; } return 'ok'; }; } glances-2.11.1/glances/outputs/static/js/components/plugin-folders/view.html000066400000000000000000000005741315472316100272420ustar00rootroot00000000000000
FOLDERS
Size
{{ folder.path }}
{{ folder.size | bytes }}
glances-2.11.1/glances/outputs/static/js/components/plugin-fs/000077500000000000000000000000001315472316100243465ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-fs/component.js000066400000000000000000000002621315472316100267060ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginFs', { controller: GlancesPluginFsController, controllerAs: 'vm', templateUrl: 'components/plugin-fs/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-fs/controller.js000066400000000000000000000026501315472316100270720ustar00rootroot00000000000000'use strict'; function GlancesPluginFsController($scope, $filter, GlancesStats, ARGUMENTS) { var vm = this; var _view = {}; vm.arguments = ARGUMENTS; vm.fileSystems = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['fs']; _view = data.views['fs']; vm.fileSystems = []; for (var i = 0; i < stats.length; i++) { var fsData = stats[i]; var shortMountPoint = fsData['mnt_point']; if (shortMountPoint.length > 9) { shortMountPoint = '_' + fsData['mnt_point'].slice(-8); } vm.fileSystems.push(fs = { 'name': fsData['device_name'], 'mountPoint': fsData['mnt_point'], 'shortMountPoint': shortMountPoint, 'percent': fsData['percent'], 'size': fsData['size'], 'used': fsData['used'], 'free': fsData['free'] }); } vm.fileSystems = $filter('orderBy')(vm.fileSystems, 'mnt_point'); }; vm.getDecoration = function (mountPoint, field) { if (_view[mountPoint][field] == undefined) { return; } return _view[mountPoint][field].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-fs/view.html000066400000000000000000000016011315472316100262040ustar00rootroot00000000000000
FILE SYS
Used Free
Total
{{ fs.shortMountPoint }} ({{ fs.name }})
{{ fs.used | bytes }} {{ fs.free | bytes }}
{{ fs.size | bytes }}
glances-2.11.1/glances/outputs/static/js/components/plugin-gpu/000077500000000000000000000000001315472316100245315ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-gpu/component.js000066400000000000000000000002651315472316100270740ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginGpu', { controller: GlancesPluginGpuController, controllerAs: 'vm', templateUrl: 'components/plugin-gpu/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-gpu/controller.js000066400000000000000000000027721315472316100272620ustar00rootroot00000000000000'use strict'; function GlancesPluginGpuController($scope, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; var _view = {}; vm.gpus = []; vm.name = "GPU"; vm.mean = {}; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['gpu']; _view = data.views['gpu']; if (stats.length === 0) { return; } vm.gpus = []; vm.name = "GPU"; vm.mean = { proc: null, mem: null }; var sameName = true; for (var i = 0; i < stats.length; i++) { var gpuData = stats[i]; var gpu = gpuData; vm.mean.proc += gpu.proc; vm.mean.mem += gpu.mem; vm.gpus.push(gpu); } if (stats.length === 1) { vm.name = stats[0].name; } else if (sameName) { vm.name = stats.length + ' GPU ' + stats[0].name; } vm.mean.proc = vm.mean.proc / stats.length; vm.mean.mem = vm.mean.mem / stats.length; } vm.getDecoration = function (gpuId, value) { if (_view[gpuId][value] == undefined) { return; } return _view[gpuId][value].decoration.toLowerCase(); }; vm.getMeanDecoration = function (value) { return vm.getDecoration(0, value); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-gpu/view.html000066400000000000000000000027671315472316100264050ustar00rootroot00000000000000
{{ vm.name }}
proc:
{{ vm.mean.proc | number : 0 }}%
N/A
mem:
{{ vm.mean.mem | number : 0 }}%
N/A
{{ gpu.gpu_id }}: {{ gpu.proc | number : 0 }}% N/A mem: {{ gpu.mem | number : 0 }}% N/A
glances-2.11.1/glances/outputs/static/js/components/plugin-ip/000077500000000000000000000000001315472316100243465ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-ip/component.js000066400000000000000000000002621315472316100267060ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginIp', { controller: GlancesPluginIpController, controllerAs: 'vm', templateUrl: 'components/plugin-ip/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-ip/controller.js000066400000000000000000000013101315472316100270620ustar00rootroot00000000000000'use strict'; function GlancesPluginIpController($scope, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.address = null; vm.gateway = null; vm.mask = null; vm.maskCidr = null; vm.publicAddress = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var ipStats = data.stats['ip']; vm.address = ipStats.address; vm.gateway = ipStats.gateway; vm.mask = ipStats.mask; vm.maskCidr = ipStats.mask_cidr; vm.publicAddress = ipStats.public_address } } glances-2.11.1/glances/outputs/static/js/components/plugin-ip/view.html000066400000000000000000000004531315472316100262100ustar00rootroot00000000000000
 - IP {{ vm.address }}/{{ vm.maskCidr }} Pub {{ vm.publicAddress }}
glances-2.11.1/glances/outputs/static/js/components/plugin-irq/000077500000000000000000000000001315472316100245315ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-irq/component.js000066400000000000000000000002651315472316100270740ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginIrq', { controller: GlancesPluginIrqController, controllerAs: 'vm', templateUrl: 'components/plugin-irq/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-irq/controller.js000066400000000000000000000012201315472316100272450ustar00rootroot00000000000000'use strict'; function GlancesPluginIrqController($scope, GlancesStats) { var vm = this; vm.irqs = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['irq']; vm.irqs = []; for (var i = 0; i < stats.length; i++) { var IrqData = stats[i]; var irq = { 'irq_line': IrqData['irq_line'], 'irq_rate': IrqData['irq_rate'] }; vm.irqs.push(irq); } } } glances-2.11.1/glances/outputs/static/js/components/plugin-irq/view.html000066400000000000000000000006261315472316100263750ustar00rootroot00000000000000
IRQ
Rate/s
{{irq.irq_line}}
{{irq.irq_rate}}
glances-2.11.1/glances/outputs/static/js/components/plugin-load/000077500000000000000000000000001315472316100246555ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-load/component.js000066400000000000000000000002701315472316100272140ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginLoad', { controller: GlancesPluginLoadController, controllerAs: 'vm', templateUrl: 'components/plugin-load/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-load/controller.js000066400000000000000000000014551315472316100274030ustar00rootroot00000000000000'use strict'; function GlancesPluginLoadController($scope, GlancesStats) { var vm = this; var _view = {}; vm.cpucore = null; vm.min1 = null; vm.min5 = null; vm.min15 = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['load']; _view = data.views['load']; vm.cpucore = stats['cpucore']; vm.min1 = stats['min1']; vm.min5 = stats['min5']; vm.min15 = stats['min15']; }; vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-load/view.html000066400000000000000000000017161315472316100265220ustar00rootroot00000000000000
LOAD
{{ vm.cpucore }}-core
1 min:
{{ vm.min1 | number : 2}}
5 min:
{{ vm.min5 | number : 2}}
15 min:
{{ vm.min15 | number : 2}}
glances-2.11.1/glances/outputs/static/js/components/plugin-mem-more/000077500000000000000000000000001315472316100254545ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-mem-more/component.js000066400000000000000000000003021315472316100300070ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginMemMore', { controller: GlancesPluginMemMoreController, controllerAs: 'vm', templateUrl: 'components/plugin-mem-more/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-mem-more/controller.js000066400000000000000000000011321315472316100301720ustar00rootroot00000000000000'use strict'; function GlancesPluginMemMoreController($scope, GlancesStats) { var vm = this; vm.active = null; vm.inactive = null; vm.buffers = null; vm.cached = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['mem']; vm.active = stats['active']; vm.inactive = stats['inactive']; vm.buffers = stats['buffers']; vm.cached = stats['cached']; } } glances-2.11.1/glances/outputs/static/js/components/plugin-mem-more/view.html000066400000000000000000000016261315472316100273210ustar00rootroot00000000000000
active:
{{ vm.active | bytes }}
inactive:
{{ vm.inactive | bytes }}
buffers:
{{ vm.buffers | bytes }}
cached:
{{ vm.cached | bytes }}
glances-2.11.1/glances/outputs/static/js/components/plugin-mem/000077500000000000000000000000001315472316100245145ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-mem/component.js000066400000000000000000000002651315472316100270570ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginMem', { controller: GlancesPluginMemController, controllerAs: 'vm', templateUrl: 'components/plugin-mem/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-mem/controller.js000066400000000000000000000014511315472316100272360ustar00rootroot00000000000000'use strict'; function GlancesPluginMemController($scope, GlancesStats) { var vm = this; var _view = {}; vm.percent = null; vm.total = null; vm.used = null; vm.free = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['mem']; _view = data.views['mem']; vm.percent = stats['percent']; vm.total = stats['total']; vm.used = stats['used']; vm.free = stats['free']; } vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-mem/view.html000066400000000000000000000014721315472316100263600ustar00rootroot00000000000000
MEM
{{ vm.percent }}%
total:
{{ vm.total | bytes }}
used:
{{ vm.used | bytes:2 }}
free:
{{ vm.free | bytes }}
glances-2.11.1/glances/outputs/static/js/components/plugin-memswap/000077500000000000000000000000001315472316100254075ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-memswap/component.js000066400000000000000000000003011315472316100277410ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginMemswap', { controller: GlancesPluginMemswapController, controllerAs: 'vm', templateUrl: 'components/plugin-memswap/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-memswap/controller.js000066400000000000000000000014661315472316100301370ustar00rootroot00000000000000'use strict'; function GlancesPluginMemswapController($scope, GlancesStats) { var vm = this; var _view = {}; vm.percent = null; vm.total = null; vm.used = null; vm.free = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['memswap']; _view = data.views['memswap']; vm.percent = stats['percent']; vm.total = stats['total']; vm.used = stats['used']; vm.free = stats['free']; }; vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-memswap/view.html000066400000000000000000000014751315472316100272560ustar00rootroot00000000000000
SWAP
{{ vm.percent }}%
total:
{{ vm.total | bytes }}
used:
{{ vm.used | bytes }}
free:
{{ vm.free | bytes }}
glances-2.11.1/glances/outputs/static/js/components/plugin-network/000077500000000000000000000000001315472316100254275ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-network/component.js000066400000000000000000000003011315472316100277610ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginNetwork', { controller: GlancesPluginNetworkController, controllerAs: 'vm', templateUrl: 'components/plugin-network/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-network/controller.js000066400000000000000000000022321315472316100301470ustar00rootroot00000000000000'use strict'; function GlancesPluginNetworkController($scope, $filter, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.networks = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var networkStats = data.stats['network']; vm.networks = []; for (var i = 0; i < networkStats.length; i++) { var networkData = networkStats[i]; var network = { 'interfaceName': networkData['interface_name'], 'rx': networkData['rx'], 'tx': networkData['tx'], 'cx': networkData['cx'], 'time_since_update': networkData['time_since_update'], 'cumulativeRx': networkData['cumulative_rx'], 'cumulativeTx': networkData['cumulative_tx'], 'cumulativeCx': networkData['cumulative_cx'] }; vm.networks.push(network); } vm.networks = $filter('orderBy')(vm.networks, 'interfaceName'); } } glances-2.11.1/glances/outputs/static/js/components/plugin-network/view.html000066400000000000000000000051051315472316100272700ustar00rootroot00000000000000
NETWORK
Rx/s
Tx/s
Rx+Tx/s
Rx
Tx
Rx+Tx
{{ network.interfaceName | min_size }}
{{ vm.arguments.byte ? (network.rx / network.time_since_update | bytes) : (network.rx / network.time_since_update | bits) }}
{{ vm.arguments.byte ? (network.tx / network.time_since_update | bytes) : (network.tx / network.time_since_update | bits) }}
{{ vm.arguments.byte ? (network.cx / network.time_since_update | bytes) : (network.cx / network.time_since_update | bits) }}
{{ vm.arguments.byte ? (network.cumulativeRx | bytes) : (network.cumulativeRx | bits) }}
{{ vm.arguments.byte ? (network.cumulativeTx | bytes) : (network.cumulativeTx | bits) }}
{{ vm.arguments.byte ? (network.cumulativeCx | bytes) : (network.cumulativeCx | bits) }}
glances-2.11.1/glances/outputs/static/js/components/plugin-percpu/000077500000000000000000000000001315472316100252345ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-percpu/component.js000066400000000000000000000002761315472316100276010ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginPercpu', { controller: GlancesPluginPercpuController, controllerAs: 'vm', templateUrl: 'components/plugin-percpu/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-percpu/controller.js000066400000000000000000000021431315472316100277550ustar00rootroot00000000000000'use strict'; function GlancesPluginPercpuController($scope, GlancesStats, GlancesPluginHelper) { var vm = this; vm.cpus = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var percpuStats = data.stats['percpu']; vm.cpus = []; for (var i = 0; i < percpuStats.length; i++) { var cpuData = percpuStats[i]; vm.cpus.push({ 'number': cpuData.cpu_number, 'total': cpuData.total, 'user': cpuData.user, 'system': cpuData.system, 'idle': cpuData.idle, 'iowait': cpuData.iowait, 'steal': cpuData.steal }); } } vm.getUserAlert = function (cpu) { return GlancesPluginHelper.getAlert('percpu', 'percpu_user_', cpu.user) }; vm.getSystemAlert = function (cpu) { return GlancesPluginHelper.getAlert('percpu', 'percpu_system_', cpu.system); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-percpu/view.html000066400000000000000000000034111315472316100270730ustar00rootroot00000000000000
PER CPU
{{ percpu.total }}%
user:
{{ percpu.user }}%
system:
{{ percpu.system }}%
idle:
{{ percpu.idle }}%
iowait:
{{ percpu.iowait }}%
steal:
{{ percpu.steal }}%
glances-2.11.1/glances/outputs/static/js/components/plugin-ports/000077500000000000000000000000001315472316100251055ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-ports/component.js000066400000000000000000000002731315472316100274470ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginPorts', { controller: GlancesPluginPortsController, controllerAs: 'vm', templateUrl: 'components/plugin-ports/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-ports/controller.js000066400000000000000000000015101315472316100276230ustar00rootroot00000000000000'use strict'; function GlancesPluginPortsController($scope, GlancesStats) { var vm = this; vm.ports = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['ports']; vm.ports = []; angular.forEach(stats, function (port) { vm.ports.push(port); }, this); } vm.getDecoration = function (port) { if (port.status === null) { return 'careful'; } if (port.status === false) { return 'critical'; } if (port.rtt_warning !== null && port.status > port.rtt_warning) { return 'warning'; } return 'ok'; }; } glances-2.11.1/glances/outputs/static/js/components/plugin-ports/view.html000066400000000000000000000010651315472316100267470ustar00rootroot00000000000000
{{(port.description ? port.description : port.host + ' ' + port.port) | min_size: 20}}
Scanning Timeout Open {{port.status * 1000.0 | number:0}}ms
glances-2.11.1/glances/outputs/static/js/components/plugin-process/000077500000000000000000000000001315472316100254145ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-process/component.js000066400000000000000000000003011315472316100277460ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginProcess', { controller: GlancesPluginProcessController, controllerAs: 'vm', templateUrl: 'components/plugin-process/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-process/controller.js000066400000000000000000000037201315472316100301370ustar00rootroot00000000000000'use strict'; function GlancesPluginProcessController(ARGUMENTS, hotkeys) { var vm = this; vm.arguments = ARGUMENTS; vm.sorter = { column: "cpu_percent", auto: true, isReverseColumn: function (column) { return !(column === 'username' || column === 'name'); }, getColumnLabel: function (column) { if (_.isEqual(column, ['io_read', 'io_write'])) { return 'io_counters'; } else { return column; } } }; // a => Sort processes automatically hotkeys.add({ combo: 'a', callback: function () { vm.sorter.column = "cpu_percent"; vm.sorter.auto = true; } }); // c => Sort processes by CPU% hotkeys.add({ combo: 'c', callback: function () { vm.sorter.column = "cpu_percent"; vm.sorter.auto = false; } }); // m => Sort processes by MEM% hotkeys.add({ combo: 'm', callback: function () { vm.sorter.column = "memory_percent"; vm.sorter.auto = false; } }); // u => Sort processes by user hotkeys.add({ combo: 'u', callback: function () { vm.sorter.column = "username"; vm.sorter.auto = false; } }); // p => Sort processes by name hotkeys.add({ combo: 'p', callback: function () { vm.sorter.column = "name"; vm.sorter.auto = false; } }); // i => Sort processes by I/O rate hotkeys.add({ combo: 'i', callback: function () { vm.sorter.column = ['io_read', 'io_write']; vm.sorter.auto = false; } }); // t => Sort processes by time hotkeys.add({ combo: 't', callback: function () { vm.sorter.column = "timemillis"; vm.sorter.auto = false; } }); } glances-2.11.1/glances/outputs/static/js/components/plugin-process/view.html000066400000000000000000000007341315472316100272600ustar00rootroot00000000000000
PROCESSES DISABLED (press 'z' to display)
glances-2.11.1/glances/outputs/static/js/components/plugin-processcount/000077500000000000000000000000001315472316100264655ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-processcount/component.js000066400000000000000000000003731315472316100310300ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginProcesscount', { controller: GlancesPluginProcesscountController, controllerAs: 'vm', bindings: { sorter: '<' }, templateUrl: 'components/plugin-processcount/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-processcount/controller.js000066400000000000000000000014041315472316100312050ustar00rootroot00000000000000'use strict'; function GlancesPluginProcesscountController($scope, GlancesStats) { var vm = this; vm.total = null; vm.running = null; vm.sleeping = null; vm.stopped = null; vm.thread = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var processcountStats = data.stats['processcount']; vm.total = processcountStats['total'] || 0; vm.running = processcountStats['running'] || 0; vm.sleeping = processcountStats['sleeping'] || 0; vm.stopped = processcountStats['stopped'] || 0; vm.thread = processcountStats['thread'] || 0; } } glances-2.11.1/glances/outputs/static/js/components/plugin-processcount/view.html000066400000000000000000000006121315472316100303240ustar00rootroot00000000000000
TASKS {{ vm.total }} ({{ vm.thread }} thr), {{ vm.running }} run, {{ vm.sleeping }} slp, {{ vm.stopped }} oth sorted {{ vm.sorter.auto ? 'automatically' : '' }} by {{ vm.sorter.getColumnLabel(vm.sorter.column) }}, flat view
glances-2.11.1/glances/outputs/static/js/components/plugin-processlist/000077500000000000000000000000001315472316100263105ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-processlist/component.js000066400000000000000000000003701315472316100306500ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginProcesslist', { controller: GlancesPluginProcesslistController, controllerAs: 'vm', bindings: { sorter: '<' }, templateUrl: 'components/plugin-processlist/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-processlist/controller.js000066400000000000000000000047411315472316100310370ustar00rootroot00000000000000'use strict'; function GlancesPluginProcesslistController($scope, GlancesStats, GlancesPluginHelper, $filter, CONFIG, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.processes = []; vm.ioReadWritePresent = false; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var processlistStats = data.stats['processlist'] || []; vm.processes = []; vm.ioReadWritePresent = false; for (var i = 0; i < processlistStats.length; i++) { var process = processlistStats[i]; process.memvirt = process.memory_info[1]; process.memres = process.memory_info[0]; process.timeplus = $filter('timedelta')(process.cpu_times); process.timemillis = $filter('timemillis')(process.cpu_times); process.ioRead = null; process.ioWrite = null; if (process.io_counters) { vm.ioReadWritePresent = true; process.ioRead = (process.io_counters[0] - process.io_counters[2]) / process.time_since_update; if (process.ioRead != 0) { process.ioRead = $filter('bytes')(process.ioRead); } process.ioWrite = (process.io_counters[1] - process.io_counters[3]) / process.time_since_update; if (process.ioWrite != 0) { process.ioWrite = $filter('bytes')(process.ioWrite); } } process.isNice = process.nice !== undefined && ((data.stats.isWindows && process.nice != 32) || (!data.stats.isWindows && process.nice != 0)); if (Array.isArray(process.cmdline)) { process.cmdline = process.cmdline.join(' '); } if (data.isWindows) { process.username = _.last(process.username.split('\\')); } vm.processes.push(process); } } vm.getCpuPercentAlert = function (process) { return GlancesPluginHelper.getAlert('processlist', 'processlist_cpu_', process.cpu_percent); }; vm.getMemoryPercentAlert = function (process) { return GlancesPluginHelper.getAlert('processlist', 'processlist_mem_', process.cpu_percent); }; vm.getLimit = function () { return CONFIG.outputs !== undefined ? CONFIG.outputs.max_processes_display : undefined; }; } glances-2.11.1/glances/outputs/static/js/components/plugin-processlist/view.html000066400000000000000000000061341315472316100301540ustar00rootroot00000000000000
CPU%
MEM%
PID
USER
NI
S
Command
{{process.cpu_percent | number:1}}
{{process.memory_percent | number:1}}
{{process.pid}}
{{process.username}}
{{process.nice | exclamation}}
{{process.status}}
{{process.name}}
{{process.cmdline}}
glances-2.11.1/glances/outputs/static/js/components/plugin-quicklook/000077500000000000000000000000001315472316100257375ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-quicklook/component.js000066400000000000000000000003071315472316100302770ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginQuicklook', { controller: GlancesPluginQuicklookController, controllerAs: 'vm', templateUrl: 'components/plugin-quicklook/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-quicklook/controller.js000066400000000000000000000023161315472316100304620ustar00rootroot00000000000000'use strict'; function GlancesPluginQuicklookController($scope, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; var _view = {}; vm.mem = null; vm.cpu = null; vm.cpu_name = null; vm.cpu_hz_current = null; vm.cpu_hz = null; vm.swap = null; vm.percpus = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['quicklook']; _view = data.views['quicklook']; vm.mem = stats.mem; vm.cpu = stats.cpu; vm.cpu_name = stats.cpu_name; vm.cpu_hz_current = stats.cpu_hz_current; vm.cpu_hz = stats.cpu_hz; vm.swap = stats.swap; vm.percpus = []; angular.forEach(stats.percpu, function (cpu) { vm.percpus.push({ 'number': cpu.cpu_number, 'total': cpu.total }); }, this); }; vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-quicklook/view.html000066400000000000000000000053541315472316100276060ustar00rootroot00000000000000
{{ vm.cpu_name }}
CPU
 
{{ vm.cpu }}%
CPU{{ percpu.number }}
 
{{ percpu.total }}%
MEM
 
{{ vm.mem }}%
SWAP
 
{{ vm.swap }}%
glances-2.11.1/glances/outputs/static/js/components/plugin-raid/000077500000000000000000000000001315472316100246555ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-raid/component.js000066400000000000000000000002701315472316100272140ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginRaid', { controller: GlancesPluginRaidController, controllerAs: 'vm', templateUrl: 'components/plugin-raid/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-raid/controller.js000066400000000000000000000030121315472316100273720ustar00rootroot00000000000000'use strict'; function GlancesPluginRaidController($scope, GlancesStats) { var vm = this; vm.disks = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var disks = []; var stats = data.stats['raid']; _.forIn(stats, function (diskData, diskKey) { var disk = { 'name': diskKey, 'type': diskData.type == null ? 'UNKNOWN' : diskData.type, 'used': diskData.used, 'available': diskData.available, 'status': diskData.status, 'degraded': diskData.used < diskData.available, 'config': diskData.config == null ? '' : diskData.config.replace('_', 'A'), 'inactive': diskData.status == 'inactive', 'components': [] }; _.forEach(diskData.components, function (number, name) { disk.components.push({ 'number': number, 'name': name }); }); disks.push(disk); }); vm.disks = disks; }; vm.hasDisks = function () { return vm.disks.length > 0; }; vm.getAlert = function (disk) { if (disk.inactive) { return 'critical'; } if (disk.degraded) { return 'warning'; } return 'ok' }; } glances-2.11.1/glances/outputs/static/js/components/plugin-raid/view.html000066400000000000000000000020521315472316100265140ustar00rootroot00000000000000
RAID disks
Used
Total
{{ disk.type | uppercase }} {{ disk.name }}
└─ Degraded mode
   └─ {{ disk.config }}
└─ Status {{ disk.status }}
   {{ $last ? '└─' : '├─' }} disk {{ component.number }}: {{ component.name }}
{{ disk.used }}
{{ disk.available }}
glances-2.11.1/glances/outputs/static/js/components/plugin-sensors/000077500000000000000000000000001315472316100254325ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-sensors/component.js000066400000000000000000000003011315472316100277640ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginSensors', { controller: GlancesPluginSensorsController, controllerAs: 'vm', templateUrl: 'components/plugin-sensors/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-sensors/controller.js000066400000000000000000000014531315472316100301560ustar00rootroot00000000000000'use strict'; function GlancesPluginSensorsController($scope, GlancesStats, GlancesPluginHelper) { var vm = this; vm.sensors = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['sensors']; _.remove(stats, function (sensor) { return (_.isArray(sensor.value) && _.isEmpty(sensor.value)) || sensor.value === 0; }); vm.sensors = stats; }; vm.getAlert = function (sensor) { var current = sensor.type == 'battery' ? 100 - sensor.value : sensor.value; return GlancesPluginHelper.getAlert('sensors', 'sensors_' + sensor.type + '_', current); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-sensors/view.html000066400000000000000000000005771315472316100273030ustar00rootroot00000000000000
SENSORS
{{ sensor.label }}
{{ sensor.unit }}
{{ sensor.value }}
glances-2.11.1/glances/outputs/static/js/components/plugin-system/000077500000000000000000000000001315472316100252625ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-system/component.js000066400000000000000000000002761315472316100276270ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginSystem', { controller: GlancesPluginSystemController, controllerAs: 'vm', templateUrl: 'components/plugin-system/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-system/controller.js000066400000000000000000000015201315472316100300010ustar00rootroot00000000000000'use strict'; function GlancesPluginSystemController($scope, GlancesStats) { var vm = this; vm.hostname = null; vm.platform = null; vm.humanReadableName = null; vm.os = { 'name': null, 'version': null }; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); $scope.$on('is_disconnected', function () { vm.isDisconnected = true; }); var loadData = function (data) { var stats = data.stats['system']; vm.hostname = stats['hostname']; vm.platform = stats['platform']; vm.os.name = stats['os_name']; vm.os.version = stats['os_version']; vm.humanReadableName = stats['hr_name']; vm.isDisconnected = false; } } glances-2.11.1/glances/outputs/static/js/components/plugin-system/view.html000066400000000000000000000006641315472316100271300ustar00rootroot00000000000000
Disconnected from {{ vm.hostname }}
glances-2.11.1/glances/outputs/static/js/components/plugin-uptime/000077500000000000000000000000001315472316100252415ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-uptime/component.js000066400000000000000000000002761315472316100276060ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginUptime', { controller: GlancesPluginUptimeController, controllerAs: 'vm', templateUrl: 'components/plugin-uptime/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-uptime/controller.js000066400000000000000000000005711315472316100277650ustar00rootroot00000000000000'use strict'; function GlancesPluginUptimeController($scope, GlancesStats) { var vm = this; vm.value = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { vm.value = data.stats['uptime']; } } glances-2.11.1/glances/outputs/static/js/components/plugin-uptime/view.html000066400000000000000000000001111315472316100270720ustar00rootroot00000000000000
Uptime: {{ vm.value }}
glances-2.11.1/glances/outputs/static/js/components/plugin-wifi/000077500000000000000000000000001315472316100246745ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/components/plugin-wifi/component.js000066400000000000000000000002701315472316100272330ustar00rootroot00000000000000'use strict'; glancesApp.component('glancesPluginWifi', { controller: GlancesPluginWifiController, controllerAs: 'vm', templateUrl: 'components/plugin-wifi/view.html' }); glances-2.11.1/glances/outputs/static/js/components/plugin-wifi/controller.js000066400000000000000000000024741315472316100274240ustar00rootroot00000000000000'use strict'; function GlancesPluginWifiController($scope, $filter, GlancesStats) { var vm = this; var _view = {}; vm.hotspots = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['wifi']; _view = data.views['wifi']; //stats = [{"ssid": "Freebox-40A258", "encrypted": true, "signal": -45, "key": "ssid", "encryption_type": "wpa2", "quality": "65/70"}]; vm.hotspots = []; for (var i = 0; i < stats.length; i++) { var hotspotData = stats[i]; if (hotspotData['ssid'] === '') { continue; } vm.hotspots.push({ 'ssid': hotspotData['ssid'], 'encrypted': hotspotData['encrypted'], 'signal': hotspotData['signal'], 'encryption_type': hotspotData['encryption_type'] }); } vm.hotspots = $filter('orderBy')(vm.hotspots, 'ssid'); }; vm.getDecoration = function (hotpost, field) { if (_view[hotpost.ssid][field] === undefined) { return; } return _view[hotpost.ssid][field].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/js/components/plugin-wifi/view.html000066400000000000000000000010351315472316100265330ustar00rootroot00000000000000
WIFI
dBm
{{ hotspot.ssid|limitTo:20 }} {{ hotspot.encryption_type }}
{{ hotspot.signal }}
glances-2.11.1/glances/outputs/static/js/directives.js000066400000000000000000000020511315472316100227520ustar00rootroot00000000000000glancesApp.directive("sortableTh", function () { return { restrict: 'A', scope: { sorter: '=' }, link: function (scope, element, attrs) { element.addClass('sortable'); scope.$watch(function () { return scope.sorter.column; }, function (newValue, oldValue) { if (angular.isArray(newValue)) { if (newValue.indexOf(attrs.column) !== -1) { element.addClass('sort'); } else { element.removeClass('sort'); } } else { if (attrs.column === newValue) { element.addClass('sort'); } else { element.removeClass('sort'); } } }); element.on('click', function () { scope.sorter.column = attrs.column; scope.$apply(); }); } }; });glances-2.11.1/glances/outputs/static/js/filters.js000066400000000000000000000061071315472316100222670ustar00rootroot00000000000000glancesApp.filter('min_size', function () { return function (input, max) { var max = max || 8; if (input.length > max) { return "_" + input.substring(input.length - max + 1) } return input }; }); glancesApp.filter('exclamation', function () { return function (input) { if (input === undefined || input === '') { return '?'; } return input; }; }); glancesApp.filter('bytes', function () { return function (bytes, low_precision) { low_precision = low_precision || false; if (isNaN(parseFloat(bytes)) || !isFinite(bytes) || bytes == 0) { return bytes; } var symbols = ['K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; var prefix = { 'Y': 1208925819614629174706176, 'Z': 1180591620717411303424, 'E': 1152921504606846976, 'P': 1125899906842624, 'T': 1099511627776, 'G': 1073741824, 'M': 1048576, 'K': 1024 }; var reverseSymbols = _(symbols).reverse().value(); for (var i = 0; i < reverseSymbols.length; i++) { var symbol = reverseSymbols[i]; var value = bytes / prefix[symbol]; if (value > 1) { var decimal_precision = 0; if (value < 10) { decimal_precision = 2; } else if (value < 100) { decimal_precision = 1; } if (low_precision) { if (symbol == 'MK') { decimal_precision = 0; } else { decimal_precision = _.min([1, decimal_precision]); } } else if (symbol == 'K') { decimal_precision = 0; } return parseFloat(value).toFixed(decimal_precision) + symbol; } } return bytes.toFixed(0); } }); glancesApp.filter('bits', function ($filter) { return function (bits, low_precision) { bits = Math.round(bits) * 8; return $filter('bytes')(bits, low_precision) + 'b'; } }); glancesApp.filter('leftPad', function () { return function (value, length, chars) { length = length || 0; chars = chars || ' '; return _.padStart(value, length, chars); } }); glancesApp.filter('timemillis', function () { return function (array) { var sum = 0.0; for (var i = 0; i < array.length; i++) { sum += array[i] * 1000.0; } return sum; } }); glancesApp.filter('timedelta', function ($filter) { return function (value) { var sum = $filter('timemillis')(value); var d = new Date(sum); return { hours: d.getUTCHours(), // TODO : multiple days ( * (d.getDay() * 24))) minutes: d.getUTCMinutes(), seconds: d.getUTCSeconds(), milliseconds: parseInt("" + d.getUTCMilliseconds() / 10) }; } }); glances-2.11.1/glances/outputs/static/js/services/000077500000000000000000000000001315472316100221005ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/js/services/favicon.js000066400000000000000000000003711315472316100240640ustar00rootroot00000000000000glancesApp.service('favicoService', function () { var favico = new Favico({ animation: 'none' }); this.badge = function (nb) { favico.badge(nb); }; this.reset = function () { favico.reset(); }; }); glances-2.11.1/glances/outputs/static/js/services/plugin_helper.js000066400000000000000000000023521315472316100252750ustar00rootroot00000000000000glancesApp.service('GlancesPluginHelper', function () { var plugin = { 'limits': {}, 'limitSuffix': ['critical', 'careful', 'warning'] }; plugin.setLimits = function (limits) { this.limits = limits; }; plugin.getAlert = function (pluginName, limitNamePrefix, current, maximum, log) { current = current || 0; maximum = maximum || 100; log = log || false; var log_str = log ? '_log' : ''; var value = (current * 100) / maximum; if (this.limits[pluginName] != undefined) { for (var i = 0; i < this.limitSuffix.length; i++) { var limitName = limitNamePrefix + this.limitSuffix[i]; var limit = this.limits[pluginName][limitName]; if (value >= limit) { var pos = limitName.lastIndexOf("_"); var className = limitName.substring(pos + 1); return className + log_str; } } } return "ok" + log_str; }; plugin.getAlertLog = function (pluginName, limitNamePrefix, current, maximum) { return this.getAlert(pluginName, limitNamePrefix, current, maximum, true); }; return plugin; }); glances-2.11.1/glances/outputs/static/js/services/stats.js000066400000000000000000000042751315472316100236040ustar00rootroot00000000000000glancesApp.service('GlancesStats', function ($http, $q, $rootScope, $timeout, GlancesPluginHelper, REFRESH_TIME, CONFIG, ARGUMENTS) { var _data = false; this.getData = function () { return _data; } // load config/limit/arguments and execute stats/views auto refresh this.init = function () { var refreshData = function () { return $q.all([ getAllStats(), getAllViews() ]).then(function (results) { _data = { 'stats': results[0], 'views': results[1], 'isBsd': results[0]['system']['os_name'] === 'FreeBSD', 'isLinux': results[0]['system']['os_name'] === 'Linux', 'isMac': results[0]['system']['os_name'] === 'Darwin', 'isWindows': results[0]['system']['os_name'] === 'Windows' }; $rootScope.$broadcast('data_refreshed', _data); nextLoad(); }, function () { $rootScope.$broadcast('is_disconnected'); nextLoad(); }); }; // load limits to init GlancePlugin helper $http.get('api/2/all/limits').then(function (response) { GlancesPluginHelper.setLimits(response.data); }); $http.get('api/2/config').then(function (response) { angular.extend(CONFIG, response.data); }); $http.get('api/2/args').then(function (response) { angular.extend(ARGUMENTS, response.data); }); var loadPromise; var cancelNextLoad = function () { $timeout.cancel(loadPromise); }; var nextLoad = function () { cancelNextLoad(); loadPromise = $timeout(refreshData, REFRESH_TIME * 1000); // in milliseconds }; refreshData(); } var getAllStats = function () { return $http.get('api/2/all').then(function (response) { return response.data; }); }; var getAllViews = function () { return $http.get('api/2/all/views').then(function (response) { return response.data; }); }; }); glances-2.11.1/glances/outputs/static/package.json000066400000000000000000000006411315472316100221300ustar00rootroot00000000000000{ "private": true, "dependencies": {}, "devDependencies": { "bower": "^1.8.0", "del": "^2.2.1", "gulp": "^3.9.1", "gulp-angular-templatecache": "^2.0.0", "gulp-concat": "^2.6.0", "gulp-ng-annotate": "^2.0.0", "gulp-rename": "^1.2.2", "main-bower-files": "^2.13.1" }, "scripts": { "build": "gulp build", "watch": "gulp watch", "postinstall": "bower install" } } glances-2.11.1/glances/outputs/static/public/000077500000000000000000000000001315472316100211175ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/public/css/000077500000000000000000000000001315472316100217075ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/public/css/bootstrap.min.css000066400000000000000000000661741315472316100252360ustar00rootroot00000000000000/*! * Bootstrap v3.3.5 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ /*! * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=5319fed74136f5128183) * Config saved to config.json and https://gist.github.com/5319fed74136f5128183 *//*! * Bootstrap v3.3.5 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12, .col-xs-13, .col-sm-13, .col-md-13, .col-lg-13, .col-xs-14, .col-sm-14, .col-md-14, .col-lg-14, .col-xs-15, .col-sm-15, .col-md-15, .col-lg-15, .col-xs-16, .col-sm-16, .col-md-16, .col-lg-16, .col-xs-17, .col-sm-17, .col-md-17, .col-lg-17, .col-xs-18, .col-sm-18, .col-md-18, .col-lg-18, .col-xs-19, .col-sm-19, .col-md-19, .col-lg-19, .col-xs-20, .col-sm-20, .col-md-20, .col-lg-20, .col-xs-21, .col-sm-21, .col-md-21, .col-lg-21, .col-xs-22, .col-sm-22, .col-md-22, .col-lg-22, .col-xs-23, .col-sm-23, .col-md-23, .col-lg-23, .col-xs-24, .col-sm-24, .col-md-24, .col-lg-24{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-13, .col-xs-14, .col-xs-15, .col-xs-16, .col-xs-17, .col-xs-18, .col-xs-19, .col-xs-20, .col-xs-21, .col-xs-22, .col-xs-23, .col-xs-24{float:left}.col-xs-24{width:100%}.col-xs-23{width:95.83333333%}.col-xs-22{width:91.66666667%}.col-xs-21{width:87.5%}.col-xs-20{width:83.33333333%}.col-xs-19{width:79.16666667%}.col-xs-18{width:75%}.col-xs-17{width:70.83333333%}.col-xs-16{width:66.66666667%}.col-xs-15{width:62.5%}.col-xs-14{width:58.33333333%}.col-xs-13{width:54.16666667%}.col-xs-12{width:50%}.col-xs-11{width:45.83333333%}.col-xs-10{width:41.66666667%}.col-xs-9{width:37.5%}.col-xs-8{width:33.33333333%}.col-xs-7{width:29.16666667%}.col-xs-6{width:25%}.col-xs-5{width:20.83333333%}.col-xs-4{width:16.66666667%}.col-xs-3{width:12.5%}.col-xs-2{width:8.33333333%}.col-xs-1{width:4.16666667%}.col-xs-pull-24{right:100%}.col-xs-pull-23{right:95.83333333%}.col-xs-pull-22{right:91.66666667%}.col-xs-pull-21{right:87.5%}.col-xs-pull-20{right:83.33333333%}.col-xs-pull-19{right:79.16666667%}.col-xs-pull-18{right:75%}.col-xs-pull-17{right:70.83333333%}.col-xs-pull-16{right:66.66666667%}.col-xs-pull-15{right:62.5%}.col-xs-pull-14{right:58.33333333%}.col-xs-pull-13{right:54.16666667%}.col-xs-pull-12{right:50%}.col-xs-pull-11{right:45.83333333%}.col-xs-pull-10{right:41.66666667%}.col-xs-pull-9{right:37.5%}.col-xs-pull-8{right:33.33333333%}.col-xs-pull-7{right:29.16666667%}.col-xs-pull-6{right:25%}.col-xs-pull-5{right:20.83333333%}.col-xs-pull-4{right:16.66666667%}.col-xs-pull-3{right:12.5%}.col-xs-pull-2{right:8.33333333%}.col-xs-pull-1{right:4.16666667%}.col-xs-pull-0{right:auto}.col-xs-push-24{left:100%}.col-xs-push-23{left:95.83333333%}.col-xs-push-22{left:91.66666667%}.col-xs-push-21{left:87.5%}.col-xs-push-20{left:83.33333333%}.col-xs-push-19{left:79.16666667%}.col-xs-push-18{left:75%}.col-xs-push-17{left:70.83333333%}.col-xs-push-16{left:66.66666667%}.col-xs-push-15{left:62.5%}.col-xs-push-14{left:58.33333333%}.col-xs-push-13{left:54.16666667%}.col-xs-push-12{left:50%}.col-xs-push-11{left:45.83333333%}.col-xs-push-10{left:41.66666667%}.col-xs-push-9{left:37.5%}.col-xs-push-8{left:33.33333333%}.col-xs-push-7{left:29.16666667%}.col-xs-push-6{left:25%}.col-xs-push-5{left:20.83333333%}.col-xs-push-4{left:16.66666667%}.col-xs-push-3{left:12.5%}.col-xs-push-2{left:8.33333333%}.col-xs-push-1{left:4.16666667%}.col-xs-push-0{left:auto}.col-xs-offset-24{margin-left:100%}.col-xs-offset-23{margin-left:95.83333333%}.col-xs-offset-22{margin-left:91.66666667%}.col-xs-offset-21{margin-left:87.5%}.col-xs-offset-20{margin-left:83.33333333%}.col-xs-offset-19{margin-left:79.16666667%}.col-xs-offset-18{margin-left:75%}.col-xs-offset-17{margin-left:70.83333333%}.col-xs-offset-16{margin-left:66.66666667%}.col-xs-offset-15{margin-left:62.5%}.col-xs-offset-14{margin-left:58.33333333%}.col-xs-offset-13{margin-left:54.16666667%}.col-xs-offset-12{margin-left:50%}.col-xs-offset-11{margin-left:45.83333333%}.col-xs-offset-10{margin-left:41.66666667%}.col-xs-offset-9{margin-left:37.5%}.col-xs-offset-8{margin-left:33.33333333%}.col-xs-offset-7{margin-left:29.16666667%}.col-xs-offset-6{margin-left:25%}.col-xs-offset-5{margin-left:20.83333333%}.col-xs-offset-4{margin-left:16.66666667%}.col-xs-offset-3{margin-left:12.5%}.col-xs-offset-2{margin-left:8.33333333%}.col-xs-offset-1{margin-left:4.16666667%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-13, .col-sm-14, .col-sm-15, .col-sm-16, .col-sm-17, .col-sm-18, .col-sm-19, .col-sm-20, .col-sm-21, .col-sm-22, .col-sm-23, .col-sm-24{float:left}.col-sm-24{width:100%}.col-sm-23{width:95.83333333%}.col-sm-22{width:91.66666667%}.col-sm-21{width:87.5%}.col-sm-20{width:83.33333333%}.col-sm-19{width:79.16666667%}.col-sm-18{width:75%}.col-sm-17{width:70.83333333%}.col-sm-16{width:66.66666667%}.col-sm-15{width:62.5%}.col-sm-14{width:58.33333333%}.col-sm-13{width:54.16666667%}.col-sm-12{width:50%}.col-sm-11{width:45.83333333%}.col-sm-10{width:41.66666667%}.col-sm-9{width:37.5%}.col-sm-8{width:33.33333333%}.col-sm-7{width:29.16666667%}.col-sm-6{width:25%}.col-sm-5{width:20.83333333%}.col-sm-4{width:16.66666667%}.col-sm-3{width:12.5%}.col-sm-2{width:8.33333333%}.col-sm-1{width:4.16666667%}.col-sm-pull-24{right:100%}.col-sm-pull-23{right:95.83333333%}.col-sm-pull-22{right:91.66666667%}.col-sm-pull-21{right:87.5%}.col-sm-pull-20{right:83.33333333%}.col-sm-pull-19{right:79.16666667%}.col-sm-pull-18{right:75%}.col-sm-pull-17{right:70.83333333%}.col-sm-pull-16{right:66.66666667%}.col-sm-pull-15{right:62.5%}.col-sm-pull-14{right:58.33333333%}.col-sm-pull-13{right:54.16666667%}.col-sm-pull-12{right:50%}.col-sm-pull-11{right:45.83333333%}.col-sm-pull-10{right:41.66666667%}.col-sm-pull-9{right:37.5%}.col-sm-pull-8{right:33.33333333%}.col-sm-pull-7{right:29.16666667%}.col-sm-pull-6{right:25%}.col-sm-pull-5{right:20.83333333%}.col-sm-pull-4{right:16.66666667%}.col-sm-pull-3{right:12.5%}.col-sm-pull-2{right:8.33333333%}.col-sm-pull-1{right:4.16666667%}.col-sm-pull-0{right:auto}.col-sm-push-24{left:100%}.col-sm-push-23{left:95.83333333%}.col-sm-push-22{left:91.66666667%}.col-sm-push-21{left:87.5%}.col-sm-push-20{left:83.33333333%}.col-sm-push-19{left:79.16666667%}.col-sm-push-18{left:75%}.col-sm-push-17{left:70.83333333%}.col-sm-push-16{left:66.66666667%}.col-sm-push-15{left:62.5%}.col-sm-push-14{left:58.33333333%}.col-sm-push-13{left:54.16666667%}.col-sm-push-12{left:50%}.col-sm-push-11{left:45.83333333%}.col-sm-push-10{left:41.66666667%}.col-sm-push-9{left:37.5%}.col-sm-push-8{left:33.33333333%}.col-sm-push-7{left:29.16666667%}.col-sm-push-6{left:25%}.col-sm-push-5{left:20.83333333%}.col-sm-push-4{left:16.66666667%}.col-sm-push-3{left:12.5%}.col-sm-push-2{left:8.33333333%}.col-sm-push-1{left:4.16666667%}.col-sm-push-0{left:auto}.col-sm-offset-24{margin-left:100%}.col-sm-offset-23{margin-left:95.83333333%}.col-sm-offset-22{margin-left:91.66666667%}.col-sm-offset-21{margin-left:87.5%}.col-sm-offset-20{margin-left:83.33333333%}.col-sm-offset-19{margin-left:79.16666667%}.col-sm-offset-18{margin-left:75%}.col-sm-offset-17{margin-left:70.83333333%}.col-sm-offset-16{margin-left:66.66666667%}.col-sm-offset-15{margin-left:62.5%}.col-sm-offset-14{margin-left:58.33333333%}.col-sm-offset-13{margin-left:54.16666667%}.col-sm-offset-12{margin-left:50%}.col-sm-offset-11{margin-left:45.83333333%}.col-sm-offset-10{margin-left:41.66666667%}.col-sm-offset-9{margin-left:37.5%}.col-sm-offset-8{margin-left:33.33333333%}.col-sm-offset-7{margin-left:29.16666667%}.col-sm-offset-6{margin-left:25%}.col-sm-offset-5{margin-left:20.83333333%}.col-sm-offset-4{margin-left:16.66666667%}.col-sm-offset-3{margin-left:12.5%}.col-sm-offset-2{margin-left:8.33333333%}.col-sm-offset-1{margin-left:4.16666667%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md-13, .col-md-14, .col-md-15, .col-md-16, .col-md-17, .col-md-18, .col-md-19, .col-md-20, .col-md-21, .col-md-22, .col-md-23, .col-md-24{float:left}.col-md-24{width:100%}.col-md-23{width:95.83333333%}.col-md-22{width:91.66666667%}.col-md-21{width:87.5%}.col-md-20{width:83.33333333%}.col-md-19{width:79.16666667%}.col-md-18{width:75%}.col-md-17{width:70.83333333%}.col-md-16{width:66.66666667%}.col-md-15{width:62.5%}.col-md-14{width:58.33333333%}.col-md-13{width:54.16666667%}.col-md-12{width:50%}.col-md-11{width:45.83333333%}.col-md-10{width:41.66666667%}.col-md-9{width:37.5%}.col-md-8{width:33.33333333%}.col-md-7{width:29.16666667%}.col-md-6{width:25%}.col-md-5{width:20.83333333%}.col-md-4{width:16.66666667%}.col-md-3{width:12.5%}.col-md-2{width:8.33333333%}.col-md-1{width:4.16666667%}.col-md-pull-24{right:100%}.col-md-pull-23{right:95.83333333%}.col-md-pull-22{right:91.66666667%}.col-md-pull-21{right:87.5%}.col-md-pull-20{right:83.33333333%}.col-md-pull-19{right:79.16666667%}.col-md-pull-18{right:75%}.col-md-pull-17{right:70.83333333%}.col-md-pull-16{right:66.66666667%}.col-md-pull-15{right:62.5%}.col-md-pull-14{right:58.33333333%}.col-md-pull-13{right:54.16666667%}.col-md-pull-12{right:50%}.col-md-pull-11{right:45.83333333%}.col-md-pull-10{right:41.66666667%}.col-md-pull-9{right:37.5%}.col-md-pull-8{right:33.33333333%}.col-md-pull-7{right:29.16666667%}.col-md-pull-6{right:25%}.col-md-pull-5{right:20.83333333%}.col-md-pull-4{right:16.66666667%}.col-md-pull-3{right:12.5%}.col-md-pull-2{right:8.33333333%}.col-md-pull-1{right:4.16666667%}.col-md-pull-0{right:auto}.col-md-push-24{left:100%}.col-md-push-23{left:95.83333333%}.col-md-push-22{left:91.66666667%}.col-md-push-21{left:87.5%}.col-md-push-20{left:83.33333333%}.col-md-push-19{left:79.16666667%}.col-md-push-18{left:75%}.col-md-push-17{left:70.83333333%}.col-md-push-16{left:66.66666667%}.col-md-push-15{left:62.5%}.col-md-push-14{left:58.33333333%}.col-md-push-13{left:54.16666667%}.col-md-push-12{left:50%}.col-md-push-11{left:45.83333333%}.col-md-push-10{left:41.66666667%}.col-md-push-9{left:37.5%}.col-md-push-8{left:33.33333333%}.col-md-push-7{left:29.16666667%}.col-md-push-6{left:25%}.col-md-push-5{left:20.83333333%}.col-md-push-4{left:16.66666667%}.col-md-push-3{left:12.5%}.col-md-push-2{left:8.33333333%}.col-md-push-1{left:4.16666667%}.col-md-push-0{left:auto}.col-md-offset-24{margin-left:100%}.col-md-offset-23{margin-left:95.83333333%}.col-md-offset-22{margin-left:91.66666667%}.col-md-offset-21{margin-left:87.5%}.col-md-offset-20{margin-left:83.33333333%}.col-md-offset-19{margin-left:79.16666667%}.col-md-offset-18{margin-left:75%}.col-md-offset-17{margin-left:70.83333333%}.col-md-offset-16{margin-left:66.66666667%}.col-md-offset-15{margin-left:62.5%}.col-md-offset-14{margin-left:58.33333333%}.col-md-offset-13{margin-left:54.16666667%}.col-md-offset-12{margin-left:50%}.col-md-offset-11{margin-left:45.83333333%}.col-md-offset-10{margin-left:41.66666667%}.col-md-offset-9{margin-left:37.5%}.col-md-offset-8{margin-left:33.33333333%}.col-md-offset-7{margin-left:29.16666667%}.col-md-offset-6{margin-left:25%}.col-md-offset-5{margin-left:20.83333333%}.col-md-offset-4{margin-left:16.66666667%}.col-md-offset-3{margin-left:12.5%}.col-md-offset-2{margin-left:8.33333333%}.col-md-offset-1{margin-left:4.16666667%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-13, .col-lg-14, .col-lg-15, .col-lg-16, .col-lg-17, .col-lg-18, .col-lg-19, .col-lg-20, .col-lg-21, .col-lg-22, .col-lg-23, .col-lg-24{float:left}.col-lg-24{width:100%}.col-lg-23{width:95.83333333%}.col-lg-22{width:91.66666667%}.col-lg-21{width:87.5%}.col-lg-20{width:83.33333333%}.col-lg-19{width:79.16666667%}.col-lg-18{width:75%}.col-lg-17{width:70.83333333%}.col-lg-16{width:66.66666667%}.col-lg-15{width:62.5%}.col-lg-14{width:58.33333333%}.col-lg-13{width:54.16666667%}.col-lg-12{width:50%}.col-lg-11{width:45.83333333%}.col-lg-10{width:41.66666667%}.col-lg-9{width:37.5%}.col-lg-8{width:33.33333333%}.col-lg-7{width:29.16666667%}.col-lg-6{width:25%}.col-lg-5{width:20.83333333%}.col-lg-4{width:16.66666667%}.col-lg-3{width:12.5%}.col-lg-2{width:8.33333333%}.col-lg-1{width:4.16666667%}.col-lg-pull-24{right:100%}.col-lg-pull-23{right:95.83333333%}.col-lg-pull-22{right:91.66666667%}.col-lg-pull-21{right:87.5%}.col-lg-pull-20{right:83.33333333%}.col-lg-pull-19{right:79.16666667%}.col-lg-pull-18{right:75%}.col-lg-pull-17{right:70.83333333%}.col-lg-pull-16{right:66.66666667%}.col-lg-pull-15{right:62.5%}.col-lg-pull-14{right:58.33333333%}.col-lg-pull-13{right:54.16666667%}.col-lg-pull-12{right:50%}.col-lg-pull-11{right:45.83333333%}.col-lg-pull-10{right:41.66666667%}.col-lg-pull-9{right:37.5%}.col-lg-pull-8{right:33.33333333%}.col-lg-pull-7{right:29.16666667%}.col-lg-pull-6{right:25%}.col-lg-pull-5{right:20.83333333%}.col-lg-pull-4{right:16.66666667%}.col-lg-pull-3{right:12.5%}.col-lg-pull-2{right:8.33333333%}.col-lg-pull-1{right:4.16666667%}.col-lg-pull-0{right:auto}.col-lg-push-24{left:100%}.col-lg-push-23{left:95.83333333%}.col-lg-push-22{left:91.66666667%}.col-lg-push-21{left:87.5%}.col-lg-push-20{left:83.33333333%}.col-lg-push-19{left:79.16666667%}.col-lg-push-18{left:75%}.col-lg-push-17{left:70.83333333%}.col-lg-push-16{left:66.66666667%}.col-lg-push-15{left:62.5%}.col-lg-push-14{left:58.33333333%}.col-lg-push-13{left:54.16666667%}.col-lg-push-12{left:50%}.col-lg-push-11{left:45.83333333%}.col-lg-push-10{left:41.66666667%}.col-lg-push-9{left:37.5%}.col-lg-push-8{left:33.33333333%}.col-lg-push-7{left:29.16666667%}.col-lg-push-6{left:25%}.col-lg-push-5{left:20.83333333%}.col-lg-push-4{left:16.66666667%}.col-lg-push-3{left:12.5%}.col-lg-push-2{left:8.33333333%}.col-lg-push-1{left:4.16666667%}.col-lg-push-0{left:auto}.col-lg-offset-24{margin-left:100%}.col-lg-offset-23{margin-left:95.83333333%}.col-lg-offset-22{margin-left:91.66666667%}.col-lg-offset-21{margin-left:87.5%}.col-lg-offset-20{margin-left:83.33333333%}.col-lg-offset-19{margin-left:79.16666667%}.col-lg-offset-18{margin-left:75%}.col-lg-offset-17{margin-left:70.83333333%}.col-lg-offset-16{margin-left:66.66666667%}.col-lg-offset-15{margin-left:62.5%}.col-lg-offset-14{margin-left:58.33333333%}.col-lg-offset-13{margin-left:54.16666667%}.col-lg-offset-12{margin-left:50%}.col-lg-offset-11{margin-left:45.83333333%}.col-lg-offset-10{margin-left:41.66666667%}.col-lg-offset-9{margin-left:37.5%}.col-lg-offset-8{margin-left:33.33333333%}.col-lg-offset-7{margin-left:29.16666667%}.col-lg-offset-6{margin-left:25%}.col-lg-offset-5{margin-left:20.83333333%}.col-lg-offset-4{margin-left:16.66666667%}.col-lg-offset-3{margin-left:12.5%}.col-lg-offset-2{margin-left:8.33333333%}.col-lg-offset-1{margin-left:4.16666667%}.col-lg-offset-0{margin-left:0}}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}glances-2.11.1/glances/outputs/static/public/css/normalize.min.css000066400000000000000000000034411315472316100252050ustar00rootroot00000000000000article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;}glances-2.11.1/glances/outputs/static/public/css/style.min.css000066400000000000000000000101551315472316100243450ustar00rootroot00000000000000body { background: black; color: #BBB; font-family: "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace; } .table { display: table; width: 100%; max-width:100%; } .table-row-group { display: table-row-group } .table-row { display: table-row; } .table-cell { display: table-cell; text-align: right; } .top-plugin { margin-bottom: 20px; } .plugin { margin-bottom: 20px; } .plugin.table-row-group .table-row:last-child .table-cell { padding-bottom: 20px; } .underline { text-decoration: underline } .bold { font-weight: bold; } .sort { font-weight: bold; color: white; } .sortable { cursor: pointer; } .text-right { text-align: right; } .text-left { text-align: left; } .sidebar .table-cell:not(.text-left) { padding-left: 10px; } /* Theme */ .title { font-weight: bold; color: white; } .highlight { font-weight: bold; color: #5D4062; } .ok, .status, .process { color: #3E7B04; /*font-weight: bold;*/ } .ok_log { background-color: #3E7B04; color: white; /*font-weight: bold;*/ } .max { color: #3E7B04; font-weight: bold; } .careful { color: #295183; font-weight: bold; } .careful_log { background-color: #295183; color: white; font-weight: bold; } .warning, .nice { color: #5D4062; font-weight: bold; } .warning_log { background-color: #5D4062; color: white; font-weight: bold; } .critical { color: #A30000; font-weight: bold; } .critical_log { background-color: #A30000; color: white; font-weight: bold; } /* Plugins */ #processlist-plugin .table-cell { padding: 0px 5px 0px 5px; white-space: nowrap; } #containers-plugin .table-cell { padding: 0px 10px 0px 10px; white-space: nowrap; } #quicklook-plugin .progress { margin-bottom: 0px; min-width: 100px; background-color: #000; height: 12px; border-radius: 0px; text-align: right; } #quicklook-plugin .progress-bar-ok { background-color: #3E7B04; } #quicklook-plugin .progress-bar-careful { background-color: #295183; } #quicklook-plugin .progress-bar-warning { background-color: #5D4062; } #quicklook-plugin .progress-bar-critical { background-color: #A30000; } #quicklook-plugin .cpu-name { white-space: nowrap; overflow: hidden; width: 100%; text-overflow: ellipsis; } #amps-plugin .process-result { max-width: 300px; overflow: hidden; white-space: pre-wrap; padding-left: 10px; text-overflow: ellipsis; } #gpu-plugin .gpu-name { white-space: nowrap; overflow: hidden; width: 100%; text-overflow: ellipsis; } /* Loading page */ #loading-page .glances-logo { background: url('../images/glances.png') no-repeat center center; background-size: contain; } @media (max-width: 750px) { #loading-page .glances-logo { height: 400px; } } @media (min-width: 750px) { #loading-page .glances-logo { height: 500px; } } /* Loading animation source : https://github.com/lukehaas/css-loaders */ #loading-page .loader:before, #loading-page .loader:after, #loading-page .loader { border-radius: 50%; width: 1em; height: 1em; -webkit-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation: loader 1.8s infinite ease-in-out; animation: loader 1.8s infinite ease-in-out; } #loading-page .loader { margin: auto; font-size: 10px; position: relative; text-indent: -9999em; -webkit-animation-delay: 0.16s; animation-delay: 0.16s; } #loading-page .loader:before { left: -3.5em; } #loading-page .loader:after { left: 3.5em; -webkit-animation-delay: 0.32s; animation-delay: 0.32s; } #loading-page .loader:before, #loading-page .loader:after { content: ''; position: absolute; top: 0; } @-webkit-keyframes loader { 0%, 80%, 100% { box-shadow: 0 2.5em 0 -1.3em #56CA69; } 40% { box-shadow: 0 2.5em 0 0 #56CA69; } } @keyframes loader { 0%, 80%, 100% { box-shadow: 0 2.5em 0 -1.3em #56CA69; } 40% { box-shadow: 0 2.5em 0 0 #56CA69; } } glances-2.11.1/glances/outputs/static/public/favicon.ico000066400000000000000000000102761315472316100232460ustar00rootroot00000000000000  ( @   !*  u/$( W\-!XO *  TKTX5# TK:x+31SK=s:7 ]\]KbG8-7qCVK269) ,N(392869+yX97)92$-77"-:6  $6768*4896*&).59877775, -:98888897%    ?glances-2.11.1/glances/outputs/static/public/images/000077500000000000000000000000001315472316100223645ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/public/images/glances.png000066400000000000000000001251041315472316100245110ustar00rootroot00000000000000PNG  IHDRzzS;xsRGBbKGD pHYs\F\FCAtIME+;Y IDATx{}sqF4xMU4I9ј8B4!{huu|zBGllU^ ' ^Zv/4$cƬnil@k@`J++ŭK^b<p.< A^RZY9h`Y: ng@k&LXG`lUw[o%@`  no޺Z=vrмU[h y8\0fx{'y_ r1حziTV=sM)Z=@P G6$}G?[i Y8\c0f zS GL9 wsT,^p -KVTTYl)-/\JK8fFHAN+6Z=@9w_=q" ᄾAwu.Z={6yrmf pBzVVf„y 쁠+N&W=bxZ@AwBzTZQQfٲ= p9i3g:U3> ]ia=\ie5h uuͯOIzF@#p(CI7ǟ|K$V7ׯk-Aa=K䂧W`^WSjw_ZY9Y3j$ ?T0@0P`%\֭=vItzgl#@AlܶNz-hp?o~k$=J++` I&u%\PKk縢/|a)cG_Y|@@@ 5j?<ǐdR|EA8zbUW~b= p$B8VU# XwAȱ 쁠=mH2ÇBN?8!YYWW~]wNK +.;2){֥j<)dUUlil-AJ++]3a  'B# ,+[Gpz= 4U2<VTT_sKAnڵN+tUU5-7fبQA=>,p,#聠Ǭ8\")Smjh%tfz {P5@O 5$= y55U5ׯ5p#QaO׺l;n-Jot<>N9@vzr%t f8\i zvܹ~ĉ4qXYWﺋ9\ } 聠w~r&<{o0ӗeUWS֮%ʹw;Ea GH6n>6f #i `cA@6sSM،iil?ƙC zk38P p\ћWS \cA=݈=GuXMBA/^3$Թ^JYjDA@aay&{R>zI$噈&p9M|ǘ1c~1clܔ)$pVZQQfٲD#@׮A@ਦ9㪫)=A@ޢjY#聠 1wx+t]wVV^S[  xEMM#,6A/7!AYsv^j3s7o7i<%(8dy8\vZBޘ1cUU5BU@Y?x;46$ e3z@؋GW]=<4bF3xO~=-y55!= 5j#!7f# A@v(^v?#-:jҌh@Jت7l)23z@ȄouA<@L2'3z@`^&46NntÇ[= p|鬬S !d,մBbFX[YWﺋJh'%YAkjk%B3AqKq2 C^Yx r^D+ ۱tH>xw4oz/wq.+B@ 4C~-tEvWw#T{~-}?KJd*+-S\Uj}d%v-ARCa]xR+N&CI>gS^X;4Z BIgTAxߢm,ƒ rGιs z q8LgoϑtAFUo׭rY^?b+5]kjk@)dlUUMKcM|v[/؏^xp?uUOTIŒv+T=YzRAŽ?wvbApJoj{xI [=-#T<^+Qi2d?s.(-xs@"6_tR>c^v2]&rf-LrVԒoq0kqqAӲN7qA_cS ~^aKD?Yr/0l<^y55Zp!Ϝ,Qز8Nҧ$!)Ad~ef F}{M.'聠d|9eRҼc'<>A &Ud\x&䪧WOA٨]s˯9*%*cI{Ze=Tط4 mVG>f[gvcfv73Iiy{Ғ^٣fY2z> VO>`Y]rLer9MF/M|"ت-u7}T൶٧د(\~\&ۉ?zμ4 s,qՃyrcfnLOZ$OXJ>yg>Lxw)VCosNؿ,d>@=闒}?E z=<Ypn-J7$UJ*d&b_.=O#UZY9zMm:_<5nK+$Ep}\-rg ecr<S͹JpIE:wُ%A]/חoRq3 t\\Y9Yt=aq*DidOXO]?KF1 hDEE a`t;'N̩iܔ)654һuK:GR -~₯?zv0@=m[YWﺋC-'Ss%}BR-.OzKؽK.S`L@,xxc9WSHD\A#RO׭ Ͽouuʵ>8Fk-[+?{(={s>Q_tez]MrArmvJ i_PZ>T(y(R\e/iS~LuL%)/>f l4/*/?IͰQ6>#r5IJ⇠dr+VϕYqof.4"o~L7$=cfkez)*~nM7>vM%ͩ2;SKLJڃP>=I{l yO%pc-Q;4,R.]᛹,kip ^Kl{aߢ ^ ]4UҶ<=šq*!]&2x]n~)5>щj$d#io\uEM0iK_- 7K%7R+V,>N}v@u?%r͹پL뗖yK.$P  F!sri?޼-^~nݜJ~\s$ ̹3G> As듊}?%#r/2{"[r=z\Zk,^v/ Zv5wuc]ޔגoAi=w\^Rq95YwFr%r/7Zd7G_,:{T4Eqxأƴ3YgN?NIO.~jEBp$Wfvn.&r MreZfQ4dP|ɮqd*)}|#Iɴç8\X&r3 I&5f#e^RIu\흢k$}" ezk$-[ttKdz}01(!/Wn?H5Mi-+1={lO>9(ݒ\_T&s̾%l)c48#L!' ByWyߔ)g8601x`3>ގDa gO_ Ӟ5!/VU9|8!/M]7g~aA%ϿGEWȢ?DI_KՁ`νar},N~@ɓāK%?|y!Y0W[޾ZO\3sm'ew?rwwң]sT3u{\gI*0O-U ?/\!_C=!^;K51[NܷegSe\{va/ߒY")Sx{2_`Tz:uGӛ@z\q2 Ԑ7Si.M xӫ2͉ G9fO&ɢVIK_$SYr}rǐdFK77ګk\YL}s=O`JXZjj'^z,=Eү[7\t\%P%"Ie̾珞3o K.V Y5˖77$x8t\T"0*7-o{t[3D`n i&k OĩxOA?҇erܚ(xakjhM!.פfxflr.tAIEA]Uݟ(M>[/ƥZs IDATfuȄjϫ{ݛK-lzs=rItѩl]2z<1/ޤ36ы=wVUnil@Lqoix02[I\uW3Sm3$}vג 绤ݟtaT KZsӧ= #E@;,q:.i\'2#3{Rv5[]\eWTgTدh]۾zG2O .LC>zD uu2ϕt\&IKFr}:k>;?5 k\F}gogdA|qusӓ@UC6no66fu^6y[K8O sPA35H'![.xmOokIgUr (=2yn$yu@U8OwSZ_w|ZZi3g=7mZ/Aιƹdr ˄2OӞC,5$z@*)/+tB^򔗻J:m̞K޺.>-2!wl˻~o--jR$G<у@v:V,DZlqՃwS9܇?$ f=dgh~?|GCZZɒ.:>Ͽ~9t\aA7\ rYiEEuN-Ы&xm $- y~鱿Á[ZoijMRLYN?aWzZaY(Iç=wĩz&nkE+ t$rR&z/tA(N&We1 nNq2!ļr\:OжNJҩ>nKOwLws6JӲ~ilg2KZO/@`FYrtV${@RICɓ\$AuU/5 ҩRVlw(wB^*gsŮ}g猤7j5{C[S[c.EgrMTcas';9r?*iheG}"лZ' =Gecq5׳(xOvzjil{xڸhַΖ4#N?.Leܿ} Ig03.CKbzr4pf̺! xy4\ 'j%5Se;n\V8F &w~ 2#IA?['uLL7E䂁eeKCfmUR^~{U"E{Zvי0m^gzrwq2%,vÛd}Y!{ ;6Jҫ:94;HM/"4䪐^}聐ύ5nif6#xJ4QfгwfULR Ii['EV/WCH\=ZF/"4_={|(:,=L9ִ}_HTET`Y`̧M+fgY$]ܑǤ? hoIgx:O!4RT3~j`z,?t=8\Uy8h޴Rg{rD 3gfrwlqTCm0SgJ28ND(J++GtM;55h~k$BR8eL*(3z&Ir7w͏;DzC`Ey5\Ad`YY0獭ZM.כ6VUp^ :+5BPL1Div/t1sE_ҷ>=`~yofo9=eLE}A$[ꌖ ARY|Y<ּ)3J! IElse=jhr$tb_iM= !wΝKCPw6Y 3!*N(ʞL.o\KD (߳WT&SYudrA(zwcުDEñ<7aQtLAd&$Uݠgf22g}d+z?"I{ثm'][X@^ZvV(ڼuX~aFݦ/+<]8.$qPEQD$=R\VϞ)a-'? NO"urvARO-_~! X+Jzn쟣(Zx WGc,LYx\\K.)ب7J"!kt [Wy8>\Ȍ^5F*sdfk3[Xܧן)F[5"6IMĥZLVA}E;CQrBYsSm, fv Yup\jip\J++GƷ[)q ǝsfaҌ!{pD5GdDqBT`e%k[N/`(S31,sĉY{mo0AYCif ,].TqY AїZ[ҙ\c$S3zp@:(z!(QԾG/Ȕ$fJ=<] gg=HFθ =#![޻G/;ۃ^ھf%ʆK={&{; Kdm=IX{2՘C/))/=ۮ&z=t;BrM5ݱG/TMy=.={3A]W<|=t=cV+ Sg6\%Gph #Y@3z7L,B t z8dr!xMeTb3X7g V%1He'A+NyzŊ<-wnr$yoJ5f2K7)Ƃ^mn^AGtK6 yuepW$tK(*NʼnK7={:3G1lڟǹy S͜I5&)L1d*,,+sC۩03"caFs@C:k!8TKZz^({Bo&i/5`u2^QZY9([<)Dzd|RPZrPB$տuw37qPq*};0=5;ZAGTZQQM/QpKji/ʀ=E_ʬ,6$۫Pxظz85˖-%nM픴D(B1{ ព6ޒDO9㧺ҐdRM;pXGd|c[8K/?Nsh:'klsQsOuÇ3A]|V6_,2 :aE7Jtg +O$%Ayee]hfywqkʹKހf,4d* fifiL;<-t z͛q]w1Aw4g]6y]۾V}^X";K7qGSfd,DxׯaҌ pDGsf^֭bwgy^$z8=sY@EdQا #ipX,^_0d{ǡ(ԟpdڣMWEDCVتz8) Lec=za/k^|L7eʵz8.= d6̀tD! j?™3.PJ++G5454 #1co8q؆ԟM{AUh1ٮ%N]כpX#$[UHR{;~C/Ri*SI0{N3w55Vթ~=- g[j I:yt b'* ^R7JUf[͙݁Auf6YN&D\I yC++tKDB=f$qLC:3_.M(ƙmf%5t$pJ* ձyEz>ս<z8#|(Fo9\}香NnrJb-.1],[UU5z8dr!Zݖh b4><6;Oq 3EV"\Ȍ^j,W:=tG]Zo@a=b,Bе65+sA+4t\E6%7#:ܷQƁnZ~xSzxϭ zK* "e*nn6\DpDwΝ{f98>m{Z\R@.!*!If,Ā΃/il͛{m~, ሮ8KWا( zq۞ozb~(]!*g-= ˛X[UAu%IDnb^ G恠#8!$W.@]dfUH/2z1M{fSnj;!*o[^xzk6o…恠;ÇwqW_s숂 hWZiW$MS˵_˯j}3ӄʭ[Zj^* ppc#B9̹_tJg|3>u"e:Qϛ6Au}$lJJuKOho>I қ =Rɹ3}$DJuJvvn߻>&UyF"}KmA:Lh1j/V!O*_24}W++$I'mee} IDAT v=zu4JBuxx|GmSS+R+j:H52'YڣW3&igij낖/Y ,6J*^#F8 zZ}X8sTuܖ-HsC ۤ).(imJʀ O^S~9͞}UAOoiEBy+T[i's$t.sQ1/e^au]IX"n$IfxuT|F=!UD:Iy)o\6esBBQoC;5MW eH&\[PU׈YR eȓu&I2*3Enڙ:j ؊ӟ&$llU4antoyVTz<\4{V^=~VAW&cL/L;\Vl~$$;Q0)]buWO9Zrz-T a;opҒ&&/T*N l\&%e0T5bmVA=IjbIIM$̪)K-@M+.Lߙv *4B'I%Tj16͞ՖAO;lVkn,wKZ_loA{𚃲T]'#omOn;tsr|sAO˶?NJx:t|'6jN}$ܐLPN2IR- ~#RAf=Mޕ[$IrYݝ;Or,9VB=IBm̃)$\9z%IC8qoy;RE|vW.=d) lmIL^]xbK(g)$uEILZRfVgoiܹg{X p+ ̇NLi+(=n-{N/IkfzeiۑQNϷ#9רI'ӫ}=HrZROZ[lKHw7sʪ:{$i :3D}1Uz^/eC;n'[۩9 >GHHIy6iIv?iC(e}ƌ z$ )7չ=-aR"a9/MߑH9P$ [QU-2Iнo[H?V*ezC2~-XFM:a{XT&%,}$I.ٿAO)7ϐf3zTnW{?u*^@:.kmOJKR6}; %ICG?fk(e޲iSGO fM.!aqe>.s\y Y .h?"ep{$q-v晆yf߹#}͑8kZms+ $ޖ!O2IR;tz7_GOo ֹRv^BR.;t[Sΐ'$ifs:$GoIyR7gso }iL8~g[xzGM<Rv!g6"eRҒNZlQߒEKGʉo|W?eI\^<mv'Rڀ^-dIKٱCGk ː'56oݔl0=zK/A:<}s.5=?Wzw6>\/}) yIrGҒ|Gc*چ[o=Ր'-IQgڙ^i+>U^v1mIڙ~CHٶ)R:$-w=#We(7ϐ'$y^yH9Ugow%ɘzyڎBO`HڑlAZ޻{:iIN2vy2I=I*8vo³̓\O&<|Q*?p˩y->ig4dafH/ާǍN!CdГ$O=|%/)lڄgN`BҒ;tԪmʨI'C~(MO!_eyɻ镻#Te83ϐ'$$6g⟾Jʩu$} O7H^7L&ߖn 4}3ЫiN6U"z yAO* Kig36o[ I IKTKٗx²W~ԬS`ݎK$-6ig 7%лz*%ɏIHy1Ώ(CdГ$ӓg?Q] N̼o SIyx9iIig{kiGz.3ޱhIŝ}$%I} linI– "a=IacH!O2IJp}}8ؓ]6ֻYp|ˡ\!O2IR博p|[ &M?FF=|0^ۘ-ʶy<ɠ'IM Ǎ"!m@T3,`\>ݿyȐ'$Iup'nܹ$gY?e!DҒ|{ѿ(2I=IR8*0Ϥ7̀VE%-ɩc~Ȑ'$I OܬI؏VD+xmz;ӒtCdГ.O9O9䴱~rVzzq yAO6tiG5>NʖVDIm̟-jnο{|3F z$Qߞ#RQ {Y=%%Ꮴva\hoTͽ1Egk%$i%wˮiG私cI `ky$9=qdaTwٳAO&k=m&LAG>~7|1)ӀuvJ˂^O)|4 t:+ "IrcKu/bKfyN $I3j ;KJ:ؑ́]4/'I2IIKPڙ>5vE5<3=`ֿ뭚AOOu֖Haig+ ;5ЛɦrXH~`RҚߧm.#Tu>'$IzS>pb%[%I1)i:l@B`;0dF'I2dz”+v>-fӳ;Ǎnȓ z$m=tRK>{/hΎIlv$Y/MӾdHzHIJ ,wvt ɂ^%Mg%- dFK8wtӗBJ֤AW$$IH~ȑڧOh%%$I⁷jJ=I$5M3I=I$5QodГ$IR^#F\hcԸZ,$IRFu!Oj|I$5"Ґg5jGO$^! yRxJ$5ރk*bY{tЩ gU z$InoՔ z$Ijgȓ z$Ij AO$IM^<8$IR—k/dГ$IRыw|3 z$Immsܸ»œ z$I2z>~Oz-dГ$IR؋'$I45%$I$xAO$I5uڙg_)guۧOk%$Ij<[dГ$Iރk*sަ)ɠ'ITydz1ǔ$$IR y{R9}V[AO$$e,KdГ$I*Q϶_9n1Xu3MAO$ n_zZˑ4%$IJTU?>cV]AO$\=SAO$)^#Fܶh}$$IR#hJ2I$U=܁I2I$5E3I2I$5QN]8s$$IRAj9ݲdГ$I*X=z9rXmI=I$$$I=hۯZI%$I V޻Ə看.OAO$niOAO$ydz1m?g=$$IgR{qۢٳ5$$Iަ<3=`{:ɹ$$I{ࡷ_}z|uۧOkH2I$ n_zzs/+.k"I=I?>cն$$IRÝw z$IoS$$I]BAF]OGYpwE$$Ij~6S[.Wg$ɠ'IRS=hŋf[FmdГ$y3o7<ݲ>SΜC[_ z$UZ6:+{ݹ$ɠ'IRlk*so[2%ɠ'IR%~Oz-$$IjXyf[U.'.$$I׳;Ǎn%VvdГ$tvt O;:>)68B$$I*ՖcJAOHᝋwnxιOϘqՐ$$>}ރ#M$OC;/ҽmig琤ٷwri:|vt HZ[Я1{|M9`o65FGOO>jH zTD4hd}*us1)I2IR,V6޻Oϝ7'&$$˽v!ouj {(EdГZ?`E|n*T?R$I=I-v7^Kg{9c{l^p$$6)bY=-ճK^]y砓$$#v;AOoGvC=uҞ=.|ca$$zߟ[XI zAϠ'IXI$I2I$I z$I$$I$ɠ'I$I2I$IRf T1^`% X 蛿 h_pυ^$I2IŇ݀Yy_gB/:$IjFN2]wyl:-}?BK$ 詨ђQ'u+7_mB۲$I"ך݁O6h͛\ \Bx=I$F"F lcX $I zj 5`.Z%B3I$ɠ ׁ &!\gГ$IR#qt,@|x!? '?d9$IdS1ƫF֊41^i)$I^AVAV "H$ɠF yWMrw%$IR#M- y޶?YI$5{ xQXįC޺)I$~je$IAOyY5v{ IF3z]3m ݐWa$IRCG논w c _/}߯/}hgWI$ɠ7aޞ~ !xVe{7}W`シB{$I zGG^&. w!e,<p{$I5wE]!ԮT$I2 b_>Rj6$IAO"5L !͊K$I=O ?p$I z*Y@`W`xa-I$T~U>BxjK$Iy+C |ڐ'I$T#1nҒ$IAO `= 8K$I3z"$ IDATc\8ŧQ!׬i6MF]߽F} [=)0jKolE8נ]xkt+!̵Q eސ䗁9dy !Lk %;50&^dS^ ׫ I `F!]Kb *p?:pU̾Pؗw!izvKݦ@|ǀ?;B/|Gnr^+ߖz @{Z_=<`Jפ}7>쓿Wtzw>/xSC ߲=6v˃<ܕa0%~K_}gS}9/JJX4`|+mЫ'6&hX&\lL[}ʝ@ !lkÀy??6 pOzޏ7w&u{=> >ҫ@\G~ ̳ zJXtJ6V٠01#%Q91!.v/lv\ |<_.:m QƆ&V݁#zNc0 8' !wPV!^?eAO5xةE{˦A/im| X6 >paaQ}]nI%m6-n~B~t_|8 peH[آA?to#h޻h=c_$U65N6k曞_*;n݃$Խ850o'z'T|s@̿KvH]Bs[ߍUPa'T9NPM'k yfq&y4x~_YOb7k5x `<Ƞ|'{6 [af0>8b{.?&z*xD~VW=?cG6 RAcdUGb?1Vx@Ng,&xaSm@9?BU<dW xȟ}drXӚH6Z>MRVGq< m=j;Ҫ"}ޫQ|`UˮU m^Hvi[viQVc#Oc\be@&l%1.J"|EͿ$^86@ղpcM~Nz/s5f@c=ɞ["Ad3uk0>FvkW.JyMBH6w~M+Aoiz|?1n`l}K#Áh5@,= 7 )VLb{nq^I=n=IE_'J[h?:\w\sM;b8\D95{ zadK zm:%]y\cܣ!GhÖ5\FO3f@,=H(i)]p Syb?ڴԱ޽kig Wgcnca+]'uݠTaU zte^Ӏy^ \}0a`ncCS*i'܊C/aՋs,Wɦ藿͏mmY !<[Dzv7 v<0sdwlkWkxAqb4eIQgm-y~S~L.o4F]2 ]U[7_$Lnɟ !,y{.-+@#{D_X{_&/_y8_b`@~^%0x[c2BEBަkʙxQJzHgv_C_go15XՒ|;/BXpr' ,6>Pj^&!{V_ }<휇?b8Ɖv\dCYGҢBH*: c]!x|ռlBxba_S E1 §*pw+yU=5ܾ-6?oi!\_F9S)-{}BxJ6wzʲo:*)uClK<Y/ . V)lʠ58G [CAjA/~m{>%! ߖV@[ɫ'pGc[*g1GGmnL'Hy|C/V*vS@w=VGw>M6uTx6?;X/Za^^ڤppr +^iԏ/ͅW! F6Yx|-Xmw+[!BF2<BK io@BRs?R9!X8xoᣞ z*"B5Jo_-aۆw+u6!pXI8"pi}r(sQ'N)F_ !,vm N|]ԲW/x=PuӘ*+Tf%,.*/58v-'{^ 4覟[R{7pjI~zM6Jd1EDبmˠڐkY ki]dXbקStEv/;وw`wg?u/wJ;^d1ƭk [{Bˠ'('CV\/v+[{lDlб;ނ{ +E+t4EI' x M&zH+W2̠eBy z {wF}/o:pJ&ẙ{87~FJ=tZV.A8ݠWiE_Dw>cH |ddp˻+y@GAhq`2i%,=)pY޾YٳPEl]MBc|-u+}/ݷ*tܻemQ S2ѓk<4'Er֭ ]BG oi>N\ ?/pYe z*3٣'Qa!0ŭkEfza{[wڷJyLHЛ]ಆ{Ƞ'fu,e] (rڀmE4gw^?\Q"_ZvPcL< dSYA[7%"upGy^bm=Ky_=.Ua"AoTVгGO2iy1n5;EM]bzq}7mz ^b==dГ=zAϠט-pY݁w!tLw*CUO2+z z*W-d{ͽ \EoI=z1~CBmq \˲J=.fs罿ŽҚoHӡ4Kл֣Bxl"1~ΣCef ^;8 @ hZe[RG!1>lS"X !RE$uylc\' R-1-o{Lma oYUrzXʺVs]&"{BAQ$d 嚒w0Aki/a%Y*4g \V-o7 \#MT" ؠG(ncz.2.{$'k~nҚ6*p7Qyq | x:xz1F|Fq=zҿ. k}Z칷~ɫ˽fSS|+-pY[в\KeyG˳Go~f"H o_1^ !yVh]WdUSt uރ1/pZkZRR8A^*a詙]+2n_2-Vn %ijC[a7c5puaͯB|Z>1SȞͭ*jգWdpNV^#ɼ!yd?ͬ&dcc]@jQ2S31Ɠ(#A=z=^ zy؛F67?dL1c<;eA a5Ccs˾v6eeг*U% !kqhX`=_Bt2詼/%=B^+py. ;= x(:l@`7`O`0֖A˰G6*58P;1#F@}zIOt2\Jz1 !̳j _/a__޳!< BonsàWpnD򩴮1nRyqBYT^u[2XZ5|.J=BNBޛàWoa9:=B8V/4~3AO(cbYZ5})9kmCy: z5VdAkB!\EoIgdS  G9(a1pXlK,ٻT;L׻K`Su݁:AO幡iiUo1/T +,:v=fA6) 5 &&Jǒ|C%ҹ(BW[Z.5A7/#`3Igpߏ1 z*D[6>lyUgE߶o,6t,o(K`+4j3f8݂AO)UȖVY>An.E'VVZd 0Ezk>GA0ƸU2W{dRdˠ+ic|U=y!UzSENﱋ\%wƚT[^̧fx/dZf z*ލsfwS9KdhJzs/pY6|r-OK\Vڠ%%-1 * !fIc/KRE~rj%׋!/=OW<̎`SI.,]{BT \T)D`QAGS4 7,V!Ec\ TA; caUcEMJ#Q#JkkIWBqsKUY/XGk7詤v1w/1`U# \*H[ҕ*GlliUD6ϬAϠ [%Ƙa/mEiB/ \V1=[9"uqS+U z~raE`1&VY|N?UIw'Kݰuj9b'S^cYWZ"}>fZ,pYZNJ?\{| VuvV!-pY[٣mҪC7boZ󇀿|=wEq3(YӠڜ4~c<Ŋ7u{W>=zKH%,g>;[][l3詚\5.!Ÿ ^_c[Y mқ gS5O/_cuѡu/7XY&P3BtVKz.y3ypAϠ8ckÁc8oRS~5o_)p_[Hr}^v;bB`~ =+18`A{fZUjk]D1b楂:?rאVM>]ω%-~p[q+o5'ce8':j[~ ~"xPS+aߩ!'K'Ϗ1)UvdIF6ДWc=⸭F=b1^cܾb%)?1x1!gs ^!v. z_pzVpYqJbzj  M1Ɠj)e}2pO#-JO=zY109(ccCX5'٭e81ȓwCcmM;1cm X˵cн_e 1^NXYE;I] O(=JsEaAd쟿hR!> \peϪc=_^n_.<`B zɺWkp=b{a j6Cڑl݀G$cߚ'_wC W`7=8>Z j|Πgkࠗ719_B]݁w{nW !lV$x{ ُlww)9mk7`*\.X@w|?x$\%??#dw§6qN=ɺ`ل/ҿ_"sll$. IDATUu z;pcK_!p;v&=S m%e^ nyo] ߗmd3?4 Akߎ+ay ,>/?"ndm-W% !̫Qͷ&zy!#d^_k൴=Z&حɾc:lй5 Y/di y1?.Zz~~kiyװ$ڠ:aw.>i5/m|7sBg_qo2bH==!XÚphal =-?>oX07Vi\r AR7 pvq/"9uC]7j zjvpphJ'G O_vHZ1y$P'y= e7cCXB84لj%^&-א 1_!dJTہ PA/siF`SuNڗS$ժߐ $RE~(O iSmud^?ȐcӠ %`SNړ/+FӴ"io+ds*iJ "mfc|Gk>l[neZ,؇l֮!o!6詢'B&|Ɋ4ENj=*֋!Gjvtޱ5|~]ݕ=U>gSs/"kbyTrrN601!ɞ~ l P%!Ueʷm%$b>?<@38Fz}s g@M+5y2 OGܡj pr!7IOU;C' K^lIda K ]0#` s83 C-Xؽ E!2 ;B!cVe^jжY.q5p{ !|q˘TK!]As=Yּ=pVϦ)tfov !Bxo2։{qWd/k p/} ܎݆c`A \m0Qjgoᆪ%ʄ? 4ɨDAiQxEP$G0300|#8 (ID2HAH#4%݋PUu> :wījsڈ|t<Z?ہo/6C߈7KùFИeh22s[+gW8rLkk7ћHD{Qf3ڡ?t޳'61uiUm YcooGĽ#k:z?ʢ룔~aJ܄2K)C;G-f/+lѓ:xK;ՊejcL{ڹ;7"k]BgFCV<}ޏrx$wWWP*]\6:;9AӷYρ"1K'P.se]1L ֠<]gCuQʛsk{X/b)Nߋ~Nxgn^D,Y˛5x.#} ?.:Gf6Q;*Q.WPF }]6"niefԍ)O;W<Cy#~?|@vꮈѲ*fSf\!Z,\}# ;ySG >I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$-fI I42s9`;``3`#``U``6pOn..LMIv4kh*0K\x`w`)~|x舸TIv$IL8 xQ`>>q>k$GaI I4w(4i)`o`<6"^lfԭdjȎ$I=ej|<1]CY䈘?Fyw,, BΚWgkrZF̐xʼB/31q'8YfM{[WԴ0"~?|c\oDuLc*Ė)cc:xO(ODÛ7g汙>L+#1F%<03kzɃUߣf^]Lօڨ>x\o}}:2ᙹ¢otٓrGK<Ы[۹H!^@Z} 3?0Jw^ +ZFx3ћӻ>6k,OO#ѳ}4aKu D}>3yG}V)eVNf7Μgl0Tf<,<}evA>A2bͼ6^~fS;/16Pf F1s>*RQ]^ao݊KmQ=2=슔 xaXx>~P&\^&4 ka e*gPfڷW'(wk\u'"d|kfLPk(gKea-ΥL@gx(C^XYK_ͦcpezn\Y47.;=nﴌxymNlʲ mA-OeFwMd)2ڦdYobجKkt^؃3\뾫j~2nZn<2N5@Y>u_OޟW;(3΢<}2(KMƕ{@Yno67,up˫2;;zmPaDo?LJ=pGd5=jDf\ Z;E[6*MCpְ{(t_jc(~:"n|Rf~>ЁT?]g#MEֲFA܏2fR{{fYFw{^qu@-wZ&k?FYc*e ?.ڰ'o+;tphbIS.0.Dj_ n?qF}n?ei%jga$nFļJj_umbowrLLuJk8/khG`x⏕F(r]Es`ubM;4+OF,zxon<0ɿ7s2J뫭Cf/Ь8سC'c~3#-wRfm3[D=V~$p`;4wzqo}]~xpEcp~JtC4Γ)A:9}a:OM}mD=|+ʰ;efpNNlMyS9Zԋ|8 7~ܔe f 1`Ӥ5mqb߁ ؎^(S)tNGG7Ϣ<-mhUóNt@]맘. wdi9$nw'/{x)Ӎ)#F%kelL$|Z\ fhl&˻x&/{m:KT>#7>q7{9Tfdؾo7@DD ? Nl^qg*Z.=ʈQ7zxW1~egXlگ+esx[cNRv"_'֣U ^sJ273=oztKv'e^} rIC2^k1f^S?SYjf^ЋF$6[z3AmM)!쿝l`GoZ/2K;z=.Н\guɼ#К$bf`n_á[q>Ʃx3 k#Y(GnIYbcSӵ@t}Е^ԉ7\m+VA!~wb #eJ^Tnkl?iҚlН;lq4e͞dz"÷~尗o5 rfD<#)KBL 2_0i˰fk)o=탶K۟؃c&B{ qn5sJyw% (/_AY3\wG5DrMfS+dzeГ; hYu7>$KkL&L%ON7 qngXFM4x8ط>z5e=gN> l3Sl~vY6yK< >hk?׋74/oGob(?ḫ(75&{ ʂԽN㺻ztz=㵆$eeXśyMố2{eisD6.Wgjg}=-G1 탶{- |^fM6?3=W[wVDμ3IgnD8wox׷x3i;}FĻ(32wO7{b]"o2|m}op\>hk5hlGQXOg; w SfuW}w`&pzk a \}2Fhݘ =oN3s1XezpֲFsG*S׻Fߦ~$nfTn?O༆̀Zl>{2bͼa﫝C3s1Eiq+=oN29^ &{G)탶^0}Q{1kͤSo~yI) ל!LAOl|/g1Vf^0nPf[?YИ "󦐤dF !LZkP(p|cUsz\ 1x1`L̕16#Ĉؚ(ՀQצ4=+txeLӁ(cOEGimbNCVZCUn 'xN 0ZiJ oז2 tgz`wڳ ΩQNiqrDKeShm&=H,ŮvRR}"3r<':OOf.Lr;zFpɼ0bl+^V_X8嵻Уwg#bɿ42 Eot~vۀ'q>W4ϝx4{imO229߃u=-#ӷf'pf}z4M?T*ˁ7v;39$5Tzt~ؾ ,5oc>BfmZk)Ḿc#WEyxeyֺK/ǷM 4֐nl_G/޵7rNc_sw̞\qъqkW5on!|s 6{;2rƮ{Mcll__FZf/}[ i(NB%- ~̯t^i-`>EE1k7덍{ 6{nYj[FךFڗ /4v#3Pc#b*S~,3WqprcáӈXhČOY^Mc#fڍI]k45jM>}>vn*gZd*O\kl_Rfњl`7eީF3%}Ѭ7~fn8Ϻ!w}-xRW4v{]}f,LHvZ/!3}@m:5ze'_=yD+auQQs]Zj."0D/,ؾ-? IDAT"p\pj%ovffFf{cUۗ>ۧl0͎ ]|f}ZDrV#{=|]_\:5UxgVIwSiС98z2 ׺1;16Fy'xpFfneimQT+u폴ȍBlܐ'egjSH2۴GMdnjH\#3ߓ}n< q}MPf2Lf^dzey8'S̔\= {:5Sz7ehƍ> |<32tZ ,+ؔrwv9< 4_{2ʹo \z%`.vLjxePt%pnf6Qf\\2{I?b]o|!3vJD ~=w 67Bg՟~8'"ΜW=e@?3W4[06^2A3"fMd7O2{\L¹ClF3۲1p`Ӏw}ӡqkqcf9l ۲i=;ae晵q[Zh7RKyBm?xz͇^k9 2.<4 33 # lF=ݮWz4_LS;xi0wʆ}_ g/(VK^؏ZkR}8?k'. ,e8_7"1Av^;s es=ƪW3)/iL`~>唱Оl6k2~OpEa۸䵈iC沾i>|`8jbsP=#)џ)Ο-1j'\ (w%4ȴ@l,wRx{pˆ^wU19ʽi; o"sشu ͻdL)әTB``nDԃ8;2Բ ֳ}-a?J~e^240|GMw .S [P>OyCz]OQe`t/g۸䵈82MozQfx ͻgFn .'"vk-6#bg?H`yS"⽽,GS͒fק{f)3T+QfU~JYOtuDdP2qצ)>>DYrdcP&XX,ɲȝw . 8?"nR`ܺV/⽏Z~)"~iv75w|-37beJEZ^Nv#+jyqCƿޖL'ergS kcDD{lFeƢm|e9j{/q+Ί_]j)zWsyW=ɹDBW&)3 N7LZCqv kefmP+y/3kc~Y2n ()kXC{v wcS_mHC1uiF f^ ]U66%&4i/ml>϶)oƛdlJ'H}'്ݎ}OxMcS')NteI2$cS=idۀ74v;6"N1$M26%ѓ_Q͙OÀ/6vH$M26%M gLwtf. Gr4s(k0>x&eͣ]eOTג&ؔdGO3֔EUw}?">oJƛdlJNԌ׊WhJƛdlJ'M{Y;Œ%o)Ɏ4Mӣ6GD,0I%M26% L6ջ9"N0)%M26%ѓ*sߋ&dIƦa3$LϠ250XR,󁛁 )/Wr&$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$i[9Y.IENDB`glances-2.11.1/glances/outputs/static/public/js/000077500000000000000000000000001315472316100215335ustar00rootroot00000000000000glances-2.11.1/glances/outputs/static/public/js/main.min.js000066400000000000000000001440471315472316100236110ustar00rootroot00000000000000var glancesApp = angular.module('glancesApp', ['glances.config', 'cfp.hotkeys']) .value('CONFIG', {}) .value('ARGUMENTS', {}) .config(["hotkeysProvider", function (hotkeysProvider) { hotkeysProvider.useNgRoute = false; hotkeysProvider.includeCheatSheet = false; }]) .run(["$rootScope", "GlancesStats", function ($rootScope, GlancesStats) { $rootScope.title = "Glances"; $rootScope.$on('data_refreshed', function (event, data) { $rootScope.title = data.stats.system.hostname + ' - Glances'; }); GlancesStats.init(); }]); glancesApp.directive("sortableTh", function () { return { restrict: 'A', scope: { sorter: '=' }, link: function (scope, element, attrs) { element.addClass('sortable'); scope.$watch(function () { return scope.sorter.column; }, function (newValue, oldValue) { if (angular.isArray(newValue)) { if (newValue.indexOf(attrs.column) !== -1) { element.addClass('sort'); } else { element.removeClass('sort'); } } else { if (attrs.column === newValue) { element.addClass('sort'); } else { element.removeClass('sort'); } } }); element.on('click', function () { scope.sorter.column = attrs.column; scope.$apply(); }); } }; }); glancesApp.filter('min_size', function () { return function (input, max) { var max = max || 8; if (input.length > max) { return "_" + input.substring(input.length - max + 1) } return input }; }); glancesApp.filter('exclamation', function () { return function (input) { if (input === undefined || input === '') { return '?'; } return input; }; }); glancesApp.filter('bytes', function () { return function (bytes, low_precision) { low_precision = low_precision || false; if (isNaN(parseFloat(bytes)) || !isFinite(bytes) || bytes == 0) { return bytes; } var symbols = ['K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; var prefix = { 'Y': 1208925819614629174706176, 'Z': 1180591620717411303424, 'E': 1152921504606846976, 'P': 1125899906842624, 'T': 1099511627776, 'G': 1073741824, 'M': 1048576, 'K': 1024 }; var reverseSymbols = _(symbols).reverse().value(); for (var i = 0; i < reverseSymbols.length; i++) { var symbol = reverseSymbols[i]; var value = bytes / prefix[symbol]; if (value > 1) { var decimal_precision = 0; if (value < 10) { decimal_precision = 2; } else if (value < 100) { decimal_precision = 1; } if (low_precision) { if (symbol == 'MK') { decimal_precision = 0; } else { decimal_precision = _.min([1, decimal_precision]); } } else if (symbol == 'K') { decimal_precision = 0; } return parseFloat(value).toFixed(decimal_precision) + symbol; } } return bytes.toFixed(0); } }); glancesApp.filter('bits', ["$filter", function ($filter) { return function (bits, low_precision) { bits = Math.round(bits) * 8; return $filter('bytes')(bits, low_precision) + 'b'; } }]); glancesApp.filter('leftPad', function () { return function (value, length, chars) { length = length || 0; chars = chars || ' '; return _.padStart(value, length, chars); } }); glancesApp.filter('timemillis', function () { return function (array) { var sum = 0.0; for (var i = 0; i < array.length; i++) { sum += array[i] * 1000.0; } return sum; } }); glancesApp.filter('timedelta', ["$filter", function ($filter) { return function (value) { var sum = $filter('timemillis')(value); var d = new Date(sum); return { hours: d.getUTCHours(), // TODO : multiple days ( * (d.getDay() * 24))) minutes: d.getUTCMinutes(), seconds: d.getUTCSeconds(), milliseconds: parseInt("" + d.getUTCMilliseconds() / 10) }; } }]); glancesApp.service('favicoService', function () { var favico = new Favico({ animation: 'none' }); this.badge = function (nb) { favico.badge(nb); }; this.reset = function () { favico.reset(); }; }); glancesApp.service('GlancesPluginHelper', function () { var plugin = { 'limits': {}, 'limitSuffix': ['critical', 'careful', 'warning'] }; plugin.setLimits = function (limits) { this.limits = limits; }; plugin.getAlert = function (pluginName, limitNamePrefix, current, maximum, log) { current = current || 0; maximum = maximum || 100; log = log || false; var log_str = log ? '_log' : ''; var value = (current * 100) / maximum; if (this.limits[pluginName] != undefined) { for (var i = 0; i < this.limitSuffix.length; i++) { var limitName = limitNamePrefix + this.limitSuffix[i]; var limit = this.limits[pluginName][limitName]; if (value >= limit) { var pos = limitName.lastIndexOf("_"); var className = limitName.substring(pos + 1); return className + log_str; } } } return "ok" + log_str; }; plugin.getAlertLog = function (pluginName, limitNamePrefix, current, maximum) { return this.getAlert(pluginName, limitNamePrefix, current, maximum, true); }; return plugin; }); glancesApp.service('GlancesStats', ["$http", "$q", "$rootScope", "$timeout", "GlancesPluginHelper", "REFRESH_TIME", "CONFIG", "ARGUMENTS", function ($http, $q, $rootScope, $timeout, GlancesPluginHelper, REFRESH_TIME, CONFIG, ARGUMENTS) { var _data = false; this.getData = function () { return _data; } // load config/limit/arguments and execute stats/views auto refresh this.init = function () { var refreshData = function () { return $q.all([ getAllStats(), getAllViews() ]).then(function (results) { _data = { 'stats': results[0], 'views': results[1], 'isBsd': results[0]['system']['os_name'] === 'FreeBSD', 'isLinux': results[0]['system']['os_name'] === 'Linux', 'isMac': results[0]['system']['os_name'] === 'Darwin', 'isWindows': results[0]['system']['os_name'] === 'Windows' }; $rootScope.$broadcast('data_refreshed', _data); nextLoad(); }, function () { $rootScope.$broadcast('is_disconnected'); nextLoad(); }); }; // load limits to init GlancePlugin helper $http.get('api/2/all/limits').then(function (response) { GlancesPluginHelper.setLimits(response.data); }); $http.get('api/2/config').then(function (response) { angular.extend(CONFIG, response.data); }); $http.get('api/2/args').then(function (response) { angular.extend(ARGUMENTS, response.data); }); var loadPromise; var cancelNextLoad = function () { $timeout.cancel(loadPromise); }; var nextLoad = function () { cancelNextLoad(); loadPromise = $timeout(refreshData, REFRESH_TIME * 1000); // in milliseconds }; refreshData(); } var getAllStats = function () { return $http.get('api/2/all').then(function (response) { return response.data; }); }; var getAllViews = function () { return $http.get('api/2/all/views').then(function (response) { return response.data; }); }; }]); 'use strict'; glancesApp.component('glances', { controller: GlancesController, controllerAs: 'vm', templateUrl: 'components/glances/view.html' }); 'use strict'; function GlancesController($scope, GlancesStats, hotkeys, ARGUMENTS) { var vm = this; vm.dataLoaded = false; vm.arguments = ARGUMENTS; $scope.$on('data_refreshed', function (event, data) { vm.hasGpu = data.stats.gpu.length > 0; vm.dataLoaded = true; }); // A => Enable/disable AMPs hotkeys.add({ combo: 'A', callback: function () { ARGUMENTS.disable_amps = !ARGUMENTS.disable_amps; } }); // d => Show/hide disk I/O stats hotkeys.add({ combo: 'd', callback: function () { ARGUMENTS.disable_diskio = !ARGUMENTS.disable_diskio; } }); // Q => Show/hide IRQ hotkeys.add({ combo: 'Q', callback: function () { ARGUMENTS.enable_irq = !ARGUMENTS.enable_irq; } }); // f => Show/hide filesystem stats hotkeys.add({ combo: 'f', callback: function () { ARGUMENTS.disable_fs = !ARGUMENTS.disable_fs; } }); // n => Show/hide network stats hotkeys.add({ combo: 'n', callback: function () { ARGUMENTS.disable_network = !ARGUMENTS.disable_network; } }); // s => Show/hide sensors stats hotkeys.add({ combo: 's', callback: function () { ARGUMENTS.disable_sensors = !ARGUMENTS.disable_sensors; } }); // 2 => Show/hide left sidebar hotkeys.add({ combo: '2', callback: function () { ARGUMENTS.disable_left_sidebar = !ARGUMENTS.disable_left_sidebar; } }); // z => Enable/disable processes stats hotkeys.add({ combo: 'z', callback: function () { ARGUMENTS.disable_process = !ARGUMENTS.disable_process; } }); // SLASH => Enable/disable short processes name hotkeys.add({ combo: '/', callback: function () { ARGUMENTS.process_short_name = !ARGUMENTS.process_short_name; } }); // D => Enable/disable Docker stats hotkeys.add({ combo: 'D', callback: function () { ARGUMENTS.disable_docker = !ARGUMENTS.disable_docker; } }); // b => Bytes or bits for network I/O hotkeys.add({ combo: 'b', callback: function () { ARGUMENTS.byte = !ARGUMENTS.byte; } }); // 'B' => Switch between bit/s and IO/s for Disk IO hotkeys.add({ combo: 'B', callback: function () { ARGUMENTS.diskio_iops = !ARGUMENTS.diskio_iops; } }); // l => Show/hide alert logs hotkeys.add({ combo: 'l', callback: function () { ARGUMENTS.disable_alert = !ARGUMENTS.disable_alert; } }); // 1 => Global CPU or per-CPU stats hotkeys.add({ combo: '1', callback: function () { ARGUMENTS.percpu = !ARGUMENTS.percpu; } }); // h => Show/hide this help screen hotkeys.add({ combo: 'h', callback: function () { ARGUMENTS.help_tag = !ARGUMENTS.help_tag; } }); // T => View network I/O as combination hotkeys.add({ combo: 'T', callback: function () { ARGUMENTS.network_sum = !ARGUMENTS.network_sum; } }); // U => View cumulative network I/O hotkeys.add({ combo: 'U', callback: function () { ARGUMENTS.network_cumul = !ARGUMENTS.network_cumul; } }); // F => Show filesystem free space hotkeys.add({ combo: 'F', callback: function () { ARGUMENTS.fs_free_space = !ARGUMENTS.fs_free_space; } }); // 3 => Enable/disable quick look plugin hotkeys.add({ combo: '3', callback: function () { ARGUMENTS.disable_quicklook = !ARGUMENTS.disable_quicklook; } }); // 6 => Enable/disable mean gpu hotkeys.add({ combo: '6', callback: function () { ARGUMENTS.meangpu = !ARGUMENTS.meangpu; } }); // G => Enable/disable gpu hotkeys.add({ combo: 'G', callback: function () { ARGUMENTS.disable_gpu = !ARGUMENTS.disable_gpu; } }); hotkeys.add({ combo: '5', callback: function () { ARGUMENTS.disable_quicklook = !ARGUMENTS.disable_quicklook; ARGUMENTS.disable_cpu = !ARGUMENTS.disable_cpu; ARGUMENTS.disable_mem = !ARGUMENTS.disable_mem; ARGUMENTS.disable_memswap = !ARGUMENTS.disable_memswap; ARGUMENTS.disable_load = !ARGUMENTS.disable_load; ARGUMENTS.disable_gpu = !ARGUMENTS.disable_gpu; } }); // I => Show/hide IP module hotkeys.add({ combo: 'I', callback: function () { ARGUMENTS.disable_ip = !ARGUMENTS.disable_ip; } }); // P => Enable/disable ports module hotkeys.add({ combo: 'P', callback: function () { ARGUMENTS.disable_ports = !ARGUMENTS.disable_ports; } }); // 'W' > Enable/Disable Wifi plugin hotkeys.add({ combo: 'W', callback: function () { ARGUMENTS.disable_wifi = !ARGUMENTS.disable_wifi; } }); } 'use strict'; glancesApp.component('glancesHelp', { controller: GlancesHelpController, controllerAs: 'vm', templateUrl: 'components/help/view.html' }); 'use strict'; function GlancesHelpController($http) { var vm = this; $http.get('api/2/help').then(function (response) { vm.help = response.data; }); } 'use strict'; glancesApp.component('glancesPluginAlert', { controller: GlancesPluginAlertController, controllerAs: 'vm', templateUrl: 'components/plugin-alert/view.html' }); 'use strict'; function GlancesPluginAlertController($scope, favicoService) { var vm = this; var _alerts = []; $scope.$on('data_refreshed', function (event, data) { var alertStats = data.stats['alert']; if (!_.isArray(alertStats)) { alertStats = []; } _alerts = []; for (var i = 0; i < alertStats.length; i++) { var alertalertStats = alertStats[i]; var alert = {}; alert.name = alertalertStats[3]; alert.level = alertalertStats[2]; alert.begin = alertalertStats[0] * 1000; alert.end = alertalertStats[1] * 1000; alert.ongoing = alertalertStats[1] == -1; alert.min = alertalertStats[6]; alert.mean = alertalertStats[5]; alert.max = alertalertStats[4]; if (!alert.ongoing) { var duration = alert.end - alert.begin; var seconds = parseInt((duration / 1000) % 60) , minutes = parseInt((duration / (1000 * 60)) % 60) , hours = parseInt((duration / (1000 * 60 * 60)) % 24); alert.duration = _.padStart(hours, 2, '0') + ":" + _.padStart(minutes, 2, '0') + ":" + _.padStart(seconds, 2, '0'); } _alerts.push(alert); } if (vm.hasOngoingAlerts()) { favicoService.badge(vm.countOngoingAlerts()); } else { favicoService.reset(); } }); vm.hasAlerts = function () { return _alerts.length > 0; }; vm.getAlerts = function () { return _alerts; }; vm.count = function () { return _alerts.length; }; vm.hasOngoingAlerts = function () { return _.filter(_alerts, {'ongoing': true}).length > 0; }; vm.countOngoingAlerts = function () { return _.filter(_alerts, {'ongoing': true}).length; } } 'use strict'; glancesApp.component('glancesPluginAmps', { controller: GlancesPluginAmpsController, controllerAs: 'vm', templateUrl: 'components/plugin-amps/view.html' }); 'use strict'; function GlancesPluginAmpsController($scope, GlancesStats, favicoService) { var vm = this; vm.processes = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var processes = data.stats['amps']; vm.processes = []; angular.forEach(processes, function (process) { if (process.result !== null) { vm.processes.push(process); } }, this); }; vm.getDescriptionDecoration = function (process) { var count = process.count; var countMin = process.countmin; var countMax = process.countmax; var decoration = "ok"; if (count > 0) { if ((countMin === null || count >= countMin) && (countMax === null || count <= countMax)) { decoration = 'ok'; } else { decoration = 'careful'; } } else { decoration = countMin === null ? 'ok' : 'critical'; } return decoration; } } 'use strict'; glancesApp.component('glancesPluginCloud', { controller: GlancesPluginCloudController, controllerAs: 'vm', templateUrl: 'components/plugin-cloud/view.html' }); 'use strict'; function GlancesPluginCloudController($scope, GlancesStats) { var vm = this; vm.provider = null; vm.instance = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['cloud']; if (stats['ami-id'] !== undefined) { vm.provider = 'AWS EC2'; vm.instance = stats['instance-type'] + ' instance ' + stats['instance-id'] + ' (' + stats['region'] + ')'; } } } 'use strict'; glancesApp.component('glancesPluginCpu', { controller: GlancesPluginCpuController, controllerAs: 'vm', templateUrl: 'components/plugin-cpu/view.html' }); 'use strict'; function GlancesPluginCpuController($scope, GlancesStats) { var vm = this; var _view = {}; vm.total = null; vm.user = null; vm.system = null; vm.idle = null; vm.nice = null; vm.irq = null; vm.iowait = null; vm.steal = null; vm.ctx_switches = null; vm.interrupts = null; vm.soft_interrupts = null; vm.syscalls = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['cpu']; _view = data.views['cpu']; vm.total = stats.total; vm.user = stats.user; vm.system = stats.system; vm.idle = stats.idle; vm.nice = stats.nice; vm.irq = stats.irq; vm.iowait = stats.iowait; vm.steal = stats.steal; if (stats.ctx_switches) { vm.ctx_switches = Math.floor(stats.ctx_switches / stats.time_since_update); } if (stats.interrupts) { vm.interrupts = Math.floor(stats.interrupts / stats.time_since_update); } if (stats.soft_interrupts) { vm.soft_interrupts = Math.floor(stats.soft_interrupts / stats.time_since_update); } if (stats.syscalls) { vm.syscalls = Math.floor(stats.syscalls / stats.time_since_update); } } vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } 'use strict'; glancesApp.component('glancesPluginDiskio', { controller: GlancesPluginDiskioController, controllerAs: 'vm', templateUrl: 'components/plugin-diskio/view.html' }); 'use strict'; function GlancesPluginDiskioController($scope, $filter, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.disks = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['diskio'] || []; stats = $filter('orderBy')(stats, 'disk_name'); vm.disks = stats.map(function(diskioData) { var timeSinceUpdate = diskioData['time_since_update']; return { 'name': diskioData['disk_name'], 'bitrate': { 'txps': $filter('bytes')(diskioData['read_bytes'] / timeSinceUpdate), 'rxps': $filter('bytes')(diskioData['write_bytes'] / timeSinceUpdate) }, 'count': { 'txps': $filter('bytes')(diskioData['read_count'] / timeSinceUpdate), 'rxps': $filter('bytes')(diskioData['write_count'] / timeSinceUpdate) }, 'alias': diskioData['alias'] !== undefined ? diskioData['alias'] : null }; }); } } 'use strict'; glancesApp.component('glancesPluginDocker', { controller: GlancesPluginDockerController, controllerAs: 'vm', templateUrl: 'components/plugin-docker/view.html' }); 'use strict'; function GlancesPluginDockerController($scope, GlancesStats) { var vm = this; vm.containers = []; vm.version = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['docker']; vm.containers = []; if (_.isEmpty(stats)) { return; } vm.containers = stats['containers'].map(function(containerData) { return { 'id': containerData.Id, 'name': containerData.Names[0].split('/').splice(-1)[0], 'status': containerData.Status, 'cpu': containerData.cpu.total, 'memory': containerData.memory.usage != undefined ? containerData.memory.usage : '?', 'ior': containerData.io.ior != undefined ? containerData.io.ior : '?', 'iow': containerData.io.iow != undefined ? containerData.io.iow : '?', 'io_time_since_update': containerData.io.time_since_update, 'rx': containerData.network.rx != undefined ? containerData.network.rx : '?', 'tx': containerData.network.tx != undefined ? containerData.network.tx : '?', 'net_time_since_update': containerData.network.time_since_update, 'command': containerData.Command, 'image': containerData.Image }; }); vm.version = stats['version']['Version']; } } 'use strict'; glancesApp.component('glancesPluginFolders', { controller: GlancesPluginFsController, controllerAs: 'vm', templateUrl: 'components/plugin-folders/view.html' }); 'use strict'; function GlancesPluginFoldersController($scope, GlancesStats) { var vm = this; vm.folders = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['folders']; vm.folders = []; for (var i = 0; i < stats.length; i++) { var folderData = stats[i]; var folder = { 'path': folderData['path'], 'size': folderData['size'], 'careful': folderData['careful'], 'warning': folderData['warning'], 'critical': folderData['critical'] }; vm.folders.push(folder); } } vm.getDecoration = function (folder) { if (!Number.isInteger(folder.size)) { return; } if (folder.critical !== null && folder.size > (folder.critical * 1000000)) { return 'critical'; } else if (folder.warning !== null && folder.size > (folder.warning * 1000000)) { return 'warning'; } else if (folder.careful !== null && folder.size > (folder.careful * 1000000)) { return 'careful'; } return 'ok'; }; } 'use strict'; glancesApp.component('glancesPluginFs', { controller: GlancesPluginFsController, controllerAs: 'vm', templateUrl: 'components/plugin-fs/view.html' }); 'use strict'; function GlancesPluginFsController($scope, $filter, GlancesStats, ARGUMENTS) { var vm = this; var _view = {}; vm.arguments = ARGUMENTS; vm.fileSystems = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['fs']; _view = data.views['fs']; vm.fileSystems = []; for (var i = 0; i < stats.length; i++) { var fsData = stats[i]; var shortMountPoint = fsData['mnt_point']; if (shortMountPoint.length > 9) { shortMountPoint = '_' + fsData['mnt_point'].slice(-8); } vm.fileSystems.push(fs = { 'name': fsData['device_name'], 'mountPoint': fsData['mnt_point'], 'shortMountPoint': shortMountPoint, 'percent': fsData['percent'], 'size': fsData['size'], 'used': fsData['used'], 'free': fsData['free'] }); } vm.fileSystems = $filter('orderBy')(vm.fileSystems, 'mnt_point'); }; vm.getDecoration = function (mountPoint, field) { if (_view[mountPoint][field] == undefined) { return; } return _view[mountPoint][field].decoration.toLowerCase(); }; } 'use strict'; glancesApp.component('glancesPluginGpu', { controller: GlancesPluginGpuController, controllerAs: 'vm', templateUrl: 'components/plugin-gpu/view.html' }); 'use strict'; function GlancesPluginGpuController($scope, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; var _view = {}; vm.gpus = []; vm.name = "GPU"; vm.mean = {}; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['gpu']; _view = data.views['gpu']; if (stats.length === 0) { return; } vm.gpus = []; vm.name = "GPU"; vm.mean = { proc: null, mem: null }; var sameName = true; for (var i = 0; i < stats.length; i++) { var gpuData = stats[i]; var gpu = gpuData; vm.mean.proc += gpu.proc; vm.mean.mem += gpu.mem; vm.gpus.push(gpu); } if (stats.length === 1) { vm.name = stats[0].name; } else if (sameName) { vm.name = stats.length + ' GPU ' + stats[0].name; } vm.mean.proc = vm.mean.proc / stats.length; vm.mean.mem = vm.mean.mem / stats.length; } vm.getDecoration = function (gpuId, value) { if (_view[gpuId][value] == undefined) { return; } return _view[gpuId][value].decoration.toLowerCase(); }; vm.getMeanDecoration = function (value) { return vm.getDecoration(0, value); }; } 'use strict'; glancesApp.component('glancesPluginIp', { controller: GlancesPluginIpController, controllerAs: 'vm', templateUrl: 'components/plugin-ip/view.html' }); 'use strict'; function GlancesPluginIpController($scope, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.address = null; vm.gateway = null; vm.mask = null; vm.maskCidr = null; vm.publicAddress = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var ipStats = data.stats['ip']; vm.address = ipStats.address; vm.gateway = ipStats.gateway; vm.mask = ipStats.mask; vm.maskCidr = ipStats.mask_cidr; vm.publicAddress = ipStats.public_address } } 'use strict'; glancesApp.component('glancesPluginIrq', { controller: GlancesPluginIrqController, controllerAs: 'vm', templateUrl: 'components/plugin-irq/view.html' }); 'use strict'; function GlancesPluginIrqController($scope, GlancesStats) { var vm = this; vm.irqs = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['irq']; vm.irqs = []; for (var i = 0; i < stats.length; i++) { var IrqData = stats[i]; var irq = { 'irq_line': IrqData['irq_line'], 'irq_rate': IrqData['irq_rate'] }; vm.irqs.push(irq); } } } 'use strict'; glancesApp.component('glancesPluginLoad', { controller: GlancesPluginLoadController, controllerAs: 'vm', templateUrl: 'components/plugin-load/view.html' }); 'use strict'; function GlancesPluginLoadController($scope, GlancesStats) { var vm = this; var _view = {}; vm.cpucore = null; vm.min1 = null; vm.min5 = null; vm.min15 = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['load']; _view = data.views['load']; vm.cpucore = stats['cpucore']; vm.min1 = stats['min1']; vm.min5 = stats['min5']; vm.min15 = stats['min15']; }; vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } 'use strict'; glancesApp.component('glancesPluginMem', { controller: GlancesPluginMemController, controllerAs: 'vm', templateUrl: 'components/plugin-mem/view.html' }); 'use strict'; function GlancesPluginMemController($scope, GlancesStats) { var vm = this; var _view = {}; vm.percent = null; vm.total = null; vm.used = null; vm.free = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['mem']; _view = data.views['mem']; vm.percent = stats['percent']; vm.total = stats['total']; vm.used = stats['used']; vm.free = stats['free']; } vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } 'use strict'; glancesApp.component('glancesPluginMemMore', { controller: GlancesPluginMemMoreController, controllerAs: 'vm', templateUrl: 'components/plugin-mem-more/view.html' }); 'use strict'; function GlancesPluginMemMoreController($scope, GlancesStats) { var vm = this; vm.active = null; vm.inactive = null; vm.buffers = null; vm.cached = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['mem']; vm.active = stats['active']; vm.inactive = stats['inactive']; vm.buffers = stats['buffers']; vm.cached = stats['cached']; } } 'use strict'; glancesApp.component('glancesPluginMemswap', { controller: GlancesPluginMemswapController, controllerAs: 'vm', templateUrl: 'components/plugin-memswap/view.html' }); 'use strict'; function GlancesPluginMemswapController($scope, GlancesStats) { var vm = this; var _view = {}; vm.percent = null; vm.total = null; vm.used = null; vm.free = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['memswap']; _view = data.views['memswap']; vm.percent = stats['percent']; vm.total = stats['total']; vm.used = stats['used']; vm.free = stats['free']; }; vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } 'use strict'; glancesApp.component('glancesPluginPercpu', { controller: GlancesPluginPercpuController, controllerAs: 'vm', templateUrl: 'components/plugin-percpu/view.html' }); 'use strict'; function GlancesPluginPercpuController($scope, GlancesStats, GlancesPluginHelper) { var vm = this; vm.cpus = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var percpuStats = data.stats['percpu']; vm.cpus = []; for (var i = 0; i < percpuStats.length; i++) { var cpuData = percpuStats[i]; vm.cpus.push({ 'number': cpuData.cpu_number, 'total': cpuData.total, 'user': cpuData.user, 'system': cpuData.system, 'idle': cpuData.idle, 'iowait': cpuData.iowait, 'steal': cpuData.steal }); } } vm.getUserAlert = function (cpu) { return GlancesPluginHelper.getAlert('percpu', 'percpu_user_', cpu.user) }; vm.getSystemAlert = function (cpu) { return GlancesPluginHelper.getAlert('percpu', 'percpu_system_', cpu.system); }; } 'use strict'; glancesApp.component('glancesPluginNetwork', { controller: GlancesPluginNetworkController, controllerAs: 'vm', templateUrl: 'components/plugin-network/view.html' }); 'use strict'; function GlancesPluginNetworkController($scope, $filter, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.networks = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var networkStats = data.stats['network']; vm.networks = []; for (var i = 0; i < networkStats.length; i++) { var networkData = networkStats[i]; var network = { 'interfaceName': networkData['interface_name'], 'rx': networkData['rx'], 'tx': networkData['tx'], 'cx': networkData['cx'], 'time_since_update': networkData['time_since_update'], 'cumulativeRx': networkData['cumulative_rx'], 'cumulativeTx': networkData['cumulative_tx'], 'cumulativeCx': networkData['cumulative_cx'] }; vm.networks.push(network); } vm.networks = $filter('orderBy')(vm.networks, 'interfaceName'); } } 'use strict'; glancesApp.component('glancesPluginPorts', { controller: GlancesPluginPortsController, controllerAs: 'vm', templateUrl: 'components/plugin-ports/view.html' }); 'use strict'; function GlancesPluginPortsController($scope, GlancesStats) { var vm = this; vm.ports = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['ports']; vm.ports = []; angular.forEach(stats, function (port) { vm.ports.push(port); }, this); } vm.getDecoration = function (port) { if (port.status === null) { return 'careful'; } if (port.status === false) { return 'critical'; } if (port.rtt_warning !== null && port.status > port.rtt_warning) { return 'warning'; } return 'ok'; }; } 'use strict'; glancesApp.component('glancesPluginProcess', { controller: GlancesPluginProcessController, controllerAs: 'vm', templateUrl: 'components/plugin-process/view.html' }); 'use strict'; function GlancesPluginProcessController(ARGUMENTS, hotkeys) { var vm = this; vm.arguments = ARGUMENTS; vm.sorter = { column: "cpu_percent", auto: true, isReverseColumn: function (column) { return !(column === 'username' || column === 'name'); }, getColumnLabel: function (column) { if (_.isEqual(column, ['io_read', 'io_write'])) { return 'io_counters'; } else { return column; } } }; // a => Sort processes automatically hotkeys.add({ combo: 'a', callback: function () { vm.sorter.column = "cpu_percent"; vm.sorter.auto = true; } }); // c => Sort processes by CPU% hotkeys.add({ combo: 'c', callback: function () { vm.sorter.column = "cpu_percent"; vm.sorter.auto = false; } }); // m => Sort processes by MEM% hotkeys.add({ combo: 'm', callback: function () { vm.sorter.column = "memory_percent"; vm.sorter.auto = false; } }); // u => Sort processes by user hotkeys.add({ combo: 'u', callback: function () { vm.sorter.column = "username"; vm.sorter.auto = false; } }); // p => Sort processes by name hotkeys.add({ combo: 'p', callback: function () { vm.sorter.column = "name"; vm.sorter.auto = false; } }); // i => Sort processes by I/O rate hotkeys.add({ combo: 'i', callback: function () { vm.sorter.column = ['io_read', 'io_write']; vm.sorter.auto = false; } }); // t => Sort processes by time hotkeys.add({ combo: 't', callback: function () { vm.sorter.column = "timemillis"; vm.sorter.auto = false; } }); } 'use strict'; glancesApp.component('glancesPluginProcesscount', { controller: GlancesPluginProcesscountController, controllerAs: 'vm', bindings: { sorter: '<' }, templateUrl: 'components/plugin-processcount/view.html' }); 'use strict'; function GlancesPluginProcesscountController($scope, GlancesStats) { var vm = this; vm.total = null; vm.running = null; vm.sleeping = null; vm.stopped = null; vm.thread = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var processcountStats = data.stats['processcount']; vm.total = processcountStats['total'] || 0; vm.running = processcountStats['running'] || 0; vm.sleeping = processcountStats['sleeping'] || 0; vm.stopped = processcountStats['stopped'] || 0; vm.thread = processcountStats['thread'] || 0; } } 'use strict'; glancesApp.component('glancesPluginProcesslist', { controller: GlancesPluginProcesslistController, controllerAs: 'vm', bindings: { sorter: '<' }, templateUrl: 'components/plugin-processlist/view.html' }); 'use strict'; function GlancesPluginProcesslistController($scope, GlancesStats, GlancesPluginHelper, $filter, CONFIG, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; vm.processes = []; vm.ioReadWritePresent = false; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var processlistStats = data.stats['processlist'] || []; vm.processes = []; vm.ioReadWritePresent = false; for (var i = 0; i < processlistStats.length; i++) { var process = processlistStats[i]; process.memvirt = process.memory_info[1]; process.memres = process.memory_info[0]; process.timeplus = $filter('timedelta')(process.cpu_times); process.timemillis = $filter('timemillis')(process.cpu_times); process.ioRead = null; process.ioWrite = null; if (process.io_counters) { vm.ioReadWritePresent = true; process.ioRead = (process.io_counters[0] - process.io_counters[2]) / process.time_since_update; if (process.ioRead != 0) { process.ioRead = $filter('bytes')(process.ioRead); } process.ioWrite = (process.io_counters[1] - process.io_counters[3]) / process.time_since_update; if (process.ioWrite != 0) { process.ioWrite = $filter('bytes')(process.ioWrite); } } process.isNice = process.nice !== undefined && ((data.stats.isWindows && process.nice != 32) || (!data.stats.isWindows && process.nice != 0)); if (Array.isArray(process.cmdline)) { process.cmdline = process.cmdline.join(' '); } if (data.isWindows) { process.username = _.last(process.username.split('\\')); } vm.processes.push(process); } } vm.getCpuPercentAlert = function (process) { return GlancesPluginHelper.getAlert('processlist', 'processlist_cpu_', process.cpu_percent); }; vm.getMemoryPercentAlert = function (process) { return GlancesPluginHelper.getAlert('processlist', 'processlist_mem_', process.cpu_percent); }; vm.getLimit = function () { return CONFIG.outputs !== undefined ? CONFIG.outputs.max_processes_display : undefined; }; } 'use strict'; glancesApp.component('glancesPluginQuicklook', { controller: GlancesPluginQuicklookController, controllerAs: 'vm', templateUrl: 'components/plugin-quicklook/view.html' }); 'use strict'; function GlancesPluginQuicklookController($scope, GlancesStats, ARGUMENTS) { var vm = this; vm.arguments = ARGUMENTS; var _view = {}; vm.mem = null; vm.cpu = null; vm.cpu_name = null; vm.cpu_hz_current = null; vm.cpu_hz = null; vm.swap = null; vm.percpus = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['quicklook']; _view = data.views['quicklook']; vm.mem = stats.mem; vm.cpu = stats.cpu; vm.cpu_name = stats.cpu_name; vm.cpu_hz_current = stats.cpu_hz_current; vm.cpu_hz = stats.cpu_hz; vm.swap = stats.swap; vm.percpus = []; angular.forEach(stats.percpu, function (cpu) { vm.percpus.push({ 'number': cpu.cpu_number, 'total': cpu.total }); }, this); }; vm.getDecoration = function (value) { if (_view[value] === undefined) { return; } return _view[value].decoration.toLowerCase(); }; } 'use strict'; glancesApp.component('glancesPluginRaid', { controller: GlancesPluginRaidController, controllerAs: 'vm', templateUrl: 'components/plugin-raid/view.html' }); 'use strict'; function GlancesPluginRaidController($scope, GlancesStats) { var vm = this; vm.disks = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var disks = []; var stats = data.stats['raid']; _.forIn(stats, function (diskData, diskKey) { var disk = { 'name': diskKey, 'type': diskData.type == null ? 'UNKNOWN' : diskData.type, 'used': diskData.used, 'available': diskData.available, 'status': diskData.status, 'degraded': diskData.used < diskData.available, 'config': diskData.config == null ? '' : diskData.config.replace('_', 'A'), 'inactive': diskData.status == 'inactive', 'components': [] }; _.forEach(diskData.components, function (number, name) { disk.components.push({ 'number': number, 'name': name }); }); disks.push(disk); }); vm.disks = disks; }; vm.hasDisks = function () { return vm.disks.length > 0; }; vm.getAlert = function (disk) { if (disk.inactive) { return 'critical'; } if (disk.degraded) { return 'warning'; } return 'ok' }; } 'use strict'; glancesApp.component('glancesPluginSensors', { controller: GlancesPluginSensorsController, controllerAs: 'vm', templateUrl: 'components/plugin-sensors/view.html' }); 'use strict'; function GlancesPluginSensorsController($scope, GlancesStats, GlancesPluginHelper) { var vm = this; vm.sensors = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['sensors']; _.remove(stats, function (sensor) { return (_.isArray(sensor.value) && _.isEmpty(sensor.value)) || sensor.value === 0; }); vm.sensors = stats; }; vm.getAlert = function (sensor) { var current = sensor.type == 'battery' ? 100 - sensor.value : sensor.value; return GlancesPluginHelper.getAlert('sensors', 'sensors_' + sensor.type + '_', current); }; } 'use strict'; glancesApp.component('glancesPluginSystem', { controller: GlancesPluginSystemController, controllerAs: 'vm', templateUrl: 'components/plugin-system/view.html' }); 'use strict'; function GlancesPluginSystemController($scope, GlancesStats) { var vm = this; vm.hostname = null; vm.platform = null; vm.humanReadableName = null; vm.os = { 'name': null, 'version': null }; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); $scope.$on('is_disconnected', function () { vm.isDisconnected = true; }); var loadData = function (data) { var stats = data.stats['system']; vm.hostname = stats['hostname']; vm.platform = stats['platform']; vm.os.name = stats['os_name']; vm.os.version = stats['os_version']; vm.humanReadableName = stats['hr_name']; vm.isDisconnected = false; } } 'use strict'; glancesApp.component('glancesPluginUptime', { controller: GlancesPluginUptimeController, controllerAs: 'vm', templateUrl: 'components/plugin-uptime/view.html' }); 'use strict'; function GlancesPluginUptimeController($scope, GlancesStats) { var vm = this; vm.value = null; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { vm.value = data.stats['uptime']; } } 'use strict'; glancesApp.component('glancesPluginWifi', { controller: GlancesPluginWifiController, controllerAs: 'vm', templateUrl: 'components/plugin-wifi/view.html' }); 'use strict'; function GlancesPluginWifiController($scope, $filter, GlancesStats) { var vm = this; var _view = {}; vm.hotspots = []; vm.$onInit = function () { loadData(GlancesStats.getData()); }; $scope.$on('data_refreshed', function (event, data) { loadData(data); }); var loadData = function (data) { var stats = data.stats['wifi']; _view = data.views['wifi']; //stats = [{"ssid": "Freebox-40A258", "encrypted": true, "signal": -45, "key": "ssid", "encryption_type": "wpa2", "quality": "65/70"}]; vm.hotspots = []; for (var i = 0; i < stats.length; i++) { var hotspotData = stats[i]; if (hotspotData['ssid'] === '') { continue; } vm.hotspots.push({ 'ssid': hotspotData['ssid'], 'encrypted': hotspotData['encrypted'], 'signal': hotspotData['signal'], 'encryption_type': hotspotData['encryption_type'] }); } vm.hotspots = $filter('orderBy')(vm.hotspots, 'ssid'); }; vm.getDecoration = function (hotpost, field) { if (_view[hotpost.ssid][field] === undefined) { return; } return _view[hotpost.ssid][field].decoration.toLowerCase(); }; } glances-2.11.1/glances/outputs/static/public/js/templates.min.js000066400000000000000000001154621315472316100246620ustar00rootroot00000000000000angular.module('glancesApp').run(['$templateCache', function($templateCache) {$templateCache.put('components/glances/view.html','
\n
\n \n
Loading...
\n
\n\n \n\n
\n
\n
\n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n\n
\n \n
\n \n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n
\n \n
\n
\n
\n \n
\n \n \n \n
\n
\n
\n
\n\n'); $templateCache.put('components/help/view.html','
\n
\n
{{vm.help.version}} {{vm.help.psutil_version}}
\n
\n
 
\n
\n
{{vm.help.configuration_file}}
\n
\n
 
\n
\n
{{vm.help.sort_auto}}
\n
{{vm.help.sort_network}}
\n
\n
\n
{{vm.help.sort_cpu}}
\n
{{vm.help.show_hide_alert}}
\n
\n
\n
{{vm.help.sort_mem}}
\n
{{vm.help.percpu}}
\n
\n
\n
{{vm.help.sort_user}}
\n
{{vm.help.show_hide_ip}}
\n
\n
\n
{{vm.help.sort_proc}}
\n
{{vm.help.enable_disable_docker}}
\n
\n
\n
{{vm.help.sort_io}}
\n
{{vm.help.view_network_io_combination}}
\n
\n
\n
{{vm.help.sort_cpu_times}}
\n
{{vm.help.view_cumulative_network}}
\n
\n
\n
{{vm.help.show_hide_diskio}}
\n
{{vm.help.show_hide_filesytem_freespace}}
\n
\n
\n
{{vm.help.show_hide_filesystem}}
\n
{{vm.help.show_hide_vm.help}}
\n
\n
\n
{{vm.help.show_hide_network}}
\n
{{vm.help.diskio_iops}}
\n
\n
\n
{{vm.help.show_hide_sensors}}
\n
{{vm.help.show_hide_top_menu}}
\n
\n
\n
{{vm.help.show_hide_left_sidebar}}
\n
{{vm.help.show_hide_amp}}
\n
\n
\n
{{vm.help.enable_disable_process_stats}}
\n
{{vm.help.show_hide_irq}}
\n
\n
\n
{{vm.help.enable_disable_gpu}}
\n
{{vm.help.enable_disable_mean_gpu}}
\n
\n
\n
{{vm.help.enable_disable_quick_look}}
\n
\n
\n
\n
{{vm.help.enable_disable_short_processname}}
\n
\n
\n
\n
{{vm.help.enable_disable_ports}}
\n
\n
\n\n
\n'); $templateCache.put('components/plugin-alert/view.html','
\n No warning or critical alert detected\n Warning or critical alerts (lasts {{vm.count()}} entries)\n
\n
\n
\n
\n
\n {{alert.begin | date : \'yyyy-MM-dd H:mm:ss\'}} ({{ alert.ongoing ? \'ongoing\' : alert.duration }}) - {{alert.level}} on {{alert.name}}\n ({{alert.max}})\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-amps/view.html','
\n
\n
\n
{{ process.name }}
\n
{{ process.count }}
\n
{{ process.result }}
\n
\n
\n
\n'); $templateCache.put('components/plugin-cloud/view.html','
\n {{ vm.provider }} {{ vm.instance }}\n
\n'); $templateCache.put('components/plugin-cpu/view.html','
\n
\n
\n
\n
\n
CPU
\n
{{ vm.total }}%
\n
\n
\n
user:
\n
\n {{ vm.user }}%\n
\n
\n
\n
system:
\n
\n {{ vm.system }}%\n
\n
\n
\n
idle:
\n
{{ vm.idle }}%
\n
\n
\n
\n \n \n
\n
\n'); $templateCache.put('components/plugin-diskio/view.html','
\n
DISK I/O
\n
R/s
\n
W/s
\n\n
IOR/s
\n
IOW/s
\n
\n
\n
{{(disk.alias ? disk.alias : disk.name) | min_size:9}}
\n
{{disk.bitrate.txps }}
\n
{{disk.bitrate.rxps }}
\n\n
{{disk.count.txps }}
\n
{{disk.count.rxps }}
\n
\n'); $templateCache.put('components/plugin-docker/view.html','
\n CONTAINERS {{ vm.containers.length }} (served by Docker {{ vm.version }})\n\n
\n
\n
Name
\n
Status
\n
CPU%
\n
MEM
\n
IOR/s
\n
IOW/s
\n
RX/s
\n
TX/s
\n
Command
\n
\n
\n
{{ container.name }}
\n
{{ container.status }}\n
\n
{{ container.cpu | number:1 }}
\n
{{ container.memory | bytes }}
\n
{{ container.ior / container.io_time_since_update | bits }}
\n
{{ container.iow / container.io_time_since_update | bits }}
\n
{{ container.rx / container.net_time_since_update | bits }}
\n
{{ container.tx / container.net_time_since_update | bits }}
\n
{{ container.command }}
\n
\n
\n
\n'); $templateCache.put('components/plugin-folders/view.html','
\n
FOLDERS
\n
Size
\n
\n
\n
{{ folder.path }}
\n
{{ folder.size | bytes }}
\n
\n'); $templateCache.put('components/plugin-fs/view.html','
\n
FILE SYS
\n
\n Used\n Free\n
\n
Total
\n
\n
\n
{{ fs.shortMountPoint }} ({{ fs.name }})\n
\n
\n {{ fs.used | bytes }}\n {{ fs.free | bytes }}\n
\n
{{ fs.size | bytes }}
\n
\n'); $templateCache.put('components/plugin-gpu/view.html','
\n
\n {{ vm.name }}\n
\n
\n
\n
proc:
\n
{{ vm.mean.proc |\n number : 0 }}%\n
\n
N/A
\n
\n
\n
mem:
\n
{{ vm.mean.mem | number :\n 0 }}%\n
\n
N/A
\n
\n
\n
\n {{ gpu.gpu_id }}:\n {{ gpu.proc | number : 0 }}%\n N/A\n mem:\n {{ gpu.mem | number : 0 }}%\n N/A\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-ip/view.html','
\n  - IP {{ vm.address }}/{{ vm.maskCidr }} Pub {{ vm.publicAddress }}\n
\n'); $templateCache.put('components/plugin-irq/view.html','
\n
IRQ
\n
\n
Rate/s
\n
\n
\n
{{irq.irq_line}}
\n
\n
{{irq.irq_rate}}
\n
\n'); $templateCache.put('components/plugin-load/view.html','
\n
\n
\n
LOAD
\n
{{ vm.cpucore }}-core
\n
\n
\n
1 min:
\n
\n {{ vm.min1 | number : 2}}\n
\n
\n
\n
5 min:
\n
\n {{ vm.min5 | number : 2}}\n
\n
\n
\n
15 min:
\n
\n {{ vm.min15 | number : 2}}\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-mem/view.html','
\n
\n
\n
MEM
\n
{{ vm.percent }}%
\n
\n
\n
total:
\n
{{ vm.total | bytes }}
\n
\n
\n
used:
\n
\n {{ vm.used | bytes:2 }}\n
\n
\n
\n
free:
\n
{{ vm.free | bytes }}
\n
\n
\n
\n'); $templateCache.put('components/plugin-mem-more/view.html','
\n
\n
\n
active:
\n
{{ vm.active | bytes }}
\n
\n
\n
inactive:
\n
{{ vm.inactive | bytes }}
\n
\n
\n
buffers:
\n
{{ vm.buffers | bytes }}
\n
\n
\n
cached:
\n
{{ vm.cached | bytes }}
\n
\n
\n
\n'); $templateCache.put('components/plugin-memswap/view.html','
\n
\n
\n
SWAP
\n
{{ vm.percent }}%
\n
\n
\n
total:
\n
{{ vm.total | bytes }}
\n
\n
\n
used:
\n
\n {{ vm.used | bytes }}\n
\n
\n
\n
free:
\n
{{ vm.free | bytes }}
\n
\n
\n
\n'); $templateCache.put('components/plugin-percpu/view.html','
\n
\n
\n
PER CPU
\n
{{ percpu.total }}%
\n
\n
\n
user:
\n
\n {{ percpu.user }}%\n
\n
\n
\n
system:
\n
\n {{ percpu.system }}%\n
\n
\n
\n
idle:
\n
{{ percpu.idle }}%
\n
\n
\n
iowait:
\n
\n {{ percpu.iowait }}%\n
\n
\n
\n
steal:
\n
\n {{ percpu.steal }}%\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-network/view.html','
\n
NETWORK
\n
Rx/s
\n
Tx/s
\n\n
\n
Rx+Tx/s
\n\n
Rx
\n
Tx
\n\n
\n
Rx+Tx
\n
\n
\n
{{ network.interfaceName | min_size }}
\n
{{ vm.arguments.byte ?\n (network.rx / network.time_since_update | bytes) : (network.rx / network.time_since_update | bits) }}\n
\n
{{ vm.arguments.byte ?\n (network.tx / network.time_since_update | bytes) : (network.tx / network.time_since_update | bits) }}\n
\n\n
\n
{{ vm.arguments.byte ?\n (network.cx / network.time_since_update | bytes) : (network.cx / network.time_since_update | bits) }}\n
\n\n
{{ vm.arguments.byte ?\n (network.cumulativeRx | bytes) : (network.cumulativeRx | bits) }}\n
\n
{{ vm.arguments.byte ?\n (network.cumulativeTx | bytes) : (network.cumulativeTx | bits) }}\n
\n\n
\n
{{ vm.arguments.byte ?\n (network.cumulativeCx | bytes) : (network.cumulativeCx | bits) }}\n
\n
\n'); $templateCache.put('components/plugin-ports/view.html','
\n
{{(port.description ? port.description : port.host + \' \' + port.port) | min_size:\n 20}}\n
\n
\n
\n Scanning\n Timeout\n Open\n {{port.status * 1000.0 | number:0}}ms\n
\n
'); $templateCache.put('components/plugin-process/view.html','
\n \n
\n
\n \n
\n
\n \n
\n
PROCESSES DISABLED (press \'z\' to display)
\n'); $templateCache.put('components/plugin-processcount/view.html','
\n TASKS\n {{ vm.total }} ({{ vm.thread }} thr),\n {{ vm.running }} run,\n {{ vm.sleeping }} slp,\n {{ vm.stopped }} oth\n sorted {{ vm.sorter.auto ? \'automatically\' : \'\' }} by {{ vm.sorter.getColumnLabel(vm.sorter.column) }}, flat view\n
'); $templateCache.put('components/plugin-processlist/view.html','
\n
\n
\n
CPU%
\n
MEM%
\n \n \n
PID
\n
USER
\n
NI
\n
S
\n \n \n \n
Command
\n
\n
\n
{{process.cpu_percent | number:1}}
\n
{{process.memory_percent | number:1}}\n
\n \n \n
{{process.pid}}
\n
{{process.username}}
\n
{{process.nice | exclamation}}
\n
{{process.status}}
\n \n \n \n
{{process.name}}
\n
{{process.cmdline}}
\n
\n
\n
\n'); $templateCache.put('components/plugin-quicklook/view.html','
\n
\n {{ vm.cpu_name }}\n
\n
\n
\n
CPU
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ vm.cpu }}%\n
\n
\n
\n
CPU{{ percpu.number }}
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ percpu.total }}%\n
\n
\n
\n
MEM
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ vm.mem }}%\n
\n
\n
\n
SWAP
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ vm.swap }}%\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-raid/view.html','
\n
RAID disks
\n
Used
\n
Total
\n
\n
\n
\n {{ disk.type | uppercase }} {{ disk.name }}\n
\u2514\u2500 Degraded mode
\n
   \u2514\u2500 {{ disk.config }}
\n\n
\u2514\u2500 Status {{ disk.status }}
\n
\n    {{ $last ? \'\u2514\u2500\' : \'\u251C\u2500\' }} disk {{ component.number }}: {{ component.name }}\n
\n
\n
{{ disk.used }}
\n
{{ disk.available }}
\n
\n'); $templateCache.put('components/plugin-sensors/view.html','
\n
SENSORS
\n
\n\n
\n
{{ sensor.label }}
\n
{{ sensor.unit }}
\n
{{ sensor.value }}
\n
\n'); $templateCache.put('components/plugin-system/view.html','
\n Disconnected from\n {{ vm.hostname }}\n \n \n
\n'); $templateCache.put('components/plugin-uptime/view.html','
\n Uptime: {{ vm.value }}\n
\n'); $templateCache.put('components/plugin-wifi/view.html','
\n
WIFI
\n
\n
dBm
\n
\n
\n
{{ hotspot.ssid|limitTo:20 }} {{ hotspot.encryption_type }}\n
\n
\n
{{ hotspot.signal }}
\n
\n');}]);glances-2.11.1/glances/outputs/static/public/js/vendor.min.js000066400000000000000000071377761315472316100242040ustar00rootroot00000000000000/** * @license AngularJS v1.6.6 * (c) 2010-2017 Google, Inc. http://angularjs.org * License: MIT */ (function(window) {'use strict'; /* exported minErrConfig, errorHandlingConfig, isValidObjectMaxDepth */ var minErrConfig = { objectMaxDepth: 5 }; /** * @ngdoc function * @name angular.errorHandlingConfig * @module ng * @kind function * * @description * Configure several aspects of error handling in AngularJS if used as a setter or return the * current configuration if used as a getter. The following options are supported: * * - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages. * * Omitted or undefined options will leave the corresponding configuration values unchanged. * * @param {Object=} config - The configuration object. May only contain the options that need to be * updated. Supported keys: * * * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a * non-positive or non-numeric value, removes the max depth limit. * Default: 5 */ function errorHandlingConfig(config) { if (isObject(config)) { if (isDefined(config.objectMaxDepth)) { minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN; } } else { return minErrConfig; } } /** * @private * @param {Number} maxDepth * @return {boolean} */ function isValidObjectMaxDepth(maxDepth) { return isNumber(maxDepth) && maxDepth > 0; } /** * @description * * This object provides a utility for producing rich Error messages within * Angular. It can be called as follows: * * var exampleMinErr = minErr('example'); * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); * * The above creates an instance of minErr in the example namespace. The * resulting error will have a namespaced error code of example.one. The * resulting error will replace {0} with the value of foo, and {1} with the * value of bar. The object is not restricted in the number of arguments it can * take. * * If fewer arguments are specified than necessary for interpolation, the extra * interpolation markers will be preserved in the final string. * * Since data will be parsed statically during a build step, some restrictions * are applied with respect to how minErr instances are created and called. * Instances should have names of the form namespaceMinErr for a minErr created * using minErr('namespace') . Error codes, namespaces and template strings * should all be static strings, not variables or general expressions. * * @param {string} module The namespace to use for the new minErr instance. * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning * error from returned function, for cases when a particular type of error is useful. * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance */ function minErr(module, ErrorConstructor) { ErrorConstructor = ErrorConstructor || Error; return function() { var code = arguments[0], template = arguments[1], message = '[' + (module ? module + ':' : '') + code + '] ', templateArgs = sliceArgs(arguments, 2).map(function(arg) { return toDebugString(arg, minErrConfig.objectMaxDepth); }), paramPrefix, i; message += template.replace(/\{\d+\}/g, function(match) { var index = +match.slice(1, -1); if (index < templateArgs.length) { return templateArgs[index]; } return match; }); message += '\nhttp://errors.angularjs.org/1.6.6/' + (module ? module + '/' : '') + code; for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]); } return new ErrorConstructor(message); }; } /* We need to tell ESLint what variables are being exported */ /* exported angular, msie, jqLite, jQuery, slice, splice, push, toString, minErrConfig, errorHandlingConfig, isValidObjectMaxDepth, ngMinErr, angularModule, uid, REGEX_STRING_REGEXP, VALIDITY_STATE_PROPERTY, lowercase, uppercase, manualLowercase, manualUppercase, nodeName_, isArrayLike, forEach, forEachSorted, reverseParams, nextUid, setHashKey, extend, toInt, inherit, merge, noop, identity, valueFn, isUndefined, isDefined, isObject, isBlankObject, isString, isNumber, isNumberNaN, isDate, isError, isArray, isFunction, isRegExp, isWindow, isScope, isFile, isFormData, isBlob, isBoolean, isPromiseLike, trim, escapeForRegexp, isElement, makeMap, includes, arrayRemove, copy, simpleCompare, equals, csp, jq, concat, sliceArgs, bind, toJsonReplacer, toJson, fromJson, convertTimezoneToLocal, timezoneToOffset, startingTag, tryDecodeURIComponent, parseKeyValue, toKeyValue, encodeUriSegment, encodeUriQuery, angularInit, bootstrap, getTestability, snake_case, bindJQuery, assertArg, assertArgFn, assertNotHasOwnProperty, getter, getBlockNodes, hasOwnProperty, createMap, stringify, NODE_TYPE_ELEMENT, NODE_TYPE_ATTRIBUTE, NODE_TYPE_TEXT, NODE_TYPE_COMMENT, NODE_TYPE_DOCUMENT, NODE_TYPE_DOCUMENT_FRAGMENT */ //////////////////////////////////// /** * @ngdoc module * @name ng * @module ng * @installation * @description * * # ng (core module) * The ng module is loaded by default when an AngularJS application is started. The module itself * contains the essential components for an AngularJS application to function. The table below * lists a high level breakdown of each of the services/factories, filters, directives and testing * components available within this core module. * *
*/ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; // The name of a form control's ValidityState property. // This is used so that it's possible for internal tests to create mock ValidityStates. var VALIDITY_STATE_PROPERTY = 'validity'; var hasOwnProperty = Object.prototype.hasOwnProperty; /** * @ngdoc function * @name angular.lowercase * @module ng * @kind function * * @deprecated * sinceVersion="1.5.0" * removeVersion="1.7.0" * Use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) instead. * * @description Converts the specified string to lowercase. * @param {string} string String to be converted to lowercase. * @returns {string} Lowercased string. */ var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;}; /** * @ngdoc function * @name angular.uppercase * @module ng * @kind function * * @deprecated * sinceVersion="1.5.0" * removeVersion="1.7.0" * Use [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) instead. * * @description Converts the specified string to uppercase. * @param {string} string String to be converted to uppercase. * @returns {string} Uppercased string. */ var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;}; var manualLowercase = function(s) { /* eslint-disable no-bitwise */ return isString(s) ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) : s; /* eslint-enable */ }; var manualUppercase = function(s) { /* eslint-disable no-bitwise */ return isString(s) ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) : s; /* eslint-enable */ }; // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods // with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387 if ('i' !== 'I'.toLowerCase()) { lowercase = manualLowercase; uppercase = manualUppercase; } var msie, // holds major version number for IE, or NaN if UA is not IE. jqLite, // delay binding since jQuery could be loaded after us. jQuery, // delay binding slice = [].slice, splice = [].splice, push = [].push, toString = Object.prototype.toString, getPrototypeOf = Object.getPrototypeOf, ngMinErr = minErr('ng'), /** @name angular */ angular = window.angular || (window.angular = {}), angularModule, uid = 0; // Support: IE 9-11 only /** * documentMode is an IE-only property * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx */ msie = window.document.documentMode; /** * @private * @param {*} obj * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, * String ...) */ function isArrayLike(obj) { // `null`, `undefined` and `window` are not array-like if (obj == null || isWindow(obj)) return false; // arrays, strings and jQuery/jqLite objects are array like // * jqLite is either the jQuery or jqLite constructor function // * we have to check the existence of jqLite first as this method is called // via the forEach method when constructing the jqLite object in the first place if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true; // Support: iOS 8.2 (not reproducible in simulator) // "length" in obj used to prevent JIT error (gh-11508) var length = 'length' in Object(obj) && obj.length; // NodeList objects (with `item` method) and // other objects with suitable length characteristics are array-like return isNumber(length) && (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item === 'function'); } /** * @ngdoc function * @name angular.forEach * @module ng * @kind function * * @description * Invokes the `iterator` function once for each item in `obj` collection, which can be either an * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value` * is the value of an object property or an array element, `key` is the object property key or * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional. * * It is worth noting that `.forEach` does not iterate over inherited properties because it filters * using the `hasOwnProperty` method. * * Unlike ES262's * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18), * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just * return the value provided. * ```js var values = {name: 'misko', gender: 'male'}; var log = []; angular.forEach(values, function(value, key) { this.push(key + ': ' + value); }, log); expect(log).toEqual(['name: misko', 'gender: male']); ``` * * @param {Object|Array} obj Object to iterate over. * @param {Function} iterator Iterator function. * @param {Object=} context Object to become context (`this`) for the iterator function. * @returns {Object|Array} Reference to `obj`. */ function forEach(obj, iterator, context) { var key, length; if (obj) { if (isFunction(obj)) { for (key in obj) { if (key !== 'prototype' && key !== 'length' && key !== 'name' && obj.hasOwnProperty(key)) { iterator.call(context, obj[key], key, obj); } } } else if (isArray(obj) || isArrayLike(obj)) { var isPrimitive = typeof obj !== 'object'; for (key = 0, length = obj.length; key < length; key++) { if (isPrimitive || key in obj) { iterator.call(context, obj[key], key, obj); } } } else if (obj.forEach && obj.forEach !== forEach) { obj.forEach(iterator, context, obj); } else if (isBlankObject(obj)) { // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty for (key in obj) { iterator.call(context, obj[key], key, obj); } } else if (typeof obj.hasOwnProperty === 'function') { // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed for (key in obj) { if (obj.hasOwnProperty(key)) { iterator.call(context, obj[key], key, obj); } } } else { // Slow path for objects which do not have a method `hasOwnProperty` for (key in obj) { if (hasOwnProperty.call(obj, key)) { iterator.call(context, obj[key], key, obj); } } } } return obj; } function forEachSorted(obj, iterator, context) { var keys = Object.keys(obj).sort(); for (var i = 0; i < keys.length; i++) { iterator.call(context, obj[keys[i]], keys[i]); } return keys; } /** * when using forEach the params are value, key, but it is often useful to have key, value. * @param {function(string, *)} iteratorFn * @returns {function(*, string)} */ function reverseParams(iteratorFn) { return function(value, key) {iteratorFn(key, value);}; } /** * A consistent way of creating unique IDs in angular. * * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before * we hit number precision issues in JavaScript. * * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M * * @returns {number} an unique alpha-numeric string */ function nextUid() { return ++uid; } /** * Set or clear the hashkey for an object. * @param obj object * @param h the hashkey (!truthy to delete the hashkey) */ function setHashKey(obj, h) { if (h) { obj.$$hashKey = h; } else { delete obj.$$hashKey; } } function baseExtend(dst, objs, deep) { var h = dst.$$hashKey; for (var i = 0, ii = objs.length; i < ii; ++i) { var obj = objs[i]; if (!isObject(obj) && !isFunction(obj)) continue; var keys = Object.keys(obj); for (var j = 0, jj = keys.length; j < jj; j++) { var key = keys[j]; var src = obj[key]; if (deep && isObject(src)) { if (isDate(src)) { dst[key] = new Date(src.valueOf()); } else if (isRegExp(src)) { dst[key] = new RegExp(src); } else if (src.nodeName) { dst[key] = src.cloneNode(true); } else if (isElement(src)) { dst[key] = src.clone(); } else { if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {}; baseExtend(dst[key], [src], true); } } else { dst[key] = src; } } } setHashKey(dst, h); return dst; } /** * @ngdoc function * @name angular.extend * @module ng * @kind function * * @description * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s) * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`. * * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use * {@link angular.merge} for this. * * @param {Object} dst Destination object. * @param {...Object} src Source object(s). * @returns {Object} Reference to `dst`. */ function extend(dst) { return baseExtend(dst, slice.call(arguments, 1), false); } /** * @ngdoc function * @name angular.merge * @module ng * @kind function * * @description * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s) * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`. * * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source * objects, performing a deep copy. * * @deprecated * sinceVersion="1.6.5" * This function is deprecated, but will not be removed in the 1.x lifecycle. * There are edge cases (see {@link angular.merge#known-issues known issues}) that are not * supported by this function. We suggest * using [lodash's merge()](https://lodash.com/docs/4.17.4#merge) instead. * * @knownIssue * This is a list of (known) object types that are not handled correctly by this function: * - [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob) * - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream) * - [`CanvasGradient`](https://developer.mozilla.org/docs/Web/API/CanvasGradient) * - AngularJS {@link $rootScope.Scope scopes}; * * @param {Object} dst Destination object. * @param {...Object} src Source object(s). * @returns {Object} Reference to `dst`. */ function merge(dst) { return baseExtend(dst, slice.call(arguments, 1), true); } function toInt(str) { return parseInt(str, 10); } var isNumberNaN = Number.isNaN || function isNumberNaN(num) { // eslint-disable-next-line no-self-compare return num !== num; }; function inherit(parent, extra) { return extend(Object.create(parent), extra); } /** * @ngdoc function * @name angular.noop * @module ng * @kind function * * @description * A function that performs no operations. This function can be useful when writing code in the * functional style. ```js function foo(callback) { var result = calculateResult(); (callback || angular.noop)(result); } ``` */ function noop() {} noop.$inject = []; /** * @ngdoc function * @name angular.identity * @module ng * @kind function * * @description * A function that returns its first argument. This function is useful when writing code in the * functional style. * ```js function transformer(transformationFn, value) { return (transformationFn || angular.identity)(value); }; // E.g. function getResult(fn, input) { return (fn || angular.identity)(input); }; getResult(function(n) { return n * 2; }, 21); // returns 42 getResult(null, 21); // returns 21 getResult(undefined, 21); // returns 21 ``` * * @param {*} value to be returned. * @returns {*} the value passed in. */ function identity($) {return $;} identity.$inject = []; function valueFn(value) {return function valueRef() {return value;};} function hasCustomToString(obj) { return isFunction(obj.toString) && obj.toString !== toString; } /** * @ngdoc function * @name angular.isUndefined * @module ng * @kind function * * @description * Determines if a reference is undefined. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is undefined. */ function isUndefined(value) {return typeof value === 'undefined';} /** * @ngdoc function * @name angular.isDefined * @module ng * @kind function * * @description * Determines if a reference is defined. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is defined. */ function isDefined(value) {return typeof value !== 'undefined';} /** * @ngdoc function * @name angular.isObject * @module ng * @kind function * * @description * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not * considered to be objects. Note that JavaScript arrays are objects. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Object` but not `null`. */ function isObject(value) { // http://jsperf.com/isobject4 return value !== null && typeof value === 'object'; } /** * Determine if a value is an object with a null prototype * * @returns {boolean} True if `value` is an `Object` with a null prototype */ function isBlankObject(value) { return value !== null && typeof value === 'object' && !getPrototypeOf(value); } /** * @ngdoc function * @name angular.isString * @module ng * @kind function * * @description * Determines if a reference is a `String`. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `String`. */ function isString(value) {return typeof value === 'string';} /** * @ngdoc function * @name angular.isNumber * @module ng * @kind function * * @description * Determines if a reference is a `Number`. * * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`. * * If you wish to exclude these then you can use the native * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite) * method. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Number`. */ function isNumber(value) {return typeof value === 'number';} /** * @ngdoc function * @name angular.isDate * @module ng * @kind function * * @description * Determines if a value is a date. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Date`. */ function isDate(value) { return toString.call(value) === '[object Date]'; } /** * @ngdoc function * @name angular.isArray * @module ng * @kind function * * @description * Determines if a reference is an `Array`. Alias of Array.isArray. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Array`. */ var isArray = Array.isArray; /** * @description * Determines if a reference is an `Error`. * Loosely based on https://www.npmjs.com/package/iserror * * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Error`. */ function isError(value) { var tag = toString.call(value); switch (tag) { case '[object Error]': return true; case '[object Exception]': return true; case '[object DOMException]': return true; default: return value instanceof Error; } } /** * @ngdoc function * @name angular.isFunction * @module ng * @kind function * * @description * Determines if a reference is a `Function`. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Function`. */ function isFunction(value) {return typeof value === 'function';} /** * Determines if a value is a regular expression object. * * @private * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `RegExp`. */ function isRegExp(value) { return toString.call(value) === '[object RegExp]'; } /** * Checks if `obj` is a window object. * * @private * @param {*} obj Object to check * @returns {boolean} True if `obj` is a window obj. */ function isWindow(obj) { return obj && obj.window === obj; } function isScope(obj) { return obj && obj.$evalAsync && obj.$watch; } function isFile(obj) { return toString.call(obj) === '[object File]'; } function isFormData(obj) { return toString.call(obj) === '[object FormData]'; } function isBlob(obj) { return toString.call(obj) === '[object Blob]'; } function isBoolean(value) { return typeof value === 'boolean'; } function isPromiseLike(obj) { return obj && isFunction(obj.then); } var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/; function isTypedArray(value) { return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value)); } function isArrayBuffer(obj) { return toString.call(obj) === '[object ArrayBuffer]'; } var trim = function(value) { return isString(value) ? value.trim() : value; }; // Copied from: // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021 // Prereq: s is a string. var escapeForRegexp = function(s) { return s .replace(/([-()[\]{}+?*.$^|,:#= 0) { array.splice(index, 1); } return index; } /** * @ngdoc function * @name angular.copy * @module ng * @kind function * * @description * Creates a deep copy of `source`, which should be an object or an array. * * * If no destination is supplied, a copy of the object or array is created. * * If a destination is provided, all of its elements (for arrays) or properties (for objects) * are deleted and then all elements/properties from the source are copied to it. * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. * * If `source` is identical to `destination` an exception will be thrown. * *
*
* Only enumerable properties are taken into account. Non-enumerable properties (both on `source` * and on `destination`) will be ignored. *
* * @param {*} source The source that will be used to make a copy. * Can be any type, including primitives, `null`, and `undefined`. * @param {(Object|Array)=} destination Destination into which the source is copied. If * provided, must be of the same type as `source`. * @returns {*} The copy or updated `destination`, if `destination` was specified. * * @example


Gender:
form = {{user | json}}
master = {{master | json}}
// Module: copyExample angular. module('copyExample', []). controller('ExampleController', ['$scope', function($scope) { $scope.master = {}; $scope.reset = function() { // Example with 1 argument $scope.user = angular.copy($scope.master); }; $scope.update = function(user) { // Example with 2 arguments angular.copy(user, $scope.master); }; $scope.reset(); }]);
*/ function copy(source, destination, maxDepth) { var stackSource = []; var stackDest = []; maxDepth = isValidObjectMaxDepth(maxDepth) ? maxDepth : NaN; if (destination) { if (isTypedArray(destination) || isArrayBuffer(destination)) { throw ngMinErr('cpta', 'Can\'t copy! TypedArray destination cannot be mutated.'); } if (source === destination) { throw ngMinErr('cpi', 'Can\'t copy! Source and destination are identical.'); } // Empty the destination object if (isArray(destination)) { destination.length = 0; } else { forEach(destination, function(value, key) { if (key !== '$$hashKey') { delete destination[key]; } }); } stackSource.push(source); stackDest.push(destination); return copyRecurse(source, destination, maxDepth); } return copyElement(source, maxDepth); function copyRecurse(source, destination, maxDepth) { maxDepth--; if (maxDepth < 0) { return '...'; } var h = destination.$$hashKey; var key; if (isArray(source)) { for (var i = 0, ii = source.length; i < ii; i++) { destination.push(copyElement(source[i], maxDepth)); } } else if (isBlankObject(source)) { // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty for (key in source) { destination[key] = copyElement(source[key], maxDepth); } } else if (source && typeof source.hasOwnProperty === 'function') { // Slow path, which must rely on hasOwnProperty for (key in source) { if (source.hasOwnProperty(key)) { destination[key] = copyElement(source[key], maxDepth); } } } else { // Slowest path --- hasOwnProperty can't be called as a method for (key in source) { if (hasOwnProperty.call(source, key)) { destination[key] = copyElement(source[key], maxDepth); } } } setHashKey(destination, h); return destination; } function copyElement(source, maxDepth) { // Simple values if (!isObject(source)) { return source; } // Already copied values var index = stackSource.indexOf(source); if (index !== -1) { return stackDest[index]; } if (isWindow(source) || isScope(source)) { throw ngMinErr('cpws', 'Can\'t copy! Making copies of Window or Scope instances is not supported.'); } var needsRecurse = false; var destination = copyType(source); if (destination === undefined) { destination = isArray(source) ? [] : Object.create(getPrototypeOf(source)); needsRecurse = true; } stackSource.push(source); stackDest.push(destination); return needsRecurse ? copyRecurse(source, destination, maxDepth) : destination; } function copyType(source) { switch (toString.call(source)) { case '[object Int8Array]': case '[object Int16Array]': case '[object Int32Array]': case '[object Float32Array]': case '[object Float64Array]': case '[object Uint8Array]': case '[object Uint8ClampedArray]': case '[object Uint16Array]': case '[object Uint32Array]': return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length); case '[object ArrayBuffer]': // Support: IE10 if (!source.slice) { // If we're in this case we know the environment supports ArrayBuffer /* eslint-disable no-undef */ var copied = new ArrayBuffer(source.byteLength); new Uint8Array(copied).set(new Uint8Array(source)); /* eslint-enable */ return copied; } return source.slice(0); case '[object Boolean]': case '[object Number]': case '[object String]': case '[object Date]': return new source.constructor(source.valueOf()); case '[object RegExp]': var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]); re.lastIndex = source.lastIndex; return re; case '[object Blob]': return new source.constructor([source], {type: source.type}); } if (isFunction(source.cloneNode)) { return source.cloneNode(true); } } } // eslint-disable-next-line no-self-compare function simpleCompare(a, b) { return a === b || (a !== a && b !== b); } /** * @ngdoc function * @name angular.equals * @module ng * @kind function * * @description * Determines if two objects or two values are equivalent. Supports value types, regular * expressions, arrays and objects. * * Two objects or values are considered equivalent if at least one of the following is true: * * * Both objects or values pass `===` comparison. * * Both objects or values are of the same type and all of their properties are equal by * comparing them with `angular.equals`. * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) * * Both values represent the same regular expression (In JavaScript, * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual * representation matches). * * During a property comparison, properties of `function` type and properties with names * that begin with `$` are ignored. * * Scope and DOMWindow objects are being compared only by identify (`===`). * * @param {*} o1 Object or value to compare. * @param {*} o2 Object or value to compare. * @returns {boolean} True if arguments are equal. * * @example

User 1

Name: Age:

User 2

Name: Age:

User 1:
{{user1 | json}}
User 2:
{{user2 | json}}
Equal:
{{result}}
angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) { $scope.user1 = {}; $scope.user2 = {}; $scope.compare = function() { $scope.result = angular.equals($scope.user1, $scope.user2); }; }]);
*/ function equals(o1, o2) { if (o1 === o2) return true; if (o1 === null || o2 === null) return false; // eslint-disable-next-line no-self-compare if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN var t1 = typeof o1, t2 = typeof o2, length, key, keySet; if (t1 === t2 && t1 === 'object') { if (isArray(o1)) { if (!isArray(o2)) return false; if ((length = o1.length) === o2.length) { for (key = 0; key < length; key++) { if (!equals(o1[key], o2[key])) return false; } return true; } } else if (isDate(o1)) { if (!isDate(o2)) return false; return simpleCompare(o1.getTime(), o2.getTime()); } else if (isRegExp(o1)) { if (!isRegExp(o2)) return false; return o1.toString() === o2.toString(); } else { if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2) || isDate(o2) || isRegExp(o2)) return false; keySet = createMap(); for (key in o1) { if (key.charAt(0) === '$' || isFunction(o1[key])) continue; if (!equals(o1[key], o2[key])) return false; keySet[key] = true; } for (key in o2) { if (!(key in keySet) && key.charAt(0) !== '$' && isDefined(o2[key]) && !isFunction(o2[key])) return false; } return true; } } return false; } var csp = function() { if (!isDefined(csp.rules)) { var ngCspElement = (window.document.querySelector('[ng-csp]') || window.document.querySelector('[data-ng-csp]')); if (ngCspElement) { var ngCspAttribute = ngCspElement.getAttribute('ng-csp') || ngCspElement.getAttribute('data-ng-csp'); csp.rules = { noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1), noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1) }; } else { csp.rules = { noUnsafeEval: noUnsafeEval(), noInlineStyle: false }; } } return csp.rules; function noUnsafeEval() { try { // eslint-disable-next-line no-new, no-new-func new Function(''); return false; } catch (e) { return true; } } }; /** * @ngdoc directive * @module ng * @name ngJq * * @element ANY * @param {string=} ngJq the name of the library available under `window` * to be used for angular.element * @description * Use this directive to force the angular.element library. This should be * used to force either jqLite by leaving ng-jq blank or setting the name of * the jquery variable under window (eg. jQuery). * * Since angular looks for this directive when it is loaded (doesn't wait for the * DOMContentLoaded event), it must be placed on an element that comes before the script * which loads angular. Also, only the first instance of `ng-jq` will be used and all * others ignored. * * @example * This example shows how to force jqLite using the `ngJq` directive to the `html` tag. ```html ... ... ``` * @example * This example shows how to use a jQuery based library of a different name. * The library name must be available at the top most 'window'. ```html ... ... ``` */ var jq = function() { if (isDefined(jq.name_)) return jq.name_; var el; var i, ii = ngAttrPrefixes.length, prefix, name; for (i = 0; i < ii; ++i) { prefix = ngAttrPrefixes[i]; el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]'); if (el) { name = el.getAttribute(prefix + 'jq'); break; } } return (jq.name_ = name); }; function concat(array1, array2, index) { return array1.concat(slice.call(array2, index)); } function sliceArgs(args, startIndex) { return slice.call(args, startIndex || 0); } /** * @ngdoc function * @name angular.bind * @module ng * @kind function * * @description * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for * `fn`). You can supply optional `args` that are prebound to the function. This feature is also * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application). * * @param {Object} self Context which `fn` should be evaluated in. * @param {function()} fn Function to be bound. * @param {...*} args Optional arguments to be prebound to the `fn` function call. * @returns {function()} Function that wraps the `fn` with all the specified bindings. */ function bind(self, fn) { var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : []; if (isFunction(fn) && !(fn instanceof RegExp)) { return curryArgs.length ? function() { return arguments.length ? fn.apply(self, concat(curryArgs, arguments, 0)) : fn.apply(self, curryArgs); } : function() { return arguments.length ? fn.apply(self, arguments) : fn.call(self); }; } else { // In IE, native methods are not functions so they cannot be bound (note: they don't need to be). return fn; } } function toJsonReplacer(key, value) { var val = value; if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') { val = undefined; } else if (isWindow(value)) { val = '$WINDOW'; } else if (value && window.document === value) { val = '$DOCUMENT'; } else if (isScope(value)) { val = '$SCOPE'; } return val; } /** * @ngdoc function * @name angular.toJson * @module ng * @kind function * * @description * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be * stripped since angular uses this notation internally. * * @param {Object|Array|Date|string|number|boolean} obj Input to be serialized into JSON. * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace. * If set to an integer, the JSON output will contain that many spaces per indentation. * @returns {string|undefined} JSON-ified string representing `obj`. * @knownIssue * * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date` * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the * `Date.prototype.toJSON` method as follows: * * ``` * var _DatetoJSON = Date.prototype.toJSON; * Date.prototype.toJSON = function() { * try { * return _DatetoJSON.call(this); * } catch(e) { * if (e instanceof RangeError) { * return null; * } * throw e; * } * }; * ``` * * See https://github.com/angular/angular.js/pull/14221 for more information. */ function toJson(obj, pretty) { if (isUndefined(obj)) return undefined; if (!isNumber(pretty)) { pretty = pretty ? 2 : null; } return JSON.stringify(obj, toJsonReplacer, pretty); } /** * @ngdoc function * @name angular.fromJson * @module ng * @kind function * * @description * Deserializes a JSON string. * * @param {string} json JSON string to deserialize. * @returns {Object|Array|string|number} Deserialized JSON string. */ function fromJson(json) { return isString(json) ? JSON.parse(json) : json; } var ALL_COLONS = /:/g; function timezoneToOffset(timezone, fallback) { // Support: IE 9-11 only, Edge 13-15+ // IE/Edge do not "understand" colon (`:`) in timezone timezone = timezone.replace(ALL_COLONS, ''); var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000; return isNumberNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset; } function addDateMinutes(date, minutes) { date = new Date(date.getTime()); date.setMinutes(date.getMinutes() + minutes); return date; } function convertTimezoneToLocal(date, timezone, reverse) { reverse = reverse ? -1 : 1; var dateTimezoneOffset = date.getTimezoneOffset(); var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset); return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset)); } /** * @returns {string} Returns the string representation of the element. */ function startingTag(element) { element = jqLite(element).clone().empty(); var elemHtml = jqLite('
').append(element).html(); try { return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) : elemHtml. match(/^(<[^>]+>)/)[1]. replace(/^<([\w-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);}); } catch (e) { return lowercase(elemHtml); } } ///////////////////////////////////////////////// /** * Tries to decode the URI component without throwing an exception. * * @private * @param str value potential URI component to check. * @returns {boolean} True if `value` can be decoded * with the decodeURIComponent function. */ function tryDecodeURIComponent(value) { try { return decodeURIComponent(value); } catch (e) { // Ignore any invalid uri component. } } /** * Parses an escaped url query string into key-value pairs. * @returns {Object.} */ function parseKeyValue(/**string*/keyValue) { var obj = {}; forEach((keyValue || '').split('&'), function(keyValue) { var splitPoint, key, val; if (keyValue) { key = keyValue = keyValue.replace(/\+/g,'%20'); splitPoint = keyValue.indexOf('='); if (splitPoint !== -1) { key = keyValue.substring(0, splitPoint); val = keyValue.substring(splitPoint + 1); } key = tryDecodeURIComponent(key); if (isDefined(key)) { val = isDefined(val) ? tryDecodeURIComponent(val) : true; if (!hasOwnProperty.call(obj, key)) { obj[key] = val; } else if (isArray(obj[key])) { obj[key].push(val); } else { obj[key] = [obj[key],val]; } } } }); return obj; } function toKeyValue(obj) { var parts = []; forEach(obj, function(value, key) { if (isArray(value)) { forEach(value, function(arrayValue) { parts.push(encodeUriQuery(key, true) + (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); }); } else { parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true))); } }); return parts.length ? parts.join('&') : ''; } /** * We need our custom method because encodeURIComponent is too aggressive and doesn't follow * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path * segments: * segment = *pchar * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" * pct-encoded = "%" HEXDIG HEXDIG * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" * / "*" / "+" / "," / ";" / "=" */ function encodeUriSegment(val) { return encodeUriQuery(val, true). replace(/%26/gi, '&'). replace(/%3D/gi, '='). replace(/%2B/gi, '+'); } /** * This method is intended for encoding *key* or *value* parts of query component. We need a custom * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be * encoded per http://tools.ietf.org/html/rfc3986: * query = *( pchar / "/" / "?" ) * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" * pct-encoded = "%" HEXDIG HEXDIG * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" * / "*" / "+" / "," / ";" / "=" */ function encodeUriQuery(val, pctEncodeSpaces) { return encodeURIComponent(val). replace(/%40/gi, '@'). replace(/%3A/gi, ':'). replace(/%24/g, '$'). replace(/%2C/gi, ','). replace(/%3B/gi, ';'). replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); } var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-']; function getNgAttribute(element, ngAttr) { var attr, i, ii = ngAttrPrefixes.length; for (i = 0; i < ii; ++i) { attr = ngAttrPrefixes[i] + ngAttr; if (isString(attr = element.getAttribute(attr))) { return attr; } } return null; } function allowAutoBootstrap(document) { var script = document.currentScript; if (!script) { // Support: IE 9-11 only // IE does not have `document.currentScript` return true; } // If the `currentScript` property has been clobbered just return false, since this indicates a probable attack if (!(script instanceof window.HTMLScriptElement || script instanceof window.SVGScriptElement)) { return false; } var attributes = script.attributes; var srcs = [attributes.getNamedItem('src'), attributes.getNamedItem('href'), attributes.getNamedItem('xlink:href')]; return srcs.every(function(src) { if (!src) { return true; } if (!src.value) { return false; } var link = document.createElement('a'); link.href = src.value; if (document.location.origin === link.origin) { // Same-origin resources are always allowed, even for non-whitelisted schemes. return true; } // Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web. // This is to prevent angular.js bundled with browser extensions from being used to bypass the // content security policy in web pages and other browser extensions. switch (link.protocol) { case 'http:': case 'https:': case 'ftp:': case 'blob:': case 'file:': case 'data:': return true; default: return false; } }); } // Cached as it has to run during loading so that document.currentScript is available. var isAutoBootstrapAllowed = allowAutoBootstrap(window.document); /** * @ngdoc directive * @name ngApp * @module ng * * @element ANY * @param {angular.Module} ngApp an optional application * {@link angular.module module} name to load. * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be * created in "strict-di" mode. This means that the application will fail to invoke functions which * do not use explicit function annotation (and are thus unsuitable for minification), as described * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in * tracking down the root of these bugs. * * @description * * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive * designates the **root element** of the application and is typically placed near the root element * of the page - e.g. on the `` or `` tags. * * There are a few things to keep in mind when using `ngApp`: * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp` * found in the document will be used to define the root element to auto-bootstrap as an * application. To run multiple applications in an HTML document you must manually bootstrap them using * {@link angular.bootstrap} instead. * - AngularJS applications cannot be nested within each other. * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`. * This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and * {@link ngRoute.ngView `ngView`}. * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector}, * causing animations to stop working and making the injector inaccessible from outside the app. * * You can specify an **AngularJS module** to be used as the root module for the application. This * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It * should contain the application code needed or have dependencies on other modules that will * contain the code. See {@link angular.module} for more information. * * In the example below if the `ngApp` directive were not placed on the `html` element then the * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` * would not be resolved to `3`. * * `ngApp` is the easiest, and most common way to bootstrap an application. *
I can add: {{a}} + {{b}} = {{ a+b }}
angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) { $scope.a = 1; $scope.b = 2; });
* * Using `ngStrictDi`, you would see something like this: *
I can add: {{a}} + {{b}} = {{ a+b }}

This renders because the controller does not fail to instantiate, by using explicit annotation style (see script.js for details)

Name:
Hello, {{name}}!

This renders because the controller does not fail to instantiate, by using explicit annotation style (see script.js for details)

I can add: {{a}} + {{b}} = {{ a+b }}

The controller could not be instantiated, due to relying on automatic function annotations (which are disabled in strict mode). As such, the content of this section is not interpolated, and there should be an error in your web console.

angular.module('ngAppStrictDemo', []) // BadController will fail to instantiate, due to relying on automatic function annotation, // rather than an explicit annotation .controller('BadController', function($scope) { $scope.a = 1; $scope.b = 2; }) // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated, // due to using explicit annotations using the array style and $inject property, respectively. .controller('GoodController1', ['$scope', function($scope) { $scope.a = 1; $scope.b = 2; }]) .controller('GoodController2', GoodController2); function GoodController2($scope) { $scope.name = 'World'; } GoodController2.$inject = ['$scope']; div[ng-controller] { margin-bottom: 1em; -webkit-border-radius: 4px; border-radius: 4px; border: 1px solid; padding: .5em; } div[ng-controller^=Good] { border-color: #d6e9c6; background-color: #dff0d8; color: #3c763d; } div[ng-controller^=Bad] { border-color: #ebccd1; background-color: #f2dede; color: #a94442; margin-bottom: 0; }
*/ function angularInit(element, bootstrap) { var appElement, module, config = {}; // The element `element` has priority over any other element. forEach(ngAttrPrefixes, function(prefix) { var name = prefix + 'app'; if (!appElement && element.hasAttribute && element.hasAttribute(name)) { appElement = element; module = element.getAttribute(name); } }); forEach(ngAttrPrefixes, function(prefix) { var name = prefix + 'app'; var candidate; if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) { appElement = candidate; module = candidate.getAttribute(name); } }); if (appElement) { if (!isAutoBootstrapAllowed) { window.console.error('Angular: disabling automatic bootstrap. * * * * ``` * * @param {DOMElement} element DOM element which is the root of angular application. * @param {Array=} modules an array of modules to load into the application. * Each item in the array should be the name of a predefined module or a (DI annotated) * function that will be invoked by the injector as a `config` block. * See: {@link angular.module modules} * @param {Object=} config an object for defining configuration options for the application. The * following keys are supported: * * * `strictDi` - disable automatic function annotation for the application. This is meant to * assist in finding bugs which break minified code. Defaults to `false`. * * @returns {auto.$injector} Returns the newly created injector for this app. */ function bootstrap(element, modules, config) { if (!isObject(config)) config = {}; var defaultConfig = { strictDi: false }; config = extend(defaultConfig, config); var doBootstrap = function() { element = jqLite(element); if (element.injector()) { var tag = (element[0] === window.document) ? 'document' : startingTag(element); // Encode angle brackets to prevent input from being sanitized to empty string #8683. throw ngMinErr( 'btstrpd', 'App already bootstrapped with this element \'{0}\'', tag.replace(//,'>')); } modules = modules || []; modules.unshift(['$provide', function($provide) { $provide.value('$rootElement', element); }]); if (config.debugInfoEnabled) { // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`. modules.push(['$compileProvider', function($compileProvider) { $compileProvider.debugInfoEnabled(true); }]); } modules.unshift('ng'); var injector = createInjector(modules, config.strictDi); injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', function bootstrapApply(scope, element, compile, injector) { scope.$apply(function() { element.data('$injector', injector); compile(element)(scope); }); }] ); return injector; }; var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/; var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) { config.debugInfoEnabled = true; window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, ''); } if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { return doBootstrap(); } window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); angular.resumeBootstrap = function(extraModules) { forEach(extraModules, function(module) { modules.push(module); }); return doBootstrap(); }; if (isFunction(angular.resumeDeferredBootstrap)) { angular.resumeDeferredBootstrap(); } } /** * @ngdoc function * @name angular.reloadWithDebugInfo * @module ng * @description * Use this function to reload the current application with debug information turned on. * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`. * * See {@link ng.$compileProvider#debugInfoEnabled} for more. */ function reloadWithDebugInfo() { window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name; window.location.reload(); } /** * @name angular.getTestability * @module ng * @description * Get the testability service for the instance of Angular on the given * element. * @param {DOMElement} element DOM element which is the root of angular application. */ function getTestability(rootElement) { var injector = angular.element(rootElement).injector(); if (!injector) { throw ngMinErr('test', 'no injector found for element argument to getTestability'); } return injector.get('$$testability'); } var SNAKE_CASE_REGEXP = /[A-Z]/g; function snake_case(name, separator) { separator = separator || '_'; return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) { return (pos ? separator : '') + letter.toLowerCase(); }); } var bindJQueryFired = false; function bindJQuery() { var originalCleanData; if (bindJQueryFired) { return; } // bind to jQuery if present; var jqName = jq(); jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present) !jqName ? undefined : // use jqLite window[jqName]; // use jQuery specified by `ngJq` // Use jQuery if it exists with proper functionality, otherwise default to us. // Angular 1.2+ requires jQuery 1.7+ for on()/off() support. // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older // versions. It will not work for sure with jQuery <1.7, though. if (jQuery && jQuery.fn.on) { jqLite = jQuery; extend(jQuery.fn, { scope: JQLitePrototype.scope, isolateScope: JQLitePrototype.isolateScope, controller: /** @type {?} */ (JQLitePrototype).controller, injector: JQLitePrototype.injector, inheritedData: JQLitePrototype.inheritedData }); // All nodes removed from the DOM via various jQuery APIs like .remove() // are passed through jQuery.cleanData. Monkey-patch this method to fire // the $destroy event on all removed nodes. originalCleanData = jQuery.cleanData; jQuery.cleanData = function(elems) { var events; for (var i = 0, elem; (elem = elems[i]) != null; i++) { events = jQuery._data(elem, 'events'); if (events && events.$destroy) { jQuery(elem).triggerHandler('$destroy'); } } originalCleanData(elems); }; } else { jqLite = JQLite; } angular.element = jqLite; // Prevent double-proxying. bindJQueryFired = true; } /** * throw error if the argument is falsy. */ function assertArg(arg, name, reason) { if (!arg) { throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required')); } return arg; } function assertArgFn(arg, name, acceptArrayAnnotation) { if (acceptArrayAnnotation && isArray(arg)) { arg = arg[arg.length - 1]; } assertArg(isFunction(arg), name, 'not a function, got ' + (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg)); return arg; } /** * throw error if the name given is hasOwnProperty * @param {String} name the name to test * @param {String} context the context in which the name is used, such as module or directive */ function assertNotHasOwnProperty(name, context) { if (name === 'hasOwnProperty') { throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); } } /** * Return the value accessible from the object by path. Any undefined traversals are ignored * @param {Object} obj starting object * @param {String} path path to traverse * @param {boolean} [bindFnToScope=true] * @returns {Object} value as accessible by path */ //TODO(misko): this function needs to be removed function getter(obj, path, bindFnToScope) { if (!path) return obj; var keys = path.split('.'); var key; var lastInstance = obj; var len = keys.length; for (var i = 0; i < len; i++) { key = keys[i]; if (obj) { obj = (lastInstance = obj)[key]; } } if (!bindFnToScope && isFunction(obj)) { return bind(lastInstance, obj); } return obj; } /** * Return the DOM siblings between the first and last node in the given array. * @param {Array} array like object * @returns {Array} the inputted object or a jqLite collection containing the nodes */ function getBlockNodes(nodes) { // TODO(perf): update `nodes` instead of creating a new object? var node = nodes[0]; var endNode = nodes[nodes.length - 1]; var blockNodes; for (var i = 1; node !== endNode && (node = node.nextSibling); i++) { if (blockNodes || nodes[i] !== node) { if (!blockNodes) { blockNodes = jqLite(slice.call(nodes, 0, i)); } blockNodes.push(node); } } return blockNodes || nodes; } /** * Creates a new object without a prototype. This object is useful for lookup without having to * guard against prototypically inherited properties via hasOwnProperty. * * Related micro-benchmarks: * - http://jsperf.com/object-create2 * - http://jsperf.com/proto-map-lookup/2 * - http://jsperf.com/for-in-vs-object-keys2 * * @returns {Object} */ function createMap() { return Object.create(null); } function stringify(value) { if (value == null) { // null || undefined return ''; } switch (typeof value) { case 'string': break; case 'number': value = '' + value; break; default: if (hasCustomToString(value) && !isArray(value) && !isDate(value)) { value = value.toString(); } else { value = toJson(value); } } return value; } var NODE_TYPE_ELEMENT = 1; var NODE_TYPE_ATTRIBUTE = 2; var NODE_TYPE_TEXT = 3; var NODE_TYPE_COMMENT = 8; var NODE_TYPE_DOCUMENT = 9; var NODE_TYPE_DOCUMENT_FRAGMENT = 11; /** * @ngdoc type * @name angular.Module * @module ng * @description * * Interface for configuring angular {@link angular.module modules}. */ function setupModuleLoader(window) { var $injectorMinErr = minErr('$injector'); var ngMinErr = minErr('ng'); function ensure(obj, name, factory) { return obj[name] || (obj[name] = factory()); } var angular = ensure(window, 'angular', Object); // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap angular.$$minErr = angular.$$minErr || minErr; return ensure(angular, 'module', function() { /** @type {Object.} */ var modules = {}; /** * @ngdoc function * @name angular.module * @module ng * @description * * The `angular.module` is a global place for creating, registering and retrieving Angular * modules. * All modules (angular core or 3rd party) that should be available to an application must be * registered using this mechanism. * * Passing one argument retrieves an existing {@link angular.Module}, * whereas passing more than one argument creates a new {@link angular.Module} * * * # Module * * A module is a collection of services, directives, controllers, filters, and configuration information. * `angular.module` is used to configure the {@link auto.$injector $injector}. * * ```js * // Create a new module * var myModule = angular.module('myModule', []); * * // register a new service * myModule.value('appName', 'MyCoolApp'); * * // configure existing services inside initialization blocks. * myModule.config(['$locationProvider', function($locationProvider) { * // Configure existing providers * $locationProvider.hashPrefix('!'); * }]); * ``` * * Then you can create an injector and load your modules like this: * * ```js * var injector = angular.injector(['ng', 'myModule']) * ``` * * However it's more likely that you'll just use * {@link ng.directive:ngApp ngApp} or * {@link angular.bootstrap} to simplify this process for you. * * @param {!string} name The name of the module to create or retrieve. * @param {!Array.=} requires If specified then new module is being created. If * unspecified then the module is being retrieved for further configuration. * @param {Function=} configFn Optional configuration function for the module. Same as * {@link angular.Module#config Module#config()}. * @returns {angular.Module} new module with the {@link angular.Module} api. */ return function module(name, requires, configFn) { var info = {}; var assertNotHasOwnProperty = function(name, context) { if (name === 'hasOwnProperty') { throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); } }; assertNotHasOwnProperty(name, 'module'); if (requires && modules.hasOwnProperty(name)) { modules[name] = null; } return ensure(modules, name, function() { if (!requires) { throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' + 'the module name or forgot to load it. If registering a module ensure that you ' + 'specify the dependencies as the second argument.', name); } /** @type {!Array.>} */ var invokeQueue = []; /** @type {!Array.} */ var configBlocks = []; /** @type {!Array.} */ var runBlocks = []; var config = invokeLater('$injector', 'invoke', 'push', configBlocks); /** @type {angular.Module} */ var moduleInstance = { // Private state _invokeQueue: invokeQueue, _configBlocks: configBlocks, _runBlocks: runBlocks, /** * @ngdoc method * @name angular.Module#info * @module ng * * @param {Object=} info Information about the module * @returns {Object|Module} The current info object for this module if called as a getter, * or `this` if called as a setter. * * @description * Read and write custom information about this module. * For example you could put the version of the module in here. * * ```js * angular.module('myModule', []).info({ version: '1.0.0' }); * ``` * * The version could then be read back out by accessing the module elsewhere: * * ``` * var version = angular.module('myModule').info().version; * ``` * * You can also retrieve this information during runtime via the * {@link $injector#modules `$injector.modules`} property: * * ```js * var version = $injector.modules['myModule'].info().version; * ``` */ info: function(value) { if (isDefined(value)) { if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value'); info = value; return this; } return info; }, /** * @ngdoc property * @name angular.Module#requires * @module ng * * @description * Holds the list of modules which the injector will load before the current module is * loaded. */ requires: requires, /** * @ngdoc property * @name angular.Module#name * @module ng * * @description * Name of the module. */ name: name, /** * @ngdoc method * @name angular.Module#provider * @module ng * @param {string} name service name * @param {Function} providerType Construction function for creating new instance of the * service. * @description * See {@link auto.$provide#provider $provide.provider()}. */ provider: invokeLaterAndSetModuleName('$provide', 'provider'), /** * @ngdoc method * @name angular.Module#factory * @module ng * @param {string} name service name * @param {Function} providerFunction Function for creating new instance of the service. * @description * See {@link auto.$provide#factory $provide.factory()}. */ factory: invokeLaterAndSetModuleName('$provide', 'factory'), /** * @ngdoc method * @name angular.Module#service * @module ng * @param {string} name service name * @param {Function} constructor A constructor function that will be instantiated. * @description * See {@link auto.$provide#service $provide.service()}. */ service: invokeLaterAndSetModuleName('$provide', 'service'), /** * @ngdoc method * @name angular.Module#value * @module ng * @param {string} name service name * @param {*} object Service instance object. * @description * See {@link auto.$provide#value $provide.value()}. */ value: invokeLater('$provide', 'value'), /** * @ngdoc method * @name angular.Module#constant * @module ng * @param {string} name constant name * @param {*} object Constant value. * @description * Because the constants are fixed, they get applied before other provide methods. * See {@link auto.$provide#constant $provide.constant()}. */ constant: invokeLater('$provide', 'constant', 'unshift'), /** * @ngdoc method * @name angular.Module#decorator * @module ng * @param {string} name The name of the service to decorate. * @param {Function} decorFn This function will be invoked when the service needs to be * instantiated and should return the decorated service instance. * @description * See {@link auto.$provide#decorator $provide.decorator()}. */ decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks), /** * @ngdoc method * @name angular.Module#animation * @module ng * @param {string} name animation name * @param {Function} animationFactory Factory function for creating new instance of an * animation. * @description * * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. * * * Defines an animation hook that can be later used with * {@link $animate $animate} service and directives that use this service. * * ```js * module.animation('.animation-name', function($inject1, $inject2) { * return { * eventName : function(element, done) { * //code to run the animation * //once complete, then run done() * return function cancellationFunction(element) { * //code to cancel the animation * } * } * } * }) * ``` * * See {@link ng.$animateProvider#register $animateProvider.register()} and * {@link ngAnimate ngAnimate module} for more information. */ animation: invokeLaterAndSetModuleName('$animateProvider', 'register'), /** * @ngdoc method * @name angular.Module#filter * @module ng * @param {string} name Filter name - this must be a valid angular expression identifier * @param {Function} filterFactory Factory function for creating new instance of filter. * @description * See {@link ng.$filterProvider#register $filterProvider.register()}. * *
* **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). *
*/ filter: invokeLaterAndSetModuleName('$filterProvider', 'register'), /** * @ngdoc method * @name angular.Module#controller * @module ng * @param {string|Object} name Controller name, or an object map of controllers where the * keys are the names and the values are the constructors. * @param {Function} constructor Controller constructor function. * @description * See {@link ng.$controllerProvider#register $controllerProvider.register()}. */ controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'), /** * @ngdoc method * @name angular.Module#directive * @module ng * @param {string|Object} name Directive name, or an object map of directives where the * keys are the names and the values are the factories. * @param {Function} directiveFactory Factory function for creating new instance of * directives. * @description * See {@link ng.$compileProvider#directive $compileProvider.directive()}. */ directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'), /** * @ngdoc method * @name angular.Module#component * @module ng * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp) * @param {Object} options Component definition object (a simplified * {@link ng.$compile#directive-definition-object directive definition object}) * * @description * See {@link ng.$compileProvider#component $compileProvider.component()}. */ component: invokeLaterAndSetModuleName('$compileProvider', 'component'), /** * @ngdoc method * @name angular.Module#config * @module ng * @param {Function} configFn Execute this function on module load. Useful for service * configuration. * @description * Use this method to register work which needs to be performed on module loading. * For more about how to configure services, see * {@link providers#provider-recipe Provider Recipe}. */ config: config, /** * @ngdoc method * @name angular.Module#run * @module ng * @param {Function} initializationFn Execute this function after injector creation. * Useful for application initialization. * @description * Use this method to register work which should be performed when the injector is done * loading all modules. */ run: function(block) { runBlocks.push(block); return this; } }; if (configFn) { config(configFn); } return moduleInstance; /** * @param {string} provider * @param {string} method * @param {String=} insertMethod * @returns {angular.Module} */ function invokeLater(provider, method, insertMethod, queue) { if (!queue) queue = invokeQueue; return function() { queue[insertMethod || 'push']([provider, method, arguments]); return moduleInstance; }; } /** * @param {string} provider * @param {string} method * @returns {angular.Module} */ function invokeLaterAndSetModuleName(provider, method, queue) { if (!queue) queue = invokeQueue; return function(recipeName, factoryFunction) { if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name; queue.push([provider, method, arguments]); return moduleInstance; }; } }); }; }); } /* global shallowCopy: true */ /** * Creates a shallow copy of an object, an array or a primitive. * * Assumes that there are no proto properties for objects. */ function shallowCopy(src, dst) { if (isArray(src)) { dst = dst || []; for (var i = 0, ii = src.length; i < ii; i++) { dst[i] = src[i]; } } else if (isObject(src)) { dst = dst || {}; for (var key in src) { if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { dst[key] = src[key]; } } } return dst || src; } /* exported toDebugString */ function serializeObject(obj, maxDepth) { var seen = []; // There is no direct way to stringify object until reaching a specific depth // and a very deep object can cause a performance issue, so we copy the object // based on this specific depth and then stringify it. if (isValidObjectMaxDepth(maxDepth)) { // This file is also included in `angular-loader`, so `copy()` might not always be available in // the closure. Therefore, it is lazily retrieved as `angular.copy()` when needed. obj = angular.copy(obj, null, maxDepth); } return JSON.stringify(obj, function(key, val) { val = toJsonReplacer(key, val); if (isObject(val)) { if (seen.indexOf(val) >= 0) return '...'; seen.push(val); } return val; }); } function toDebugString(obj, maxDepth) { if (typeof obj === 'function') { return obj.toString().replace(/ \{[\s\S]*$/, ''); } else if (isUndefined(obj)) { return 'undefined'; } else if (typeof obj !== 'string') { return serializeObject(obj, maxDepth); } return obj; } /* global angularModule: true, version: true, $CompileProvider, htmlAnchorDirective, inputDirective, inputDirective, formDirective, scriptDirective, selectDirective, optionDirective, ngBindDirective, ngBindHtmlDirective, ngBindTemplateDirective, ngClassDirective, ngClassEvenDirective, ngClassOddDirective, ngCloakDirective, ngControllerDirective, ngFormDirective, ngHideDirective, ngIfDirective, ngIncludeDirective, ngIncludeFillContentDirective, ngInitDirective, ngNonBindableDirective, ngPluralizeDirective, ngRepeatDirective, ngShowDirective, ngStyleDirective, ngSwitchDirective, ngSwitchWhenDirective, ngSwitchDefaultDirective, ngOptionsDirective, ngTranscludeDirective, ngModelDirective, ngListDirective, ngChangeDirective, patternDirective, patternDirective, requiredDirective, requiredDirective, minlengthDirective, minlengthDirective, maxlengthDirective, maxlengthDirective, ngValueDirective, ngModelOptionsDirective, ngAttributeAliasDirectives, ngEventDirectives, $AnchorScrollProvider, $AnimateProvider, $CoreAnimateCssProvider, $$CoreAnimateJsProvider, $$CoreAnimateQueueProvider, $$AnimateRunnerFactoryProvider, $$AnimateAsyncRunFactoryProvider, $BrowserProvider, $CacheFactoryProvider, $ControllerProvider, $DateProvider, $DocumentProvider, $$IsDocumentHiddenProvider, $ExceptionHandlerProvider, $FilterProvider, $$ForceReflowProvider, $InterpolateProvider, $IntervalProvider, $HttpProvider, $HttpParamSerializerProvider, $HttpParamSerializerJQLikeProvider, $HttpBackendProvider, $xhrFactoryProvider, $jsonpCallbacksProvider, $LocationProvider, $LogProvider, $$MapProvider, $ParseProvider, $RootScopeProvider, $QProvider, $$QProvider, $$SanitizeUriProvider, $SceProvider, $SceDelegateProvider, $SnifferProvider, $TemplateCacheProvider, $TemplateRequestProvider, $$TestabilityProvider, $TimeoutProvider, $$RAFProvider, $WindowProvider, $$jqLiteProvider, $$CookieReaderProvider */ /** * @ngdoc object * @name angular.version * @module ng * @description * An object that contains information about the current AngularJS version. * * This object has the following properties: * * - `full` – `{string}` – Full version string, such as "0.9.18". * - `major` – `{number}` – Major version number, such as "0". * - `minor` – `{number}` – Minor version number, such as "9". * - `dot` – `{number}` – Dot version number, such as "18". * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { // These placeholder strings will be replaced by grunt's `build` task. // They need to be double- or single-quoted. full: '1.6.6', major: 1, minor: 6, dot: 6, codeName: 'interdimensional-cable' }; function publishExternalAPI(angular) { extend(angular, { 'errorHandlingConfig': errorHandlingConfig, 'bootstrap': bootstrap, 'copy': copy, 'extend': extend, 'merge': merge, 'equals': equals, 'element': jqLite, 'forEach': forEach, 'injector': createInjector, 'noop': noop, 'bind': bind, 'toJson': toJson, 'fromJson': fromJson, 'identity': identity, 'isUndefined': isUndefined, 'isDefined': isDefined, 'isString': isString, 'isFunction': isFunction, 'isObject': isObject, 'isNumber': isNumber, 'isElement': isElement, 'isArray': isArray, 'version': version, 'isDate': isDate, 'lowercase': lowercase, 'uppercase': uppercase, 'callbacks': {$$counter: 0}, 'getTestability': getTestability, 'reloadWithDebugInfo': reloadWithDebugInfo, '$$minErr': minErr, '$$csp': csp, '$$encodeUriSegment': encodeUriSegment, '$$encodeUriQuery': encodeUriQuery, '$$stringify': stringify }); angularModule = setupModuleLoader(window); angularModule('ng', ['ngLocale'], ['$provide', function ngModule($provide) { // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it. $provide.provider({ $$sanitizeUri: $$SanitizeUriProvider }); $provide.provider('$compile', $CompileProvider). directive({ a: htmlAnchorDirective, input: inputDirective, textarea: inputDirective, form: formDirective, script: scriptDirective, select: selectDirective, option: optionDirective, ngBind: ngBindDirective, ngBindHtml: ngBindHtmlDirective, ngBindTemplate: ngBindTemplateDirective, ngClass: ngClassDirective, ngClassEven: ngClassEvenDirective, ngClassOdd: ngClassOddDirective, ngCloak: ngCloakDirective, ngController: ngControllerDirective, ngForm: ngFormDirective, ngHide: ngHideDirective, ngIf: ngIfDirective, ngInclude: ngIncludeDirective, ngInit: ngInitDirective, ngNonBindable: ngNonBindableDirective, ngPluralize: ngPluralizeDirective, ngRepeat: ngRepeatDirective, ngShow: ngShowDirective, ngStyle: ngStyleDirective, ngSwitch: ngSwitchDirective, ngSwitchWhen: ngSwitchWhenDirective, ngSwitchDefault: ngSwitchDefaultDirective, ngOptions: ngOptionsDirective, ngTransclude: ngTranscludeDirective, ngModel: ngModelDirective, ngList: ngListDirective, ngChange: ngChangeDirective, pattern: patternDirective, ngPattern: patternDirective, required: requiredDirective, ngRequired: requiredDirective, minlength: minlengthDirective, ngMinlength: minlengthDirective, maxlength: maxlengthDirective, ngMaxlength: maxlengthDirective, ngValue: ngValueDirective, ngModelOptions: ngModelOptionsDirective }). directive({ ngInclude: ngIncludeFillContentDirective }). directive(ngAttributeAliasDirectives). directive(ngEventDirectives); $provide.provider({ $anchorScroll: $AnchorScrollProvider, $animate: $AnimateProvider, $animateCss: $CoreAnimateCssProvider, $$animateJs: $$CoreAnimateJsProvider, $$animateQueue: $$CoreAnimateQueueProvider, $$AnimateRunner: $$AnimateRunnerFactoryProvider, $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider, $browser: $BrowserProvider, $cacheFactory: $CacheFactoryProvider, $controller: $ControllerProvider, $document: $DocumentProvider, $$isDocumentHidden: $$IsDocumentHiddenProvider, $exceptionHandler: $ExceptionHandlerProvider, $filter: $FilterProvider, $$forceReflow: $$ForceReflowProvider, $interpolate: $InterpolateProvider, $interval: $IntervalProvider, $http: $HttpProvider, $httpParamSerializer: $HttpParamSerializerProvider, $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider, $httpBackend: $HttpBackendProvider, $xhrFactory: $xhrFactoryProvider, $jsonpCallbacks: $jsonpCallbacksProvider, $location: $LocationProvider, $log: $LogProvider, $parse: $ParseProvider, $rootScope: $RootScopeProvider, $q: $QProvider, $$q: $$QProvider, $sce: $SceProvider, $sceDelegate: $SceDelegateProvider, $sniffer: $SnifferProvider, $templateCache: $TemplateCacheProvider, $templateRequest: $TemplateRequestProvider, $$testability: $$TestabilityProvider, $timeout: $TimeoutProvider, $window: $WindowProvider, $$rAF: $$RAFProvider, $$jqLite: $$jqLiteProvider, $$Map: $$MapProvider, $$cookieReader: $$CookieReaderProvider }); } ]) .info({ angularVersion: '1.6.6' }); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Any commits to this file should be reviewed with security in mind. * * Changes to this file can potentially create security vulnerabilities. * * An approval from 2 Core members with history of modifying * * this file is required. * * * * Does the change somehow allow for arbitrary javascript to be executed? * * Or allows for someone to change the prototype of built-in objects? * * Or gives undesired access to variables likes document or window? * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* global JQLitePrototype: true, BOOLEAN_ATTR: true, ALIASED_ATTR: true */ ////////////////////////////////// //JQLite ////////////////////////////////// /** * @ngdoc function * @name angular.element * @module ng * @kind function * * @description * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element. * * If jQuery is available, `angular.element` is an alias for the * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element` * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**. * * jqLite is a tiny, API-compatible subset of jQuery that allows * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most * commonly needed functionality with the goal of having a very small footprint. * * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a * specific version of jQuery if multiple versions exist on the page. * *
**Note:** All element references in Angular are always wrapped with jQuery or * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.
* *
**Note:** Keep in mind that this function will not find elements * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)` * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.
* * ## Angular's jqLite * jqLite provides only the following jQuery methods: * * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument * - [`after()`](http://api.jquery.com/after/) * - [`append()`](http://api.jquery.com/append/) * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters * - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData * - [`children()`](http://api.jquery.com/children/) - Does not support selectors * - [`clone()`](http://api.jquery.com/clone/) * - [`contents()`](http://api.jquery.com/contents/) * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing. * - [`data()`](http://api.jquery.com/data/) * - [`detach()`](http://api.jquery.com/detach/) * - [`empty()`](http://api.jquery.com/empty/) * - [`eq()`](http://api.jquery.com/eq/) * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name * - [`hasClass()`](http://api.jquery.com/hasClass/) * - [`html()`](http://api.jquery.com/html/) * - [`next()`](http://api.jquery.com/next/) - Does not support selectors * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors * - [`prepend()`](http://api.jquery.com/prepend/) * - [`prop()`](http://api.jquery.com/prop/) * - [`ready()`](http://api.jquery.com/ready/) (_deprecated_, use `angular.element(callback)` instead of `angular.element(document).ready(callback)`) * - [`remove()`](http://api.jquery.com/remove/) * - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument * - [`removeData()`](http://api.jquery.com/removeData/) * - [`replaceWith()`](http://api.jquery.com/replaceWith/) * - [`text()`](http://api.jquery.com/text/) * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers * - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter * - [`val()`](http://api.jquery.com/val/) * - [`wrap()`](http://api.jquery.com/wrap/) * * ## jQuery/jqLite Extras * Angular also provides the following additional methods and events to both jQuery and jqLite: * * ### Events * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM * element before it is removed. * * ### Methods * - `controller(name)` - retrieves the controller of the current element or its parent. By default * retrieves controller associated with the `ngController` directive. If `name` is provided as * camelCase directive name, then the controller for this directive will be retrieved (e.g. * `'ngModel'`). * - `injector()` - retrieves the injector of the current element or its parent. * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to * be enabled. * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the * current element. This getter should be used only on elements that contain a directive which starts a new isolate * scope. Calling `scope()` on this element always returns the original non-isolate scope. * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled. * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top * parent element is reached. * * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See * https://github.com/angular/angular.js/issues/14251 for more information. * * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. * @returns {Object} jQuery object. */ JQLite.expando = 'ng339'; var jqCache = JQLite.cache = {}, jqId = 1; /* * !!! This is an undocumented "private" function !!! */ JQLite._data = function(node) { //jQuery always returns an object on cache miss return this.cache[node[this.expando]] || {}; }; function jqNextId() { return ++jqId; } var DASH_LOWERCASE_REGEXP = /-([a-z])/g; var MS_HACK_REGEXP = /^-ms-/; var MOUSE_EVENT_MAP = { mouseleave: 'mouseout', mouseenter: 'mouseover' }; var jqLiteMinErr = minErr('jqLite'); /** * Converts kebab-case to camelCase. * There is also a special case for the ms prefix starting with a lowercase letter. * @param name Name to normalize */ function cssKebabToCamel(name) { return kebabToCamel(name.replace(MS_HACK_REGEXP, 'ms-')); } function fnCamelCaseReplace(all, letter) { return letter.toUpperCase(); } /** * Converts kebab-case to camelCase. * @param name Name to normalize */ function kebabToCamel(name) { return name .replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace); } var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/; var HTML_REGEXP = /<|&#?\w+;/; var TAG_NAME_REGEXP = /<([\w:-]+)/; var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi; var wrapMap = { 'option': [1, ''], 'thead': [1, '
', '
'], 'col': [2, '', '
'], 'tr': [2, '', '
'], 'td': [3, '', '
'], '_default': [0, '', ''] }; wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; function jqLiteIsTextNode(html) { return !HTML_REGEXP.test(html); } function jqLiteAcceptsData(node) { // The window object can accept data but has no nodeType // Otherwise we are only interested in elements (1) and documents (9) var nodeType = node.nodeType; return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT; } function jqLiteHasData(node) { for (var key in jqCache[node.ng339]) { return true; } return false; } function jqLiteBuildFragment(html, context) { var tmp, tag, wrap, fragment = context.createDocumentFragment(), nodes = [], i; if (jqLiteIsTextNode(html)) { // Convert non-html into a text node nodes.push(context.createTextNode(html)); } else { // Convert html into DOM nodes tmp = fragment.appendChild(context.createElement('div')); tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase(); wrap = wrapMap[tag] || wrapMap._default; tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, '<$1>') + wrap[2]; // Descend through wrappers to the right content i = wrap[0]; while (i--) { tmp = tmp.lastChild; } nodes = concat(nodes, tmp.childNodes); tmp = fragment.firstChild; tmp.textContent = ''; } // Remove wrapper from fragment fragment.textContent = ''; fragment.innerHTML = ''; // Clear inner HTML forEach(nodes, function(node) { fragment.appendChild(node); }); return fragment; } function jqLiteParseHTML(html, context) { context = context || window.document; var parsed; if ((parsed = SINGLE_TAG_REGEXP.exec(html))) { return [context.createElement(parsed[1])]; } if ((parsed = jqLiteBuildFragment(html, context))) { return parsed.childNodes; } return []; } function jqLiteWrapNode(node, wrapper) { var parent = node.parentNode; if (parent) { parent.replaceChild(wrapper, node); } wrapper.appendChild(node); } // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259. var jqLiteContains = window.Node.prototype.contains || /** @this */ function(arg) { // eslint-disable-next-line no-bitwise return !!(this.compareDocumentPosition(arg) & 16); }; ///////////////////////////////////////////// function JQLite(element) { if (element instanceof JQLite) { return element; } var argIsString; if (isString(element)) { element = trim(element); argIsString = true; } if (!(this instanceof JQLite)) { if (argIsString && element.charAt(0) !== '<') { throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element'); } return new JQLite(element); } if (argIsString) { jqLiteAddNodes(this, jqLiteParseHTML(element)); } else if (isFunction(element)) { jqLiteReady(element); } else { jqLiteAddNodes(this, element); } } function jqLiteClone(element) { return element.cloneNode(true); } function jqLiteDealoc(element, onlyDescendants) { if (!onlyDescendants && jqLiteAcceptsData(element)) jqLite.cleanData([element]); if (element.querySelectorAll) { jqLite.cleanData(element.querySelectorAll('*')); } } function jqLiteOff(element, type, fn, unsupported) { if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument'); var expandoStore = jqLiteExpandoStore(element); var events = expandoStore && expandoStore.events; var handle = expandoStore && expandoStore.handle; if (!handle) return; //no listeners registered if (!type) { for (type in events) { if (type !== '$destroy') { element.removeEventListener(type, handle); } delete events[type]; } } else { var removeHandler = function(type) { var listenerFns = events[type]; if (isDefined(fn)) { arrayRemove(listenerFns || [], fn); } if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) { element.removeEventListener(type, handle); delete events[type]; } }; forEach(type.split(' '), function(type) { removeHandler(type); if (MOUSE_EVENT_MAP[type]) { removeHandler(MOUSE_EVENT_MAP[type]); } }); } } function jqLiteRemoveData(element, name) { var expandoId = element.ng339; var expandoStore = expandoId && jqCache[expandoId]; if (expandoStore) { if (name) { delete expandoStore.data[name]; return; } if (expandoStore.handle) { if (expandoStore.events.$destroy) { expandoStore.handle({}, '$destroy'); } jqLiteOff(element); } delete jqCache[expandoId]; element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it } } function jqLiteExpandoStore(element, createIfNecessary) { var expandoId = element.ng339, expandoStore = expandoId && jqCache[expandoId]; if (createIfNecessary && !expandoStore) { element.ng339 = expandoId = jqNextId(); expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined}; } return expandoStore; } function jqLiteData(element, key, value) { if (jqLiteAcceptsData(element)) { var prop; var isSimpleSetter = isDefined(value); var isSimpleGetter = !isSimpleSetter && key && !isObject(key); var massGetter = !key; var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter); var data = expandoStore && expandoStore.data; if (isSimpleSetter) { // data('key', value) data[kebabToCamel(key)] = value; } else { if (massGetter) { // data() return data; } else { if (isSimpleGetter) { // data('key') // don't force creation of expandoStore if it doesn't exist yet return data && data[kebabToCamel(key)]; } else { // mass-setter: data({key1: val1, key2: val2}) for (prop in key) { data[kebabToCamel(prop)] = key[prop]; } } } } } } function jqLiteHasClass(element, selector) { if (!element.getAttribute) return false; return ((' ' + (element.getAttribute('class') || '') + ' ').replace(/[\n\t]/g, ' '). indexOf(' ' + selector + ' ') > -1); } function jqLiteRemoveClass(element, cssClasses) { if (cssClasses && element.setAttribute) { forEach(cssClasses.split(' '), function(cssClass) { element.setAttribute('class', trim( (' ' + (element.getAttribute('class') || '') + ' ') .replace(/[\n\t]/g, ' ') .replace(' ' + trim(cssClass) + ' ', ' ')) ); }); } } function jqLiteAddClass(element, cssClasses) { if (cssClasses && element.setAttribute) { var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') .replace(/[\n\t]/g, ' '); forEach(cssClasses.split(' '), function(cssClass) { cssClass = trim(cssClass); if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { existingClasses += cssClass + ' '; } }); element.setAttribute('class', trim(existingClasses)); } } function jqLiteAddNodes(root, elements) { // THIS CODE IS VERY HOT. Don't make changes without benchmarking. if (elements) { // if a Node (the most common case) if (elements.nodeType) { root[root.length++] = elements; } else { var length = elements.length; // if an Array or NodeList and not a Window if (typeof length === 'number' && elements.window !== elements) { if (length) { for (var i = 0; i < length; i++) { root[root.length++] = elements[i]; } } } else { root[root.length++] = elements; } } } } function jqLiteController(element, name) { return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller'); } function jqLiteInheritedData(element, name, value) { // if element is the document object work with the html element instead // this makes $(document).scope() possible if (element.nodeType === NODE_TYPE_DOCUMENT) { element = element.documentElement; } var names = isArray(name) ? name : [name]; while (element) { for (var i = 0, ii = names.length; i < ii; i++) { if (isDefined(value = jqLite.data(element, names[i]))) return value; } // If dealing with a document fragment node with a host element, and no parent, use the host // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM // to lookup parent controllers. element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host); } } function jqLiteEmpty(element) { jqLiteDealoc(element, true); while (element.firstChild) { element.removeChild(element.firstChild); } } function jqLiteRemove(element, keepData) { if (!keepData) jqLiteDealoc(element); var parent = element.parentNode; if (parent) parent.removeChild(element); } function jqLiteDocumentLoaded(action, win) { win = win || window; if (win.document.readyState === 'complete') { // Force the action to be run async for consistent behavior // from the action's point of view // i.e. it will definitely not be in a $apply win.setTimeout(action); } else { // No need to unbind this handler as load is only ever called once jqLite(win).on('load', action); } } function jqLiteReady(fn) { function trigger() { window.document.removeEventListener('DOMContentLoaded', trigger); window.removeEventListener('load', trigger); fn(); } // check if document is already loaded if (window.document.readyState === 'complete') { window.setTimeout(fn); } else { // We can not use jqLite since we are not done loading and jQuery could be loaded later. // Works for modern browsers and IE9 window.document.addEventListener('DOMContentLoaded', trigger); // Fallback to window.onload for others window.addEventListener('load', trigger); } } ////////////////////////////////////////// // Functions which are declared directly. ////////////////////////////////////////// var JQLitePrototype = JQLite.prototype = { ready: jqLiteReady, toString: function() { var value = []; forEach(this, function(e) { value.push('' + e);}); return '[' + value.join(', ') + ']'; }, eq: function(index) { return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]); }, length: 0, push: push, sort: [].sort, splice: [].splice }; ////////////////////////////////////////// // Functions iterating getter/setters. // these functions return self on setter and // value on get. ////////////////////////////////////////// var BOOLEAN_ATTR = {}; forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) { BOOLEAN_ATTR[lowercase(value)] = value; }); var BOOLEAN_ELEMENTS = {}; forEach('input,select,option,textarea,button,form,details'.split(','), function(value) { BOOLEAN_ELEMENTS[value] = true; }); var ALIASED_ATTR = { 'ngMinlength': 'minlength', 'ngMaxlength': 'maxlength', 'ngMin': 'min', 'ngMax': 'max', 'ngPattern': 'pattern', 'ngStep': 'step' }; function getBooleanAttrName(element, name) { // check dom last since we will most likely fail on name var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()]; // booleanAttr is here twice to minimize DOM access return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr; } function getAliasedAttrName(name) { return ALIASED_ATTR[name]; } forEach({ data: jqLiteData, removeData: jqLiteRemoveData, hasData: jqLiteHasData, cleanData: function jqLiteCleanData(nodes) { for (var i = 0, ii = nodes.length; i < ii; i++) { jqLiteRemoveData(nodes[i]); } } }, function(fn, name) { JQLite[name] = fn; }); forEach({ data: jqLiteData, inheritedData: jqLiteInheritedData, scope: function(element) { // Can't use jqLiteData here directly so we stay compatible with jQuery! return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']); }, isolateScope: function(element) { // Can't use jqLiteData here directly so we stay compatible with jQuery! return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate'); }, controller: jqLiteController, injector: function(element) { return jqLiteInheritedData(element, '$injector'); }, removeAttr: function(element, name) { element.removeAttribute(name); }, hasClass: jqLiteHasClass, css: function(element, name, value) { name = cssKebabToCamel(name); if (isDefined(value)) { element.style[name] = value; } else { return element.style[name]; } }, attr: function(element, name, value) { var ret; var nodeType = element.nodeType; if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT || !element.getAttribute) { return; } var lowercasedName = lowercase(name); var isBooleanAttr = BOOLEAN_ATTR[lowercasedName]; if (isDefined(value)) { // setter if (value === null || (value === false && isBooleanAttr)) { element.removeAttribute(name); } else { element.setAttribute(name, isBooleanAttr ? lowercasedName : value); } } else { // getter ret = element.getAttribute(name); if (isBooleanAttr && ret !== null) { ret = lowercasedName; } // Normalize non-existing attributes to undefined (as jQuery). return ret === null ? undefined : ret; } }, prop: function(element, name, value) { if (isDefined(value)) { element[name] = value; } else { return element[name]; } }, text: (function() { getText.$dv = ''; return getText; function getText(element, value) { if (isUndefined(value)) { var nodeType = element.nodeType; return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : ''; } element.textContent = value; } })(), val: function(element, value) { if (isUndefined(value)) { if (element.multiple && nodeName_(element) === 'select') { var result = []; forEach(element.options, function(option) { if (option.selected) { result.push(option.value || option.text); } }); return result; } return element.value; } element.value = value; }, html: function(element, value) { if (isUndefined(value)) { return element.innerHTML; } jqLiteDealoc(element, true); element.innerHTML = value; }, empty: jqLiteEmpty }, function(fn, name) { /** * Properties: writes return selection, reads return first value */ JQLite.prototype[name] = function(arg1, arg2) { var i, key; var nodeCount = this.length; // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it // in a way that survives minification. // jqLiteEmpty takes no arguments but is a setter. if (fn !== jqLiteEmpty && (isUndefined((fn.length === 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) { if (isObject(arg1)) { // we are a write, but the object properties are the key/values for (i = 0; i < nodeCount; i++) { if (fn === jqLiteData) { // data() takes the whole object in jQuery fn(this[i], arg1); } else { for (key in arg1) { fn(this[i], key, arg1[key]); } } } // return self for chaining return this; } else { // we are a read, so read the first child. // TODO: do we still need this? var value = fn.$dv; // Only if we have $dv do we iterate over all, otherwise it is just the first element. var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount; for (var j = 0; j < jj; j++) { var nodeValue = fn(this[j], arg1, arg2); value = value ? value + nodeValue : nodeValue; } return value; } } else { // we are a write, so apply to all children for (i = 0; i < nodeCount; i++) { fn(this[i], arg1, arg2); } // return self for chaining return this; } }; }); function createEventHandler(element, events) { var eventHandler = function(event, type) { // jQuery specific api event.isDefaultPrevented = function() { return event.defaultPrevented; }; var eventFns = events[type || event.type]; var eventFnsLength = eventFns ? eventFns.length : 0; if (!eventFnsLength) return; if (isUndefined(event.immediatePropagationStopped)) { var originalStopImmediatePropagation = event.stopImmediatePropagation; event.stopImmediatePropagation = function() { event.immediatePropagationStopped = true; if (event.stopPropagation) { event.stopPropagation(); } if (originalStopImmediatePropagation) { originalStopImmediatePropagation.call(event); } }; } event.isImmediatePropagationStopped = function() { return event.immediatePropagationStopped === true; }; // Some events have special handlers that wrap the real handler var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper; // Copy event handlers in case event handlers array is modified during execution. if ((eventFnsLength > 1)) { eventFns = shallowCopy(eventFns); } for (var i = 0; i < eventFnsLength; i++) { if (!event.isImmediatePropagationStopped()) { handlerWrapper(element, event, eventFns[i]); } } }; // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all // events on `element` eventHandler.elem = element; return eventHandler; } function defaultHandlerWrapper(element, event, handler) { handler.call(element, event); } function specialMouseHandlerWrapper(target, event, handler) { // Refer to jQuery's implementation of mouseenter & mouseleave // Read about mouseenter and mouseleave: // http://www.quirksmode.org/js/events_mouse.html#link8 var related = event.relatedTarget; // For mousenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if (!related || (related !== target && !jqLiteContains.call(target, related))) { handler.call(target, event); } } ////////////////////////////////////////// // Functions iterating traversal. // These functions chain results into a single // selector. ////////////////////////////////////////// forEach({ removeData: jqLiteRemoveData, on: function jqLiteOn(element, type, fn, unsupported) { if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters'); // Do not add event handlers to non-elements because they will not be cleaned up. if (!jqLiteAcceptsData(element)) { return; } var expandoStore = jqLiteExpandoStore(element, true); var events = expandoStore.events; var handle = expandoStore.handle; if (!handle) { handle = expandoStore.handle = createEventHandler(element, events); } // http://jsperf.com/string-indexof-vs-split var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type]; var i = types.length; var addHandler = function(type, specialHandlerWrapper, noEventListener) { var eventFns = events[type]; if (!eventFns) { eventFns = events[type] = []; eventFns.specialHandlerWrapper = specialHandlerWrapper; if (type !== '$destroy' && !noEventListener) { element.addEventListener(type, handle); } } eventFns.push(fn); }; while (i--) { type = types[i]; if (MOUSE_EVENT_MAP[type]) { addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper); addHandler(type, undefined, true); } else { addHandler(type); } } }, off: jqLiteOff, one: function(element, type, fn) { element = jqLite(element); //add the listener twice so that when it is called //you can remove the original function and still be //able to call element.off(ev, fn) normally element.on(type, function onFn() { element.off(type, fn); element.off(type, onFn); }); element.on(type, fn); }, replaceWith: function(element, replaceNode) { var index, parent = element.parentNode; jqLiteDealoc(element); forEach(new JQLite(replaceNode), function(node) { if (index) { parent.insertBefore(node, index.nextSibling); } else { parent.replaceChild(node, element); } index = node; }); }, children: function(element) { var children = []; forEach(element.childNodes, function(element) { if (element.nodeType === NODE_TYPE_ELEMENT) { children.push(element); } }); return children; }, contents: function(element) { return element.contentDocument || element.childNodes || []; }, append: function(element, node) { var nodeType = element.nodeType; if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return; node = new JQLite(node); for (var i = 0, ii = node.length; i < ii; i++) { var child = node[i]; element.appendChild(child); } }, prepend: function(element, node) { if (element.nodeType === NODE_TYPE_ELEMENT) { var index = element.firstChild; forEach(new JQLite(node), function(child) { element.insertBefore(child, index); }); } }, wrap: function(element, wrapNode) { jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]); }, remove: jqLiteRemove, detach: function(element) { jqLiteRemove(element, true); }, after: function(element, newElement) { var index = element, parent = element.parentNode; if (parent) { newElement = new JQLite(newElement); for (var i = 0, ii = newElement.length; i < ii; i++) { var node = newElement[i]; parent.insertBefore(node, index.nextSibling); index = node; } } }, addClass: jqLiteAddClass, removeClass: jqLiteRemoveClass, toggleClass: function(element, selector, condition) { if (selector) { forEach(selector.split(' '), function(className) { var classCondition = condition; if (isUndefined(classCondition)) { classCondition = !jqLiteHasClass(element, className); } (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className); }); } }, parent: function(element) { var parent = element.parentNode; return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null; }, next: function(element) { return element.nextElementSibling; }, find: function(element, selector) { if (element.getElementsByTagName) { return element.getElementsByTagName(selector); } else { return []; } }, clone: jqLiteClone, triggerHandler: function(element, event, extraParameters) { var dummyEvent, eventFnsCopy, handlerArgs; var eventName = event.type || event; var expandoStore = jqLiteExpandoStore(element); var events = expandoStore && expandoStore.events; var eventFns = events && events[eventName]; if (eventFns) { // Create a dummy event to pass to the handlers dummyEvent = { preventDefault: function() { this.defaultPrevented = true; }, isDefaultPrevented: function() { return this.defaultPrevented === true; }, stopImmediatePropagation: function() { this.immediatePropagationStopped = true; }, isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; }, stopPropagation: noop, type: eventName, target: element }; // If a custom event was provided then extend our dummy event with it if (event.type) { dummyEvent = extend(dummyEvent, event); } // Copy event handlers in case event handlers array is modified during execution. eventFnsCopy = shallowCopy(eventFns); handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent]; forEach(eventFnsCopy, function(fn) { if (!dummyEvent.isImmediatePropagationStopped()) { fn.apply(element, handlerArgs); } }); } } }, function(fn, name) { /** * chaining functions */ JQLite.prototype[name] = function(arg1, arg2, arg3) { var value; for (var i = 0, ii = this.length; i < ii; i++) { if (isUndefined(value)) { value = fn(this[i], arg1, arg2, arg3); if (isDefined(value)) { // any function which returns a value needs to be wrapped value = jqLite(value); } } else { jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3)); } } return isDefined(value) ? value : this; }; }); // bind legacy bind/unbind to on/off JQLite.prototype.bind = JQLite.prototype.on; JQLite.prototype.unbind = JQLite.prototype.off; // Provider for private $$jqLite service /** @this */ function $$jqLiteProvider() { this.$get = function $$jqLite() { return extend(JQLite, { hasClass: function(node, classes) { if (node.attr) node = node[0]; return jqLiteHasClass(node, classes); }, addClass: function(node, classes) { if (node.attr) node = node[0]; return jqLiteAddClass(node, classes); }, removeClass: function(node, classes) { if (node.attr) node = node[0]; return jqLiteRemoveClass(node, classes); } }); }; } /** * Computes a hash of an 'obj'. * Hash of a: * string is string * number is number as string * object is either result of calling $$hashKey function on the object or uniquely generated id, * that is also assigned to the $$hashKey property of the object. * * @param obj * @returns {string} hash string such that the same input will have the same hash string. * The resulting string key is in 'type:hashKey' format. */ function hashKey(obj, nextUidFn) { var key = obj && obj.$$hashKey; if (key) { if (typeof key === 'function') { key = obj.$$hashKey(); } return key; } var objType = typeof obj; if (objType === 'function' || (objType === 'object' && obj !== null)) { key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)(); } else { key = objType + ':' + obj; } return key; } // A minimal ES2015 Map implementation. // Should be bug/feature equivalent to the native implementations of supported browsers // (for the features required in Angular). // See https://kangax.github.io/compat-table/es6/#test-Map var nanKey = Object.create(null); function NgMapShim() { this._keys = []; this._values = []; this._lastKey = NaN; this._lastIndex = -1; } NgMapShim.prototype = { _idx: function(key) { if (key === this._lastKey) { return this._lastIndex; } this._lastKey = key; this._lastIndex = this._keys.indexOf(key); return this._lastIndex; }, _transformKey: function(key) { return isNumberNaN(key) ? nanKey : key; }, get: function(key) { key = this._transformKey(key); var idx = this._idx(key); if (idx !== -1) { return this._values[idx]; } }, set: function(key, value) { key = this._transformKey(key); var idx = this._idx(key); if (idx === -1) { idx = this._lastIndex = this._keys.length; } this._keys[idx] = key; this._values[idx] = value; // Support: IE11 // Do not `return this` to simulate the partial IE11 implementation }, delete: function(key) { key = this._transformKey(key); var idx = this._idx(key); if (idx === -1) { return false; } this._keys.splice(idx, 1); this._values.splice(idx, 1); this._lastKey = NaN; this._lastIndex = -1; return true; } }; // For now, always use `NgMapShim`, even if `window.Map` is available. Some native implementations // are still buggy (often in subtle ways) and can cause hard-to-debug failures. When native `Map` // implementations get more stable, we can reconsider switching to `window.Map` (when available). var NgMap = NgMapShim; var $$MapProvider = [/** @this */function() { this.$get = [function() { return NgMap; }]; }]; /** * @ngdoc function * @module ng * @name angular.injector * @kind function * * @description * Creates an injector object that can be used for retrieving services as well as for * dependency injection (see {@link guide/di dependency injection}). * * @param {Array.} modules A list of module functions or their aliases. See * {@link angular.module}. The `ng` module must be explicitly added. * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which * disallows argument name annotation inference. * @returns {injector} Injector object. See {@link auto.$injector $injector}. * * @example * Typical usage * ```js * // create an injector * var $injector = angular.injector(['ng']); * * // use the injector to kick off your application * // use the type inference to auto inject arguments, or use implicit injection * $injector.invoke(function($rootScope, $compile, $document) { * $compile($document)($rootScope); * $rootScope.$digest(); * }); * ``` * * Sometimes you want to get access to the injector of a currently running Angular app * from outside Angular. Perhaps, you want to inject and compile some markup after the * application has been bootstrapped. You can do this using the extra `injector()` added * to JQuery/jqLite elements. See {@link angular.element}. * * *This is fairly rare but could be the case if a third party library is injecting the * markup.* * * In the following example a new block of HTML containing a `ng-controller` * directive is added to the end of the document body by JQuery. We then compile and link * it into the current AngularJS scope. * * ```js * var $div = $('
{{content.label}}
'); * $(document.body).append($div); * * angular.element(document).injector().invoke(function($compile) { * var scope = angular.element($div).scope(); * $compile($div)(scope); * }); * ``` */ /** * @ngdoc module * @name auto * @installation * @description * * Implicit module which gets automatically added to each {@link auto.$injector $injector}. */ var ARROW_ARG = /^([^(]+?)=>/; var FN_ARGS = /^[^(]*\(\s*([^)]*)\)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var $injectorMinErr = minErr('$injector'); function stringifyFn(fn) { return Function.prototype.toString.call(fn); } function extractArgs(fn) { var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''), args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS); return args; } function anonFn(fn) { // For anonymous functions, showing at the very least the function signature can help in // debugging. var args = extractArgs(fn); if (args) { return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')'; } return 'fn'; } function annotate(fn, strictDi, name) { var $inject, argDecl, last; if (typeof fn === 'function') { if (!($inject = fn.$inject)) { $inject = []; if (fn.length) { if (strictDi) { if (!isString(name) || !name) { name = fn.name || anonFn(fn); } throw $injectorMinErr('strictdi', '{0} is not using explicit annotation and cannot be invoked in strict mode', name); } argDecl = extractArgs(fn); forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { arg.replace(FN_ARG, function(all, underscore, name) { $inject.push(name); }); }); } fn.$inject = $inject; } } else if (isArray(fn)) { last = fn.length - 1; assertArgFn(fn[last], 'fn'); $inject = fn.slice(0, last); } else { assertArgFn(fn, 'fn', true); } return $inject; } /////////////////////////////////////// /** * @ngdoc service * @name $injector * * @description * * `$injector` is used to retrieve object instances as defined by * {@link auto.$provide provider}, instantiate types, invoke methods, * and load modules. * * The following always holds true: * * ```js * var $injector = angular.injector(); * expect($injector.get('$injector')).toBe($injector); * expect($injector.invoke(function($injector) { * return $injector; * })).toBe($injector); * ``` * * # Injection Function Annotation * * JavaScript does not have annotations, and annotations are needed for dependency injection. The * following are all valid ways of annotating function with injection arguments and are equivalent. * * ```js * // inferred (only works if code not minified/obfuscated) * $injector.invoke(function(serviceA){}); * * // annotated * function explicit(serviceA) {}; * explicit.$inject = ['serviceA']; * $injector.invoke(explicit); * * // inline * $injector.invoke(['serviceA', function(serviceA){}]); * ``` * * ## Inference * * In JavaScript calling `toString()` on a function returns the function definition. The definition * can then be parsed and the function arguments can be extracted. This method of discovering * annotations is disallowed when the injector is in strict mode. * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the * argument names. * * ## `$inject` Annotation * By adding an `$inject` property onto a function the injection parameters can be specified. * * ## Inline * As an array of injection names, where the last item in the array is the function to call. */ /** * @ngdoc property * @name $injector#modules * @type {Object} * @description * A hash containing all the modules that have been loaded into the * $injector. * * You can use this property to find out information about a module via the * {@link angular.Module#info `myModule.info(...)`} method. * * For example: * * ``` * var info = $injector.modules['ngAnimate'].info(); * ``` * * **Do not use this property to attempt to modify the modules after the application * has been bootstrapped.** */ /** * @ngdoc method * @name $injector#get * * @description * Return an instance of the service. * * @param {string} name The name of the instance to retrieve. * @param {string=} caller An optional string to provide the origin of the function call for error messages. * @return {*} The instance. */ /** * @ngdoc method * @name $injector#invoke * * @description * Invoke the method and supply the method arguments from the `$injector`. * * @param {Function|Array.} fn The injectable function to invoke. Function parameters are * injected according to the {@link guide/di $inject Annotation} rules. * @param {Object=} self The `this` for the invoked method. * @param {Object=} locals Optional object. If preset then any argument names are read from this * object first, before the `$injector` is consulted. * @returns {*} the value returned by the invoked `fn` function. */ /** * @ngdoc method * @name $injector#has * * @description * Allows the user to query if the particular service exists. * * @param {string} name Name of the service to query. * @returns {boolean} `true` if injector has given service. */ /** * @ngdoc method * @name $injector#instantiate * @description * Create a new instance of JS type. The method takes a constructor function, invokes the new * operator, and supplies all of the arguments to the constructor function as specified by the * constructor annotation. * * @param {Function} Type Annotated constructor function. * @param {Object=} locals Optional object. If preset then any argument names are read from this * object first, before the `$injector` is consulted. * @returns {Object} new instance of `Type`. */ /** * @ngdoc method * @name $injector#annotate * * @description * Returns an array of service names which the function is requesting for injection. This API is * used by the injector to determine which services need to be injected into the function when the * function is invoked. There are three ways in which the function can be annotated with the needed * dependencies. * * # Argument names * * The simplest form is to extract the dependencies from the arguments of the function. This is done * by converting the function into a string using `toString()` method and extracting the argument * names. * ```js * // Given * function MyController($scope, $route) { * // ... * } * * // Then * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); * ``` * * You can disallow this method by using strict injection mode. * * This method does not work with code minification / obfuscation. For this reason the following * annotation strategies are supported. * * # The `$inject` property * * If a function has an `$inject` property and its value is an array of strings, then the strings * represent names of services to be injected into the function. * ```js * // Given * var MyController = function(obfuscatedScope, obfuscatedRoute) { * // ... * } * // Define function dependencies * MyController['$inject'] = ['$scope', '$route']; * * // Then * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); * ``` * * # The array notation * * It is often desirable to inline Injected functions and that's when setting the `$inject` property * is very inconvenient. In these situations using the array notation to specify the dependencies in * a way that survives minification is a better choice: * * ```js * // We wish to write this (not minification / obfuscation safe) * injector.invoke(function($compile, $rootScope) { * // ... * }); * * // We are forced to write break inlining * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) { * // ... * }; * tmpFn.$inject = ['$compile', '$rootScope']; * injector.invoke(tmpFn); * * // To better support inline function the inline annotation is supported * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { * // ... * }]); * * // Therefore * expect(injector.annotate( * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}]) * ).toEqual(['$compile', '$rootScope']); * ``` * * @param {Function|Array.} fn Function for which dependent service names need to * be retrieved as described above. * * @param {boolean=} [strictDi=false] Disallow argument name annotation inference. * * @returns {Array.} The names of the services which the function requires. */ /** * @ngdoc service * @name $provide * * @description * * The {@link auto.$provide $provide} service has a number of methods for registering components * with the {@link auto.$injector $injector}. Many of these functions are also exposed on * {@link angular.Module}. * * An Angular **service** is a singleton object created by a **service factory**. These **service * factories** are functions which, in turn, are created by a **service provider**. * The **service providers** are constructor functions. When instantiated they must contain a * property called `$get`, which holds the **service factory** function. * * When you request a service, the {@link auto.$injector $injector} is responsible for finding the * correct **service provider**, instantiating it and then calling its `$get` **service factory** * function to get the instance of the **service**. * * Often services have no configuration options and there is no need to add methods to the service * provider. The provider will be no more than a constructor function with a `$get` property. For * these cases the {@link auto.$provide $provide} service has additional helper methods to register * services without specifying a provider. * * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the * {@link auto.$injector $injector} * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by * providers and services. * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by * services, not providers. * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function** * that will be wrapped in a **service provider** object, whose `$get` property will contain the * given factory function. * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function** * that will be wrapped in a **service provider** object, whose `$get` property will instantiate * a new object using the given constructor function. * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that * will be able to modify or replace the implementation of another service. * * See the individual methods for more information and examples. */ /** * @ngdoc method * @name $provide#provider * @description * * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions * are constructor functions, whose instances are responsible for "providing" a factory for a * service. * * Service provider names start with the name of the service they provide followed by `Provider`. * For example, the {@link ng.$log $log} service has a provider called * {@link ng.$logProvider $logProvider}. * * Service provider objects can have additional methods which allow configuration of the provider * and its service. Importantly, you can configure what kind of service is created by the `$get` * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a * method {@link ng.$logProvider#debugEnabled debugEnabled} * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the * console or not. * * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key. * @param {(Object|function())} provider If the provider is: * * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created. * - `Constructor`: a new instance of the provider will be created using * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`. * * @returns {Object} registered provider instance * @example * * The following example shows how to create a simple event tracking service and register it using * {@link auto.$provide#provider $provide.provider()}. * * ```js * // Define the eventTracker provider * function EventTrackerProvider() { * var trackingUrl = '/track'; * * // A provider method for configuring where the tracked events should been saved * this.setTrackingUrl = function(url) { * trackingUrl = url; * }; * * // The service factory function * this.$get = ['$http', function($http) { * var trackedEvents = {}; * return { * // Call this to track an event * event: function(event) { * var count = trackedEvents[event] || 0; * count += 1; * trackedEvents[event] = count; * return count; * }, * // Call this to save the tracked events to the trackingUrl * save: function() { * $http.post(trackingUrl, trackedEvents); * } * }; * }]; * } * * describe('eventTracker', function() { * var postSpy; * * beforeEach(module(function($provide) { * // Register the eventTracker provider * $provide.provider('eventTracker', EventTrackerProvider); * })); * * beforeEach(module(function(eventTrackerProvider) { * // Configure eventTracker provider * eventTrackerProvider.setTrackingUrl('/custom-track'); * })); * * it('tracks events', inject(function(eventTracker) { * expect(eventTracker.event('login')).toEqual(1); * expect(eventTracker.event('login')).toEqual(2); * })); * * it('saves to the tracking url', inject(function(eventTracker, $http) { * postSpy = spyOn($http, 'post'); * eventTracker.event('login'); * eventTracker.save(); * expect(postSpy).toHaveBeenCalled(); * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track'); * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track'); * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 }); * })); * }); * ``` */ /** * @ngdoc method * @name $provide#factory * @description * * Register a **service factory**, which will be called to return the service instance. * This is short for registering a service where its provider consists of only a `$get` property, * which is the given service factory function. * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to * configure your service in a provider. * * @param {string} name The name of the instance. * @param {Function|Array.} $getFn The injectable $getFn for the instance creation. * Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`. * @returns {Object} registered provider instance * * @example * Here is an example of registering a service * ```js * $provide.factory('ping', ['$http', function($http) { * return function ping() { * return $http.send('/ping'); * }; * }]); * ``` * You would then inject and use this service like this: * ```js * someModule.controller('Ctrl', ['ping', function(ping) { * ping(); * }]); * ``` */ /** * @ngdoc method * @name $provide#service * @description * * Register a **service constructor**, which will be invoked with `new` to create the service * instance. * This is short for registering a service where its provider's `$get` property is a factory * function that returns an instance instantiated by the injector from the service constructor * function. * * Internally it looks a bit like this: * * ``` * { * $get: function() { * return $injector.instantiate(constructor); * } * } * ``` * * * You should use {@link auto.$provide#service $provide.service(class)} if you define your service * as a type/class. * * @param {string} name The name of the instance. * @param {Function|Array.} constructor An injectable class (constructor function) * that will be instantiated. * @returns {Object} registered provider instance * * @example * Here is an example of registering a service using * {@link auto.$provide#service $provide.service(class)}. * ```js * var Ping = function($http) { * this.$http = $http; * }; * * Ping.$inject = ['$http']; * * Ping.prototype.send = function() { * return this.$http.get('/ping'); * }; * $provide.service('ping', Ping); * ``` * You would then inject and use this service like this: * ```js * someModule.controller('Ctrl', ['ping', function(ping) { * ping.send(); * }]); * ``` */ /** * @ngdoc method * @name $provide#value * @description * * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a * number, an array, an object or a function. This is short for registering a service where its * provider's `$get` property is a factory function that takes no arguments and returns the **value * service**. That also means it is not possible to inject other services into a value service. * * Value services are similar to constant services, except that they cannot be injected into a * module configuration function (see {@link angular.Module#config}) but they can be overridden by * an Angular {@link auto.$provide#decorator decorator}. * * @param {string} name The name of the instance. * @param {*} value The value. * @returns {Object} registered provider instance * * @example * Here are some examples of creating value services. * ```js * $provide.value('ADMIN_USER', 'admin'); * * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 }); * * $provide.value('halfOf', function(value) { * return value / 2; * }); * ``` */ /** * @ngdoc method * @name $provide#constant * @description * * Register a **constant service** with the {@link auto.$injector $injector}, such as a string, * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not * possible to inject other services into a constant. * * But unlike {@link auto.$provide#value value}, a constant can be * injected into a module configuration function (see {@link angular.Module#config}) and it cannot * be overridden by an Angular {@link auto.$provide#decorator decorator}. * * @param {string} name The name of the constant. * @param {*} value The constant value. * @returns {Object} registered instance * * @example * Here a some examples of creating constants: * ```js * $provide.constant('SHARD_HEIGHT', 306); * * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']); * * $provide.constant('double', function(value) { * return value * 2; * }); * ``` */ /** * @ngdoc method * @name $provide#decorator * @description * * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function * intercepts the creation of a service, allowing it to override or modify the behavior of the * service. The return value of the decorator function may be the original service, or a new service * that replaces (or wraps and delegates to) the original service. * * You can find out more about using decorators in the {@link guide/decorators} guide. * * @param {string} name The name of the service to decorate. * @param {Function|Array.} decorator This function will be invoked when the service needs to be * provided and should return the decorated service instance. The function is called using * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable. * Local injection arguments: * * * `$delegate` - The original service instance, which can be replaced, monkey patched, configured, * decorated or delegated to. * * @example * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting * calls to {@link ng.$log#error $log.warn()}. * ```js * $provide.decorator('$log', ['$delegate', function($delegate) { * $delegate.warn = $delegate.error; * return $delegate; * }]); * ``` */ function createInjector(modulesToLoad, strictDi) { strictDi = (strictDi === true); var INSTANTIATING = {}, providerSuffix = 'Provider', path = [], loadedModules = new NgMap(), providerCache = { $provide: { provider: supportObject(provider), factory: supportObject(factory), service: supportObject(service), value: supportObject(value), constant: supportObject(constant), decorator: decorator } }, providerInjector = (providerCache.$injector = createInternalInjector(providerCache, function(serviceName, caller) { if (angular.isString(caller)) { path.push(caller); } throw $injectorMinErr('unpr', 'Unknown provider: {0}', path.join(' <- ')); })), instanceCache = {}, protoInstanceInjector = createInternalInjector(instanceCache, function(serviceName, caller) { var provider = providerInjector.get(serviceName + providerSuffix, caller); return instanceInjector.invoke( provider.$get, provider, undefined, serviceName); }), instanceInjector = protoInstanceInjector; providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) }; instanceInjector.modules = providerInjector.modules = createMap(); var runBlocks = loadModules(modulesToLoad); instanceInjector = protoInstanceInjector.get('$injector'); instanceInjector.strictDi = strictDi; forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); }); return instanceInjector; //////////////////////////////////// // $provider //////////////////////////////////// function supportObject(delegate) { return function(key, value) { if (isObject(key)) { forEach(key, reverseParams(delegate)); } else { return delegate(key, value); } }; } function provider(name, provider_) { assertNotHasOwnProperty(name, 'service'); if (isFunction(provider_) || isArray(provider_)) { provider_ = providerInjector.instantiate(provider_); } if (!provider_.$get) { throw $injectorMinErr('pget', 'Provider \'{0}\' must define $get factory method.', name); } return (providerCache[name + providerSuffix] = provider_); } function enforceReturnValue(name, factory) { return /** @this */ function enforcedReturnValue() { var result = instanceInjector.invoke(factory, this); if (isUndefined(result)) { throw $injectorMinErr('undef', 'Provider \'{0}\' must return a value from $get factory method.', name); } return result; }; } function factory(name, factoryFn, enforce) { return provider(name, { $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn }); } function service(name, constructor) { return factory(name, ['$injector', function($injector) { return $injector.instantiate(constructor); }]); } function value(name, val) { return factory(name, valueFn(val), false); } function constant(name, value) { assertNotHasOwnProperty(name, 'constant'); providerCache[name] = value; instanceCache[name] = value; } function decorator(serviceName, decorFn) { var origProvider = providerInjector.get(serviceName + providerSuffix), orig$get = origProvider.$get; origProvider.$get = function() { var origInstance = instanceInjector.invoke(orig$get, origProvider); return instanceInjector.invoke(decorFn, null, {$delegate: origInstance}); }; } //////////////////////////////////// // Module Loading //////////////////////////////////// function loadModules(modulesToLoad) { assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array'); var runBlocks = [], moduleFn; forEach(modulesToLoad, function(module) { if (loadedModules.get(module)) return; loadedModules.set(module, true); function runInvokeQueue(queue) { var i, ii; for (i = 0, ii = queue.length; i < ii; i++) { var invokeArgs = queue[i], provider = providerInjector.get(invokeArgs[0]); provider[invokeArgs[1]].apply(provider, invokeArgs[2]); } } try { if (isString(module)) { moduleFn = angularModule(module); instanceInjector.modules[module] = moduleFn; runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); runInvokeQueue(moduleFn._invokeQueue); runInvokeQueue(moduleFn._configBlocks); } else if (isFunction(module)) { runBlocks.push(providerInjector.invoke(module)); } else if (isArray(module)) { runBlocks.push(providerInjector.invoke(module)); } else { assertArgFn(module, 'module'); } } catch (e) { if (isArray(module)) { module = module[module.length - 1]; } if (e.message && e.stack && e.stack.indexOf(e.message) === -1) { // Safari & FF's stack traces don't contain error.message content // unlike those of Chrome and IE // So if stack doesn't contain message, we create a new string that contains both. // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here. // eslint-disable-next-line no-ex-assign e = e.message + '\n' + e.stack; } throw $injectorMinErr('modulerr', 'Failed to instantiate module {0} due to:\n{1}', module, e.stack || e.message || e); } }); return runBlocks; } //////////////////////////////////// // internal Injector //////////////////////////////////// function createInternalInjector(cache, factory) { function getService(serviceName, caller) { if (cache.hasOwnProperty(serviceName)) { if (cache[serviceName] === INSTANTIATING) { throw $injectorMinErr('cdep', 'Circular dependency found: {0}', serviceName + ' <- ' + path.join(' <- ')); } return cache[serviceName]; } else { try { path.unshift(serviceName); cache[serviceName] = INSTANTIATING; cache[serviceName] = factory(serviceName, caller); return cache[serviceName]; } catch (err) { if (cache[serviceName] === INSTANTIATING) { delete cache[serviceName]; } throw err; } finally { path.shift(); } } } function injectionArgs(fn, locals, serviceName) { var args = [], $inject = createInjector.$$annotate(fn, strictDi, serviceName); for (var i = 0, length = $inject.length; i < length; i++) { var key = $inject[i]; if (typeof key !== 'string') { throw $injectorMinErr('itkn', 'Incorrect injection token! Expected service name as string, got {0}', key); } args.push(locals && locals.hasOwnProperty(key) ? locals[key] : getService(key, serviceName)); } return args; } function isClass(func) { // Support: IE 9-11 only // IE 9-11 do not support classes and IE9 leaks with the code below. if (msie || typeof func !== 'function') { return false; } var result = func.$$ngIsClass; if (!isBoolean(result)) { // Support: Edge 12-13 only // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/ result = func.$$ngIsClass = /^(?:class\b|constructor\()/.test(stringifyFn(func)); } return result; } function invoke(fn, self, locals, serviceName) { if (typeof locals === 'string') { serviceName = locals; locals = null; } var args = injectionArgs(fn, locals, serviceName); if (isArray(fn)) { fn = fn[fn.length - 1]; } if (!isClass(fn)) { // http://jsperf.com/angularjs-invoke-apply-vs-switch // #5388 return fn.apply(self, args); } else { args.unshift(null); return new (Function.prototype.bind.apply(fn, args))(); } } function instantiate(Type, locals, serviceName) { // Check if Type is annotated and use just the given function at n-1 as parameter // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); var ctor = (isArray(Type) ? Type[Type.length - 1] : Type); var args = injectionArgs(Type, locals, serviceName); // Empty object at position 0 is ignored for invocation with `new`, but required. args.unshift(null); return new (Function.prototype.bind.apply(ctor, args))(); } return { invoke: invoke, instantiate: instantiate, get: getService, annotate: createInjector.$$annotate, has: function(name) { return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); } }; } } createInjector.$$annotate = annotate; /** * @ngdoc provider * @name $anchorScrollProvider * @this * * @description * Use `$anchorScrollProvider` to disable automatic scrolling whenever * {@link ng.$location#hash $location.hash()} changes. */ function $AnchorScrollProvider() { var autoScrollingEnabled = true; /** * @ngdoc method * @name $anchorScrollProvider#disableAutoScrolling * * @description * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
* Use this method to disable automatic scrolling. * * If automatic scrolling is disabled, one must explicitly call * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the * current hash. */ this.disableAutoScrolling = function() { autoScrollingEnabled = false; }; /** * @ngdoc service * @name $anchorScroll * @kind function * @requires $window * @requires $location * @requires $rootScope * * @description * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified * in the * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document). * * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to * match any anchor whenever it changes. This can be disabled by calling * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}. * * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a * vertical scroll-offset (either fixed or dynamic). * * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of * {@link ng.$location#hash $location.hash()} will be used. * * @property {(number|function|jqLite)} yOffset * If set, specifies a vertical scroll-offset. This is often useful when there are fixed * positioned elements at the top of the page, such as navbars, headers etc. * * `yOffset` can be specified in various ways: * - **number**: A fixed number of pixels to be used as offset.

* - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return * a number representing the offset (in pixels).

* - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from * the top of the page to the element's bottom will be used as offset.
* **Note**: The element will be taken into account only as long as its `position` is set to * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust * their height and/or positioning according to the viewport's size. * *
*
* In order for `yOffset` to work properly, scrolling should take place on the document's root and * not some child element. *
* * @example
Go to bottom You're at the bottom!
angular.module('anchorScrollExample', []) .controller('ScrollController', ['$scope', '$location', '$anchorScroll', function($scope, $location, $anchorScroll) { $scope.gotoBottom = function() { // set the location.hash to the id of // the element you wish to scroll to. $location.hash('bottom'); // call $anchorScroll() $anchorScroll(); }; }]); #scrollArea { height: 280px; overflow: auto; } #bottom { display: block; margin-top: 2000px; }
* *
* The example below illustrates the use of a vertical scroll-offset (specified as a fixed value). * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details. * * @example
Anchor {{x}} of 5
angular.module('anchorScrollOffsetExample', []) .run(['$anchorScroll', function($anchorScroll) { $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels }]) .controller('headerCtrl', ['$anchorScroll', '$location', '$scope', function($anchorScroll, $location, $scope) { $scope.gotoAnchor = function(x) { var newHash = 'anchor' + x; if ($location.hash() !== newHash) { // set the $location.hash to `newHash` and // $anchorScroll will automatically scroll to it $location.hash('anchor' + x); } else { // call $anchorScroll() explicitly, // since $location.hash hasn't changed $anchorScroll(); } }; } ]); body { padding-top: 50px; } .anchor { border: 2px dashed DarkOrchid; padding: 10px 10px 200px 10px; } .fixed-header { background-color: rgba(0, 0, 0, 0.2); height: 50px; position: fixed; top: 0; left: 0; right: 0; } .fixed-header > a { display: inline-block; margin: 5px 15px; }
*/ this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) { var document = $window.document; // Helper function to get first anchor from a NodeList // (using `Array#some()` instead of `angular#forEach()` since it's more performant // and working in all supported browsers.) function getFirstAnchor(list) { var result = null; Array.prototype.some.call(list, function(element) { if (nodeName_(element) === 'a') { result = element; return true; } }); return result; } function getYOffset() { var offset = scroll.yOffset; if (isFunction(offset)) { offset = offset(); } else if (isElement(offset)) { var elem = offset[0]; var style = $window.getComputedStyle(elem); if (style.position !== 'fixed') { offset = 0; } else { offset = elem.getBoundingClientRect().bottom; } } else if (!isNumber(offset)) { offset = 0; } return offset; } function scrollTo(elem) { if (elem) { elem.scrollIntoView(); var offset = getYOffset(); if (offset) { // `offset` is the number of pixels we should scroll UP in order to align `elem` properly. // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the // top of the viewport. // // IF the number of pixels from the top of `elem` to the end of the page's content is less // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some // way down the page. // // This is often the case for elements near the bottom of the page. // // In such cases we do not need to scroll the whole `offset` up, just the difference between // the top of the element and the offset, which is enough to align the top of `elem` at the // desired position. var elemTop = elem.getBoundingClientRect().top; $window.scrollBy(0, elemTop - offset); } } else { $window.scrollTo(0, 0); } } function scroll(hash) { // Allow numeric hashes hash = isString(hash) ? hash : isNumber(hash) ? hash.toString() : $location.hash(); var elm; // empty hash, scroll to the top of the page if (!hash) scrollTo(null); // element with given id else if ((elm = document.getElementById(hash))) scrollTo(elm); // first anchor with given name :-D else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm); // no element and hash === 'top', scroll to the top of the page else if (hash === 'top') scrollTo(null); } // does not scroll when user clicks on anchor link that is currently on // (no url change, no $location.hash() change), browser native does scroll if (autoScrollingEnabled) { $rootScope.$watch(function autoScrollWatch() {return $location.hash();}, function autoScrollWatchAction(newVal, oldVal) { // skip the initial scroll if $location.hash is empty if (newVal === oldVal && newVal === '') return; jqLiteDocumentLoaded(function() { $rootScope.$evalAsync(scroll); }); }); } return scroll; }]; } var $animateMinErr = minErr('$animate'); var ELEMENT_NODE = 1; var NG_ANIMATE_CLASSNAME = 'ng-animate'; function mergeClasses(a,b) { if (!a && !b) return ''; if (!a) return b; if (!b) return a; if (isArray(a)) a = a.join(' '); if (isArray(b)) b = b.join(' '); return a + ' ' + b; } function extractElementNode(element) { for (var i = 0; i < element.length; i++) { var elm = element[i]; if (elm.nodeType === ELEMENT_NODE) { return elm; } } } function splitClasses(classes) { if (isString(classes)) { classes = classes.split(' '); } // Use createMap() to prevent class assumptions involving property names in // Object.prototype var obj = createMap(); forEach(classes, function(klass) { // sometimes the split leaves empty string values // incase extra spaces were applied to the options if (klass.length) { obj[klass] = true; } }); return obj; } // if any other type of options value besides an Object value is // passed into the $animate.method() animation then this helper code // will be run which will ignore it. While this patch is not the // greatest solution to this, a lot of existing plugins depend on // $animate to either call the callback (< 1.2) or return a promise // that can be changed. This helper function ensures that the options // are wiped clean incase a callback function is provided. function prepareAnimateOptions(options) { return isObject(options) ? options : {}; } var $$CoreAnimateJsProvider = /** @this */ function() { this.$get = noop; }; // this is prefixed with Core since it conflicts with // the animateQueueProvider defined in ngAnimate/animateQueue.js var $$CoreAnimateQueueProvider = /** @this */ function() { var postDigestQueue = new NgMap(); var postDigestElements = []; this.$get = ['$$AnimateRunner', '$rootScope', function($$AnimateRunner, $rootScope) { return { enabled: noop, on: noop, off: noop, pin: noop, push: function(element, event, options, domOperation) { if (domOperation) { domOperation(); } options = options || {}; if (options.from) { element.css(options.from); } if (options.to) { element.css(options.to); } if (options.addClass || options.removeClass) { addRemoveClassesPostDigest(element, options.addClass, options.removeClass); } var runner = new $$AnimateRunner(); // since there are no animations to run the runner needs to be // notified that the animation call is complete. runner.complete(); return runner; } }; function updateData(data, classes, value) { var changed = false; if (classes) { classes = isString(classes) ? classes.split(' ') : isArray(classes) ? classes : []; forEach(classes, function(className) { if (className) { changed = true; data[className] = value; } }); } return changed; } function handleCSSClassChanges() { forEach(postDigestElements, function(element) { var data = postDigestQueue.get(element); if (data) { var existing = splitClasses(element.attr('class')); var toAdd = ''; var toRemove = ''; forEach(data, function(status, className) { var hasClass = !!existing[className]; if (status !== hasClass) { if (status) { toAdd += (toAdd.length ? ' ' : '') + className; } else { toRemove += (toRemove.length ? ' ' : '') + className; } } }); forEach(element, function(elm) { if (toAdd) { jqLiteAddClass(elm, toAdd); } if (toRemove) { jqLiteRemoveClass(elm, toRemove); } }); postDigestQueue.delete(element); } }); postDigestElements.length = 0; } function addRemoveClassesPostDigest(element, add, remove) { var data = postDigestQueue.get(element) || {}; var classesAdded = updateData(data, add, true); var classesRemoved = updateData(data, remove, false); if (classesAdded || classesRemoved) { postDigestQueue.set(element, data); postDigestElements.push(element); if (postDigestElements.length === 1) { $rootScope.$$postDigest(handleCSSClassChanges); } } } }]; }; /** * @ngdoc provider * @name $animateProvider * * @description * Default implementation of $animate that doesn't perform any animations, instead just * synchronously performs DOM updates and resolves the returned runner promise. * * In order to enable animations the `ngAnimate` module has to be loaded. * * To see the functional implementation check out `src/ngAnimate/animate.js`. */ var $AnimateProvider = ['$provide', /** @this */ function($provide) { var provider = this; var classNameFilter = null; var customFilter = null; this.$$registeredAnimations = Object.create(null); /** * @ngdoc method * @name $animateProvider#register * * @description * Registers a new injectable animation factory function. The factory function produces the * animation object which contains callback functions for each event that is expected to be * animated. * * * `eventFn`: `function(element, ... , doneFunction, options)` * The element to animate, the `doneFunction` and the options fed into the animation. Depending * on the type of animation additional arguments will be injected into the animation function. The * list below explains the function signatures for the different animation methods: * * - setClass: function(element, addedClasses, removedClasses, doneFunction, options) * - addClass: function(element, addedClasses, doneFunction, options) * - removeClass: function(element, removedClasses, doneFunction, options) * - enter, leave, move: function(element, doneFunction, options) * - animate: function(element, fromStyles, toStyles, doneFunction, options) * * Make sure to trigger the `doneFunction` once the animation is fully complete. * * ```js * return { * //enter, leave, move signature * eventFn : function(element, done, options) { * //code to run the animation * //once complete, then run done() * return function endFunction(wasCancelled) { * //code to cancel the animation * } * } * } * ``` * * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to). * @param {Function} factory The factory function that will be executed to return the animation * object. */ this.register = function(name, factory) { if (name && name.charAt(0) !== '.') { throw $animateMinErr('notcsel', 'Expecting class selector starting with \'.\' got \'{0}\'.', name); } var key = name + '-animation'; provider.$$registeredAnimations[name.substr(1)] = key; $provide.factory(key, factory); }; /** * @ngdoc method * @name $animateProvider#customFilter * * @description * Sets and/or returns the custom filter function that is used to "filter" animations, i.e. * determine if an animation is allowed or not. When no filter is specified (the default), no * animation will be blocked. Setting the `customFilter` value will only allow animations for * which the filter function's return value is truthy. * * This allows to easily create arbitrarily complex rules for filtering animations, such as * allowing specific events only, or enabling animations on specific subtrees of the DOM, etc. * Filtering animations can also boost performance for low-powered devices, as well as * applications containing a lot of structural operations. * *
* **Best Practice:** * Keep the filtering function as lean as possible, because it will be called for each DOM * action (e.g. insertion, removal, class change) performed by "animation-aware" directives. * See {@link guide/animations#which-directives-support-animations- here} for a list of built-in * directives that support animations. * Performing computationally expensive or time-consuming operations on each call of the * filtering function can make your animations sluggish. *
* * **Note:** If present, `customFilter` will be checked before * {@link $animateProvider#classNameFilter classNameFilter}. * * @param {Function=} filterFn - The filter function which will be used to filter all animations. * If a falsy value is returned, no animation will be performed. The function will be called * with the following arguments: * - **node** `{DOMElement}` - The DOM element to be animated. * - **event** `{String}` - The name of the animation event (e.g. `enter`, `leave`, `addClass` * etc). * - **options** `{Object}` - A collection of options/styles used for the animation. * @return {Function} The current filter function or `null` if there is none set. */ this.customFilter = function(filterFn) { if (arguments.length === 1) { customFilter = isFunction(filterFn) ? filterFn : null; } return customFilter; }; /** * @ngdoc method * @name $animateProvider#classNameFilter * * @description * Sets and/or returns the CSS class regular expression that is checked when performing * an animation. Upon bootstrap the classNameFilter value is not set at all and will * therefore enable $animate to attempt to perform an animation on any element that is triggered. * When setting the `classNameFilter` value, animations will only be performed on elements * that successfully match the filter expression. This in turn can boost performance * for low-powered devices as well as applications containing a lot of structural operations. * * **Note:** If present, `classNameFilter` will be checked after * {@link $animateProvider#customFilter customFilter}. If `customFilter` is present and returns * false, `classNameFilter` will not be checked. * * @param {RegExp=} expression The className expression which will be checked against all animations * @return {RegExp} The current CSS className expression value. If null then there is no expression value */ this.classNameFilter = function(expression) { if (arguments.length === 1) { classNameFilter = (expression instanceof RegExp) ? expression : null; if (classNameFilter) { var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]'); if (reservedRegex.test(classNameFilter.toString())) { classNameFilter = null; throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME); } } } return classNameFilter; }; this.$get = ['$$animateQueue', function($$animateQueue) { function domInsert(element, parentElement, afterElement) { // if for some reason the previous element was removed // from the dom sometime before this code runs then let's // just stick to using the parent element as the anchor if (afterElement) { var afterNode = extractElementNode(afterElement); if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) { afterElement = null; } } if (afterElement) { afterElement.after(element); } else { parentElement.prepend(element); } } /** * @ngdoc service * @name $animate * @description The $animate service exposes a series of DOM utility methods that provide support * for animation hooks. The default behavior is the application of DOM operations, however, * when an animation is detected (and animations are enabled), $animate will do the heavy lifting * to ensure that animation runs with the triggered DOM operation. * * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't * included and only when it is active then the animation hooks that `$animate` triggers will be * functional. Once active then all structural `ng-` directives will trigger animations as they perform * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`, * `ngShow`, `ngHide` and `ngMessages` also provide support for animations. * * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives. * * To learn more about enabling animation support, click here to visit the * {@link ngAnimate ngAnimate module page}. */ return { // we don't call it directly since non-existant arguments may // be interpreted as null within the sub enabled function /** * * @ngdoc method * @name $animate#on * @kind function * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...) * has fired on the given element or among any of its children. Once the listener is fired, the provided callback * is fired with the following params: * * ```js * $animate.on('enter', container, * function callback(element, phase) { * // cool we detected an enter animation within the container * } * ); * ``` * * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...) * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself * as well as among its children * @param {Function} callback the callback function that will be fired when the listener is triggered * * The arguments present in the callback function are: * * `element` - The captured DOM element that the animation was fired on. * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends). */ on: $$animateQueue.on, /** * * @ngdoc method * @name $animate#off * @kind function * @description Deregisters an event listener based on the event which has been associated with the provided element. This method * can be used in three different ways depending on the arguments: * * ```js * // remove all the animation event listeners listening for `enter` * $animate.off('enter'); * * // remove listeners for all animation events from the container element * $animate.off(container); * * // remove all the animation event listeners listening for `enter` on the given element and its children * $animate.off('enter', container); * * // remove the event listener function provided by `callback` that is set * // to listen for `enter` on the given `container` as well as its children * $animate.off('enter', container, callback); * ``` * * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move, * addClass, removeClass, etc...), or the container element. If it is the element, all other * arguments are ignored. * @param {DOMElement=} container the container element the event listener was placed on * @param {Function=} callback the callback function that was registered as the listener */ off: $$animateQueue.off, /** * @ngdoc method * @name $animate#pin * @kind function * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists * outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the * element despite being outside the realm of the application or within another application. Say for example if the application * was bootstrapped on an element that is somewhere inside of the `` tag, but we wanted to allow for an element to be situated * as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind * that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association. * * Note that this feature is only active when the `ngAnimate` module is used. * * @param {DOMElement} element the external element that will be pinned * @param {DOMElement} parentElement the host parent element that will be associated with the external element */ pin: $$animateQueue.pin, /** * * @ngdoc method * @name $animate#enabled * @kind function * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This * function can be called in four ways: * * ```js * // returns true or false * $animate.enabled(); * * // changes the enabled state for all animations * $animate.enabled(false); * $animate.enabled(true); * * // returns true or false if animations are enabled for an element * $animate.enabled(element); * * // changes the enabled state for an element and its children * $animate.enabled(element, true); * $animate.enabled(element, false); * ``` * * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state * @param {boolean=} enabled whether or not the animations will be enabled for the element * * @return {boolean} whether or not animations are enabled */ enabled: $$animateQueue.enabled, /** * @ngdoc method * @name $animate#cancel * @kind function * @description Cancels the provided animation. * * @param {Promise} animationPromise The animation promise that is returned when an animation is started. */ cancel: function(runner) { if (runner.end) { runner.end(); } }, /** * * @ngdoc method * @name $animate#enter * @kind function * @description Inserts the element into the DOM either after the `after` element (if provided) or * as the first child within the `parent` element and then triggers an animation. * A promise is returned that will be resolved during the next digest once the animation * has completed. * * @param {DOMElement} element the element which will be inserted into the DOM * @param {DOMElement} parent the parent element which will append the element as * a child (so long as the after element is not present) * @param {DOMElement=} after the sibling element after which the element will be appended * @param {object=} options an optional collection of options/styles that will be applied to the element. * The object can have the following properties: * * - **addClass** - `{string}` - space-separated CSS classes to add to element * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to` * - **removeClass** - `{string}` - space-separated CSS classes to remove from element * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from` * * @return {Promise} the animation callback promise */ enter: function(element, parent, after, options) { parent = parent && jqLite(parent); after = after && jqLite(after); parent = parent || after.parent(); domInsert(element, parent, after); return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options)); }, /** * * @ngdoc method * @name $animate#move * @kind function * @description Inserts (moves) the element into its new position in the DOM either after * the `after` element (if provided) or as the first child within the `parent` element * and then triggers an animation. A promise is returned that will be resolved * during the next digest once the animation has completed. * * @param {DOMElement} element the element which will be moved into the new DOM position * @param {DOMElement} parent the parent element which will append the element as * a child (so long as the after element is not present) * @param {DOMElement=} after the sibling element after which the element will be appended * @param {object=} options an optional collection of options/styles that will be applied to the element. * The object can have the following properties: * * - **addClass** - `{string}` - space-separated CSS classes to add to element * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to` * - **removeClass** - `{string}` - space-separated CSS classes to remove from element * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from` * * @return {Promise} the animation callback promise */ move: function(element, parent, after, options) { parent = parent && jqLite(parent); after = after && jqLite(after); parent = parent || after.parent(); domInsert(element, parent, after); return $$animateQueue.push(element, 'move', prepareAnimateOptions(options)); }, /** * @ngdoc method * @name $animate#leave * @kind function * @description Triggers an animation and then removes the element from the DOM. * When the function is called a promise is returned that will be resolved during the next * digest once the animation has completed. * * @param {DOMElement} element the element which will be removed from the DOM * @param {object=} options an optional collection of options/styles that will be applied to the element. * The object can have the following properties: * * - **addClass** - `{string}` - space-separated CSS classes to add to element * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to` * - **removeClass** - `{string}` - space-separated CSS classes to remove from element * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from` * * @return {Promise} the animation callback promise */ leave: function(element, options) { return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() { element.remove(); }); }, /** * @ngdoc method * @name $animate#addClass * @kind function * * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon * execution, the addClass operation will only be handled after the next digest and it will not trigger an * animation if element already contains the CSS class or if the class is removed at a later step. * Note that class-based animations are treated differently compared to structural animations * (like enter, move and leave) since the CSS classes may be added/removed at different points * depending if CSS or JavaScript animations are used. * * @param {DOMElement} element the element which the CSS classes will be applied to * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces) * @param {object=} options an optional collection of options/styles that will be applied to the element. * The object can have the following properties: * * - **addClass** - `{string}` - space-separated CSS classes to add to element * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to` * - **removeClass** - `{string}` - space-separated CSS classes to remove from element * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from` * * @return {Promise} the animation callback promise */ addClass: function(element, className, options) { options = prepareAnimateOptions(options); options.addClass = mergeClasses(options.addclass, className); return $$animateQueue.push(element, 'addClass', options); }, /** * @ngdoc method * @name $animate#removeClass * @kind function * * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon * execution, the removeClass operation will only be handled after the next digest and it will not trigger an * animation if element does not contain the CSS class or if the class is added at a later step. * Note that class-based animations are treated differently compared to structural animations * (like enter, move and leave) since the CSS classes may be added/removed at different points * depending if CSS or JavaScript animations are used. * * @param {DOMElement} element the element which the CSS classes will be applied to * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces) * @param {object=} options an optional collection of options/styles that will be applied to the element. * The object can have the following properties: * * - **addClass** - `{string}` - space-separated CSS classes to add to element * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to` * - **removeClass** - `{string}` - space-separated CSS classes to remove from element * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from` * * @return {Promise} the animation callback promise */ removeClass: function(element, className, options) { options = prepareAnimateOptions(options); options.removeClass = mergeClasses(options.removeClass, className); return $$animateQueue.push(element, 'removeClass', options); }, /** * @ngdoc method * @name $animate#setClass * @kind function * * @description Performs both the addition and removal of a CSS classes on an element and (during the process) * triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and * `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has * passed. Note that class-based animations are treated differently compared to structural animations * (like enter, move and leave) since the CSS classes may be added/removed at different points * depending if CSS or JavaScript animations are used. * * @param {DOMElement} element the element which the CSS classes will be applied to * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces) * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces) * @param {object=} options an optional collection of options/styles that will be applied to the element. * The object can have the following properties: * * - **addClass** - `{string}` - space-separated CSS classes to add to element * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to` * - **removeClass** - `{string}` - space-separated CSS classes to remove from element * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from` * * @return {Promise} the animation callback promise */ setClass: function(element, add, remove, options) { options = prepareAnimateOptions(options); options.addClass = mergeClasses(options.addClass, add); options.removeClass = mergeClasses(options.removeClass, remove); return $$animateQueue.push(element, 'setClass', options); }, /** * @ngdoc method * @name $animate#animate * @kind function * * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element. * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take * on the provided styles. For example, if a transition animation is set for the given className, then the provided `from` and * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding * style in `to`, the style in `from` is applied immediately, and no animation is run. * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate` * method (or as part of the `options` parameter): * * ```js * ngModule.animation('.my-inline-animation', function() { * return { * animate : function(element, from, to, done, options) { * //animation * done(); * } * } * }); * ``` * * @param {DOMElement} element the element which the CSS styles will be applied to * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation. * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation. * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element. * (Note that if no animation is detected then this value will not be applied to the element.) * @param {object=} options an optional collection of options/styles that will be applied to the element. * The object can have the following properties: * * - **addClass** - `{string}` - space-separated CSS classes to add to element * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to` * - **removeClass** - `{string}` - space-separated CSS classes to remove from element * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from` * * @return {Promise} the animation callback promise */ animate: function(element, from, to, className, options) { options = prepareAnimateOptions(options); options.from = options.from ? extend(options.from, from) : from; options.to = options.to ? extend(options.to, to) : to; className = className || 'ng-inline-animate'; options.tempClasses = mergeClasses(options.tempClasses, className); return $$animateQueue.push(element, 'animate', options); } }; }]; }]; var $$AnimateAsyncRunFactoryProvider = /** @this */ function() { this.$get = ['$$rAF', function($$rAF) { var waitQueue = []; function waitForTick(fn) { waitQueue.push(fn); if (waitQueue.length > 1) return; $$rAF(function() { for (var i = 0; i < waitQueue.length; i++) { waitQueue[i](); } waitQueue = []; }); } return function() { var passed = false; waitForTick(function() { passed = true; }); return function(callback) { if (passed) { callback(); } else { waitForTick(callback); } }; }; }]; }; var $$AnimateRunnerFactoryProvider = /** @this */ function() { this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout', function($q, $sniffer, $$animateAsyncRun, $$isDocumentHidden, $timeout) { var INITIAL_STATE = 0; var DONE_PENDING_STATE = 1; var DONE_COMPLETE_STATE = 2; AnimateRunner.chain = function(chain, callback) { var index = 0; next(); function next() { if (index === chain.length) { callback(true); return; } chain[index](function(response) { if (response === false) { callback(false); return; } index++; next(); }); } }; AnimateRunner.all = function(runners, callback) { var count = 0; var status = true; forEach(runners, function(runner) { runner.done(onProgress); }); function onProgress(response) { status = status && response; if (++count === runners.length) { callback(status); } } }; function AnimateRunner(host) { this.setHost(host); var rafTick = $$animateAsyncRun(); var timeoutTick = function(fn) { $timeout(fn, 0, false); }; this._doneCallbacks = []; this._tick = function(fn) { if ($$isDocumentHidden()) { timeoutTick(fn); } else { rafTick(fn); } }; this._state = 0; } AnimateRunner.prototype = { setHost: function(host) { this.host = host || {}; }, done: function(fn) { if (this._state === DONE_COMPLETE_STATE) { fn(); } else { this._doneCallbacks.push(fn); } }, progress: noop, getPromise: function() { if (!this.promise) { var self = this; this.promise = $q(function(resolve, reject) { self.done(function(status) { if (status === false) { reject(); } else { resolve(); } }); }); } return this.promise; }, then: function(resolveHandler, rejectHandler) { return this.getPromise().then(resolveHandler, rejectHandler); }, 'catch': function(handler) { return this.getPromise()['catch'](handler); }, 'finally': function(handler) { return this.getPromise()['finally'](handler); }, pause: function() { if (this.host.pause) { this.host.pause(); } }, resume: function() { if (this.host.resume) { this.host.resume(); } }, end: function() { if (this.host.end) { this.host.end(); } this._resolve(true); }, cancel: function() { if (this.host.cancel) { this.host.cancel(); } this._resolve(false); }, complete: function(response) { var self = this; if (self._state === INITIAL_STATE) { self._state = DONE_PENDING_STATE; self._tick(function() { self._resolve(response); }); } }, _resolve: function(response) { if (this._state !== DONE_COMPLETE_STATE) { forEach(this._doneCallbacks, function(fn) { fn(response); }); this._doneCallbacks.length = 0; this._state = DONE_COMPLETE_STATE; } } }; return AnimateRunner; }]; }; /* exported $CoreAnimateCssProvider */ /** * @ngdoc service * @name $animateCss * @kind object * @this * * @description * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included, * then the `$animateCss` service will actually perform animations. * * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}. */ var $CoreAnimateCssProvider = function() { this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) { return function(element, initialOptions) { // all of the animation functions should create // a copy of the options data, however, if a // parent service has already created a copy then // we should stick to using that var options = initialOptions || {}; if (!options.$$prepared) { options = copy(options); } // there is no point in applying the styles since // there is no animation that goes on at all in // this version of $animateCss. if (options.cleanupStyles) { options.from = options.to = null; } if (options.from) { element.css(options.from); options.from = null; } var closed, runner = new $$AnimateRunner(); return { start: run, end: run }; function run() { $$rAF(function() { applyAnimationContents(); if (!closed) { runner.complete(); } closed = true; }); return runner; } function applyAnimationContents() { if (options.addClass) { element.addClass(options.addClass); options.addClass = null; } if (options.removeClass) { element.removeClass(options.removeClass); options.removeClass = null; } if (options.to) { element.css(options.to); options.to = null; } } }; }]; }; /* global stripHash: true */ /** * ! This is a private undocumented service ! * * @name $browser * @requires $log * @description * This object has two goals: * * - hide all the global state in the browser caused by the window object * - abstract away all the browser specific features and inconsistencies * * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser` * service, which can be used for convenient testing of the application without the interaction with * the real browser apis. */ /** * @param {object} window The global window object. * @param {object} document jQuery wrapped document. * @param {object} $log window.console or an object with the same interface. * @param {object} $sniffer $sniffer service */ function Browser(window, document, $log, $sniffer) { var self = this, location = window.location, history = window.history, setTimeout = window.setTimeout, clearTimeout = window.clearTimeout, pendingDeferIds = {}; self.isMock = false; var outstandingRequestCount = 0; var outstandingRequestCallbacks = []; // TODO(vojta): remove this temporary api self.$$completeOutstandingRequest = completeOutstandingRequest; self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; }; /** * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks` * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed. */ function completeOutstandingRequest(fn) { try { fn.apply(null, sliceArgs(arguments, 1)); } finally { outstandingRequestCount--; if (outstandingRequestCount === 0) { while (outstandingRequestCallbacks.length) { try { outstandingRequestCallbacks.pop()(); } catch (e) { $log.error(e); } } } } } function getHash(url) { var index = url.indexOf('#'); return index === -1 ? '' : url.substr(index); } /** * @private * Note: this method is used only by scenario runner * TODO(vojta): prefix this method with $$ ? * @param {function()} callback Function that will be called when no outstanding request */ self.notifyWhenNoOutstandingRequests = function(callback) { if (outstandingRequestCount === 0) { callback(); } else { outstandingRequestCallbacks.push(callback); } }; ////////////////////////////////////////////////////////////// // URL API ////////////////////////////////////////////////////////////// var cachedState, lastHistoryState, lastBrowserUrl = location.href, baseElement = document.find('base'), pendingLocation = null, getCurrentState = !$sniffer.history ? noop : function getCurrentState() { try { return history.state; } catch (e) { // MSIE can reportedly throw when there is no state (UNCONFIRMED). } }; cacheState(); /** * @name $browser#url * * @description * GETTER: * Without any argument, this method just returns current value of location.href. * * SETTER: * With at least one argument, this method sets url to new value. * If html5 history api supported, pushState/replaceState is used, otherwise * location.href/location.replace is used. * Returns its own instance to allow chaining * * NOTE: this api is intended for use only by the $location service. Please use the * {@link ng.$location $location service} to change url. * * @param {string} url New url (when used as setter) * @param {boolean=} replace Should new url replace current history record? * @param {object=} state object to use with pushState/replaceState */ self.url = function(url, replace, state) { // In modern browsers `history.state` is `null` by default; treating it separately // from `undefined` would cause `$browser.url('/foo')` to change `history.state` // to undefined via `pushState`. Instead, let's change `undefined` to `null` here. if (isUndefined(state)) { state = null; } // Android Browser BFCache causes location, history reference to become stale. if (location !== window.location) location = window.location; if (history !== window.history) history = window.history; // setter if (url) { var sameState = lastHistoryState === state; // Don't change anything if previous and current URLs and states match. This also prevents // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode. // See https://github.com/angular/angular.js/commit/ffb2701 if (lastBrowserUrl === url && (!$sniffer.history || sameState)) { return self; } var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url); lastBrowserUrl = url; lastHistoryState = state; // Don't use history API if only the hash changed // due to a bug in IE10/IE11 which leads // to not firing a `hashchange` nor `popstate` event // in some cases (see #9143). if ($sniffer.history && (!sameBase || !sameState)) { history[replace ? 'replaceState' : 'pushState'](state, '', url); cacheState(); } else { if (!sameBase) { pendingLocation = url; } if (replace) { location.replace(url); } else if (!sameBase) { location.href = url; } else { location.hash = getHash(url); } if (location.href !== url) { pendingLocation = url; } } if (pendingLocation) { pendingLocation = url; } return self; // getter } else { // - pendingLocation is needed as browsers don't allow to read out // the new location.href if a reload happened or if there is a bug like in iOS 9 (see // https://openradar.appspot.com/22186109). // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 return pendingLocation || location.href.replace(/%27/g,'\''); } }; /** * @name $browser#state * * @description * This method is a getter. * * Return history.state or null if history.state is undefined. * * @returns {object} state */ self.state = function() { return cachedState; }; var urlChangeListeners = [], urlChangeInit = false; function cacheStateAndFireUrlChange() { pendingLocation = null; fireStateOrUrlChange(); } // This variable should be used *only* inside the cacheState function. var lastCachedState = null; function cacheState() { // This should be the only place in $browser where `history.state` is read. cachedState = getCurrentState(); cachedState = isUndefined(cachedState) ? null : cachedState; // Prevent callbacks fo fire twice if both hashchange & popstate were fired. if (equals(cachedState, lastCachedState)) { cachedState = lastCachedState; } lastCachedState = cachedState; lastHistoryState = cachedState; } function fireStateOrUrlChange() { var prevLastHistoryState = lastHistoryState; cacheState(); if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) { return; } lastBrowserUrl = self.url(); lastHistoryState = cachedState; forEach(urlChangeListeners, function(listener) { listener(self.url(), cachedState); }); } /** * @name $browser#onUrlChange * * @description * Register callback function that will be called, when url changes. * * It's only called when the url is changed from outside of angular: * - user types different url into address bar * - user clicks on history (forward/back) button * - user clicks on a link * * It's not called when url is changed by $browser.url() method * * The listener gets called with new url as parameter. * * NOTE: this api is intended for use only by the $location service. Please use the * {@link ng.$location $location service} to monitor url changes in angular apps. * * @param {function(string)} listener Listener function to be called when url changes. * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous. */ self.onUrlChange = function(callback) { // TODO(vojta): refactor to use node's syntax for events if (!urlChangeInit) { // We listen on both (hashchange/popstate) when available, as some browsers don't // fire popstate when user changes the address bar and don't fire hashchange when url // changed by push/replaceState // html5 history api - popstate event if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange); // hashchange event jqLite(window).on('hashchange', cacheStateAndFireUrlChange); urlChangeInit = true; } urlChangeListeners.push(callback); return callback; }; /** * @private * Remove popstate and hashchange handler from window. * * NOTE: this api is intended for use only by $rootScope. */ self.$$applicationDestroyed = function() { jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange); }; /** * Checks whether the url has changed outside of Angular. * Needs to be exported to be able to check for changes that have been done in sync, * as hashchange/popstate events fire in async. */ self.$$checkUrlChange = fireStateOrUrlChange; ////////////////////////////////////////////////////////////// // Misc API ////////////////////////////////////////////////////////////// /** * @name $browser#baseHref * * @description * Returns current * (always relative - without domain) * * @returns {string} The current base href */ self.baseHref = function() { var href = baseElement.attr('href'); return href ? href.replace(/^(https?:)?\/\/[^/]*/, '') : ''; }; /** * @name $browser#defer * @param {function()} fn A function, who's execution should be deferred. * @param {number=} [delay=0] of milliseconds to defer the function execution. * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`. * * @description * Executes a fn asynchronously via `setTimeout(fn, delay)`. * * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed * via `$browser.defer.flush()`. * */ self.defer = function(fn, delay) { var timeoutId; outstandingRequestCount++; timeoutId = setTimeout(function() { delete pendingDeferIds[timeoutId]; completeOutstandingRequest(fn); }, delay || 0); pendingDeferIds[timeoutId] = true; return timeoutId; }; /** * @name $browser#defer.cancel * * @description * Cancels a deferred task identified with `deferId`. * * @param {*} deferId Token returned by the `$browser.defer` function. * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully * canceled. */ self.defer.cancel = function(deferId) { if (pendingDeferIds[deferId]) { delete pendingDeferIds[deferId]; clearTimeout(deferId); completeOutstandingRequest(noop); return true; } return false; }; } /** @this */ function $BrowserProvider() { this.$get = ['$window', '$log', '$sniffer', '$document', function($window, $log, $sniffer, $document) { return new Browser($window, $document, $log, $sniffer); }]; } /** * @ngdoc service * @name $cacheFactory * @this * * @description * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to * them. * * ```js * * var cache = $cacheFactory('cacheId'); * expect($cacheFactory.get('cacheId')).toBe(cache); * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined(); * * cache.put("key", "value"); * cache.put("another key", "another value"); * * // We've specified no options on creation * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); * * ``` * * * @param {string} cacheId Name or id of the newly created cache. * @param {object=} options Options object that specifies the cache behavior. Properties: * * - `{number=}` `capacity` — turns the cache into LRU cache. * * @returns {object} Newly created cache object with the following set of methods: * * - `{object}` `info()` — Returns id, size, and options of cache. * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns * it. * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss. * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache. * - `{void}` `removeAll()` — Removes all cached values. * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. * * @example

Cached Values

:

Cache Info

:
angular.module('cacheExampleApp', []). controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) { $scope.keys = []; $scope.cache = $cacheFactory('cacheId'); $scope.put = function(key, value) { if (angular.isUndefined($scope.cache.get(key))) { $scope.keys.push(key); } $scope.cache.put(key, angular.isUndefined(value) ? null : value); }; }]); p { margin: 10px 0 3px; }
*/ function $CacheFactoryProvider() { this.$get = function() { var caches = {}; function cacheFactory(cacheId, options) { if (cacheId in caches) { throw minErr('$cacheFactory')('iid', 'CacheId \'{0}\' is already taken!', cacheId); } var size = 0, stats = extend({}, options, {id: cacheId}), data = createMap(), capacity = (options && options.capacity) || Number.MAX_VALUE, lruHash = createMap(), freshEnd = null, staleEnd = null; /** * @ngdoc type * @name $cacheFactory.Cache * * @description * A cache object used to store and retrieve data, primarily used by * {@link $http $http} and the {@link ng.directive:script script} directive to cache * templates and other data. * * ```js * angular.module('superCache') * .factory('superCache', ['$cacheFactory', function($cacheFactory) { * return $cacheFactory('super-cache'); * }]); * ``` * * Example test: * * ```js * it('should behave like a cache', inject(function(superCache) { * superCache.put('key', 'value'); * superCache.put('another key', 'another value'); * * expect(superCache.info()).toEqual({ * id: 'super-cache', * size: 2 * }); * * superCache.remove('another key'); * expect(superCache.get('another key')).toBeUndefined(); * * superCache.removeAll(); * expect(superCache.info()).toEqual({ * id: 'super-cache', * size: 0 * }); * })); * ``` */ return (caches[cacheId] = { /** * @ngdoc method * @name $cacheFactory.Cache#put * @kind function * * @description * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be * retrieved later, and incrementing the size of the cache if the key was not already * present in the cache. If behaving like an LRU cache, it will also remove stale * entries from the set. * * It will not insert undefined values into the cache. * * @param {string} key the key under which the cached data is stored. * @param {*} value the value to store alongside the key. If it is undefined, the key * will not be stored. * @returns {*} the value stored. */ put: function(key, value) { if (isUndefined(value)) return; if (capacity < Number.MAX_VALUE) { var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); refresh(lruEntry); } if (!(key in data)) size++; data[key] = value; if (size > capacity) { this.remove(staleEnd.key); } return value; }, /** * @ngdoc method * @name $cacheFactory.Cache#get * @kind function * * @description * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object. * * @param {string} key the key of the data to be retrieved * @returns {*} the value stored. */ get: function(key) { if (capacity < Number.MAX_VALUE) { var lruEntry = lruHash[key]; if (!lruEntry) return; refresh(lruEntry); } return data[key]; }, /** * @ngdoc method * @name $cacheFactory.Cache#remove * @kind function * * @description * Removes an entry from the {@link $cacheFactory.Cache Cache} object. * * @param {string} key the key of the entry to be removed */ remove: function(key) { if (capacity < Number.MAX_VALUE) { var lruEntry = lruHash[key]; if (!lruEntry) return; if (lruEntry === freshEnd) freshEnd = lruEntry.p; if (lruEntry === staleEnd) staleEnd = lruEntry.n; link(lruEntry.n,lruEntry.p); delete lruHash[key]; } if (!(key in data)) return; delete data[key]; size--; }, /** * @ngdoc method * @name $cacheFactory.Cache#removeAll * @kind function * * @description * Clears the cache object of any entries. */ removeAll: function() { data = createMap(); size = 0; lruHash = createMap(); freshEnd = staleEnd = null; }, /** * @ngdoc method * @name $cacheFactory.Cache#destroy * @kind function * * @description * Destroys the {@link $cacheFactory.Cache Cache} object entirely, * removing it from the {@link $cacheFactory $cacheFactory} set. */ destroy: function() { data = null; stats = null; lruHash = null; delete caches[cacheId]; }, /** * @ngdoc method * @name $cacheFactory.Cache#info * @kind function * * @description * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}. * * @returns {object} an object with the following properties: *
    *
  • **id**: the id of the cache instance
  • *
  • **size**: the number of entries kept in the cache instance
  • *
  • **...**: any additional properties from the options object when creating the * cache.
  • *
*/ info: function() { return extend({}, stats, {size: size}); } }); /** * makes the `entry` the freshEnd of the LRU linked list */ function refresh(entry) { if (entry !== freshEnd) { if (!staleEnd) { staleEnd = entry; } else if (staleEnd === entry) { staleEnd = entry.n; } link(entry.n, entry.p); link(entry, freshEnd); freshEnd = entry; freshEnd.n = null; } } /** * bidirectionally links two entries of the LRU linked list */ function link(nextEntry, prevEntry) { if (nextEntry !== prevEntry) { if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify } } } /** * @ngdoc method * @name $cacheFactory#info * * @description * Get information about all the caches that have been created * * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info` */ cacheFactory.info = function() { var info = {}; forEach(caches, function(cache, cacheId) { info[cacheId] = cache.info(); }); return info; }; /** * @ngdoc method * @name $cacheFactory#get * * @description * Get access to a cache object by the `cacheId` used when it was created. * * @param {string} cacheId Name or id of a cache to access. * @returns {object} Cache object identified by the cacheId or undefined if no such cache. */ cacheFactory.get = function(cacheId) { return caches[cacheId]; }; return cacheFactory; }; } /** * @ngdoc service * @name $templateCache * @this * * @description * The first time a template is used, it is loaded in the template cache for quick retrieval. You * can load templates directly into the cache in a `script` tag, or by consuming the * `$templateCache` service directly. * * Adding via the `script` tag: * * ```html * * ``` * * **Note:** the `script` tag containing the template does not need to be included in the `head` of * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE, * element with ng-app attribute), otherwise the template will be ignored. * * Adding via the `$templateCache` service: * * ```js * var myApp = angular.module('myApp', []); * myApp.run(function($templateCache) { * $templateCache.put('templateId.html', 'This is the content of the template'); * }); * ``` * * To retrieve the template later, simply use it in your component: * ```js * myApp.component('myComponent', { * templateUrl: 'templateId.html' * }); * ``` * * or get it via the `$templateCache` service: * ```js * $templateCache.get('templateId.html') * ``` * * See {@link ng.$cacheFactory $cacheFactory}. * */ function $TemplateCacheProvider() { this.$get = ['$cacheFactory', function($cacheFactory) { return $cacheFactory('templates'); }]; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Any commits to this file should be reviewed with security in mind. * * Changes to this file can potentially create security vulnerabilities. * * An approval from 2 Core members with history of modifying * * this file is required. * * * * Does the change somehow allow for arbitrary javascript to be executed? * * Or allows for someone to change the prototype of built-in objects? * * Or gives undesired access to variables like document or window? * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE! * * DOM-related variables: * * - "node" - DOM Node * - "element" - DOM Element or Node * - "$node" or "$element" - jqLite-wrapped node or element * * * Compiler related stuff: * * - "linkFn" - linking fn of a single directive * - "nodeLinkFn" - function that aggregates all linking fns for a particular node * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList) */ /** * @ngdoc service * @name $compile * @kind function * * @description * Compiles an HTML string or DOM into a template and produces a template function, which * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together. * * The compilation is a process of walking the DOM tree and matching DOM elements to * {@link ng.$compileProvider#directive directives}. * *
* **Note:** This document is an in-depth reference of all directive options. * For a gentle introduction to directives with examples of common use cases, * see the {@link guide/directive directive guide}. *
* * ## Comprehensive Directive API * * There are many different options for a directive. * * The difference resides in the return value of the factory function. * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)} * that defines the directive properties, or just the `postLink` function (all other properties will have * the default values). * *
* **Best Practice:** It's recommended to use the "directive definition object" form. *
* * Here's an example directive declared with a Directive Definition Object: * * ```js * var myModule = angular.module(...); * * myModule.directive('directiveName', function factory(injectables) { * var directiveDefinitionObject = { * {@link $compile#-priority- priority}: 0, * {@link $compile#-template- template}: '
', // or // function(tElement, tAttrs) { ... }, * // or * // {@link $compile#-templateurl- templateUrl}: 'directive.html', // or // function(tElement, tAttrs) { ... }, * {@link $compile#-transclude- transclude}: false, * {@link $compile#-restrict- restrict}: 'A', * {@link $compile#-templatenamespace- templateNamespace}: 'html', * {@link $compile#-scope- scope}: false, * {@link $compile#-controller- controller}: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, * {@link $compile#-controlleras- controllerAs}: 'stringIdentifier', * {@link $compile#-bindtocontroller- bindToController}: false, * {@link $compile#-require- require}: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], * {@link $compile#-multielement- multiElement}: false, * {@link $compile#-compile- compile}: function compile(tElement, tAttrs, transclude) { * return { * {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... }, * {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... } * } * // or * // return function postLink( ... ) { ... } * }, * // or * // {@link $compile#-link- link}: { * // {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... }, * // {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... } * // } * // or * // {@link $compile#-link- link}: function postLink( ... ) { ... } * }; * return directiveDefinitionObject; * }); * ``` * *
* **Note:** Any unspecified options will use the default value. You can see the default values below. *
* * Therefore the above can be simplified as: * * ```js * var myModule = angular.module(...); * * myModule.directive('directiveName', function factory(injectables) { * var directiveDefinitionObject = { * link: function postLink(scope, iElement, iAttrs) { ... } * }; * return directiveDefinitionObject; * // or * // return function postLink(scope, iElement, iAttrs) { ... } * }); * ``` * * ### Life-cycle hooks * Directive controllers can provide the following methods that are called by Angular at points in the life-cycle of the * directive: * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and * had their bindings initialized (and before the pre & post linking functions for the directives on * this element). This is a good place to put initialization code for your controller. * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an * object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a * component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will * also be called when your bindings are initialized. * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on * changes. Any actions that you wish to take in response to the changes that you detect must be * invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook * could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not * be detected by Angular's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments; * if detecting changes, you must store the previous value(s) for comparison to the current values. * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent * components will have their `$onDestroy()` hook called before child components. * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link * function this hook can be used to set up DOM event handlers and do direct DOM manipulation. * Note that child elements that contain `templateUrl` directives will not have been compiled and linked since * they are waiting for their template to load asynchronously and their own compilation and linking has been * suspended until that occurs. * * #### Comparison with Angular 2 life-cycle hooks * Angular 2 also uses life-cycle hooks for its components. While the Angular 1 life-cycle hooks are similar there are * some differences that you should be aware of, especially when it comes to moving your code from Angular 1 to Angular 2: * * * Angular 1 hooks are prefixed with `$`, such as `$onInit`. Angular 2 hooks are prefixed with `ng`, such as `ngOnInit`. * * Angular 1 hooks can be defined on the controller prototype or added to the controller inside its constructor. * In Angular 2 you can only define hooks on the prototype of the Component class. * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in Angular 1 than you would to * `ngDoCheck` in Angular 2 * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be * propagated throughout the application. * Angular 2 does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an * error or do nothing depending upon the state of `enableProdMode()`. * * #### Life-cycle hook examples * * This example shows how you can check for mutations to a Date object even though the identity of the object * has not changed. * * * * angular.module('do-check-module', []) * .component('app', { * template: * 'Month: ' + * 'Date: {{ $ctrl.date }}' + * '', * controller: function() { * this.date = new Date(); * this.month = this.date.getMonth(); * this.updateDate = function() { * this.date.setMonth(this.month); * }; * } * }) * .component('test', { * bindings: { date: '<' }, * template: * '
{{ $ctrl.log | json }}
', * controller: function() { * var previousValue; * this.log = []; * this.$doCheck = function() { * var currentValue = this.date && this.date.valueOf(); * if (previousValue !== currentValue) { * this.log.push('doCheck: date mutated: ' + this.date); * previousValue = currentValue; * } * }; * } * }); *
* * * *
* * This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large * arrays or objects can have a negative impact on your application performance) * * * *
* * *
{{ items }}
* *
*
* * angular.module('do-check-module', []) * .component('test', { * bindings: { items: '<' }, * template: * '
{{ $ctrl.log | json }}
', * controller: function() { * this.log = []; * * this.$doCheck = function() { * if (this.items_ref !== this.items) { * this.log.push('doCheck: items changed'); * this.items_ref = this.items; * } * if (!angular.equals(this.items_clone, this.items)) { * this.log.push('doCheck: items mutated'); * this.items_clone = angular.copy(this.items); * } * }; * } * }); *
*
* * * ### Directive Definition Object * * The directive definition object provides instructions to the {@link ng.$compile * compiler}. The attributes are: * * #### `multiElement` * When this property is set to true (default is `false`), the HTML compiler will collect DOM nodes between * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them * together as the directive elements. It is recommended that this feature be used on directives * which are not strictly behavioral (such as {@link ngClick}), and which * do not manipulate or replace child nodes (such as {@link ngInclude}). * * #### `priority` * When there are multiple directives defined on a single DOM element, sometimes it * is necessary to specify the order in which the directives are applied. The `priority` is used * to sort the directives before their `compile` functions get called. Priority is defined as a * number. Directives with greater numerical `priority` are compiled first. Pre-link functions * are also run in priority order, but post-link functions are run in reverse order. The order * of directives with the same priority is undefined. The default priority is `0`. * * #### `terminal` * If set to true then the current `priority` will be the last set of directives * which will execute (any directives at the current priority will still execute * as the order of execution on same `priority` is undefined). Note that expressions * and other directives used in the directive's template will also be excluded from execution. * * #### `scope` * The scope property can be `false`, `true`, or an object: * * * **`false` (default):** No scope will be created for the directive. The directive will use its * parent's scope. * * * **`true`:** A new child scope that prototypically inherits from its parent will be created for * the directive's element. If multiple directives on the same element request a new scope, * only one new scope is created. * * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's template. * The 'isolate' scope differs from normal scope in that it does not prototypically * inherit from its parent scope. This is useful when creating reusable components, which should not * accidentally read or modify data in the parent scope. Note that an isolate scope * directive without a `template` or `templateUrl` will not apply the isolate scope * to its children elements. * * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the * directive's element. These local properties are useful for aliasing values for templates. The keys in * the object hash map to the name of the property on the isolate scope; the values define how the property * is bound to the parent scope, via matching attributes on the directive's element: * * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is * always a string since DOM attributes are strings. If no `attr` name is specified then the * attribute name is assumed to be the same as the local name. Given `` and the isolate scope definition `scope: { localName:'@myAttr' }`, * the directive's scope property `localName` will reflect the interpolated value of `hello * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's * scope. The `name` is read from the parent scope (not the directive's scope). * * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope. * If no `attr` name is specified then the attribute name is assumed to be the same as the local * name. Given `` and the isolate scope definition `scope: { * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in * `localModel` and vice versa. Optional attributes should be marked as such with a question mark: * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`}) * will be thrown upon discovering changes to the local value, since it will be impossible to sync * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`} * method is used for tracking changes, and the equality check is based on object identity. * However, if an object literal or an array literal is passed as the binding expression, the * equality check is done by value (using the {@link angular.equals} function). It's also possible * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional). * * * `<` or `` and directive definition of * `scope: { localModel:'` and the isolate scope definition `scope: { * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope * via an expression to the parent scope. This can be done by passing a map of local variable names * and values into the expression wrapper fn. For example, if the expression is `increment(amount)` * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`. * * In general it's possible to apply more than one directive to one element, but there might be limitations * depending on the type of scope required by the directives. The following points will help explain these limitations. * For simplicity only two directives are taken into account, but it is also applicable for several directives: * * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope * * **child scope** + **no scope** => Both directives will share one single child scope * * **child scope** + **child scope** => Both directives will share one single child scope * * **isolated scope** + **no scope** => The isolated directive will use it's own created isolated scope. The other directive will use * its parent's scope * * **isolated scope** + **child scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives cannot * be applied to the same element. * * **isolated scope** + **isolated scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives * cannot be applied to the same element. * * * #### `bindToController` * This property is used to bind scope properties directly to the controller. It can be either * `true` or an object hash with the same format as the `scope` property. * * When an isolate scope is used for a directive (see above), `bindToController: true` will * allow a component to have its properties bound to the controller, rather than to scope. * * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller * properties. You can access these bindings once they have been initialized by providing a controller method called * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings * initialized. * *
* **Deprecation warning:** if `$compileProcvider.preAssignBindingsEnabled(true)` was called, bindings for non-ES6 class * controllers are bound to `this` before the controller constructor is called but this use is now deprecated. Please * place initialization code that relies upon bindings inside a `$onInit` method on the controller, instead. *
* * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property. * This will set up the scope bindings to the controller directly. Note that `scope` can still be used * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate * scope (useful for component directives). * * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`. * * * #### `controller` * Controller constructor function. The controller is instantiated before the * pre-linking phase and can be accessed by other directives (see * `require` attribute). This allows the directives to communicate with each other and augment * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals: * * * `$scope` - Current scope associated with the element * * `$element` - Current element * * `$attrs` - Current attributes object for the element * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope: * `function([scope], cloneLinkingFn, futureParentElement, slotName)`: * * `scope`: (optional) override the scope. * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content. * * `futureParentElement` (optional): * * defines the parent to which the `cloneLinkingFn` will add the cloned elements. * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`. * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements) * and when the `cloneLinkingFn` is passed, * as those elements need to created and cloned in a special way when they are defined outside their * usual containers (e.g. like ``). * * See also the `directive.templateNamespace` property. * * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`) * then the default transclusion is provided. * The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns * `true` if the specified slot contains content (i.e. one or more DOM nodes). * * #### `require` * Require another directive and inject its controller as the fourth argument to the linking function. The * `require` property can be a string, an array or an object: * * a **string** containing the name of the directive to pass to the linking function * * an **array** containing the names of directives to pass to the linking function. The argument passed to the * linking function will be an array of controllers in the same order as the names in the `require` property * * an **object** whose property values are the names of the directives to pass to the linking function. The argument * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding * controllers. * * If the `require` property is an object and `bindToController` is truthy, then the required controllers are * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers * have been constructed but before `$onInit` is called. * If the name of the required controller is the same as the local name (the key), the name can be * omitted. For example, `{parentDir: '^^'}` is equivalent to `{parentDir: '^^parentDir'}`. * See the {@link $compileProvider#component} helper for an example of how this can be used. * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is * raised (unless no link function is specified and the required controllers are not being bound to the directive * controller, in which case error checking is skipped). The name can be prefixed with: * * * (no prefix) - Locate the required controller on the current element. Throw an error if not found. * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found. * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found. * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass * `null` to the `link` fn if not found. * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass * `null` to the `link` fn if not found. * * * #### `controllerAs` * Identifier name for a reference to the controller in the directive's scope. * This allows the controller to be referenced from the directive template. This is especially * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the * `controllerAs` reference might overwrite a property that already exists on the parent scope. * * * #### `restrict` * String of subset of `EACM` which restricts the directive to a specific directive * declaration style. If omitted, the defaults (elements and attributes) are used. * * * `E` - Element name (default): `` * * `A` - Attribute (default): `
` * * `C` - Class: `
` * * `M` - Comment: `` * * * #### `templateNamespace` * String representing the document type used by the markup in the template. * AngularJS needs this information as those elements need to be created and cloned * in a special way when they are defined outside their usual containers like `` and ``. * * * `html` - All root nodes in the template are HTML. Root nodes may also be * top-level elements such as `` or ``. * * `svg` - The root nodes in the template are SVG elements (excluding ``). * * `math` - The root nodes in the template are MathML elements (excluding ``). * * If no `templateNamespace` is specified, then the namespace is considered to be `html`. * * #### `template` * HTML markup that may: * * Replace the contents of the directive's element (default). * * Replace the directive's element itself (if `replace` is true - DEPRECATED). * * Wrap the contents of the directive's element (if `transclude` is true). * * Value may be: * * * A string. For example `
{{delete_str}}
`. * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile` * function api below) and returns a string value. * * * #### `templateUrl` * This is similar to `template` but the template is loaded from the specified URL, asynchronously. * * Because template loading is asynchronous the compiler will suspend compilation of directives on that element * for later when the template has been resolved. In the meantime it will continue to compile and link * sibling and parent elements as though this element had not contained any directives. * * The compiler does not suspend the entire compilation to wait for templates to be loaded because this * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the * case when only one deeply nested directive has `templateUrl`. * * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache} * * You can specify `templateUrl` as a string representing the URL or as a function which takes two * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns * a string value representing the url. In either case, the template URL is passed through {@link * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}. * * * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0) * specify what the template should replace. Defaults to `false`. * * * `true` - the template will replace the directive's element. * * `false` - the template will replace the contents of the directive's element. * * The replacement process migrates all of the attributes / classes from the old element to the new * one. See the {@link guide/directive#template-expanding-directive * Directives Guide} for an example. * * There are very few scenarios where element replacement is required for the application function, * the main one being reusable custom components that are used within SVG contexts * (because SVG doesn't work with custom elements in the DOM tree). * * #### `transclude` * Extract the contents of the element where the directive appears and make it available to the directive. * The contents are compiled and provided to the directive as a **transclusion function**. See the * {@link $compile#transclusion Transclusion} section below. * * * #### `compile` * * ```js * function compile(tElement, tAttrs, transclude) { ... } * ``` * * The compile function deals with transforming the template DOM. Since most directives do not do * template transformation, it is not used often. The compile function takes the following arguments: * * * `tElement` - template element - The element where the directive has been declared. It is * safe to do template transformation on the element and child elements only. * * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared * between all directive compile functions. * * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)` * *
* **Note:** The template instance and the link instance may be different objects if the template has * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration * should be done in a linking function rather than in a compile function. *
*
* **Note:** The compile function cannot handle directives that recursively use themselves in their * own templates or compile functions. Compiling these directives results in an infinite loop and * stack overflow errors. * * This can be avoided by manually using $compile in the postLink function to imperatively compile * a directive's template instead of relying on automatic template compilation via `template` or * `templateUrl` declaration or manual compilation inside the compile function. *
* *
* **Note:** The `transclude` function that is passed to the compile function is deprecated, as it * e.g. does not know about the right outer scope. Please use the transclude function that is passed * to the link function instead. *
* A compile function can have a return value which can be either a function or an object. * * * returning a (post-link) function - is equivalent to registering the linking function via the * `link` property of the config object when the compile function is empty. * * * returning an object with function(s) registered via `pre` and `post` properties - allows you to * control when a linking function should be called during the linking phase. See info about * pre-linking and post-linking functions below. * * * #### `link` * This property is used only if the `compile` property is not defined. * * ```js * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } * ``` * * The link function is responsible for registering DOM listeners as well as updating the DOM. It is * executed after the template has been cloned. This is where most of the directive logic will be * put. * * * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the * directive for registering {@link ng.$rootScope.Scope#$watch watches}. * * * `iElement` - instance element - The element where the directive is to be used. It is safe to * manipulate the children of the element only in `postLink` function since the children have * already been linked. * * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared * between all directive linking functions. * * * `controller` - the directive's required controller instance(s) - Instances are shared * among all directives, which allows the directives to use the controllers as a communication * channel. The exact value depends on the directive's `require` property: * * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one * * `string`: the controller instance * * `array`: array of controller instances * * If a required controller cannot be found, and it is optional, the instance is `null`, * otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown. * * Note that you can also require the directive's own controller - it will be made available like * any other controller. * * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope. * This is the same as the `$transclude` parameter of directive controllers, * see {@link ng.$compile#-controller- the controller section for details}. * `function([scope], cloneLinkingFn, futureParentElement)`. * * #### Pre-linking function * * Executed before the child elements are linked. Not safe to do DOM transformation since the * compiler linking function will fail to locate the correct elements for linking. * * #### Post-linking function * * Executed after the child elements are linked. * * Note that child elements that contain `templateUrl` directives will not have been compiled * and linked since they are waiting for their template to load asynchronously and their own * compilation and linking has been suspended until that occurs. * * It is safe to do DOM transformation in the post-linking function on elements that are not waiting * for their async templates to be resolved. * * * ### Transclusion * * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and * copying them to another part of the DOM, while maintaining their connection to the original AngularJS * scope from where they were taken. * * Transclusion is used (often with {@link ngTransclude}) to insert the * original contents of a directive's element into a specified place in the template of the directive. * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded * content has access to the properties on the scope from which it was taken, even if the directive * has isolated scope. * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}. * * This makes it possible for the widget to have private state for its template, while the transcluded * content has access to its originating scope. * *
* **Note:** When testing an element transclude directive you must not place the directive at the root of the * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives * Testing Transclusion Directives}. *
* * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the * directive's element, the entire element or multiple parts of the element contents: * * * `true` - transclude the content (i.e. the child nodes) of the directive's element. * * `'element'` - transclude the whole of the directive's element including any directives on this * element that defined at a lower priority than this directive. When used, the `template` * property is ignored. * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template. * * **Mult-slot transclusion** is declared by providing an object for the `transclude` property. * * This object is a map where the keys are the name of the slot to fill and the value is an element selector * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`) * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc). * * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives} * * If the element selector is prefixed with a `?` then that slot is optional. * * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `` elements to * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive. * * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and * injectable into the directive's controller. * * * #### Transclusion Functions * * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion * function** to the directive's `link` function and `controller`. This transclusion function is a special * **linking function** that will return the compiled contents linked to a new transclusion scope. * *
* If you are just using {@link ngTransclude} then you don't need to worry about this function, since * ngTransclude will deal with it for us. *
* * If you want to manually control the insertion and removal of the transcluded content in your directive * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery * object that contains the compiled DOM, which is linked to the correct transclusion scope. * * When you call a transclusion function you can pass in a **clone attach function**. This function accepts * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded * content and the `scope` is the newly created transclusion scope, which the clone will be linked to. * *
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope. *
* * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone * attach function**: * * ```js * var transcludedContent, transclusionScope; * * $transclude(function(clone, scope) { * element.append(clone); * transcludedContent = clone; * transclusionScope = scope; * }); * ``` * * Later, if you want to remove the transcluded content from your DOM then you should also destroy the * associated transclusion scope: * * ```js * transcludedContent.remove(); * transclusionScope.$destroy(); * ``` * *
* **Best Practice**: if you intend to add and remove transcluded content manually in your directive * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it), * then you are also responsible for calling `$destroy` on the transclusion scope. *
* * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat} * automatically destroy their transcluded clones as necessary so you do not need to worry about this if * you are simply using {@link ngTransclude} to inject the transclusion into your directive. * * * #### Transclusion Scopes * * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it * was taken. * * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look * like this: * * ```html *
*
*
*
*
*
* ``` * * The `$parent` scope hierarchy will look like this: * ``` - $rootScope - isolate - transclusion ``` * * but the scopes will inherit prototypically from different scopes to their `$parent`. * ``` - $rootScope - transclusion - isolate ``` * * * ### Attributes * * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the * `link()` or `compile()` functions. It has a variety of uses. * * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways: * 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access * to the attributes. * * * *Directive inter-communication:* All directives share the same instance of the attributes * object which allows the directives to use the attributes object as inter directive * communication. * * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object * allowing other directives to read the interpolated value. * * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes * that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also * the only way to easily get the actual value because during the linking phase the interpolation * hasn't been evaluated yet and so the value is at this time set to `undefined`. * * ```js * function linkingFn(scope, elm, attrs, ctrl) { * // get the attribute value * console.log(attrs.ngModel); * * // change the attribute * attrs.$set('ngModel', 'new value'); * * // observe changes to interpolated attribute * attrs.$observe('ngModel', function(value) { * console.log('ngModel has changed value to ' + value); * }); * } * ``` * * ## Example * *
* **Note**: Typically directives are registered with `module.directive`. The example below is * to illustrate how `$compile` works. *
*


it('should auto compile', function() { var textarea = $('textarea'); var output = $('div[compile]'); // The initial state reads 'Hello Angular'. expect(output.getText()).toBe('Hello Angular'); textarea.clear(); textarea.sendKeys('{{name}}!'); expect(output.getText()).toBe('Angular!'); });
* * * @param {string|DOMElement} element Element or HTML string to compile into a template function. * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED. * *
* **Note:** Passing a `transclude` function to the $compile function is deprecated, as it * e.g. will not use the right outer scope. Please pass the transclude function as a * `parentBoundTranscludeFn` to the link function instead. *
* * @param {number} maxPriority only apply directives lower than given priority (Only effects the * root element(s), not their children) * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template * (a DOM element/tree) to a scope. Where: * * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to. * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the * `template` and call the `cloneAttachFn` function allowing the caller to attach the * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is * called as:
`cloneAttachFn(clonedElement, scope)` where: * * * `clonedElement` - is a clone of the original `element` passed into the compiler. * * `scope` - is the current scope with which the linking function is working with. * * * `options` - An optional object hash with linking options. If `options` is provided, then the following * keys may be used to control linking behavior: * * * `parentBoundTranscludeFn` - the transclude function made available to * directives; if given, it will be passed through to the link functions of * directives found in `element` during compilation. * * `transcludeControllers` - an object hash with keys that map controller names * to a hash with the key `instance`, which maps to the controller instance; * if given, it will make the controllers available to directives on the compileNode: * ``` * { * parent: { * instance: parentControllerInstance * } * } * ``` * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add * the cloned elements; only needed for transcludes that are allowed to contain non html * elements (e.g. SVG elements). See also the directive.controller property. * * Calling the linking function returns the element of the template. It is either the original * element passed in, or the clone of the element if the `cloneAttachFn` is provided. * * After linking the view is not updated until after a call to $digest which typically is done by * Angular automatically. * * If you need access to the bound view, there are two ways to do it: * * - If you are not asking the linking function to clone the template, create the DOM element(s) * before you send them to the compiler and keep this reference around. * ```js * var element = $compile('

{{total}}

')(scope); * ``` * * - if on the other hand, you need the element to be cloned, the view reference from the original * example would not point to the clone, but rather to the original template that was cloned. In * this case, you can access the clone via the cloneAttachFn: * ```js * var templateElement = angular.element('

{{total}}

'), * scope = ....; * * var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) { * //attach the clone to DOM document at the right place * }); * * //now we have reference to the cloned DOM via `clonedElement` * ``` * * * For information on how the compiler works, see the * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. * * @knownIssue * * ### Double Compilation * Double compilation occurs when an already compiled part of the DOM gets compiled again. This is an undesired effect and can lead to misbehaving directives, performance issues, and memory leaks. Refer to the Compiler Guide {@link guide/compiler#double-compilation-and-how-to-avoid-it section on double compilation} for an in-depth explanation and ways to avoid it. * */ var $compileMinErr = minErr('$compile'); function UNINITIALIZED_VALUE() {} var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE(); /** * @ngdoc provider * @name $compileProvider * * @description */ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider']; /** @this */ function $CompileProvider($provide, $$sanitizeUriProvider) { var hasDirectives = {}, Suffix = 'Directive', COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w-]+)\s+(.*)$/, CLASS_DIRECTIVE_REGEXP = /(([\w-]+)(?::([^;]+))?;?)/, ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'), REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/; // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes // The assumption is that future DOM event attribute names will begin with // 'on' and be composed of only English letters. var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; var bindingCache = createMap(); function parseIsolateBindings(scope, directiveName, isController) { var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*([\w$]*)\s*$/; var bindings = createMap(); forEach(scope, function(definition, scopeName) { if (definition in bindingCache) { bindings[scopeName] = bindingCache[definition]; return; } var match = definition.match(LOCAL_REGEXP); if (!match) { throw $compileMinErr('iscp', 'Invalid {3} for directive \'{0}\'.' + ' Definition: {... {1}: \'{2}\' ...}', directiveName, scopeName, definition, (isController ? 'controller bindings definition' : 'isolate scope definition')); } bindings[scopeName] = { mode: match[1][0], collection: match[2] === '*', optional: match[3] === '?', attrName: match[4] || scopeName }; if (match[4]) { bindingCache[definition] = bindings[scopeName]; } }); return bindings; } function parseDirectiveBindings(directive, directiveName) { var bindings = { isolateScope: null, bindToController: null }; if (isObject(directive.scope)) { if (directive.bindToController === true) { bindings.bindToController = parseIsolateBindings(directive.scope, directiveName, true); bindings.isolateScope = {}; } else { bindings.isolateScope = parseIsolateBindings(directive.scope, directiveName, false); } } if (isObject(directive.bindToController)) { bindings.bindToController = parseIsolateBindings(directive.bindToController, directiveName, true); } if (bindings.bindToController && !directive.controller) { // There is no controller throw $compileMinErr('noctrl', 'Cannot bind to controller without directive \'{0}\'s controller.', directiveName); } return bindings; } function assertValidDirectiveName(name) { var letter = name.charAt(0); if (!letter || letter !== lowercase(letter)) { throw $compileMinErr('baddir', 'Directive/Component name \'{0}\' is invalid. The first character must be a lowercase letter', name); } if (name !== name.trim()) { throw $compileMinErr('baddir', 'Directive/Component name \'{0}\' is invalid. The name should not contain leading or trailing whitespaces', name); } } function getDirectiveRequire(directive) { var require = directive.require || (directive.controller && directive.name); if (!isArray(require) && isObject(require)) { forEach(require, function(value, key) { var match = value.match(REQUIRE_PREFIX_REGEXP); var name = value.substring(match[0].length); if (!name) require[key] = match[0] + key; }); } return require; } function getDirectiveRestrict(restrict, name) { if (restrict && !(isString(restrict) && /[EACM]/.test(restrict))) { throw $compileMinErr('badrestrict', 'Restrict property \'{0}\' of directive \'{1}\' is invalid', restrict, name); } return restrict || 'EA'; } /** * @ngdoc method * @name $compileProvider#directive * @kind function * * @description * Register a new directive with the compiler. * * @param {string|Object} name Name of the directive in camel-case (i.e. ngBind which * will match as ng-bind), or an object map of directives where the keys are the * names and the values are the factories. * @param {Function|Array} directiveFactory An injectable directive factory function. See the * {@link guide/directive directive guide} and the {@link $compile compile API} for more info. * @returns {ng.$compileProvider} Self for chaining. */ this.directive = function registerDirective(name, directiveFactory) { assertArg(name, 'name'); assertNotHasOwnProperty(name, 'directive'); if (isString(name)) { assertValidDirectiveName(name); assertArg(directiveFactory, 'directiveFactory'); if (!hasDirectives.hasOwnProperty(name)) { hasDirectives[name] = []; $provide.factory(name + Suffix, ['$injector', '$exceptionHandler', function($injector, $exceptionHandler) { var directives = []; forEach(hasDirectives[name], function(directiveFactory, index) { try { var directive = $injector.invoke(directiveFactory); if (isFunction(directive)) { directive = { compile: valueFn(directive) }; } else if (!directive.compile && directive.link) { directive.compile = valueFn(directive.link); } directive.priority = directive.priority || 0; directive.index = index; directive.name = directive.name || name; directive.require = getDirectiveRequire(directive); directive.restrict = getDirectiveRestrict(directive.restrict, name); directive.$$moduleName = directiveFactory.$$moduleName; directives.push(directive); } catch (e) { $exceptionHandler(e); } }); return directives; }]); } hasDirectives[name].push(directiveFactory); } else { forEach(name, reverseParams(registerDirective)); } return this; }; /** * @ngdoc method * @name $compileProvider#component * @module ng * @param {string|Object} name Name of the component in camelCase (i.e. `myComp` which will match ``), * or an object map of components where the keys are the names and the values are the component definition objects. * @param {Object} options Component definition object (a simplified * {@link ng.$compile#directive-definition-object directive definition object}), * with the following properties (all optional): * * - `controller` – `{(string|function()=}` – controller constructor function that should be * associated with newly created scope or the name of a {@link ng.$compile#-controller- * registered controller} if passed as a string. An empty `noop` function by default. * - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope. * If present, the controller will be published to scope under the `controllerAs` name. * If not present, this will default to be `$ctrl`. * - `template` – `{string=|function()=}` – html template as a string or a function that * returns an html template as a string which should be used as the contents of this component. * Empty string by default. * * If `template` is a function, then it is {@link auto.$injector#invoke injected} with * the following locals: * * - `$element` - Current element * - `$attrs` - Current attributes object for the element * * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html * template that should be used as the contents of this component. * * If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with * the following locals: * * - `$element` - Current element * - `$attrs` - Current attributes object for the element * * - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties. * Component properties are always bound to the component controller and not to the scope. * See {@link ng.$compile#-bindtocontroller- `bindToController`}. * - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled. * Disabled by default. * - `require` - `{Object=}` - requires the controllers of other directives and binds them to * this component's controller. The object keys specify the property names under which the required * controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}. * - `$...` – additional properties to attach to the directive factory function and the controller * constructor function. (This is used by the component router to annotate) * * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls. * @description * Register a **component definition** with the compiler. This is a shorthand for registering a special * type of directive, which represents a self-contained UI component in your application. Such components * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`). * * Component definitions are very simple and do not require as much configuration as defining general * directives. Component definitions usually consist only of a template and a controller backing it. * * In order to make the definition easier, components enforce best practices like use of `controllerAs`, * `bindToController`. They always have **isolate scope** and are restricted to elements. * * Here are a few examples of how you would usually define components: * * ```js * var myMod = angular.module(...); * myMod.component('myComp', { * template: '
My name is {{$ctrl.name}}
', * controller: function() { * this.name = 'shahar'; * } * }); * * myMod.component('myComp', { * template: '
My name is {{$ctrl.name}}
', * bindings: {name: '@'} * }); * * myMod.component('myComp', { * templateUrl: 'views/my-comp.html', * controller: 'MyCtrl', * controllerAs: 'ctrl', * bindings: {name: '@'} * }); * * ``` * For more examples, and an in-depth guide, see the {@link guide/component component guide}. * *
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}. */ this.component = function registerComponent(name, options) { if (!isString(name)) { forEach(name, reverseParams(bind(this, registerComponent))); return this; } var controller = options.controller || function() {}; function factory($injector) { function makeInjectable(fn) { if (isFunction(fn) || isArray(fn)) { return /** @this */ function(tElement, tAttrs) { return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs}); }; } else { return fn; } } var template = (!options.template && !options.templateUrl ? '' : options.template); var ddo = { controller: controller, controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl', template: makeInjectable(template), templateUrl: makeInjectable(options.templateUrl), transclude: options.transclude, scope: {}, bindToController: options.bindings || {}, restrict: 'E', require: options.require }; // Copy annotations (starting with $) over to the DDO forEach(options, function(val, key) { if (key.charAt(0) === '$') ddo[key] = val; }); return ddo; } // TODO(pete) remove the following `forEach` before we release 1.6.0 // The component-router@0.2.0 looks for the annotations on the controller constructor // Nothing in Angular looks for annotations on the factory function but we can't remove // it from 1.5.x yet. // Copy any annotation properties (starting with $) over to the factory and controller constructor functions // These could be used by libraries such as the new component router forEach(options, function(val, key) { if (key.charAt(0) === '$') { factory[key] = val; // Don't try to copy over annotations to named controller if (isFunction(controller)) controller[key] = val; } }); factory.$inject = ['$injector']; return this.directive(name, factory); }; /** * @ngdoc method * @name $compileProvider#aHrefSanitizationWhitelist * @kind function * * @description * Retrieves or overrides the default regular expression that is used for whitelisting of safe * urls during a[href] sanitization. * * The sanitization is a security measure aimed at preventing XSS attacks via html links. * * Any url about to be assigned to a[href] via data-binding is first normalized and turned into * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` * regular expression. If a match is found, the original url is written into the dom. Otherwise, * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. * * @param {RegExp=} regexp New regexp to whitelist urls with. * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for * chaining otherwise. */ this.aHrefSanitizationWhitelist = function(regexp) { if (isDefined(regexp)) { $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp); return this; } else { return $$sanitizeUriProvider.aHrefSanitizationWhitelist(); } }; /** * @ngdoc method * @name $compileProvider#imgSrcSanitizationWhitelist * @kind function * * @description * Retrieves or overrides the default regular expression that is used for whitelisting of safe * urls during img[src] sanitization. * * The sanitization is a security measure aimed at prevent XSS attacks via html links. * * Any url about to be assigned to img[src] via data-binding is first normalized and turned into * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` * regular expression. If a match is found, the original url is written into the dom. Otherwise, * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. * * @param {RegExp=} regexp New regexp to whitelist urls with. * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for * chaining otherwise. */ this.imgSrcSanitizationWhitelist = function(regexp) { if (isDefined(regexp)) { $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp); return this; } else { return $$sanitizeUriProvider.imgSrcSanitizationWhitelist(); } }; /** * @ngdoc method * @name $compileProvider#debugInfoEnabled * * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the * current debugInfoEnabled state * @returns {*} current value if used as getter or itself (chaining) if used as setter * * @kind function * * @description * Call this method to enable/disable various debug runtime information in the compiler such as adding * binding information and a reference to the current scope on to DOM elements. * If enabled, the compiler will add the following to DOM elements that have been bound to the scope * * `ng-binding` CSS class * * `$binding` data property containing an array of the binding expressions * * You may want to disable this in production for a significant performance boost. See * {@link guide/production#disabling-debug-data Disabling Debug Data} for more. * * The default value is true. */ var debugInfoEnabled = true; this.debugInfoEnabled = function(enabled) { if (isDefined(enabled)) { debugInfoEnabled = enabled; return this; } return debugInfoEnabled; }; /** * @ngdoc method * @name $compileProvider#preAssignBindingsEnabled * * @param {boolean=} enabled update the preAssignBindingsEnabled state if provided, otherwise just return the * current preAssignBindingsEnabled state * @returns {*} current value if used as getter or itself (chaining) if used as setter * * @kind function * * @description * Call this method to enable/disable whether directive controllers are assigned bindings before * calling the controller's constructor. * If enabled (true), the compiler assigns the value of each of the bindings to the * properties of the controller object before the constructor of this object is called. * * If disabled (false), the compiler calls the constructor first before assigning bindings. * * The default value is false. * * @deprecated * sinceVersion="1.6.0" * removeVersion="1.7.0" * * This method and the option to assign the bindings before calling the controller's constructor * will be removed in v1.7.0. */ var preAssignBindingsEnabled = false; this.preAssignBindingsEnabled = function(enabled) { if (isDefined(enabled)) { preAssignBindingsEnabled = enabled; return this; } return preAssignBindingsEnabled; }; /** * @ngdoc method * @name $compileProvider#strictComponentBindingsEnabled * * @param {boolean=} enabled update the strictComponentBindingsEnabled state if provided, otherwise just return the * current strictComponentBindingsEnabled state * @returns {*} current value if used as getter or itself (chaining) if used as setter * * @kind function * * @description * Call this method to enable/disable strict component bindings check. If enabled, the compiler will enforce that * for all bindings of a component that are not set as optional with `?`, an attribute needs to be provided * on the component's HTML tag. * * The default value is false. */ var strictComponentBindingsEnabled = false; this.strictComponentBindingsEnabled = function(enabled) { if (isDefined(enabled)) { strictComponentBindingsEnabled = enabled; return this; } return strictComponentBindingsEnabled; }; var TTL = 10; /** * @ngdoc method * @name $compileProvider#onChangesTtl * @description * * Sets the number of times `$onChanges` hooks can trigger new changes before giving up and * assuming that the model is unstable. * * The current default is 10 iterations. * * In complex applications it's possible that dependencies between `$onChanges` hooks and bindings will result * in several iterations of calls to these hooks. However if an application needs more than the default 10 * iterations to stabilize then you should investigate what is causing the model to continuously change during * the `$onChanges` hook execution. * * Increasing the TTL could have performance implications, so you should not change it without proper justification. * * @param {number} limit The number of `$onChanges` hook iterations. * @returns {number|object} the current limit (or `this` if called as a setter for chaining) */ this.onChangesTtl = function(value) { if (arguments.length) { TTL = value; return this; } return TTL; }; var commentDirectivesEnabledConfig = true; /** * @ngdoc method * @name $compileProvider#commentDirectivesEnabled * @description * * It indicates to the compiler * whether or not directives on comments should be compiled. * Defaults to `true`. * * Calling this function with false disables the compilation of directives * on comments for the whole application. * This results in a compilation performance gain, * as the compiler doesn't have to check comments when looking for directives. * This should however only be used if you are sure that no comment directives are used in * the application (including any 3rd party directives). * * @param {boolean} enabled `false` if the compiler may ignore directives on comments * @returns {boolean|object} the current value (or `this` if called as a setter for chaining) */ this.commentDirectivesEnabled = function(value) { if (arguments.length) { commentDirectivesEnabledConfig = value; return this; } return commentDirectivesEnabledConfig; }; var cssClassDirectivesEnabledConfig = true; /** * @ngdoc method * @name $compileProvider#cssClassDirectivesEnabled * @description * * It indicates to the compiler * whether or not directives on element classes should be compiled. * Defaults to `true`. * * Calling this function with false disables the compilation of directives * on element classes for the whole application. * This results in a compilation performance gain, * as the compiler doesn't have to check element classes when looking for directives. * This should however only be used if you are sure that no class directives are used in * the application (including any 3rd party directives). * * @param {boolean} enabled `false` if the compiler may ignore directives on element classes * @returns {boolean|object} the current value (or `this` if called as a setter for chaining) */ this.cssClassDirectivesEnabled = function(value) { if (arguments.length) { cssClassDirectivesEnabledConfig = value; return this; } return cssClassDirectivesEnabledConfig; }; this.$get = [ '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse', '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri', function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse, $controller, $rootScope, $sce, $animate, $$sanitizeUri) { var SIMPLE_ATTR_NAME = /^\w/; var specialAttrHolder = window.document.createElement('div'); var commentDirectivesEnabled = commentDirectivesEnabledConfig; var cssClassDirectivesEnabled = cssClassDirectivesEnabledConfig; var onChangesTtl = TTL; // The onChanges hooks should all be run together in a single digest // When changes occur, the call to trigger their hooks will be added to this queue var onChangesQueue; // This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest function flushOnChangesQueue() { try { if (!(--onChangesTtl)) { // We have hit the TTL limit so reset everything onChangesQueue = undefined; throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL); } // We must run this hook in an apply since the $$postDigest runs outside apply $rootScope.$apply(function() { var errors = []; for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) { try { onChangesQueue[i](); } catch (e) { errors.push(e); } } // Reset the queue to trigger a new schedule next time there is a change onChangesQueue = undefined; if (errors.length) { throw errors; } }); } finally { onChangesTtl++; } } function Attributes(element, attributesToCopy) { if (attributesToCopy) { var keys = Object.keys(attributesToCopy); var i, l, key; for (i = 0, l = keys.length; i < l; i++) { key = keys[i]; this[key] = attributesToCopy[key]; } } else { this.$attr = {}; } this.$$element = element; } Attributes.prototype = { /** * @ngdoc method * @name $compile.directive.Attributes#$normalize * @kind function * * @description * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or * `data-`) to its normalized, camelCase form. * * Also there is special case for Moz prefix starting with upper case letter. * * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives} * * @param {string} name Name to normalize */ $normalize: directiveNormalize, /** * @ngdoc method * @name $compile.directive.Attributes#$addClass * @kind function * * @description * Adds the CSS class value specified by the classVal parameter to the element. If animations * are enabled then an animation will be triggered for the class addition. * * @param {string} classVal The className value that will be added to the element */ $addClass: function(classVal) { if (classVal && classVal.length > 0) { $animate.addClass(this.$$element, classVal); } }, /** * @ngdoc method * @name $compile.directive.Attributes#$removeClass * @kind function * * @description * Removes the CSS class value specified by the classVal parameter from the element. If * animations are enabled then an animation will be triggered for the class removal. * * @param {string} classVal The className value that will be removed from the element */ $removeClass: function(classVal) { if (classVal && classVal.length > 0) { $animate.removeClass(this.$$element, classVal); } }, /** * @ngdoc method * @name $compile.directive.Attributes#$updateClass * @kind function * * @description * Adds and removes the appropriate CSS class values to the element based on the difference * between the new and old CSS class values (specified as newClasses and oldClasses). * * @param {string} newClasses The current CSS className value * @param {string} oldClasses The former CSS className value */ $updateClass: function(newClasses, oldClasses) { var toAdd = tokenDifference(newClasses, oldClasses); if (toAdd && toAdd.length) { $animate.addClass(this.$$element, toAdd); } var toRemove = tokenDifference(oldClasses, newClasses); if (toRemove && toRemove.length) { $animate.removeClass(this.$$element, toRemove); } }, /** * Set a normalized attribute on the element in a way such that all directives * can share the attribute. This function properly handles boolean attributes. * @param {string} key Normalized key. (ie ngAttribute) * @param {string|boolean} value The value to set. If `null` attribute will be deleted. * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute. * Defaults to true. * @param {string=} attrName Optional none normalized name. Defaults to key. */ $set: function(key, value, writeAttr, attrName) { // TODO: decide whether or not to throw an error if "class" //is set through this function since it may cause $updateClass to //become unstable. var node = this.$$element[0], booleanKey = getBooleanAttrName(node, key), aliasedKey = getAliasedAttrName(key), observer = key, nodeName; if (booleanKey) { this.$$element.prop(key, value); attrName = booleanKey; } else if (aliasedKey) { this[aliasedKey] = value; observer = aliasedKey; } this[key] = value; // translate normalized key to actual key if (attrName) { this.$attr[key] = attrName; } else { attrName = this.$attr[key]; if (!attrName) { this.$attr[key] = attrName = snake_case(key, '-'); } } nodeName = nodeName_(this.$$element); if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) || (nodeName === 'img' && key === 'src')) { // sanitize a[href] and img[src] values this[key] = value = $$sanitizeUri(value, key === 'src'); } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) { // sanitize img[srcset] values var result = ''; // first check if there are spaces because it's not the same pattern var trimmedSrcset = trim(value); // ( 999x ,| 999w ,| ,|, ) var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/; var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/; // split srcset into tuple of uri and descriptor except for the last item var rawUris = trimmedSrcset.split(pattern); // for each tuples var nbrUrisWith2parts = Math.floor(rawUris.length / 2); for (var i = 0; i < nbrUrisWith2parts; i++) { var innerIdx = i * 2; // sanitize the uri result += $$sanitizeUri(trim(rawUris[innerIdx]), true); // add the descriptor result += (' ' + trim(rawUris[innerIdx + 1])); } // split the last item into uri and descriptor var lastTuple = trim(rawUris[i * 2]).split(/\s/); // sanitize the last uri result += $$sanitizeUri(trim(lastTuple[0]), true); // and add the last descriptor if any if (lastTuple.length === 2) { result += (' ' + trim(lastTuple[1])); } this[key] = value = result; } if (writeAttr !== false) { if (value === null || isUndefined(value)) { this.$$element.removeAttr(attrName); } else { if (SIMPLE_ATTR_NAME.test(attrName)) { this.$$element.attr(attrName, value); } else { setSpecialAttr(this.$$element[0], attrName, value); } } } // fire observers var $$observers = this.$$observers; if ($$observers) { forEach($$observers[observer], function(fn) { try { fn(value); } catch (e) { $exceptionHandler(e); } }); } }, /** * @ngdoc method * @name $compile.directive.Attributes#$observe * @kind function * * @description * Observes an interpolated attribute. * * The observer function will be invoked once during the next `$digest` following * compilation. The observer is then invoked whenever the interpolated value * changes. * * @param {string} key Normalized key. (ie ngAttribute) . * @param {function(interpolatedValue)} fn Function that will be called whenever the interpolated value of the attribute changes. * See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation * guide} for more info. * @returns {function()} Returns a deregistration function for this observer. */ $observe: function(key, fn) { var attrs = this, $$observers = (attrs.$$observers || (attrs.$$observers = createMap())), listeners = ($$observers[key] || ($$observers[key] = [])); listeners.push(fn); $rootScope.$evalAsync(function() { if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) { // no one registered attribute interpolation function, so lets call it manually fn(attrs[key]); } }); return function() { arrayRemove(listeners, fn); }; } }; function setSpecialAttr(element, attrName, value) { // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute` // so we have to jump through some hoops to get such an attribute // https://github.com/angular/angular.js/pull/13318 specialAttrHolder.innerHTML = ''; var attributes = specialAttrHolder.firstChild.attributes; var attribute = attributes[0]; // We have to remove the attribute from its container element before we can add it to the destination element attributes.removeNamedItem(attribute.name); attribute.value = value; element.attributes.setNamedItem(attribute); } function safeAddClass($element, className) { try { $element.addClass(className); } catch (e) { // ignore, since it means that we are trying to set class on // SVG element, where class name is read-only. } } var startSymbol = $interpolate.startSymbol(), endSymbol = $interpolate.endSymbol(), denormalizeTemplate = (startSymbol === '{{' && endSymbol === '}}') ? identity : function denormalizeTemplate(template) { return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol); }, NG_ATTR_BINDING = /^ngAttr[A-Z]/; var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/; compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) { var bindings = $element.data('$binding') || []; if (isArray(binding)) { bindings = bindings.concat(binding); } else { bindings.push(binding); } $element.data('$binding', bindings); } : noop; compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) { safeAddClass($element, 'ng-binding'); } : noop; compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) { var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope'; $element.data(dataName, scope); } : noop; compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) { safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope'); } : noop; compile.$$createComment = function(directiveName, comment) { var content = ''; if (debugInfoEnabled) { content = ' ' + (directiveName || '') + ': '; if (comment) content += comment + ' '; } return window.document.createComment(content); }; return compile; //================================ function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) { if (!($compileNodes instanceof jqLite)) { // jquery always rewraps, whereas we need to preserve the original selector so that we can // modify it. $compileNodes = jqLite($compileNodes); } var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority, ignoreDirective, previousCompileContext); compile.$$addScopeClass($compileNodes); var namespace = null; return function publicLinkFn(scope, cloneConnectFn, options) { if (!$compileNodes) { throw $compileMinErr('multilink', 'This element has already been linked.'); } assertArg(scope, 'scope'); if (previousCompileContext && previousCompileContext.needsNewScope) { // A parent directive did a replace and a directive on this element asked // for transclusion, which caused us to lose a layer of element on which // we could hold the new transclusion scope, so we will create it manually // here. scope = scope.$parent.$new(); } options = options || {}; var parentBoundTranscludeFn = options.parentBoundTranscludeFn, transcludeControllers = options.transcludeControllers, futureParentElement = options.futureParentElement; // When `parentBoundTranscludeFn` is passed, it is a // `controllersBoundTransclude` function (it was previously passed // as `transclude` to directive.link) so we must unwrap it to get // its `boundTranscludeFn` if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) { parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude; } if (!namespace) { namespace = detectNamespaceForChildElements(futureParentElement); } var $linkNode; if (namespace !== 'html') { // When using a directive with replace:true and templateUrl the $compileNodes // (or a child element inside of them) // might change, so we need to recreate the namespace adapted compileNodes // for call to the link function. // Note: This will already clone the nodes... $linkNode = jqLite( wrapTemplate(namespace, jqLite('
').append($compileNodes).html()) ); } else if (cloneConnectFn) { // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart // and sometimes changes the structure of the DOM. $linkNode = JQLitePrototype.clone.call($compileNodes); } else { $linkNode = $compileNodes; } if (transcludeControllers) { for (var controllerName in transcludeControllers) { $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance); } } compile.$$addScopeInfo($linkNode, scope); if (cloneConnectFn) cloneConnectFn($linkNode, scope); if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn); if (!cloneConnectFn) { $compileNodes = compositeLinkFn = null; } return $linkNode; }; } function detectNamespaceForChildElements(parentElement) { // TODO: Make this detect MathML as well... var node = parentElement && parentElement[0]; if (!node) { return 'html'; } else { return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html'; } } /** * Compile function matches each node in nodeList against the directives. Once all directives * for a particular node are collected their compile functions are executed. The compile * functions return values - the linking functions - are combined into a composite linking * function, which is the a linking function for the node. * * @param {NodeList} nodeList an array of nodes or NodeList to compile * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the * scope argument is auto-generated to the new child of the transcluded parent scope. * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then * the rootElement must be set the jqLite collection of the compile root. This is * needed so that the jqLite collection items can be replaced with widgets. * @param {number=} maxPriority Max directive priority. * @returns {Function} A composite linking function of all of the matched directives or null. */ function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, previousCompileContext) { var linkFns = [], // `nodeList` can be either an element's `.childNodes` (live NodeList) // or a jqLite/jQuery collection or an array notLiveList = isArray(nodeList) || (nodeList instanceof jqLite), attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound; for (var i = 0; i < nodeList.length; i++) { attrs = new Attributes(); // Support: IE 11 only // Workaround for #11781 and #14924 if (msie === 11) { mergeConsecutiveTextNodes(nodeList, i, notLiveList); } // We must always refer to `nodeList[i]` hereafter, // since the nodes can be replaced underneath us. directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined, ignoreDirective); nodeLinkFn = (directives.length) ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement, null, [], [], previousCompileContext) : null; if (nodeLinkFn && nodeLinkFn.scope) { compile.$$addScopeClass(attrs.$$element); } childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !(childNodes = nodeList[i].childNodes) || !childNodes.length) ? null : compileNodes(childNodes, nodeLinkFn ? ( (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement) && nodeLinkFn.transclude) : transcludeFn); if (nodeLinkFn || childLinkFn) { linkFns.push(i, nodeLinkFn, childLinkFn); linkFnFound = true; nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn; } //use the previous context only for the first element in the virtual group previousCompileContext = null; } // return a linking function if we have found anything, null otherwise return linkFnFound ? compositeLinkFn : null; function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) { var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn; var stableNodeList; if (nodeLinkFnFound) { // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our // offsets don't get screwed up var nodeListLength = nodeList.length; stableNodeList = new Array(nodeListLength); // create a sparse array by only copying the elements which have a linkFn for (i = 0; i < linkFns.length; i += 3) { idx = linkFns[i]; stableNodeList[idx] = nodeList[idx]; } } else { stableNodeList = nodeList; } for (i = 0, ii = linkFns.length; i < ii;) { node = stableNodeList[linkFns[i++]]; nodeLinkFn = linkFns[i++]; childLinkFn = linkFns[i++]; if (nodeLinkFn) { if (nodeLinkFn.scope) { childScope = scope.$new(); compile.$$addScopeInfo(jqLite(node), childScope); } else { childScope = scope; } if (nodeLinkFn.transcludeOnThisElement) { childBoundTranscludeFn = createBoundTranscludeFn( scope, nodeLinkFn.transclude, parentBoundTranscludeFn); } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) { childBoundTranscludeFn = parentBoundTranscludeFn; } else if (!parentBoundTranscludeFn && transcludeFn) { childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn); } else { childBoundTranscludeFn = null; } nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn); } else if (childLinkFn) { childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn); } } } } function mergeConsecutiveTextNodes(nodeList, idx, notLiveList) { var node = nodeList[idx]; var parent = node.parentNode; var sibling; if (node.nodeType !== NODE_TYPE_TEXT) { return; } while (true) { sibling = parent ? node.nextSibling : nodeList[idx + 1]; if (!sibling || sibling.nodeType !== NODE_TYPE_TEXT) { break; } node.nodeValue = node.nodeValue + sibling.nodeValue; if (sibling.parentNode) { sibling.parentNode.removeChild(sibling); } if (notLiveList && sibling === nodeList[idx + 1]) { nodeList.splice(idx + 1, 1); } } } function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) { function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) { if (!transcludedScope) { transcludedScope = scope.$new(false, containingScope); transcludedScope.$$transcluded = true; } return transcludeFn(transcludedScope, cloneFn, { parentBoundTranscludeFn: previousBoundTranscludeFn, transcludeControllers: controllers, futureParentElement: futureParentElement }); } // We need to attach the transclusion slots onto the `boundTranscludeFn` // so that they are available inside the `controllersBoundTransclude` function var boundSlots = boundTranscludeFn.$$slots = createMap(); for (var slotName in transcludeFn.$$slots) { if (transcludeFn.$$slots[slotName]) { boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn); } else { boundSlots[slotName] = null; } } return boundTranscludeFn; } /** * Looks for directives on the given node and adds them to the directive collection which is * sorted. * * @param node Node to search. * @param directives An array to which the directives are added to. This array is sorted before * the function returns. * @param attrs The shared attrs object which is used to populate the normalized attributes. * @param {number=} maxPriority Max directive priority. */ function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) { var nodeType = node.nodeType, attrsMap = attrs.$attr, match, nodeName, className; switch (nodeType) { case NODE_TYPE_ELEMENT: /* Element */ nodeName = nodeName_(node); // use the node name: addDirective(directives, directiveNormalize(nodeName), 'E', maxPriority, ignoreDirective); // iterate over the attributes for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes, j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) { var attrStartName = false; var attrEndName = false; attr = nAttrs[j]; name = attr.name; value = attr.value; // support ngAttr attribute binding ngAttrName = directiveNormalize(name); isNgAttr = NG_ATTR_BINDING.test(ngAttrName); if (isNgAttr) { name = name.replace(PREFIX_REGEXP, '') .substr(8).replace(/_(.)/g, function(match, letter) { return letter.toUpperCase(); }); } var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE); if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) { attrStartName = name; attrEndName = name.substr(0, name.length - 5) + 'end'; name = name.substr(0, name.length - 6); } nName = directiveNormalize(name.toLowerCase()); attrsMap[nName] = name; if (isNgAttr || !attrs.hasOwnProperty(nName)) { attrs[nName] = value; if (getBooleanAttrName(node, nName)) { attrs[nName] = true; // presence means true } } addAttrInterpolateDirective(node, directives, value, nName, isNgAttr); addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, attrEndName); } if (nodeName === 'input' && node.getAttribute('type') === 'hidden') { // Hidden input elements can have strange behaviour when navigating back to the page // This tells the browser not to try to cache and reinstate previous values node.setAttribute('autocomplete', 'off'); } // use class as directive if (!cssClassDirectivesEnabled) break; className = node.className; if (isObject(className)) { // Maybe SVGAnimatedString className = className.animVal; } if (isString(className) && className !== '') { while ((match = CLASS_DIRECTIVE_REGEXP.exec(className))) { nName = directiveNormalize(match[2]); if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) { attrs[nName] = trim(match[3]); } className = className.substr(match.index + match[0].length); } } break; case NODE_TYPE_TEXT: /* Text Node */ addTextInterpolateDirective(directives, node.nodeValue); break; case NODE_TYPE_COMMENT: /* Comment */ if (!commentDirectivesEnabled) break; collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective); break; } directives.sort(byPriority); return directives; } function collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective) { // function created because of performance, try/catch disables // the optimization of the whole function #14848 try { var match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue); if (match) { var nName = directiveNormalize(match[1]); if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) { attrs[nName] = trim(match[2]); } } } catch (e) { // turns out that under some circumstances IE9 throws errors when one attempts to read // comment's node value. // Just ignore it and continue. (Can't seem to reproduce in test case.) } } /** * Given a node with a directive-start it collects all of the siblings until it finds * directive-end. * @param node * @param attrStart * @param attrEnd * @returns {*} */ function groupScan(node, attrStart, attrEnd) { var nodes = []; var depth = 0; if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) { do { if (!node) { throw $compileMinErr('uterdir', 'Unterminated attribute, found \'{0}\' but no matching \'{1}\' found.', attrStart, attrEnd); } if (node.nodeType === NODE_TYPE_ELEMENT) { if (node.hasAttribute(attrStart)) depth++; if (node.hasAttribute(attrEnd)) depth--; } nodes.push(node); node = node.nextSibling; } while (depth > 0); } else { nodes.push(node); } return jqLite(nodes); } /** * Wrapper for linking function which converts normal linking function into a grouped * linking function. * @param linkFn * @param attrStart * @param attrEnd * @returns {Function} */ function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) { return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) { element = groupScan(element[0], attrStart, attrEnd); return linkFn(scope, element, attrs, controllers, transcludeFn); }; } /** * A function generator that is used to support both eager and lazy compilation * linking function. * @param eager * @param $compileNodes * @param transcludeFn * @param maxPriority * @param ignoreDirective * @param previousCompileContext * @returns {Function} */ function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) { var compiled; if (eager) { return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext); } return /** @this */ function lazyCompilation() { if (!compiled) { compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext); // Null out all of these references in order to make them eligible for garbage collection // since this is a potentially long lived closure $compileNodes = transcludeFn = previousCompileContext = null; } return compiled.apply(this, arguments); }; } /** * Once the directives have been collected, their compile functions are executed. This method * is responsible for inlining directive templates as well as terminating the application * of the directives if the terminal directive has been reached. * * @param {Array} directives Array of collected directives to execute their compile function. * this needs to be pre-sorted by priority order. * @param {Node} compileNode The raw DOM node to apply the compile functions to * @param {Object} templateAttrs The shared attribute function * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the * scope argument is auto-generated to the new * child of the transcluded parent scope. * @param {JQLite} jqCollection If we are working on the root of the compile tree then this * argument has the root jqLite array so that we can replace nodes * on it. * @param {Object=} originalReplaceDirective An optional directive that will be ignored when * compiling the transclusion. * @param {Array.} preLinkFns * @param {Array.} postLinkFns * @param {Object} previousCompileContext Context used for previous compilation of the current * node * @returns {Function} linkFn */ function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, previousCompileContext) { previousCompileContext = previousCompileContext || {}; var terminalPriority = -Number.MAX_VALUE, newScopeDirective = previousCompileContext.newScopeDirective, controllerDirectives = previousCompileContext.controllerDirectives, newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, templateDirective = previousCompileContext.templateDirective, nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, hasTranscludeDirective = false, hasTemplate = false, hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective, $compileNode = templateAttrs.$$element = jqLite(compileNode), directive, directiveName, $template, replaceDirective = originalReplaceDirective, childTranscludeFn = transcludeFn, linkFn, didScanForMultipleTransclusion = false, mightHaveMultipleTransclusionError = false, directiveValue; // executes all directives on the current element for (var i = 0, ii = directives.length; i < ii; i++) { directive = directives[i]; var attrStart = directive.$$start; var attrEnd = directive.$$end; // collect multiblock sections if (attrStart) { $compileNode = groupScan(compileNode, attrStart, attrEnd); } $template = undefined; if (terminalPriority > directive.priority) { break; // prevent further processing of directives } directiveValue = directive.scope; if (directiveValue) { // skip the check for directives with async templates, we'll check the derived sync // directive when the template arrives if (!directive.templateUrl) { if (isObject(directiveValue)) { // This directive is trying to add an isolated scope. // Check that there is no scope of any kind already assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective, directive, $compileNode); newIsolateScopeDirective = directive; } else { // This directive is trying to add a child scope. // Check that there is no isolated scope already assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive, $compileNode); } } newScopeDirective = newScopeDirective || directive; } directiveName = directive.name; // If we encounter a condition that can result in transclusion on the directive, // then scan ahead in the remaining directives for others that may cause a multiple // transclusion error to be thrown during the compilation process. If a matching directive // is found, then we know that when we encounter a transcluded directive, we need to eagerly // compile the `transclude` function rather than doing it lazily in order to throw // exceptions at the correct time if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template)) || (directive.transclude && !directive.$$tlb))) { var candidateDirective; for (var scanningIndex = i + 1; (candidateDirective = directives[scanningIndex++]);) { if ((candidateDirective.transclude && !candidateDirective.$$tlb) || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) { mightHaveMultipleTransclusionError = true; break; } } didScanForMultipleTransclusion = true; } if (!directive.templateUrl && directive.controller) { controllerDirectives = controllerDirectives || createMap(); assertNoDuplicate('\'' + directiveName + '\' controller', controllerDirectives[directiveName], directive, $compileNode); controllerDirectives[directiveName] = directive; } directiveValue = directive.transclude; if (directiveValue) { hasTranscludeDirective = true; // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion. // This option should only be used by directives that know how to safely handle element transclusion, // where the transcluded nodes are added or replaced after linking. if (!directive.$$tlb) { assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode); nonTlbTranscludeDirective = directive; } if (directiveValue === 'element') { hasElementTranscludeDirective = true; terminalPriority = directive.priority; $template = $compileNode; $compileNode = templateAttrs.$$element = jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName])); compileNode = $compileNode[0]; replaceWith(jqCollection, sliceArgs($template), compileNode); // Support: Chrome < 50 // https://github.com/angular/angular.js/issues/14041 // In the versions of V8 prior to Chrome 50, the document fragment that is created // in the `replaceWith` function is improperly garbage collected despite still // being referenced by the `parentNode` property of all of the child nodes. By adding // a reference to the fragment via a different property, we can avoid that incorrect // behavior. // TODO: remove this line after Chrome 50 has been released $template[0].$$parentNode = $template[0].parentNode; childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority, replaceDirective && replaceDirective.name, { // Don't pass in: // - controllerDirectives - otherwise we'll create duplicates controllers // - newIsolateScopeDirective or templateDirective - combining templates with // element transclusion doesn't make sense. // // We need only nonTlbTranscludeDirective so that we prevent putting transclusion // on the same element more than once. nonTlbTranscludeDirective: nonTlbTranscludeDirective }); } else { var slots = createMap(); if (!isObject(directiveValue)) { $template = jqLite(jqLiteClone(compileNode)).contents(); } else { // We have transclusion slots, // collect them up, compile them and store their transclusion functions $template = []; var slotMap = createMap(); var filledSlots = createMap(); // Parse the element selectors forEach(directiveValue, function(elementSelector, slotName) { // If an element selector starts with a ? then it is optional var optional = (elementSelector.charAt(0) === '?'); elementSelector = optional ? elementSelector.substring(1) : elementSelector; slotMap[elementSelector] = slotName; // We explicitly assign `null` since this implies that a slot was defined but not filled. // Later when calling boundTransclusion functions with a slot name we only error if the // slot is `undefined` slots[slotName] = null; // filledSlots contains `true` for all slots that are either optional or have been // filled. This is used to check that we have not missed any required slots filledSlots[slotName] = optional; }); // Add the matching elements into their slot forEach($compileNode.contents(), function(node) { var slotName = slotMap[directiveNormalize(nodeName_(node))]; if (slotName) { filledSlots[slotName] = true; slots[slotName] = slots[slotName] || []; slots[slotName].push(node); } else { $template.push(node); } }); // Check for required slots that were not filled forEach(filledSlots, function(filled, slotName) { if (!filled) { throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName); } }); for (var slotName in slots) { if (slots[slotName]) { // Only define a transclusion function if the slot was filled slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn); } } } $compileNode.empty(); // clear contents childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined, undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope}); childTranscludeFn.$$slots = slots; } } if (directive.template) { hasTemplate = true; assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; directiveValue = (isFunction(directive.template)) ? directive.template($compileNode, templateAttrs) : directive.template; directiveValue = denormalizeTemplate(directiveValue); if (directive.replace) { replaceDirective = directive; if (jqLiteIsTextNode(directiveValue)) { $template = []; } else { $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue))); } compileNode = $template[0]; if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { throw $compileMinErr('tplrt', 'Template for directive \'{0}\' must have exactly one root element. {1}', directiveName, ''); } replaceWith(jqCollection, $compileNode, compileNode); var newTemplateAttrs = {$attr: {}}; // combine directives from the original node and from the template: // - take the array of directives for this element // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed) // - collect directives from the template and sort them by priority // - combine directives as: processed + template + unprocessed var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs); var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1)); if (newIsolateScopeDirective || newScopeDirective) { // The original directive caused the current element to be replaced but this element // also needs to have a new scope, so we need to tell the template directives // that they would need to get their scope from further up, if they require transclusion markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective); } directives = directives.concat(templateDirectives).concat(unprocessedDirectives); mergeTemplateAttributes(templateAttrs, newTemplateAttrs); ii = directives.length; } else { $compileNode.html(directiveValue); } } if (directive.templateUrl) { hasTemplate = true; assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; if (directive.replace) { replaceDirective = directive; } // eslint-disable-next-line no-func-assign nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode, templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, { controllerDirectives: controllerDirectives, newScopeDirective: (newScopeDirective !== directive) && newScopeDirective, newIsolateScopeDirective: newIsolateScopeDirective, templateDirective: templateDirective, nonTlbTranscludeDirective: nonTlbTranscludeDirective }); ii = directives.length; } else if (directive.compile) { try { linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); var context = directive.$$originalDirective || directive; if (isFunction(linkFn)) { addLinkFns(null, bind(context, linkFn), attrStart, attrEnd); } else if (linkFn) { addLinkFns(bind(context, linkFn.pre), bind(context, linkFn.post), attrStart, attrEnd); } } catch (e) { $exceptionHandler(e, startingTag($compileNode)); } } if (directive.terminal) { nodeLinkFn.terminal = true; terminalPriority = Math.max(terminalPriority, directive.priority); } } nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true; nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective; nodeLinkFn.templateOnThisElement = hasTemplate; nodeLinkFn.transclude = childTranscludeFn; previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective; // might be normal or delayed nodeLinkFn depending on if templateUrl is present return nodeLinkFn; //////////////////// function addLinkFns(pre, post, attrStart, attrEnd) { if (pre) { if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd); pre.require = directive.require; pre.directiveName = directiveName; if (newIsolateScopeDirective === directive || directive.$$isolateScope) { pre = cloneAndAnnotateFn(pre, {isolateScope: true}); } preLinkFns.push(pre); } if (post) { if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd); post.require = directive.require; post.directiveName = directiveName; if (newIsolateScopeDirective === directive || directive.$$isolateScope) { post = cloneAndAnnotateFn(post, {isolateScope: true}); } postLinkFns.push(post); } } function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element, attrs, scopeBindingInfo; if (compileNode === linkNode) { attrs = templateAttrs; $element = templateAttrs.$$element; } else { $element = jqLite(linkNode); attrs = new Attributes($element, templateAttrs); } controllerScope = scope; if (newIsolateScopeDirective) { isolateScope = scope.$new(true); } else if (newScopeDirective) { controllerScope = scope.$parent; } if (boundTranscludeFn) { // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn` // is later passed as `parentBoundTranscludeFn` to `publicLinkFn` transcludeFn = controllersBoundTransclude; transcludeFn.$$boundTransclude = boundTranscludeFn; // expose the slots on the `$transclude` function transcludeFn.isSlotFilled = function(slotName) { return !!boundTranscludeFn.$$slots[slotName]; }; } if (controllerDirectives) { elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective); } if (newIsolateScopeDirective) { // Initialize isolate scope bindings for new isolate scope directive. compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective || templateDirective === newIsolateScopeDirective.$$originalDirective))); compile.$$addScopeClass($element, true); isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings; scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope, isolateScope.$$isolateBindings, newIsolateScopeDirective); if (scopeBindingInfo.removeWatches) { isolateScope.$on('$destroy', scopeBindingInfo.removeWatches); } } // Initialize bindToController bindings for (var name in elementControllers) { var controllerDirective = controllerDirectives[name]; var controller = elementControllers[name]; var bindings = controllerDirective.$$bindings.bindToController; if (preAssignBindingsEnabled) { if (bindings) { controller.bindingInfo = initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective); } else { controller.bindingInfo = {}; } var controllerResult = controller(); if (controllerResult !== controller.instance) { // If the controller constructor has a return value, overwrite the instance // from setupControllers controller.instance = controllerResult; $element.data('$' + controllerDirective.name + 'Controller', controllerResult); if (controller.bindingInfo.removeWatches) { controller.bindingInfo.removeWatches(); } controller.bindingInfo = initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective); } } else { controller.instance = controller(); $element.data('$' + controllerDirective.name + 'Controller', controller.instance); controller.bindingInfo = initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective); } } // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy forEach(controllerDirectives, function(controllerDirective, name) { var require = controllerDirective.require; if (controllerDirective.bindToController && !isArray(require) && isObject(require)) { extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers)); } }); // Handle the init and destroy lifecycle hooks on all controllers that have them forEach(elementControllers, function(controller) { var controllerInstance = controller.instance; if (isFunction(controllerInstance.$onChanges)) { try { controllerInstance.$onChanges(controller.bindingInfo.initialChanges); } catch (e) { $exceptionHandler(e); } } if (isFunction(controllerInstance.$onInit)) { try { controllerInstance.$onInit(); } catch (e) { $exceptionHandler(e); } } if (isFunction(controllerInstance.$doCheck)) { controllerScope.$watch(function() { controllerInstance.$doCheck(); }); controllerInstance.$doCheck(); } if (isFunction(controllerInstance.$onDestroy)) { controllerScope.$on('$destroy', function callOnDestroyHook() { controllerInstance.$onDestroy(); }); } }); // PRELINKING for (i = 0, ii = preLinkFns.length; i < ii; i++) { linkFn = preLinkFns[i]; invokeLinkFn(linkFn, linkFn.isolateScope ? isolateScope : scope, $element, attrs, linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn ); } // RECURSION // We only pass the isolate scope, if the isolate directive has a template, // otherwise the child elements do not belong to the isolate directive. var scopeToChild = scope; if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) { scopeToChild = isolateScope; } if (childLinkFn) { childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn); } // POSTLINKING for (i = postLinkFns.length - 1; i >= 0; i--) { linkFn = postLinkFns[i]; invokeLinkFn(linkFn, linkFn.isolateScope ? isolateScope : scope, $element, attrs, linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn ); } // Trigger $postLink lifecycle hooks forEach(elementControllers, function(controller) { var controllerInstance = controller.instance; if (isFunction(controllerInstance.$postLink)) { controllerInstance.$postLink(); } }); // This is the function that is injected as `$transclude`. // Note: all arguments are optional! function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) { var transcludeControllers; // No scope passed in: if (!isScope(scope)) { slotName = futureParentElement; futureParentElement = cloneAttachFn; cloneAttachFn = scope; scope = undefined; } if (hasElementTranscludeDirective) { transcludeControllers = elementControllers; } if (!futureParentElement) { futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element; } if (slotName) { // slotTranscludeFn can be one of three things: // * a transclude function - a filled slot // * `null` - an optional slot that was not filled // * `undefined` - a slot that was not declared (i.e. invalid) var slotTranscludeFn = boundTranscludeFn.$$slots[slotName]; if (slotTranscludeFn) { return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild); } else if (isUndefined(slotTranscludeFn)) { throw $compileMinErr('noslot', 'No parent directive that requires a transclusion with slot name "{0}". ' + 'Element: {1}', slotName, startingTag($element)); } } else { return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild); } } } } function getControllers(directiveName, require, $element, elementControllers) { var value; if (isString(require)) { var match = require.match(REQUIRE_PREFIX_REGEXP); var name = require.substring(match[0].length); var inheritType = match[1] || match[3]; var optional = match[2] === '?'; //If only parents then start at the parent element if (inheritType === '^^') { $element = $element.parent(); //Otherwise attempt getting the controller from elementControllers in case //the element is transcluded (and has no data) and to avoid .data if possible } else { value = elementControllers && elementControllers[name]; value = value && value.instance; } if (!value) { var dataName = '$' + name + 'Controller'; value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName); } if (!value && !optional) { throw $compileMinErr('ctreq', 'Controller \'{0}\', required by directive \'{1}\', can\'t be found!', name, directiveName); } } else if (isArray(require)) { value = []; for (var i = 0, ii = require.length; i < ii; i++) { value[i] = getControllers(directiveName, require[i], $element, elementControllers); } } else if (isObject(require)) { value = {}; forEach(require, function(controller, property) { value[property] = getControllers(directiveName, controller, $element, elementControllers); }); } return value || null; } function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) { var elementControllers = createMap(); for (var controllerKey in controllerDirectives) { var directive = controllerDirectives[controllerKey]; var locals = { $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, $element: $element, $attrs: attrs, $transclude: transcludeFn }; var controller = directive.controller; if (controller === '@') { controller = attrs[directive.name]; } var controllerInstance = $controller(controller, locals, true, directive.controllerAs); // For directives with element transclusion the element is a comment. // In this case .data will not attach any data. // Instead, we save the controllers for the element in a local hash and attach to .data // later, once we have the actual element. elementControllers[directive.name] = controllerInstance; $element.data('$' + directive.name + 'Controller', controllerInstance.instance); } return elementControllers; } // Depending upon the context in which a directive finds itself it might need to have a new isolated // or child scope created. For instance: // * if the directive has been pulled into a template because another directive with a higher priority // asked for element transclusion // * if the directive itself asks for transclusion but it is at the root of a template and the original // element was replaced. See https://github.com/angular/angular.js/issues/12936 function markDirectiveScope(directives, isolateScope, newScope) { for (var j = 0, jj = directives.length; j < jj; j++) { directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope}); } } /** * looks up the directive and decorates it with exception handling and proper parameters. We * call this the boundDirective. * * @param {string} name name of the directive to look up. * @param {string} location The directive must be found in specific format. * String containing any of theses characters: * * * `E`: element name * * `A': attribute * * `C`: class * * `M`: comment * @returns {boolean} true if directive was added. */ function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, endAttrName) { if (name === ignoreDirective) return null; var match = null; if (hasDirectives.hasOwnProperty(name)) { for (var directive, directives = $injector.get(name + Suffix), i = 0, ii = directives.length; i < ii; i++) { directive = directives[i]; if ((isUndefined(maxPriority) || maxPriority > directive.priority) && directive.restrict.indexOf(location) !== -1) { if (startAttrName) { directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName}); } if (!directive.$$bindings) { var bindings = directive.$$bindings = parseDirectiveBindings(directive, directive.name); if (isObject(bindings.isolateScope)) { directive.$$isolateBindings = bindings.isolateScope; } } tDirectives.push(directive); match = directive; } } } return match; } /** * looks up the directive and returns true if it is a multi-element directive, * and therefore requires DOM nodes between -start and -end markers to be grouped * together. * * @param {string} name name of the directive to look up. * @returns true if directive was registered as multi-element. */ function directiveIsMultiElement(name) { if (hasDirectives.hasOwnProperty(name)) { for (var directive, directives = $injector.get(name + Suffix), i = 0, ii = directives.length; i < ii; i++) { directive = directives[i]; if (directive.multiElement) { return true; } } } return false; } /** * When the element is replaced with HTML template then the new attributes * on the template need to be merged with the existing attributes in the DOM. * The desired effect is to have both of the attributes present. * * @param {object} dst destination attributes (original DOM) * @param {object} src source attributes (from the directive template) */ function mergeTemplateAttributes(dst, src) { var srcAttr = src.$attr, dstAttr = dst.$attr; // reapply the old attributes to the new element forEach(dst, function(value, key) { if (key.charAt(0) !== '$') { if (src[key] && src[key] !== value) { if (value.length) { value += (key === 'style' ? ';' : ' ') + src[key]; } else { value = src[key]; } } dst.$set(key, value, true, srcAttr[key]); } }); // copy the new attributes on the old attrs object forEach(src, function(value, key) { // Check if we already set this attribute in the loop above. // `dst` will never contain hasOwnProperty as DOM parser won't let it. // You will get an "InvalidCharacterError: DOM Exception 5" error if you // have an attribute like "has-own-property" or "data-has-own-property", etc. if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') { dst[key] = value; if (key !== 'class' && key !== 'style') { dstAttr[key] = srcAttr[key]; } } }); } function compileTemplateUrl(directives, $compileNode, tAttrs, $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) { var linkQueue = [], afterTemplateNodeLinkFn, afterTemplateChildLinkFn, beforeTemplateCompileNode = $compileNode[0], origAsyncDirective = directives.shift(), derivedSyncDirective = inherit(origAsyncDirective, { templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective }), templateUrl = (isFunction(origAsyncDirective.templateUrl)) ? origAsyncDirective.templateUrl($compileNode, tAttrs) : origAsyncDirective.templateUrl, templateNamespace = origAsyncDirective.templateNamespace; $compileNode.empty(); $templateRequest(templateUrl) .then(function(content) { var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn; content = denormalizeTemplate(content); if (origAsyncDirective.replace) { if (jqLiteIsTextNode(content)) { $template = []; } else { $template = removeComments(wrapTemplate(templateNamespace, trim(content))); } compileNode = $template[0]; if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { throw $compileMinErr('tplrt', 'Template for directive \'{0}\' must have exactly one root element. {1}', origAsyncDirective.name, templateUrl); } tempTemplateAttrs = {$attr: {}}; replaceWith($rootElement, $compileNode, compileNode); var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs); if (isObject(origAsyncDirective.scope)) { // the original directive that caused the template to be loaded async required // an isolate scope markDirectiveScope(templateDirectives, true); } directives = templateDirectives.concat(directives); mergeTemplateAttributes(tAttrs, tempTemplateAttrs); } else { compileNode = beforeTemplateCompileNode; $compileNode.html(content); } directives.unshift(derivedSyncDirective); afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns, previousCompileContext); forEach($rootElement, function(node, i) { if (node === compileNode) { $rootElement[i] = $compileNode[0]; } }); afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); while (linkQueue.length) { var scope = linkQueue.shift(), beforeTemplateLinkNode = linkQueue.shift(), linkRootElement = linkQueue.shift(), boundTranscludeFn = linkQueue.shift(), linkNode = $compileNode[0]; if (scope.$$destroyed) continue; if (beforeTemplateLinkNode !== beforeTemplateCompileNode) { var oldClasses = beforeTemplateLinkNode.className; if (!(previousCompileContext.hasElementTranscludeDirective && origAsyncDirective.replace)) { // it was cloned therefore we have to clone as well. linkNode = jqLiteClone(compileNode); } replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode); // Copy in CSS classes from original node safeAddClass(jqLite(linkNode), oldClasses); } if (afterTemplateNodeLinkFn.transcludeOnThisElement) { childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); } else { childBoundTranscludeFn = boundTranscludeFn; } afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, childBoundTranscludeFn); } linkQueue = null; }).catch(function(error) { if (isError(error)) { $exceptionHandler(error); } }); return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) { var childBoundTranscludeFn = boundTranscludeFn; if (scope.$$destroyed) return; if (linkQueue) { linkQueue.push(scope, node, rootElement, childBoundTranscludeFn); } else { if (afterTemplateNodeLinkFn.transcludeOnThisElement) { childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); } afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn); } }; } /** * Sorting function for bound directives. */ function byPriority(a, b) { var diff = b.priority - a.priority; if (diff !== 0) return diff; if (a.name !== b.name) return (a.name < b.name) ? -1 : 1; return a.index - b.index; } function assertNoDuplicate(what, previousDirective, directive, element) { function wrapModuleNameIfDefined(moduleName) { return moduleName ? (' (module: ' + moduleName + ')') : ''; } if (previousDirective) { throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}', previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName), directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element)); } } function addTextInterpolateDirective(directives, text) { var interpolateFn = $interpolate(text, true); if (interpolateFn) { directives.push({ priority: 0, compile: function textInterpolateCompileFn(templateNode) { var templateNodeParent = templateNode.parent(), hasCompileParent = !!templateNodeParent.length; // When transcluding a template that has bindings in the root // we don't have a parent and thus need to add the class during linking fn. if (hasCompileParent) compile.$$addBindingClass(templateNodeParent); return function textInterpolateLinkFn(scope, node) { var parent = node.parent(); if (!hasCompileParent) compile.$$addBindingClass(parent); compile.$$addBindingInfo(parent, interpolateFn.expressions); scope.$watch(interpolateFn, function interpolateFnWatchAction(value) { node[0].nodeValue = value; }); }; } }); } } function wrapTemplate(type, template) { type = lowercase(type || 'html'); switch (type) { case 'svg': case 'math': var wrapper = window.document.createElement('div'); wrapper.innerHTML = '<' + type + '>' + template + ''; return wrapper.childNodes[0].childNodes; default: return template; } } function getTrustedContext(node, attrNormalizedName) { if (attrNormalizedName === 'srcdoc') { return $sce.HTML; } var tag = nodeName_(node); // All tags with src attributes require a RESOURCE_URL value, except for // img and various html5 media tags. if (attrNormalizedName === 'src' || attrNormalizedName === 'ngSrc') { if (['img', 'video', 'audio', 'source', 'track'].indexOf(tag) === -1) { return $sce.RESOURCE_URL; } // maction[xlink:href] can source SVG. It's not limited to . } else if (attrNormalizedName === 'xlinkHref' || (tag === 'form' && attrNormalizedName === 'action') || // links can be stylesheets or imports, which can run script in the current origin (tag === 'link' && attrNormalizedName === 'href') ) { return $sce.RESOURCE_URL; } } function addAttrInterpolateDirective(node, directives, value, name, isNgAttr) { var trustedContext = getTrustedContext(node, name); var mustHaveExpression = !isNgAttr; var allOrNothing = ALL_OR_NOTHING_ATTRS[name] || isNgAttr; var interpolateFn = $interpolate(value, mustHaveExpression, trustedContext, allOrNothing); // no interpolation found -> ignore if (!interpolateFn) return; if (name === 'multiple' && nodeName_(node) === 'select') { throw $compileMinErr('selmulti', 'Binding to the \'multiple\' attribute is not supported. Element: {0}', startingTag(node)); } if (EVENT_HANDLER_ATTR_REGEXP.test(name)) { throw $compileMinErr('nodomevents', 'Interpolations for HTML DOM event attributes are disallowed. Please use the ' + 'ng- versions (such as ng-click instead of onclick) instead.'); } directives.push({ priority: 100, compile: function() { return { pre: function attrInterpolatePreLinkFn(scope, element, attr) { var $$observers = (attr.$$observers || (attr.$$observers = createMap())); // If the attribute has changed since last $interpolate()ed var newValue = attr[name]; if (newValue !== value) { // we need to interpolate again since the attribute value has been updated // (e.g. by another directive's compile function) // ensure unset/empty values make interpolateFn falsy interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing); value = newValue; } // if attribute was updated so that there is no interpolation going on we don't want to // register any observers if (!interpolateFn) return; // initialize attr object so that it's ready in case we need the value for isolate // scope initialization, otherwise the value would not be available from isolate // directive's linking fn during linking phase attr[name] = interpolateFn(scope); ($$observers[name] || ($$observers[name] = [])).$$inter = true; (attr.$$observers && attr.$$observers[name].$$scope || scope). $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) { //special case for class attribute addition + removal //so that class changes can tap into the animation //hooks provided by the $animate service. Be sure to //skip animations when the first digest occurs (when //both the new and the old values are the same) since //the CSS classes are the non-interpolated values if (name === 'class' && newValue !== oldValue) { attr.$updateClass(newValue, oldValue); } else { attr.$set(name, newValue); } }); } }; } }); } /** * This is a special jqLite.replaceWith, which can replace items which * have no parents, provided that the containing jqLite collection is provided. * * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes * in the root of the tree. * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep * the shell, but replace its DOM node reference. * @param {Node} newNode The new DOM node. */ function replaceWith($rootElement, elementsToRemove, newNode) { var firstElementToRemove = elementsToRemove[0], removeCount = elementsToRemove.length, parent = firstElementToRemove.parentNode, i, ii; if ($rootElement) { for (i = 0, ii = $rootElement.length; i < ii; i++) { if ($rootElement[i] === firstElementToRemove) { $rootElement[i++] = newNode; for (var j = i, j2 = j + removeCount - 1, jj = $rootElement.length; j < jj; j++, j2++) { if (j2 < jj) { $rootElement[j] = $rootElement[j2]; } else { delete $rootElement[j]; } } $rootElement.length -= removeCount - 1; // If the replaced element is also the jQuery .context then replace it // .context is a deprecated jQuery api, so we should set it only when jQuery set it // http://api.jquery.com/context/ if ($rootElement.context === firstElementToRemove) { $rootElement.context = newNode; } break; } } } if (parent) { parent.replaceChild(newNode, firstElementToRemove); } // Append all the `elementsToRemove` to a fragment. This will... // - remove them from the DOM // - allow them to still be traversed with .nextSibling // - allow a single fragment.qSA to fetch all elements being removed var fragment = window.document.createDocumentFragment(); for (i = 0; i < removeCount; i++) { fragment.appendChild(elementsToRemove[i]); } if (jqLite.hasData(firstElementToRemove)) { // Copy over user data (that includes Angular's $scope etc.). Don't copy private // data here because there's no public interface in jQuery to do that and copying over // event listeners (which is the main use of private data) wouldn't work anyway. jqLite.data(newNode, jqLite.data(firstElementToRemove)); // Remove $destroy event listeners from `firstElementToRemove` jqLite(firstElementToRemove).off('$destroy'); } // Cleanup any data/listeners on the elements and children. // This includes invoking the $destroy event on any elements with listeners. jqLite.cleanData(fragment.querySelectorAll('*')); // Update the jqLite collection to only contain the `newNode` for (i = 1; i < removeCount; i++) { delete elementsToRemove[i]; } elementsToRemove[0] = newNode; elementsToRemove.length = 1; } function cloneAndAnnotateFn(fn, annotation) { return extend(function() { return fn.apply(null, arguments); }, fn, annotation); } function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) { try { linkFn(scope, $element, attrs, controllers, transcludeFn); } catch (e) { $exceptionHandler(e, startingTag($element)); } } function strictBindingsCheck(attrName, directiveName) { if (strictComponentBindingsEnabled) { throw $compileMinErr('missingattr', 'Attribute \'{0}\' of \'{1}\' is non-optional and must be set!', attrName, directiveName); } } // Set up $watches for isolate scope and controller bindings. function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) { var removeWatchCollection = []; var initialChanges = {}; var changes; forEach(bindings, function initializeBinding(definition, scopeName) { var attrName = definition.attrName, optional = definition.optional, mode = definition.mode, // @, =, <, or & lastValue, parentGet, parentSet, compare, removeWatch; switch (mode) { case '@': if (!optional && !hasOwnProperty.call(attrs, attrName)) { strictBindingsCheck(attrName, directive.name); destination[scopeName] = attrs[attrName] = undefined; } removeWatch = attrs.$observe(attrName, function(value) { if (isString(value) || isBoolean(value)) { var oldValue = destination[scopeName]; recordChanges(scopeName, value, oldValue); destination[scopeName] = value; } }); attrs.$$observers[attrName].$$scope = scope; lastValue = attrs[attrName]; if (isString(lastValue)) { // If the attribute has been provided then we trigger an interpolation to ensure // the value is there for use in the link fn destination[scopeName] = $interpolate(lastValue)(scope); } else if (isBoolean(lastValue)) { // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted // the value to boolean rather than a string, so we special case this situation destination[scopeName] = lastValue; } initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]); removeWatchCollection.push(removeWatch); break; case '=': if (!hasOwnProperty.call(attrs, attrName)) { if (optional) break; strictBindingsCheck(attrName, directive.name); attrs[attrName] = undefined; } if (optional && !attrs[attrName]) break; parentGet = $parse(attrs[attrName]); if (parentGet.literal) { compare = equals; } else { compare = simpleCompare; } parentSet = parentGet.assign || function() { // reset the change, or we will throw this exception on every $digest lastValue = destination[scopeName] = parentGet(scope); throw $compileMinErr('nonassign', 'Expression \'{0}\' in attribute \'{1}\' used with directive \'{2}\' is non-assignable!', attrs[attrName], attrName, directive.name); }; lastValue = destination[scopeName] = parentGet(scope); var parentValueWatch = function parentValueWatch(parentValue) { if (!compare(parentValue, destination[scopeName])) { // we are out of sync and need to copy if (!compare(parentValue, lastValue)) { // parent changed and it has precedence destination[scopeName] = parentValue; } else { // if the parent can be assigned then do so parentSet(scope, parentValue = destination[scopeName]); } } lastValue = parentValue; return lastValue; }; parentValueWatch.$stateful = true; if (definition.collection) { removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch); } else { removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal); } removeWatchCollection.push(removeWatch); break; case '<': if (!hasOwnProperty.call(attrs, attrName)) { if (optional) break; strictBindingsCheck(attrName, directive.name); attrs[attrName] = undefined; } if (optional && !attrs[attrName]) break; parentGet = $parse(attrs[attrName]); var deepWatch = parentGet.literal; var initialValue = destination[scopeName] = parentGet(scope); initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]); removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) { if (oldValue === newValue) { if (oldValue === initialValue || (deepWatch && equals(oldValue, initialValue))) { return; } oldValue = initialValue; } recordChanges(scopeName, newValue, oldValue); destination[scopeName] = newValue; }, deepWatch); removeWatchCollection.push(removeWatch); break; case '&': if (!optional && !hasOwnProperty.call(attrs, attrName)) { strictBindingsCheck(attrName, directive.name); } // Don't assign Object.prototype method to scope parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop; // Don't assign noop to destination if expression is not valid if (parentGet === noop && optional) break; destination[scopeName] = function(locals) { return parentGet(scope, locals); }; break; } }); function recordChanges(key, currentValue, previousValue) { if (isFunction(destination.$onChanges) && !simpleCompare(currentValue, previousValue)) { // If we have not already scheduled the top level onChangesQueue handler then do so now if (!onChangesQueue) { scope.$$postDigest(flushOnChangesQueue); onChangesQueue = []; } // If we have not already queued a trigger of onChanges for this controller then do so now if (!changes) { changes = {}; onChangesQueue.push(triggerOnChangesHook); } // If the has been a change on this property already then we need to reuse the previous value if (changes[key]) { previousValue = changes[key].previousValue; } // Store this change changes[key] = new SimpleChange(previousValue, currentValue); } } function triggerOnChangesHook() { destination.$onChanges(changes); // Now clear the changes so that we schedule onChanges when more changes arrive changes = undefined; } return { initialChanges: initialChanges, removeWatches: removeWatchCollection.length && function removeWatches() { for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) { removeWatchCollection[i](); } } }; } }]; } function SimpleChange(previous, current) { this.previousValue = previous; this.currentValue = current; } SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; }; var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i; var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g; /** * Converts all accepted directives format into proper directive name. * @param name Name to normalize */ function directiveNormalize(name) { return name .replace(PREFIX_REGEXP, '') .replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace); } /** * @ngdoc type * @name $compile.directive.Attributes * * @description * A shared object between directive compile / linking functions which contains normalized DOM * element attributes. The values reflect current binding state `{{ }}`. The normalization is * needed since all of these are treated as equivalent in Angular: * * ``` * * ``` */ /** * @ngdoc property * @name $compile.directive.Attributes#$attr * * @description * A map of DOM element attribute names to the normalized name. This is * needed to do reverse lookup from normalized name back to actual name. */ /** * @ngdoc method * @name $compile.directive.Attributes#$set * @kind function * * @description * Set DOM element attribute value. * * * @param {string} name Normalized element attribute name of the property to modify. The name is * reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr} * property to the original name. * @param {string} value Value to set the attribute to. The value can be an interpolated string. */ /** * Closure compiler type information */ function nodesetLinkingFn( /* angular.Scope */ scope, /* NodeList */ nodeList, /* Element */ rootElement, /* function(Function) */ boundTranscludeFn ) {} function directiveLinkingFn( /* nodesetLinkingFn */ nodesetLinkingFn, /* angular.Scope */ scope, /* Node */ node, /* Element */ rootElement, /* function(Function) */ boundTranscludeFn ) {} function tokenDifference(str1, str2) { var values = '', tokens1 = str1.split(/\s+/), tokens2 = str2.split(/\s+/); outer: for (var i = 0; i < tokens1.length; i++) { var token = tokens1[i]; for (var j = 0; j < tokens2.length; j++) { if (token === tokens2[j]) continue outer; } values += (values.length > 0 ? ' ' : '') + token; } return values; } function removeComments(jqNodes) { jqNodes = jqLite(jqNodes); var i = jqNodes.length; if (i <= 1) { return jqNodes; } while (i--) { var node = jqNodes[i]; if (node.nodeType === NODE_TYPE_COMMENT || (node.nodeType === NODE_TYPE_TEXT && node.nodeValue.trim() === '')) { splice.call(jqNodes, i, 1); } } return jqNodes; } var $controllerMinErr = minErr('$controller'); var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/; function identifierForController(controller, ident) { if (ident && isString(ident)) return ident; if (isString(controller)) { var match = CNTRL_REG.exec(controller); if (match) return match[3]; } } /** * @ngdoc provider * @name $controllerProvider * @this * * @description * The {@link ng.$controller $controller service} is used by Angular to create new * controllers. * * This provider allows controller registration via the * {@link ng.$controllerProvider#register register} method. */ function $ControllerProvider() { var controllers = {}, globals = false; /** * @ngdoc method * @name $controllerProvider#has * @param {string} name Controller name to check. */ this.has = function(name) { return controllers.hasOwnProperty(name); }; /** * @ngdoc method * @name $controllerProvider#register * @param {string|Object} name Controller name, or an object map of controllers where the keys are * the names and the values are the constructors. * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI * annotations in the array notation). */ this.register = function(name, constructor) { assertNotHasOwnProperty(name, 'controller'); if (isObject(name)) { extend(controllers, name); } else { controllers[name] = constructor; } }; /** * @ngdoc method * @name $controllerProvider#allowGlobals * @description If called, allows `$controller` to find controller constructors on `window` * * @deprecated * sinceVersion="v1.3.0" * removeVersion="v1.7.0" * This method of finding controllers has been deprecated. */ this.allowGlobals = function() { globals = true; }; this.$get = ['$injector', '$window', function($injector, $window) { /** * @ngdoc service * @name $controller * @requires $injector * * @param {Function|string} constructor If called with a function then it's considered to be the * controller constructor function. Otherwise it's considered to be a string which is used * to retrieve the controller constructor using the following steps: * * * check if a controller with given name is registered via `$controllerProvider` * * check if evaluating the string on the current scope returns a constructor * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global * `window` object (deprecated, not recommended) * * The string can use the `controller as property` syntax, where the controller instance is published * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this * to work correctly. * * @param {Object} locals Injection locals for Controller. * @return {Object} Instance of given controller. * * @description * `$controller` service is responsible for instantiating controllers. * * It's just a simple call to {@link auto.$injector $injector}, but extracted into * a service, so that one can override this service with [BC version](https://gist.github.com/1649788). */ return function $controller(expression, locals, later, ident) { // PRIVATE API: // param `later` --- indicates that the controller's constructor is invoked at a later time. // If true, $controller will allocate the object with the correct // prototype chain, but will not invoke the controller until a returned // callback is invoked. // param `ident` --- An optional label which overrides the label parsed from the controller // expression, if any. var instance, match, constructor, identifier; later = later === true; if (ident && isString(ident)) { identifier = ident; } if (isString(expression)) { match = expression.match(CNTRL_REG); if (!match) { throw $controllerMinErr('ctrlfmt', 'Badly formed controller string \'{0}\'. ' + 'Must match `__name__ as __id__` or `__name__`.', expression); } constructor = match[1]; identifier = identifier || match[3]; expression = controllers.hasOwnProperty(constructor) ? controllers[constructor] : getter(locals.$scope, constructor, true) || (globals ? getter($window, constructor, true) : undefined); if (!expression) { throw $controllerMinErr('ctrlreg', 'The controller with the name \'{0}\' is not registered.', constructor); } assertArgFn(expression, constructor, true); } if (later) { // Instantiate controller later: // This machinery is used to create an instance of the object before calling the // controller's constructor itself. // // This allows properties to be added to the controller before the constructor is // invoked. Primarily, this is used for isolate scope bindings in $compile. // // This feature is not intended for use by applications, and is thus not documented // publicly. // Object creation: http://jsperf.com/create-constructor/2 var controllerPrototype = (isArray(expression) ? expression[expression.length - 1] : expression).prototype; instance = Object.create(controllerPrototype || null); if (identifier) { addIdentifier(locals, identifier, instance, constructor || expression.name); } return extend(function $controllerInit() { var result = $injector.invoke(expression, instance, locals, constructor); if (result !== instance && (isObject(result) || isFunction(result))) { instance = result; if (identifier) { // If result changed, re-assign controllerAs value to scope. addIdentifier(locals, identifier, instance, constructor || expression.name); } } return instance; }, { instance: instance, identifier: identifier }); } instance = $injector.instantiate(expression, locals, constructor); if (identifier) { addIdentifier(locals, identifier, instance, constructor || expression.name); } return instance; }; function addIdentifier(locals, identifier, instance, name) { if (!(locals && isObject(locals.$scope))) { throw minErr('$controller')('noscp', 'Cannot export controller \'{0}\' as \'{1}\'! No $scope object provided via `locals`.', name, identifier); } locals.$scope[identifier] = instance; } }]; } /** * @ngdoc service * @name $document * @requires $window * @this * * @description * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object. * * @example

$document title:

window.document title:

angular.module('documentExample', []) .controller('ExampleController', ['$scope', '$document', function($scope, $document) { $scope.title = $document[0].title; $scope.windowTitle = angular.element(window.document)[0].title; }]);
*/ function $DocumentProvider() { this.$get = ['$window', function(window) { return jqLite(window.document); }]; } /** * @private * @this * Listens for document visibility change and makes the current status accessible. */ function $$IsDocumentHiddenProvider() { this.$get = ['$document', '$rootScope', function($document, $rootScope) { var doc = $document[0]; var hidden = doc && doc.hidden; $document.on('visibilitychange', changeListener); $rootScope.$on('$destroy', function() { $document.off('visibilitychange', changeListener); }); function changeListener() { hidden = doc.hidden; } return function() { return hidden; }; }]; } /** * @ngdoc service * @name $exceptionHandler * @requires ng.$log * @this * * @description * Any uncaught exception in angular expressions is delegated to this service. * The default implementation simply delegates to `$log.error` which logs it into * the browser console. * * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing. * * ## Example: * * The example below will overwrite the default `$exceptionHandler` in order to (a) log uncaught * errors to the backend for later inspection by the developers and (b) to use `$log.warn()` instead * of `$log.error()`. * * ```js * angular. * module('exceptionOverwrite', []). * factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) { * return function myExceptionHandler(exception, cause) { * logErrorsToBackend(exception, cause); * $log.warn(exception, cause); * }; * }]); * ``` * *
* Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind` * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler} * (unless executed during a digest). * * If you wish, you can manually delegate exceptions, e.g. * `try { ... } catch(e) { $exceptionHandler(e); }` * * @param {Error} exception Exception associated with the error. * @param {string=} cause Optional information about the context in which * the error was thrown. * */ function $ExceptionHandlerProvider() { this.$get = ['$log', function($log) { return function(exception, cause) { $log.error.apply($log, arguments); }; }]; } var $$ForceReflowProvider = /** @this */ function() { this.$get = ['$document', function($document) { return function(domNode) { //the line below will force the browser to perform a repaint so //that all the animated elements within the animation frame will //be properly updated and drawn on screen. This is required to //ensure that the preparation animation is properly flushed so that //the active state picks up from there. DO NOT REMOVE THIS LINE. //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND //WILL TAKE YEARS AWAY FROM YOUR LIFE. if (domNode) { if (!domNode.nodeType && domNode instanceof jqLite) { domNode = domNode[0]; } } else { domNode = $document[0].body; } return domNode.offsetWidth + 1; }; }]; }; var APPLICATION_JSON = 'application/json'; var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'}; var JSON_START = /^\[|^\{(?!\{)/; var JSON_ENDS = { '[': /]$/, '{': /}$/ }; var JSON_PROTECTION_PREFIX = /^\)]\}',?\n/; var $httpMinErr = minErr('$http'); function serializeValue(v) { if (isObject(v)) { return isDate(v) ? v.toISOString() : toJson(v); } return v; } /** @this */ function $HttpParamSerializerProvider() { /** * @ngdoc service * @name $httpParamSerializer * @description * * Default {@link $http `$http`} params serializer that converts objects to strings * according to the following rules: * * * `{'foo': 'bar'}` results in `foo=bar` * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object) * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element) * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object) * * Note that serializer will sort the request parameters alphabetically. * */ this.$get = function() { return function ngParamSerializer(params) { if (!params) return ''; var parts = []; forEachSorted(params, function(value, key) { if (value === null || isUndefined(value) || isFunction(value)) return; if (isArray(value)) { forEach(value, function(v) { parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v))); }); } else { parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value))); } }); return parts.join('&'); }; }; } /** @this */ function $HttpParamSerializerJQLikeProvider() { /** * @ngdoc service * @name $httpParamSerializerJQLike * * @description * * Alternative {@link $http `$http`} params serializer that follows * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic. * The serializer will also sort the params alphabetically. * * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property: * * ```js * $http({ * url: myUrl, * method: 'GET', * params: myParams, * paramSerializer: '$httpParamSerializerJQLike' * }); * ``` * * It is also possible to set it as the default `paramSerializer` in the * {@link $httpProvider#defaults `$httpProvider`}. * * Additionally, you can inject the serializer and use it explicitly, for example to serialize * form data for submission: * * ```js * .controller(function($http, $httpParamSerializerJQLike) { * //... * * $http({ * url: myUrl, * method: 'POST', * data: $httpParamSerializerJQLike(myData), * headers: { * 'Content-Type': 'application/x-www-form-urlencoded' * } * }); * * }); * ``` * * */ this.$get = function() { return function jQueryLikeParamSerializer(params) { if (!params) return ''; var parts = []; serialize(params, '', true); return parts.join('&'); function serialize(toSerialize, prefix, topLevel) { if (toSerialize === null || isUndefined(toSerialize)) return; if (isArray(toSerialize)) { forEach(toSerialize, function(value, index) { serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']'); }); } else if (isObject(toSerialize) && !isDate(toSerialize)) { forEachSorted(toSerialize, function(value, key) { serialize(value, prefix + (topLevel ? '' : '[') + key + (topLevel ? '' : ']')); }); } else { parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize))); } } }; }; } function defaultHttpResponseTransform(data, headers) { if (isString(data)) { // Strip json vulnerability protection prefix and trim whitespace var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim(); if (tempData) { var contentType = headers('Content-Type'); var hasJsonContentType = contentType && (contentType.indexOf(APPLICATION_JSON) === 0); if (hasJsonContentType || isJsonLike(tempData)) { try { data = fromJson(tempData); } catch (e) { if (!hasJsonContentType) { return data; } throw $httpMinErr('baddata', 'Data must be a valid JSON object. Received: "{0}". ' + 'Parse error: "{1}"', data, e); } } } } return data; } function isJsonLike(str) { var jsonStart = str.match(JSON_START); return jsonStart && JSON_ENDS[jsonStart[0]].test(str); } /** * Parse headers into key value object * * @param {string} headers Raw headers as a string * @returns {Object} Parsed headers as key value object */ function parseHeaders(headers) { var parsed = createMap(), i; function fillInParsed(key, val) { if (key) { parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; } } if (isString(headers)) { forEach(headers.split('\n'), function(line) { i = line.indexOf(':'); fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1))); }); } else if (isObject(headers)) { forEach(headers, function(headerVal, headerKey) { fillInParsed(lowercase(headerKey), trim(headerVal)); }); } return parsed; } /** * Returns a function that provides access to parsed headers. * * Headers are lazy parsed when first requested. * @see parseHeaders * * @param {(string|Object)} headers Headers to provide access to. * @returns {function(string=)} Returns a getter function which if called with: * * - if called with an argument returns a single header value or null * - if called with no arguments returns an object containing all headers. */ function headersGetter(headers) { var headersObj; return function(name) { if (!headersObj) headersObj = parseHeaders(headers); if (name) { var value = headersObj[lowercase(name)]; if (value === undefined) { value = null; } return value; } return headersObj; }; } /** * Chain all given functions * * This function is used for both request and response transforming * * @param {*} data Data to transform. * @param {function(string=)} headers HTTP headers getter fn. * @param {number} status HTTP status code of the response. * @param {(Function|Array.)} fns Function or an array of functions. * @returns {*} Transformed data. */ function transformData(data, headers, status, fns) { if (isFunction(fns)) { return fns(data, headers, status); } forEach(fns, function(fn) { data = fn(data, headers, status); }); return data; } function isSuccess(status) { return 200 <= status && status < 300; } /** * @ngdoc provider * @name $httpProvider * @this * * @description * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service. * */ function $HttpProvider() { /** * @ngdoc property * @name $httpProvider#defaults * @description * * Object containing default values for all {@link ng.$http $http} requests. * * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses * by default. See {@link $http#caching $http Caching} for more information. * * - **`defaults.headers`** - {Object} - Default headers for all $http requests. * Refer to {@link ng.$http#setting-http-headers $http} for documentation on * setting default headers. * - **`defaults.headers.common`** * - **`defaults.headers.post`** * - **`defaults.headers.put`** * - **`defaults.headers.patch`** * * - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the * callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the * {@link $jsonpCallbacks} service. Defaults to `'callback'`. * * - **`defaults.paramSerializer`** - `{string|function(Object):string}` - A function * used to the prepare string representation of request parameters (specified as an object). * If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}. * Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}. * * - **`defaults.transformRequest`** - * `{Array|function(data, headersGetter)}` - * An array of functions (or a single function) which are applied to the request data. * By default, this is an array with one request transformation function: * * - If the `data` property of the request configuration object contains an object, serialize it * into JSON format. * * - **`defaults.transformResponse`** - * `{Array|function(data, headersGetter, status)}` - * An array of functions (or a single function) which are applied to the response data. By default, * this is an array which applies one response transformation function that does two things: * * - If XSRF prefix is detected, strip it * (see {@link ng.$http#security-considerations Security Considerations in the $http docs}). * - If the `Content-Type` is `application/json` or the response looks like JSON, * deserialize it using a JSON parser. * * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token. * Defaults value is `'XSRF-TOKEN'`. * * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the * XSRF token. Defaults value is `'X-XSRF-TOKEN'`. * **/ var defaults = this.defaults = { // transform incoming response data transformResponse: [defaultHttpResponseTransform], // transform outgoing request data transformRequest: [function(d) { return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d; }], // default headers headers: { common: { 'Accept': 'application/json, text/plain, */*' }, post: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), put: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), patch: shallowCopy(CONTENT_TYPE_APPLICATION_JSON) }, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', paramSerializer: '$httpParamSerializer', jsonpCallbackParam: 'callback' }; var useApplyAsync = false; /** * @ngdoc method * @name $httpProvider#useApplyAsync * @description * * Configure $http service to combine processing of multiple http responses received at around * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in * significant performance improvement for bigger applications that make many HTTP requests * concurrently (common during application bootstrap). * * Defaults to false. If no value is specified, returns the current configured value. * * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred * "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window * to load and share the same digest cycle. * * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining. * otherwise, returns the current configured value. **/ this.useApplyAsync = function(value) { if (isDefined(value)) { useApplyAsync = !!value; return this; } return useApplyAsync; }; /** * @ngdoc property * @name $httpProvider#interceptors * @description * * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http} * pre-processing of request or postprocessing of responses. * * These service factories are ordered by request, i.e. they are applied in the same order as the * array, on request, but reverse order, on response. * * {@link ng.$http#interceptors Interceptors detailed info} **/ var interceptorFactories = this.interceptors = []; this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce', function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) { var defaultCache = $cacheFactory('$http'); /** * Make sure that default param serializer is exposed as a function */ defaults.paramSerializer = isString(defaults.paramSerializer) ? $injector.get(defaults.paramSerializer) : defaults.paramSerializer; /** * Interceptors stored in reverse order. Inner interceptors before outer interceptors. * The reversal is needed so that we can build up the interception chain around the * server request. */ var reversedInterceptors = []; forEach(interceptorFactories, function(interceptorFactory) { reversedInterceptors.unshift(isString(interceptorFactory) ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory)); }); /** * @ngdoc service * @kind function * @name $http * @requires ng.$httpBackend * @requires $cacheFactory * @requires $rootScope * @requires $q * @requires $injector * * @description * The `$http` service is a core Angular service that facilitates communication with the remote * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest) * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP). * * For unit testing applications that use `$http` service, see * {@link ngMock.$httpBackend $httpBackend mock}. * * For a higher level of abstraction, please check out the {@link ngResource.$resource * $resource} service. * * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage * it is important to familiarize yourself with these APIs and the guarantees they provide. * * * ## General usage * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} — * that is used to generate an HTTP request and returns a {@link ng.$q promise}. * * ```js * // Simple GET request example: * $http({ * method: 'GET', * url: '/someUrl' * }).then(function successCallback(response) { * // this callback will be called asynchronously * // when the response is available * }, function errorCallback(response) { * // called asynchronously if an error occurs * // or server returns response with an error status. * }); * ``` * * The response object has these properties: * * - **data** – `{string|Object}` – The response body transformed with the transform * functions. * - **status** – `{number}` – HTTP status code of the response. * - **headers** – `{function([headerName])}` – Header getter function. * - **config** – `{Object}` – The configuration object that was used to generate the request. * - **statusText** – `{string}` – HTTP status text of the response. * - **xhrStatus** – `{string}` – Status of the XMLHttpRequest (`complete`, `error`, `timeout` or `abort`). * * A response status code between 200 and 299 is considered a success status and will result in * the success callback being called. Any response status code outside of that range is * considered an error status and will result in the error callback being called. * Also, status codes less than -1 are normalized to zero. -1 usually means the request was * aborted, e.g. using a `config.timeout`. * Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning * that the outcome (success or error) will be determined by the final response status code. * * * ## Shortcut methods * * Shortcut methods are also available. All shortcut methods require passing in the URL, and * request data must be passed in for POST/PUT requests. An optional config can be passed as the * last argument. * * ```js * $http.get('/someUrl', config).then(successCallback, errorCallback); * $http.post('/someUrl', data, config).then(successCallback, errorCallback); * ``` * * Complete list of shortcut methods: * * - {@link ng.$http#get $http.get} * - {@link ng.$http#head $http.head} * - {@link ng.$http#post $http.post} * - {@link ng.$http#put $http.put} * - {@link ng.$http#delete $http.delete} * - {@link ng.$http#jsonp $http.jsonp} * - {@link ng.$http#patch $http.patch} * * * ## Writing Unit Tests that use $http * When unit testing (using {@link ngMock ngMock}), it is necessary to call * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending * request using trained responses. * * ``` * $httpBackend.expectGET(...); * $http.get(...); * $httpBackend.flush(); * ``` * * ## Setting HTTP Headers * * The $http service will automatically add certain HTTP headers to all requests. These defaults * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration * object, which currently contains this default configuration: * * - `$httpProvider.defaults.headers.common` (headers that are common for all requests): * - Accept: application/json, text/plain, \*/\* * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests) * - `Content-Type: application/json` * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests) * - `Content-Type: application/json` * * To add or overwrite these defaults, simply add or remove a property from these configuration * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object * with the lowercased HTTP method name as the key, e.g. * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`. * * The defaults can also be set at runtime via the `$http.defaults` object in the same * fashion. For example: * * ``` * module.run(function($http) { * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'; * }); * ``` * * In addition, you can supply a `headers` property in the config object passed when * calling `$http(config)`, which overrides the defaults without changing them globally. * * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis, * Use the `headers` property, setting the desired header to `undefined`. For example: * * ```js * var req = { * method: 'POST', * url: 'http://example.com', * headers: { * 'Content-Type': undefined * }, * data: { test: 'test' } * } * * $http(req).then(function(){...}, function(){...}); * ``` * * ## Transforming Requests and Responses * * Both requests and responses can be transformed using transformation functions: `transformRequest` * and `transformResponse`. These properties can be a single function that returns * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions, * which allows you to `push` or `unshift` a new transformation function into the transformation chain. * *
* **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline. * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference). * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest * function will be reflected on the scope and in any templates where the object is data-bound. * To prevent this, transform functions should have no side-effects. * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return. *
* * ### Default Transformations * * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and * `defaults.transformResponse` properties. If a request does not provide its own transformations * then these will be applied. * * You can augment or replace the default transformations by modifying these properties by adding to or * replacing the array. * * Angular provides the following default transformations: * * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`) is * an array with one function that does the following: * * - If the `data` property of the request configuration object contains an object, serialize it * into JSON format. * * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`) is * an array with one function that does the following: * * - If XSRF prefix is detected, strip it (see Security Considerations section below). * - If the `Content-Type` is `application/json` or the response looks like JSON, * deserialize it using a JSON parser. * * * ### Overriding the Default Transformations Per Request * * If you wish to override the request/response transformations only for a single request then provide * `transformRequest` and/or `transformResponse` properties on the configuration object passed * into `$http`. * * Note that if you provide these properties on the config object the default transformations will be * overwritten. If you wish to augment the default transformations then you must include them in your * local transformation array. * * The following code demonstrates adding a new response transformation to be run after the default response * transformations have been run. * * ```js * function appendTransform(defaults, transform) { * * // We can't guarantee that the default transformation is an array * defaults = angular.isArray(defaults) ? defaults : [defaults]; * * // Append the new transformation to the defaults * return defaults.concat(transform); * } * * $http({ * url: '...', * method: 'GET', * transformResponse: appendTransform($http.defaults.transformResponse, function(value) { * return doTransform(value); * }) * }); * ``` * * * ## Caching * * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must * set the config.cache value or the default cache value to TRUE or to a cache object (created * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes * precedence over the default cache value. * * In order to: * * cache all responses - set the default cache value to TRUE or to a cache object * * cache a specific response - set config.cache value to TRUE or to a cache object * * If caching is enabled, but neither the default cache nor config.cache are set to a cache object, * then the default `$cacheFactory("$http")` object is used. * * The default cache value can be set by updating the * {@link ng.$http#defaults `$http.defaults.cache`} property or the * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property. * * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using * the relevant cache object. The next time the same request is made, the response is returned * from the cache without sending a request to the server. * * Take note that: * * * Only GET and JSONP requests are cached. * * The cache key is the request URL including search parameters; headers are not considered. * * Cached responses are returned asynchronously, in the same way as responses from the server. * * If multiple identical requests are made using the same cache, which is not yet populated, * one request will be made to the server and remaining requests will return the same response. * * A cache-control header on the response does not affect if or how responses are cached. * * * ## Interceptors * * Before you start creating interceptors, be sure to understand the * {@link ng.$q $q and deferred/promise APIs}. * * For purposes of global error handling, authentication, or any kind of synchronous or * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be * able to intercept requests before they are handed to the server and * responses before they are handed over to the application code that * initiated these requests. The interceptors leverage the {@link ng.$q * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing. * * The interceptors are service factories that are registered with the `$httpProvider` by * adding them to the `$httpProvider.interceptors` array. The factory is called and * injected with dependencies (if specified) and returns the interceptor. * * There are two kinds of interceptors (and two kinds of rejection interceptors): * * * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to * modify the `config` object or create a new one. The function needs to return the `config` * object directly, or a promise containing the `config` or a new `config` object. * * `requestError`: interceptor gets called when a previous interceptor threw an error or * resolved with a rejection. * * `response`: interceptors get called with http `response` object. The function is free to * modify the `response` object or create a new one. The function needs to return the `response` * object directly, or as a promise containing the `response` or a new `response` object. * * `responseError`: interceptor gets called when a previous interceptor threw an error or * resolved with a rejection. * * * ```js * // register the interceptor as a service * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { * return { * // optional method * 'request': function(config) { * // do something on success * return config; * }, * * // optional method * 'requestError': function(rejection) { * // do something on error * if (canRecover(rejection)) { * return responseOrNewPromise * } * return $q.reject(rejection); * }, * * * * // optional method * 'response': function(response) { * // do something on success * return response; * }, * * // optional method * 'responseError': function(rejection) { * // do something on error * if (canRecover(rejection)) { * return responseOrNewPromise * } * return $q.reject(rejection); * } * }; * }); * * $httpProvider.interceptors.push('myHttpInterceptor'); * * * // alternatively, register the interceptor via an anonymous factory * $httpProvider.interceptors.push(function($q, dependency1, dependency2) { * return { * 'request': function(config) { * // same as above * }, * * 'response': function(response) { * // same as above * } * }; * }); * ``` * * ## Security Considerations * * When designing web applications, consider security threats from: * * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) * * Both server and the client must cooperate in order to eliminate these threats. Angular comes * pre-configured with strategies that address these issues, but for this to work backend server * cooperation is required. * * ### JSON Vulnerability Protection * * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) * allows third party website to turn your JSON resource URL into * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To * counter this your server can prefix all JSON requests with following string `")]}',\n"`. * Angular will automatically strip the prefix before processing it as JSON. * * For example if your server needs to return: * ```js * ['one','two'] * ``` * * which is vulnerable to attack, your server can return: * ```js * )]}', * ['one','two'] * ``` * * Angular will strip the prefix, before processing the JSON. * * * ### Cross Site Request Forgery (XSRF) Protection * * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by * which the attacker can trick an authenticated user into unknowingly executing actions on your * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the * cookie, your server can be assured that the XHR came from JavaScript running on your domain. * The header will not be set for cross-domain requests. * * To take advantage of this, your server needs to set a token in a JavaScript readable session * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure * that only JavaScript running on your domain could have sent the request. The token must be * unique for each user and must be verifiable by the server (to prevent the JavaScript from * making up its own tokens). We recommend that the token is a digest of your site's * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) * for added security. * * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, * or the per-request config object. * * In order to prevent collisions in environments where multiple Angular apps share the * same domain or subdomain, we recommend that each application uses unique cookie name. * * @param {object} config Object describing the request to be made and how it should be * processed. The object has following properties: * * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) * - **url** – `{string|TrustedObject}` – Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. * - **params** – `{Object.}` – Map of strings or objects which will be serialized * with the `paramSerializer` and appended as GET parameters. * - **data** – `{string|Object}` – Data to be sent as the request message data. * - **headers** – `{Object}` – Map of strings or functions which return strings representing * HTTP headers to send to the server. If the return value of a function is null, the * header will not be sent. Functions accept a config object as an argument. * - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object. * To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`. * The handler will be called in the context of a `$apply` block. * - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload * object. To bind events to the XMLHttpRequest object, use `eventHandlers`. * The handler will be called in the context of a `$apply` block. * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token. * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token. * - **transformRequest** – * `{function(data, headersGetter)|Array.}` – * transform function or an array of such functions. The transform function takes the http * request body and headers and returns its transformed (typically serialized) version. * See {@link ng.$http#overriding-the-default-transformations-per-request * Overriding the Default Transformations} * - **transformResponse** – * `{function(data, headersGetter, status)|Array.}` – * transform function or an array of such functions. The transform function takes the http * response body, headers and status and returns its transformed (typically deserialized) version. * See {@link ng.$http#overriding-the-default-transformations-per-request * Overriding the Default Transformations} * - **paramSerializer** - `{string|function(Object):string}` - A function used to * prepare the string representation of request parameters (specified as an object). * If specified as string, it is interpreted as function registered with the * {@link $injector $injector}, which means you can create your own serializer * by registering it as a {@link auto.$provide#service service}. * The default serializer is the {@link $httpParamSerializer $httpParamSerializer}; * alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike} * - **cache** – `{boolean|Object}` – A boolean value or object created with * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response. * See {@link $http#caching $http Caching} for more information. * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} * that should abort the request when resolved. * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials) * for more information. * - **responseType** - `{string}` - see * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype). * * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object * when the request succeeds or fails. * * * @property {Array.} pendingRequests Array of config objects for currently pending * requests. This is primarily meant to be used for debugging purposes. * * * @example

http status code: {{status}}
http response data: {{data}}
angular.module('httpExample', []) .config(['$sceDelegateProvider', function($sceDelegateProvider) { // We must whitelist the JSONP endpoint that we are using to show that we trust it $sceDelegateProvider.resourceUrlWhitelist([ 'self', 'https://angularjs.org/**' ]); }]) .controller('FetchController', ['$scope', '$http', '$templateCache', function($scope, $http, $templateCache) { $scope.method = 'GET'; $scope.url = 'http-hello.html'; $scope.fetch = function() { $scope.code = null; $scope.response = null; $http({method: $scope.method, url: $scope.url, cache: $templateCache}). then(function(response) { $scope.status = response.status; $scope.data = response.data; }, function(response) { $scope.data = response.data || 'Request failed'; $scope.status = response.status; }); }; $scope.updateModel = function(method, url) { $scope.method = method; $scope.url = url; }; }]); Hello, $http! var status = element(by.binding('status')); var data = element(by.binding('data')); var fetchBtn = element(by.id('fetchbtn')); var sampleGetBtn = element(by.id('samplegetbtn')); var invalidJsonpBtn = element(by.id('invalidjsonpbtn')); it('should make an xhr GET request', function() { sampleGetBtn.click(); fetchBtn.click(); expect(status.getText()).toMatch('200'); expect(data.getText()).toMatch(/Hello, \$http!/); }); // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185 // it('should make a JSONP request to angularjs.org', function() { // var sampleJsonpBtn = element(by.id('samplejsonpbtn')); // sampleJsonpBtn.click(); // fetchBtn.click(); // expect(status.getText()).toMatch('200'); // expect(data.getText()).toMatch(/Super Hero!/); // }); it('should make JSONP request to invalid URL and invoke the error handler', function() { invalidJsonpBtn.click(); fetchBtn.click(); expect(status.getText()).toMatch('0'); expect(data.getText()).toMatch('Request failed'); });
*/ function $http(requestConfig) { if (!isObject(requestConfig)) { throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig); } if (!isString($sce.valueOf(requestConfig.url))) { throw minErr('$http')('badreq', 'Http request configuration url must be a string or a $sce trusted object. Received: {0}', requestConfig.url); } var config = extend({ method: 'get', transformRequest: defaults.transformRequest, transformResponse: defaults.transformResponse, paramSerializer: defaults.paramSerializer, jsonpCallbackParam: defaults.jsonpCallbackParam }, requestConfig); config.headers = mergeHeaders(requestConfig); config.method = uppercase(config.method); config.paramSerializer = isString(config.paramSerializer) ? $injector.get(config.paramSerializer) : config.paramSerializer; $browser.$$incOutstandingRequestCount(); var requestInterceptors = []; var responseInterceptors = []; var promise = $q.resolve(config); // apply interceptors forEach(reversedInterceptors, function(interceptor) { if (interceptor.request || interceptor.requestError) { requestInterceptors.unshift(interceptor.request, interceptor.requestError); } if (interceptor.response || interceptor.responseError) { responseInterceptors.push(interceptor.response, interceptor.responseError); } }); promise = chainInterceptors(promise, requestInterceptors); promise = promise.then(serverRequest); promise = chainInterceptors(promise, responseInterceptors); promise = promise.finally(completeOutstandingRequest); return promise; function chainInterceptors(promise, interceptors) { for (var i = 0, ii = interceptors.length; i < ii;) { var thenFn = interceptors[i++]; var rejectFn = interceptors[i++]; promise = promise.then(thenFn, rejectFn); } interceptors.length = 0; return promise; } function completeOutstandingRequest() { $browser.$$completeOutstandingRequest(noop); } function executeHeaderFns(headers, config) { var headerContent, processedHeaders = {}; forEach(headers, function(headerFn, header) { if (isFunction(headerFn)) { headerContent = headerFn(config); if (headerContent != null) { processedHeaders[header] = headerContent; } } else { processedHeaders[header] = headerFn; } }); return processedHeaders; } function mergeHeaders(config) { var defHeaders = defaults.headers, reqHeaders = extend({}, config.headers), defHeaderName, lowercaseDefHeaderName, reqHeaderName; defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]); // using for-in instead of forEach to avoid unnecessary iteration after header has been found defaultHeadersIteration: for (defHeaderName in defHeaders) { lowercaseDefHeaderName = lowercase(defHeaderName); for (reqHeaderName in reqHeaders) { if (lowercase(reqHeaderName) === lowercaseDefHeaderName) { continue defaultHeadersIteration; } } reqHeaders[defHeaderName] = defHeaders[defHeaderName]; } // execute if header value is a function for merged headers return executeHeaderFns(reqHeaders, shallowCopy(config)); } function serverRequest(config) { var headers = config.headers; var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest); // strip content-type if data is undefined if (isUndefined(reqData)) { forEach(headers, function(value, header) { if (lowercase(header) === 'content-type') { delete headers[header]; } }); } if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) { config.withCredentials = defaults.withCredentials; } // send request return sendReq(config, reqData).then(transformResponse, transformResponse); } function transformResponse(response) { // make a copy since the response must be cacheable var resp = extend({}, response); resp.data = transformData(response.data, response.headers, response.status, config.transformResponse); return (isSuccess(response.status)) ? resp : $q.reject(resp); } } $http.pendingRequests = []; /** * @ngdoc method * @name $http#get * * @description * Shortcut method to perform `GET` request. * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ /** * @ngdoc method * @name $http#delete * * @description * Shortcut method to perform `DELETE` request. * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ /** * @ngdoc method * @name $http#head * * @description * Shortcut method to perform `HEAD` request. * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ /** * @ngdoc method * @name $http#jsonp * * @description * Shortcut method to perform `JSONP` request. * * Note that, since JSONP requests are sensitive because the response is given full access to the browser, * the url must be declared, via {@link $sce} as a trusted resource URL. * You can trust a URL by adding it to the whitelist via * {@link $sceDelegateProvider#resourceUrlWhitelist `$sceDelegateProvider.resourceUrlWhitelist`} or * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}. * * JSONP requests must specify a callback to be used in the response from the server. This callback * is passed as a query parameter in the request. You must specify the name of this parameter by * setting the `jsonpCallbackParam` property on the request config object. * * ``` * $http.jsonp('some/trusted/url', {jsonpCallbackParam: 'callback'}) * ``` * * You can also specify a default callback parameter name in `$http.defaults.jsonpCallbackParam`. * Initially this is set to `'callback'`. * *
* You can no longer use the `JSON_CALLBACK` string as a placeholder for specifying where the callback * parameter value should go. *
* * If you would like to customise where and how the callbacks are stored then try overriding * or decorating the {@link $jsonpCallbacks} service. * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ createShortMethods('get', 'delete', 'head', 'jsonp'); /** * @ngdoc method * @name $http#post * * @description * Shortcut method to perform `POST` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ /** * @ngdoc method * @name $http#put * * @description * Shortcut method to perform `PUT` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ /** * @ngdoc method * @name $http#patch * * @description * Shortcut method to perform `PATCH` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ createShortMethodsWithData('post', 'put', 'patch'); /** * @ngdoc property * @name $http#defaults * * @description * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of * default headers, withCredentials as well as request and response transformations. * * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above. */ $http.defaults = defaults; return $http; function createShortMethods(names) { forEach(arguments, function(name) { $http[name] = function(url, config) { return $http(extend({}, config || {}, { method: name, url: url })); }; }); } function createShortMethodsWithData(name) { forEach(arguments, function(name) { $http[name] = function(url, data, config) { return $http(extend({}, config || {}, { method: name, url: url, data: data })); }; }); } /** * Makes the request. * * !!! ACCESSES CLOSURE VARS: * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests */ function sendReq(config, reqData) { var deferred = $q.defer(), promise = deferred.promise, cache, cachedResp, reqHeaders = config.headers, isJsonp = lowercase(config.method) === 'jsonp', url = config.url; if (isJsonp) { // JSONP is a pretty sensitive operation where we're allowing a script to have full access to // our DOM and JS space. So we require that the URL satisfies SCE.RESOURCE_URL. url = $sce.getTrustedResourceUrl(url); } else if (!isString(url)) { // If it is not a string then the URL must be a $sce trusted object url = $sce.valueOf(url); } url = buildUrl(url, config.paramSerializer(config.params)); if (isJsonp) { // Check the url and add the JSONP callback placeholder url = sanitizeJsonpCallbackParam(url, config.jsonpCallbackParam); } $http.pendingRequests.push(config); promise.then(removePendingReq, removePendingReq); if ((config.cache || defaults.cache) && config.cache !== false && (config.method === 'GET' || config.method === 'JSONP')) { cache = isObject(config.cache) ? config.cache : isObject(/** @type {?} */ (defaults).cache) ? /** @type {?} */ (defaults).cache : defaultCache; } if (cache) { cachedResp = cache.get(url); if (isDefined(cachedResp)) { if (isPromiseLike(cachedResp)) { // cached request has already been sent, but there is no response yet cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult); } else { // serving from cache if (isArray(cachedResp)) { resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3], cachedResp[4]); } else { resolvePromise(cachedResp, 200, {}, 'OK', 'complete'); } } } else { // put the promise for the non-transformed response into cache as a placeholder cache.put(url, promise); } } // if we won't have the response in cache, set the xsrf headers and // send the request to the backend if (isUndefined(cachedResp)) { var xsrfValue = urlIsSameOrigin(config.url) ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName] : undefined; if (xsrfValue) { reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue; } $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, config.withCredentials, config.responseType, createApplyHandlers(config.eventHandlers), createApplyHandlers(config.uploadEventHandlers)); } return promise; function createApplyHandlers(eventHandlers) { if (eventHandlers) { var applyHandlers = {}; forEach(eventHandlers, function(eventHandler, key) { applyHandlers[key] = function(event) { if (useApplyAsync) { $rootScope.$applyAsync(callEventHandler); } else if ($rootScope.$$phase) { callEventHandler(); } else { $rootScope.$apply(callEventHandler); } function callEventHandler() { eventHandler(event); } }; }); return applyHandlers; } } /** * Callback registered to $httpBackend(): * - caches the response if desired * - resolves the raw $http promise * - calls $apply */ function done(status, response, headersString, statusText, xhrStatus) { if (cache) { if (isSuccess(status)) { cache.put(url, [status, response, parseHeaders(headersString), statusText, xhrStatus]); } else { // remove promise from the cache cache.remove(url); } } function resolveHttpPromise() { resolvePromise(response, status, headersString, statusText, xhrStatus); } if (useApplyAsync) { $rootScope.$applyAsync(resolveHttpPromise); } else { resolveHttpPromise(); if (!$rootScope.$$phase) $rootScope.$apply(); } } /** * Resolves the raw $http promise. */ function resolvePromise(response, status, headers, statusText, xhrStatus) { //status: HTTP response status code, 0, -1 (aborted by timeout / promise) status = status >= -1 ? status : 0; (isSuccess(status) ? deferred.resolve : deferred.reject)({ data: response, status: status, headers: headersGetter(headers), config: config, statusText: statusText, xhrStatus: xhrStatus }); } function resolvePromiseWithResult(result) { resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText, result.xhrStatus); } function removePendingReq() { var idx = $http.pendingRequests.indexOf(config); if (idx !== -1) $http.pendingRequests.splice(idx, 1); } } function buildUrl(url, serializedParams) { if (serializedParams.length > 0) { url += ((url.indexOf('?') === -1) ? '?' : '&') + serializedParams; } return url; } function sanitizeJsonpCallbackParam(url, key) { if (/[&?][^=]+=JSON_CALLBACK/.test(url)) { // Throw if the url already contains a reference to JSON_CALLBACK throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url); } var callbackParamRegex = new RegExp('[&?]' + key + '='); if (callbackParamRegex.test(url)) { // Throw if the callback param was already provided throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', key, url); } // Add in the JSON_CALLBACK callback param value url += ((url.indexOf('?') === -1) ? '?' : '&') + key + '=JSON_CALLBACK'; return url; } }]; } /** * @ngdoc service * @name $xhrFactory * @this * * @description * Factory function used to create XMLHttpRequest objects. * * Replace or decorate this service to create your own custom XMLHttpRequest objects. * * ``` * angular.module('myApp', []) * .factory('$xhrFactory', function() { * return function createXhr(method, url) { * return new window.XMLHttpRequest({mozSystem: true}); * }; * }); * ``` * * @param {string} method HTTP method of the request (GET, POST, PUT, ..) * @param {string} url URL of the request. */ function $xhrFactoryProvider() { this.$get = function() { return function createXhr() { return new window.XMLHttpRequest(); }; }; } /** * @ngdoc service * @name $httpBackend * @requires $jsonpCallbacks * @requires $document * @requires $xhrFactory * @this * * @description * HTTP backend used by the {@link ng.$http service} that delegates to * XMLHttpRequest object or JSONP and deals with browser incompatibilities. * * You should never need to use this service directly, instead use the higher-level abstractions: * {@link ng.$http $http} or {@link ngResource.$resource $resource}. * * During testing this implementation is swapped with {@link ngMock.$httpBackend mock * $httpBackend} which can be trained with responses. */ function $HttpBackendProvider() { this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) { return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]); }]; } function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) { // TODO(vojta): fix the signature return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) { url = url || $browser.url(); if (lowercase(method) === 'jsonp') { var callbackPath = callbacks.createCallback(url); var jsonpDone = jsonpReq(url, callbackPath, function(status, text) { // jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING) var response = (status === 200) && callbacks.getResponse(callbackPath); completeRequest(callback, status, response, '', text, 'complete'); callbacks.removeCallback(callbackPath); }); } else { var xhr = createXhr(method, url); xhr.open(method, url, true); forEach(headers, function(value, key) { if (isDefined(value)) { xhr.setRequestHeader(key, value); } }); xhr.onload = function requestLoaded() { var statusText = xhr.statusText || ''; // responseText is the old-school way of retrieving response (supported by IE9) // response/responseType properties were introduced in XHR Level2 spec (supported by IE10) var response = ('response' in xhr) ? xhr.response : xhr.responseText; // normalize IE9 bug (http://bugs.jquery.com/ticket/1450) var status = xhr.status === 1223 ? 204 : xhr.status; // fix status code when it is 0 (0 status is undocumented). // Occurs when accessing file resources or on Android 4.1 stock browser // while retrieving files from application cache. if (status === 0) { status = response ? 200 : urlResolve(url).protocol === 'file' ? 404 : 0; } completeRequest(callback, status, response, xhr.getAllResponseHeaders(), statusText, 'complete'); }; var requestError = function() { // The response is always empty // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error completeRequest(callback, -1, null, null, '', 'error'); }; var requestAborted = function() { completeRequest(callback, -1, null, null, '', 'abort'); }; var requestTimeout = function() { // The response is always empty // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error completeRequest(callback, -1, null, null, '', 'timeout'); }; xhr.onerror = requestError; xhr.onabort = requestAborted; xhr.ontimeout = requestTimeout; forEach(eventHandlers, function(value, key) { xhr.addEventListener(key, value); }); forEach(uploadEventHandlers, function(value, key) { xhr.upload.addEventListener(key, value); }); if (withCredentials) { xhr.withCredentials = true; } if (responseType) { try { xhr.responseType = responseType; } catch (e) { // WebKit added support for the json responseType value on 09/03/2013 // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are // known to throw when setting the value "json" as the response type. Other older // browsers implementing the responseType // // The json response type can be ignored if not supported, because JSON payloads are // parsed on the client-side regardless. if (responseType !== 'json') { throw e; } } } xhr.send(isUndefined(post) ? null : post); } if (timeout > 0) { var timeoutId = $browserDefer(timeoutRequest, timeout); } else if (isPromiseLike(timeout)) { timeout.then(timeoutRequest); } function timeoutRequest() { if (jsonpDone) { jsonpDone(); } if (xhr) { xhr.abort(); } } function completeRequest(callback, status, response, headersString, statusText, xhrStatus) { // cancel timeout and subsequent timeout promise resolution if (isDefined(timeoutId)) { $browserDefer.cancel(timeoutId); } jsonpDone = xhr = null; callback(status, response, headersString, statusText, xhrStatus); } }; function jsonpReq(url, callbackPath, done) { url = url.replace('JSON_CALLBACK', callbackPath); // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.: // - fetches local scripts via XHR and evals them // - adds and immediately removes script elements from the document var script = rawDocument.createElement('script'), callback = null; script.type = 'text/javascript'; script.src = url; script.async = true; callback = function(event) { script.removeEventListener('load', callback); script.removeEventListener('error', callback); rawDocument.body.removeChild(script); script = null; var status = -1; var text = 'unknown'; if (event) { if (event.type === 'load' && !callbacks.wasCalled(callbackPath)) { event = { type: 'error' }; } text = event.type; status = event.type === 'error' ? 404 : 200; } if (done) { done(status, text); } }; script.addEventListener('load', callback); script.addEventListener('error', callback); rawDocument.body.appendChild(script); return callback; } } var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate'); $interpolateMinErr.throwNoconcat = function(text) { throw $interpolateMinErr('noconcat', 'Error while interpolating: {0}\nStrict Contextual Escaping disallows ' + 'interpolations that concatenate multiple expressions when a trusted value is ' + 'required. See http://docs.angularjs.org/api/ng.$sce', text); }; $interpolateMinErr.interr = function(text, err) { return $interpolateMinErr('interr', 'Can\'t interpolate: {0}\n{1}', text, err.toString()); }; /** * @ngdoc provider * @name $interpolateProvider * @this * * @description * * Used for configuring the interpolation markup. Defaults to `{{` and `}}`. * *
* This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular * template within a Python Jinja template (or any other template language). Mixing templating * languages is **very dangerous**. The embedding template language will not safely escape Angular * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS) * security bugs! *
* * @example
//demo.label//
it('should interpolate binding with custom symbols', function() { expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.'); });
*/ function $InterpolateProvider() { var startSymbol = '{{'; var endSymbol = '}}'; /** * @ngdoc method * @name $interpolateProvider#startSymbol * @description * Symbol to denote start of expression in the interpolated string. Defaults to `{{`. * * @param {string=} value new value to set the starting symbol to. * @returns {string|self} Returns the symbol when used as getter and self if used as setter. */ this.startSymbol = function(value) { if (value) { startSymbol = value; return this; } else { return startSymbol; } }; /** * @ngdoc method * @name $interpolateProvider#endSymbol * @description * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. * * @param {string=} value new value to set the ending symbol to. * @returns {string|self} Returns the symbol when used as getter and self if used as setter. */ this.endSymbol = function(value) { if (value) { endSymbol = value; return this; } else { return endSymbol; } }; this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) { var startSymbolLength = startSymbol.length, endSymbolLength = endSymbol.length, escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'), escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g'); function escape(ch) { return '\\\\\\' + ch; } function unescapeText(text) { return text.replace(escapedStartRegexp, startSymbol). replace(escapedEndRegexp, endSymbol); } // TODO: this is the same as the constantWatchDelegate in parse.js function constantWatchDelegate(scope, listener, objectEquality, constantInterp) { var unwatch = scope.$watch(function constantInterpolateWatch(scope) { unwatch(); return constantInterp(scope); }, listener, objectEquality); return unwatch; } /** * @ngdoc service * @name $interpolate * @kind function * * @requires $parse * @requires $sce * * @description * * Compiles a string with markup into an interpolation function. This service is used by the * HTML {@link ng.$compile $compile} service for data binding. See * {@link ng.$interpolateProvider $interpolateProvider} for configuring the * interpolation markup. * * * ```js * var $interpolate = ...; // injected * var exp = $interpolate('Hello {{name | uppercase}}!'); * expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!'); * ``` * * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is * `true`, the interpolation function will return `undefined` unless all embedded expressions * evaluate to a value other than `undefined`. * * ```js * var $interpolate = ...; // injected * var context = {greeting: 'Hello', name: undefined }; * * // default "forgiving" mode * var exp = $interpolate('{{greeting}} {{name}}!'); * expect(exp(context)).toEqual('Hello !'); * * // "allOrNothing" mode * exp = $interpolate('{{greeting}} {{name}}!', false, null, true); * expect(exp(context)).toBeUndefined(); * context.name = 'Angular'; * expect(exp(context)).toEqual('Hello Angular!'); * ``` * * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior. * * #### Escaped Interpolation * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash). * It will be rendered as a regular start/end marker, and will not be interpreted as an expression * or binding. * * This enables web-servers to prevent script injection attacks and defacing attacks, to some * degree, while also enabling code examples to work without relying on the * {@link ng.directive:ngNonBindable ngNonBindable} directive. * * **For security purposes, it is strongly encouraged that web servers escape user-supplied data, * replacing angle brackets (<, >) with &lt; and &gt; respectively, and replacing all * interpolation start/end markers with their escaped counterparts.** * * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered * output when the $interpolate service processes the text. So, for HTML elements interpolated * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such, * this is typically useful only when user-data is used in rendering a template from the server, or * when otherwise untrusted data is used by a directive. * * * *
*

{{apptitle}}: \{\{ username = "defaced value"; \}\} *

*

{{username}} attempts to inject code which will deface the * application, but fails to accomplish their task, because the server has correctly * escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash) * characters.

*

Instead, the result of the attempted script injection is visible, and can be removed * from the database by an administrator.

*
*
*
* * @knownIssue * It is currently not possible for an interpolated expression to contain the interpolation end * symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e. * an interpolated expression consisting of a single-quote (`'`) and the `' }}` string. * * @knownIssue * All directives and components must use the standard `{{` `}}` interpolation symbols * in their templates. If you change the application interpolation symbols the {@link $compile} * service will attempt to denormalize the standard symbols to the custom symbols. * The denormalization process is not clever enough to know not to replace instances of the standard * symbols where they would not normally be treated as interpolation symbols. For example in the following * code snippet the closing braces of the literal object will get incorrectly denormalized: * * ``` *
* ``` * * See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information. * * @param {string} text The text with markup to interpolate. * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have * embedded expression in order to return an interpolation function. Strings with no * embedded expression will return null for the interpolation function. * @param {string=} trustedContext when provided, the returned function passes the interpolated * result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult, * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that * provides Strict Contextual Escaping for details. * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined * unless all embedded expressions evaluate to a value other than `undefined`. * @returns {function(context)} an interpolation function which is used to compute the * interpolated string. The function has these parameters: * * - `context`: evaluation context for all expressions embedded in the interpolated text */ function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) { // Provide a quick exit and simplified result function for text with no interpolation if (!text.length || text.indexOf(startSymbol) === -1) { var constantInterp; if (!mustHaveExpression) { var unescapedText = unescapeText(text); constantInterp = valueFn(unescapedText); constantInterp.exp = text; constantInterp.expressions = []; constantInterp.$$watchDelegate = constantWatchDelegate; } return constantInterp; } allOrNothing = !!allOrNothing; var startIndex, endIndex, index = 0, expressions = [], parseFns = [], textLength = text.length, exp, concat = [], expressionPositions = []; while (index < textLength) { if (((startIndex = text.indexOf(startSymbol, index)) !== -1) && ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) !== -1)) { if (index !== startIndex) { concat.push(unescapeText(text.substring(index, startIndex))); } exp = text.substring(startIndex + startSymbolLength, endIndex); expressions.push(exp); parseFns.push($parse(exp, parseStringifyInterceptor)); index = endIndex + endSymbolLength; expressionPositions.push(concat.length); concat.push(''); } else { // we did not find an interpolation, so we have to add the remainder to the separators array if (index !== textLength) { concat.push(unescapeText(text.substring(index))); } break; } } // Concatenating expressions makes it hard to reason about whether some combination of // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a // single expression be used for iframe[src], object[src], etc., we ensure that the value // that's used is assigned or constructed by some JS code somewhere that is more testable or // make it obvious that you bound the value to some user controlled value. This helps reduce // the load when auditing for XSS issues. if (trustedContext && concat.length > 1) { $interpolateMinErr.throwNoconcat(text); } if (!mustHaveExpression || expressions.length) { var compute = function(values) { for (var i = 0, ii = expressions.length; i < ii; i++) { if (allOrNothing && isUndefined(values[i])) return; concat[expressionPositions[i]] = values[i]; } return concat.join(''); }; var getValue = function(value) { return trustedContext ? $sce.getTrusted(trustedContext, value) : $sce.valueOf(value); }; return extend(function interpolationFn(context) { var i = 0; var ii = expressions.length; var values = new Array(ii); try { for (; i < ii; i++) { values[i] = parseFns[i](context); } return compute(values); } catch (err) { $exceptionHandler($interpolateMinErr.interr(text, err)); } }, { // all of these properties are undocumented for now exp: text, //just for compatibility with regular watchers created via $watch expressions: expressions, $$watchDelegate: function(scope, listener) { var lastValue; return scope.$watchGroup(parseFns, /** @this */ function interpolateFnWatcher(values, oldValues) { var currValue = compute(values); if (isFunction(listener)) { listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope); } lastValue = currValue; }); } }); } function parseStringifyInterceptor(value) { try { value = getValue(value); return allOrNothing && !isDefined(value) ? value : stringify(value); } catch (err) { $exceptionHandler($interpolateMinErr.interr(text, err)); } } } /** * @ngdoc method * @name $interpolate#startSymbol * @description * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`. * * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change * the symbol. * * @returns {string} start symbol. */ $interpolate.startSymbol = function() { return startSymbol; }; /** * @ngdoc method * @name $interpolate#endSymbol * @description * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. * * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change * the symbol. * * @returns {string} end symbol. */ $interpolate.endSymbol = function() { return endSymbol; }; return $interpolate; }]; } /** @this */ function $IntervalProvider() { this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser', function($rootScope, $window, $q, $$q, $browser) { var intervals = {}; /** * @ngdoc service * @name $interval * * @description * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay` * milliseconds. * * The return value of registering an interval function is a promise. This promise will be * notified upon each tick of the interval, and will be resolved after `count` iterations, or * run indefinitely if `count` is not defined. The value of the notification will be the * number of iterations that have run. * To cancel an interval, call `$interval.cancel(promise)`. * * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to * move forward by `millis` milliseconds and trigger any functions scheduled to run in that * time. * *
* **Note**: Intervals created by this service must be explicitly destroyed when you are finished * with them. In particular they are not automatically destroyed when a controller's scope or a * directive's element are destroyed. * You should take this into consideration and make sure to always cancel the interval at the * appropriate moment. See the example below for more details on how and when to do this. *
* * @param {function()} fn A function that should be called repeatedly. If no additional arguments * are passed (see below), the function is called with the current iteration count. * @param {number} delay Number of milliseconds between each function call. * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat * indefinitely. * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. * @param {...*=} Pass additional parameters to the executed function. * @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete. * * @example * * * * *
*
*
* Current time is: *
* Blood 1 : {{blood_1}} * Blood 2 : {{blood_2}} * * * *
*
* *
*
*/ function interval(fn, delay, count, invokeApply) { var hasParams = arguments.length > 4, args = hasParams ? sliceArgs(arguments, 4) : [], setInterval = $window.setInterval, clearInterval = $window.clearInterval, iteration = 0, skipApply = (isDefined(invokeApply) && !invokeApply), deferred = (skipApply ? $$q : $q).defer(), promise = deferred.promise; count = isDefined(count) ? count : 0; promise.$$intervalId = setInterval(function tick() { if (skipApply) { $browser.defer(callback); } else { $rootScope.$evalAsync(callback); } deferred.notify(iteration++); if (count > 0 && iteration >= count) { deferred.resolve(iteration); clearInterval(promise.$$intervalId); delete intervals[promise.$$intervalId]; } if (!skipApply) $rootScope.$apply(); }, delay); intervals[promise.$$intervalId] = deferred; return promise; function callback() { if (!hasParams) { fn(iteration); } else { fn.apply(null, args); } } } /** * @ngdoc method * @name $interval#cancel * * @description * Cancels a task associated with the `promise`. * * @param {Promise=} promise returned by the `$interval` function. * @returns {boolean} Returns `true` if the task was successfully canceled. */ interval.cancel = function(promise) { if (promise && promise.$$intervalId in intervals) { // Interval cancels should not report as unhandled promise. markQExceptionHandled(intervals[promise.$$intervalId].promise); intervals[promise.$$intervalId].reject('canceled'); $window.clearInterval(promise.$$intervalId); delete intervals[promise.$$intervalId]; return true; } return false; }; return interval; }]; } /** * @ngdoc service * @name $jsonpCallbacks * @requires $window * @description * This service handles the lifecycle of callbacks to handle JSONP requests. * Override this service if you wish to customise where the callbacks are stored and * how they vary compared to the requested url. */ var $jsonpCallbacksProvider = /** @this */ function() { this.$get = function() { var callbacks = angular.callbacks; var callbackMap = {}; function createCallback(callbackId) { var callback = function(data) { callback.data = data; callback.called = true; }; callback.id = callbackId; return callback; } return { /** * @ngdoc method * @name $jsonpCallbacks#createCallback * @param {string} url the url of the JSONP request * @returns {string} the callback path to send to the server as part of the JSONP request * @description * {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback * to pass to the server, which will be used to call the callback with its payload in the JSONP response. */ createCallback: function(url) { var callbackId = '_' + (callbacks.$$counter++).toString(36); var callbackPath = 'angular.callbacks.' + callbackId; var callback = createCallback(callbackId); callbackMap[callbackPath] = callbacks[callbackId] = callback; return callbackPath; }, /** * @ngdoc method * @name $jsonpCallbacks#wasCalled * @param {string} callbackPath the path to the callback that was sent in the JSONP request * @returns {boolean} whether the callback has been called, as a result of the JSONP response * @description * {@link $httpBackend} calls this method to find out whether the JSONP response actually called the * callback that was passed in the request. */ wasCalled: function(callbackPath) { return callbackMap[callbackPath].called; }, /** * @ngdoc method * @name $jsonpCallbacks#getResponse * @param {string} callbackPath the path to the callback that was sent in the JSONP request * @returns {*} the data received from the response via the registered callback * @description * {@link $httpBackend} calls this method to get hold of the data that was provided to the callback * in the JSONP response. */ getResponse: function(callbackPath) { return callbackMap[callbackPath].data; }, /** * @ngdoc method * @name $jsonpCallbacks#removeCallback * @param {string} callbackPath the path to the callback that was sent in the JSONP request * @description * {@link $httpBackend} calls this method to remove the callback after the JSONP request has * completed or timed-out. */ removeCallback: function(callbackPath) { var callback = callbackMap[callbackPath]; delete callbacks[callback.id]; delete callbackMap[callbackPath]; } }; }; }; /** * @ngdoc service * @name $locale * * @description * $locale service provides localization rules for various Angular components. As of right now the * only public api is: * * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) */ var PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/, DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; var $locationMinErr = minErr('$location'); /** * Encode path using encodeUriSegment, ignoring forward slashes * * @param {string} path Path to encode * @returns {string} */ function encodePath(path) { var segments = path.split('/'), i = segments.length; while (i--) { segments[i] = encodeUriSegment(segments[i]); } return segments.join('/'); } function parseAbsoluteUrl(absoluteUrl, locationObj) { var parsedUrl = urlResolve(absoluteUrl); locationObj.$$protocol = parsedUrl.protocol; locationObj.$$host = parsedUrl.hostname; locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null; } var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/; function parseAppUrl(url, locationObj) { if (DOUBLE_SLASH_REGEX.test(url)) { throw $locationMinErr('badpath', 'Invalid url "{0}".', url); } var prefixed = (url.charAt(0) !== '/'); if (prefixed) { url = '/' + url; } var match = urlResolve(url); locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname); locationObj.$$search = parseKeyValue(match.search); locationObj.$$hash = decodeURIComponent(match.hash); // make sure path starts with '/'; if (locationObj.$$path && locationObj.$$path.charAt(0) !== '/') { locationObj.$$path = '/' + locationObj.$$path; } } function startsWith(str, search) { return str.slice(0, search.length) === search; } /** * * @param {string} base * @param {string} url * @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with * the expected string. */ function stripBaseUrl(base, url) { if (startsWith(url, base)) { return url.substr(base.length); } } function stripHash(url) { var index = url.indexOf('#'); return index === -1 ? url : url.substr(0, index); } function trimEmptyHash(url) { return url.replace(/(#.+)|#$/, '$1'); } function stripFile(url) { return url.substr(0, stripHash(url).lastIndexOf('/') + 1); } /* return the server only (scheme://host:port) */ function serverBase(url) { return url.substring(0, url.indexOf('/', url.indexOf('//') + 2)); } /** * LocationHtml5Url represents a URL * This object is exposed as $location service when HTML5 mode is enabled and supported * * @constructor * @param {string} appBase application base URL * @param {string} appBaseNoFile application base URL stripped of any filename * @param {string} basePrefix URL path prefix */ function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) { this.$$html5 = true; basePrefix = basePrefix || ''; parseAbsoluteUrl(appBase, this); /** * Parse given HTML5 (regular) URL string into properties * @param {string} url HTML5 URL * @private */ this.$$parse = function(url) { var pathUrl = stripBaseUrl(appBaseNoFile, url); if (!isString(pathUrl)) { throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url, appBaseNoFile); } parseAppUrl(pathUrl, this); if (!this.$$path) { this.$$path = '/'; } this.$$compose(); }; /** * Compose url and update `absUrl` property * @private */ this.$$compose = function() { var search = toKeyValue(this.$$search), hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/' this.$$urlUpdatedByLocation = true; }; this.$$parseLinkUrl = function(url, relHref) { if (relHref && relHref[0] === '#') { // special case for links to hash fragments: // keep the old url and only replace the hash fragment this.hash(relHref.slice(1)); return true; } var appUrl, prevAppUrl; var rewrittenUrl; if (isDefined(appUrl = stripBaseUrl(appBase, url))) { prevAppUrl = appUrl; if (basePrefix && isDefined(appUrl = stripBaseUrl(basePrefix, appUrl))) { rewrittenUrl = appBaseNoFile + (stripBaseUrl('/', appUrl) || appUrl); } else { rewrittenUrl = appBase + prevAppUrl; } } else if (isDefined(appUrl = stripBaseUrl(appBaseNoFile, url))) { rewrittenUrl = appBaseNoFile + appUrl; } else if (appBaseNoFile === url + '/') { rewrittenUrl = appBaseNoFile; } if (rewrittenUrl) { this.$$parse(rewrittenUrl); } return !!rewrittenUrl; }; } /** * LocationHashbangUrl represents URL * This object is exposed as $location service when developer doesn't opt into html5 mode. * It also serves as the base class for html5 mode fallback on legacy browsers. * * @constructor * @param {string} appBase application base URL * @param {string} appBaseNoFile application base URL stripped of any filename * @param {string} hashPrefix hashbang prefix */ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) { parseAbsoluteUrl(appBase, this); /** * Parse given hashbang URL into properties * @param {string} url Hashbang URL * @private */ this.$$parse = function(url) { var withoutBaseUrl = stripBaseUrl(appBase, url) || stripBaseUrl(appBaseNoFile, url); var withoutHashUrl; if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') { // The rest of the URL starts with a hash so we have // got either a hashbang path or a plain hash fragment withoutHashUrl = stripBaseUrl(hashPrefix, withoutBaseUrl); if (isUndefined(withoutHashUrl)) { // There was no hashbang prefix so we just have a hash fragment withoutHashUrl = withoutBaseUrl; } } else { // There was no hashbang path nor hash fragment: // If we are in HTML5 mode we use what is left as the path; // Otherwise we ignore what is left if (this.$$html5) { withoutHashUrl = withoutBaseUrl; } else { withoutHashUrl = ''; if (isUndefined(withoutBaseUrl)) { appBase = url; /** @type {?} */ (this).replace(); } } } parseAppUrl(withoutHashUrl, this); this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); this.$$compose(); /* * In Windows, on an anchor node on documents loaded from * the filesystem, the browser will return a pathname * prefixed with the drive name ('/C:/path') when a * pathname without a drive is set: * * a.setAttribute('href', '/foo') * * a.pathname === '/C:/foo' //true * * Inside of Angular, we're always using pathnames that * do not include drive names for routing. */ function removeWindowsDriveName(path, url, base) { /* Matches paths for file protocol on windows, such as /C:/foo/bar, and captures only /foo/bar. */ var windowsFilePathExp = /^\/[A-Z]:(\/.*)/; var firstPathSegmentMatch; //Get the relative path from the input URL. if (startsWith(url, base)) { url = url.replace(base, ''); } // The input URL intentionally contains a first path segment that ends with a colon. if (windowsFilePathExp.exec(url)) { return path; } firstPathSegmentMatch = windowsFilePathExp.exec(path); return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path; } }; /** * Compose hashbang URL and update `absUrl` property * @private */ this.$$compose = function() { var search = toKeyValue(this.$$search), hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : ''); this.$$urlUpdatedByLocation = true; }; this.$$parseLinkUrl = function(url, relHref) { if (stripHash(appBase) === stripHash(url)) { this.$$parse(url); return true; } return false; }; } /** * LocationHashbangUrl represents URL * This object is exposed as $location service when html5 history api is enabled but the browser * does not support it. * * @constructor * @param {string} appBase application base URL * @param {string} appBaseNoFile application base URL stripped of any filename * @param {string} hashPrefix hashbang prefix */ function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) { this.$$html5 = true; LocationHashbangUrl.apply(this, arguments); this.$$parseLinkUrl = function(url, relHref) { if (relHref && relHref[0] === '#') { // special case for links to hash fragments: // keep the old url and only replace the hash fragment this.hash(relHref.slice(1)); return true; } var rewrittenUrl; var appUrl; if (appBase === stripHash(url)) { rewrittenUrl = url; } else if ((appUrl = stripBaseUrl(appBaseNoFile, url))) { rewrittenUrl = appBase + hashPrefix + appUrl; } else if (appBaseNoFile === url + '/') { rewrittenUrl = appBaseNoFile; } if (rewrittenUrl) { this.$$parse(rewrittenUrl); } return !!rewrittenUrl; }; this.$$compose = function() { var search = toKeyValue(this.$$search), hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#' this.$$absUrl = appBase + hashPrefix + this.$$url; this.$$urlUpdatedByLocation = true; }; } var locationPrototype = { /** * Ensure absolute URL is initialized. * @private */ $$absUrl:'', /** * Are we in html5 mode? * @private */ $$html5: false, /** * Has any change been replacing? * @private */ $$replace: false, /** * @ngdoc method * @name $location#absUrl * * @description * This method is getter only. * * Return full URL representation with all segments encoded according to rules specified in * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt). * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo * var absUrl = $location.absUrl(); * // => "http://example.com/#/some/path?foo=bar&baz=xoxo" * ``` * * @return {string} full URL */ absUrl: locationGetter('$$absUrl'), /** * @ngdoc method * @name $location#url * * @description * This method is getter / setter. * * Return URL (e.g. `/path?a=b#hash`) when called without any parameter. * * Change path, search and hash, when called with parameter and return `$location`. * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo * var url = $location.url(); * // => "/some/path?foo=bar&baz=xoxo" * ``` * * @param {string=} url New URL without base prefix (e.g. `/path?a=b#hash`) * @return {string} url */ url: function(url) { if (isUndefined(url)) { return this.$$url; } var match = PATH_MATCH.exec(url); if (match[1] || url === '') this.path(decodeURIComponent(match[1])); if (match[2] || match[1] || url === '') this.search(match[3] || ''); this.hash(match[5] || ''); return this; }, /** * @ngdoc method * @name $location#protocol * * @description * This method is getter only. * * Return protocol of current URL. * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo * var protocol = $location.protocol(); * // => "http" * ``` * * @return {string} protocol of current URL */ protocol: locationGetter('$$protocol'), /** * @ngdoc method * @name $location#host * * @description * This method is getter only. * * Return host of current URL. * * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only. * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo * var host = $location.host(); * // => "example.com" * * // given URL http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo * host = $location.host(); * // => "example.com" * host = location.host; * // => "example.com:8080" * ``` * * @return {string} host of current URL. */ host: locationGetter('$$host'), /** * @ngdoc method * @name $location#port * * @description * This method is getter only. * * Return port of current URL. * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo * var port = $location.port(); * // => 80 * ``` * * @return {Number} port */ port: locationGetter('$$port'), /** * @ngdoc method * @name $location#path * * @description * This method is getter / setter. * * Return path of current URL when called without any parameter. * * Change path when called with parameter and return `$location`. * * Note: Path should always begin with forward slash (/), this method will add the forward slash * if it is missing. * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo * var path = $location.path(); * // => "/some/path" * ``` * * @param {(string|number)=} path New path * @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter */ path: locationGetterSetter('$$path', function(path) { path = path !== null ? path.toString() : ''; return path.charAt(0) === '/' ? path : '/' + path; }), /** * @ngdoc method * @name $location#search * * @description * This method is getter / setter. * * Return search part (as object) of current URL when called without any parameter. * * Change search part when called with parameter and return `$location`. * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo * var searchObject = $location.search(); * // => {foo: 'bar', baz: 'xoxo'} * * // set foo to 'yipee' * $location.search('foo', 'yipee'); * // $location.search() => {foo: 'yipee', baz: 'xoxo'} * ``` * * @param {string|Object.|Object.>} search New search params - string or * hash object. * * When called with a single argument the method acts as a setter, setting the `search` component * of `$location` to the specified value. * * If the argument is a hash object containing an array of values, these values will be encoded * as duplicate search parameters in the URL. * * @param {(string|Number|Array|boolean)=} paramValue If `search` is a string or number, then `paramValue` * will override only a single search property. * * If `paramValue` is an array, it will override the property of the `search` component of * `$location` specified via the first argument. * * If `paramValue` is `null`, the property specified via the first argument will be deleted. * * If `paramValue` is `true`, the property specified via the first argument will be added with no * value nor trailing equal sign. * * @return {Object} If called with no arguments returns the parsed `search` object. If called with * one or more arguments returns `$location` object itself. */ search: function(search, paramValue) { switch (arguments.length) { case 0: return this.$$search; case 1: if (isString(search) || isNumber(search)) { search = search.toString(); this.$$search = parseKeyValue(search); } else if (isObject(search)) { search = copy(search, {}); // remove object undefined or null properties forEach(search, function(value, key) { if (value == null) delete search[key]; }); this.$$search = search; } else { throw $locationMinErr('isrcharg', 'The first argument of the `$location#search()` call must be a string or an object.'); } break; default: if (isUndefined(paramValue) || paramValue === null) { delete this.$$search[search]; } else { this.$$search[search] = paramValue; } } this.$$compose(); return this; }, /** * @ngdoc method * @name $location#hash * * @description * This method is getter / setter. * * Returns the hash fragment when called without any parameters. * * Changes the hash fragment when called with a parameter and returns `$location`. * * * ```js * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue * var hash = $location.hash(); * // => "hashValue" * ``` * * @param {(string|number)=} hash New hash fragment * @return {string} hash */ hash: locationGetterSetter('$$hash', function(hash) { return hash !== null ? hash.toString() : ''; }), /** * @ngdoc method * @name $location#replace * * @description * If called, all changes to $location during the current `$digest` will replace the current history * record, instead of adding a new one. */ replace: function() { this.$$replace = true; return this; } }; forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) { Location.prototype = Object.create(locationPrototype); /** * @ngdoc method * @name $location#state * * @description * This method is getter / setter. * * Return the history state object when called without any parameter. * * Change the history state object when called with one parameter and return `$location`. * The state object is later passed to `pushState` or `replaceState`. * * NOTE: This method is supported only in HTML5 mode and only in browsers supporting * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support * older browsers (like IE9 or Android < 4.0), don't use this method. * * @param {object=} state State object for pushState or replaceState * @return {object} state */ Location.prototype.state = function(state) { if (!arguments.length) { return this.$$state; } if (Location !== LocationHtml5Url || !this.$$html5) { throw $locationMinErr('nostate', 'History API state support is available only ' + 'in HTML5 mode and only in browsers supporting HTML5 History API'); } // The user might modify `stateObject` after invoking `$location.state(stateObject)` // but we're changing the $$state reference to $browser.state() during the $digest // so the modification window is narrow. this.$$state = isUndefined(state) ? null : state; this.$$urlUpdatedByLocation = true; return this; }; }); function locationGetter(property) { return /** @this */ function() { return this[property]; }; } function locationGetterSetter(property, preprocess) { return /** @this */ function(value) { if (isUndefined(value)) { return this[property]; } this[property] = preprocess(value); this.$$compose(); return this; }; } /** * @ngdoc service * @name $location * * @requires $rootElement * * @description * The $location service parses the URL in the browser address bar (based on the * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL * available to your application. Changes to the URL in the address bar are reflected into * $location service and changes to $location are reflected into the browser address bar. * * **The $location service:** * * - Exposes the current URL in the browser address bar, so you can * - Watch and observe the URL. * - Change the URL. * - Synchronizes the URL with the browser when the user * - Changes the address bar. * - Clicks the back or forward button (or clicks a History link). * - Clicks on a link. * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash). * * For more information see {@link guide/$location Developer Guide: Using $location} */ /** * @ngdoc provider * @name $locationProvider * @this * * @description * Use the `$locationProvider` to configure how the application deep linking paths are stored. */ function $LocationProvider() { var hashPrefix = '!', html5Mode = { enabled: false, requireBase: true, rewriteLinks: true }; /** * @ngdoc method * @name $locationProvider#hashPrefix * @description * The default value for the prefix is `'!'`. * @param {string=} prefix Prefix for hash part (containing path and search) * @returns {*} current value if used as getter or itself (chaining) if used as setter */ this.hashPrefix = function(prefix) { if (isDefined(prefix)) { hashPrefix = prefix; return this; } else { return hashPrefix; } }; /** * @ngdoc method * @name $locationProvider#html5Mode * @description * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value. * If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported * properties: * - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to * change urls where supported. Will fall back to hash-prefixed paths in browsers that do not * support `pushState`. * - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies * whether or not a tag is required to be present. If `enabled` and `requireBase` are * true, and a base tag is not present, an error will be thrown when `$location` is injected. * See the {@link guide/$location $location guide for more information} * - **rewriteLinks** - `{boolean|string}` - (default: `true`) When html5Mode is enabled, * enables/disables URL rewriting for relative links. If set to a string, URL rewriting will * only happen on links with an attribute that matches the given string. For example, if set * to `'internal-link'`, then the URL will only be rewritten for `` links. * Note that [attribute name normalization](guide/directive#normalization) does not apply * here, so `'internalLink'` will **not** match `'internal-link'`. * * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter */ this.html5Mode = function(mode) { if (isBoolean(mode)) { html5Mode.enabled = mode; return this; } else if (isObject(mode)) { if (isBoolean(mode.enabled)) { html5Mode.enabled = mode.enabled; } if (isBoolean(mode.requireBase)) { html5Mode.requireBase = mode.requireBase; } if (isBoolean(mode.rewriteLinks) || isString(mode.rewriteLinks)) { html5Mode.rewriteLinks = mode.rewriteLinks; } return this; } else { return html5Mode; } }; /** * @ngdoc event * @name $location#$locationChangeStart * @eventType broadcast on root scope * @description * Broadcasted before a URL will change. * * This change can be prevented by calling * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more * details about event object. Upon successful change * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired. * * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when * the browser supports the HTML5 History API. * * @param {Object} angularEvent Synthetic event object. * @param {string} newUrl New URL * @param {string=} oldUrl URL that was before it was changed. * @param {string=} newState New history state object * @param {string=} oldState History state object that was before it was changed. */ /** * @ngdoc event * @name $location#$locationChangeSuccess * @eventType broadcast on root scope * @description * Broadcasted after a URL was changed. * * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when * the browser supports the HTML5 History API. * * @param {Object} angularEvent Synthetic event object. * @param {string} newUrl New URL * @param {string=} oldUrl URL that was before it was changed. * @param {string=} newState New history state object * @param {string=} oldState History state object that was before it was changed. */ this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window', function($rootScope, $browser, $sniffer, $rootElement, $window) { var $location, LocationMode, baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to '' initialUrl = $browser.url(), appBase; if (html5Mode.enabled) { if (!baseHref && html5Mode.requireBase) { throw $locationMinErr('nobase', '$location in HTML5 mode requires a tag to be present!'); } appBase = serverBase(initialUrl) + (baseHref || '/'); LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url; } else { appBase = stripHash(initialUrl); LocationMode = LocationHashbangUrl; } var appBaseNoFile = stripFile(appBase); $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix); $location.$$parseLinkUrl(initialUrl, initialUrl); $location.$$state = $browser.state(); var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i; function setBrowserUrlWithFallback(url, replace, state) { var oldUrl = $location.url(); var oldState = $location.$$state; try { $browser.url(url, replace, state); // Make sure $location.state() returns referentially identical (not just deeply equal) // state object; this makes possible quick checking if the state changed in the digest // loop. Checking deep equality would be too expensive. $location.$$state = $browser.state(); } catch (e) { // Restore old values if pushState fails $location.url(oldUrl); $location.$$state = oldState; throw e; } } $rootElement.on('click', function(event) { var rewriteLinks = html5Mode.rewriteLinks; // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser) // currently we open nice url link and redirect then if (!rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 || event.button === 2) return; var elm = jqLite(event.target); // traverse the DOM up to find first A tag while (nodeName_(elm[0]) !== 'a') { // ignore rewriting if no A tag (reached root element, or no parent - removed from document) if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return; } if (isString(rewriteLinks) && isUndefined(elm.attr(rewriteLinks))) return; var absHref = elm.prop('href'); // get the actual href attribute - see // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx var relHref = elm.attr('href') || elm.attr('xlink:href'); if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') { // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during // an animation. absHref = urlResolve(absHref.animVal).href; } // Ignore when url is started with javascript: or mailto: if (IGNORE_URI_REGEXP.test(absHref)) return; if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) { if ($location.$$parseLinkUrl(absHref, relHref)) { // We do a preventDefault for all urls that are part of the angular application, // in html5mode and also without, so that we are able to abort navigation without // getting double entries in the location history. event.preventDefault(); // update location manually if ($location.absUrl() !== $browser.url()) { $rootScope.$apply(); // hack to work around FF6 bug 684208 when scenario runner clicks on links $window.angular['ff-684208-preventDefault'] = true; } } } }); // rewrite hashbang url <> html5 url if (trimEmptyHash($location.absUrl()) !== trimEmptyHash(initialUrl)) { $browser.url($location.absUrl(), true); } var initializing = true; // update $location when $browser url changes $browser.onUrlChange(function(newUrl, newState) { if (!startsWith(newUrl, appBaseNoFile)) { // If we are navigating outside of the app then force a reload $window.location.href = newUrl; return; } $rootScope.$evalAsync(function() { var oldUrl = $location.absUrl(); var oldState = $location.$$state; var defaultPrevented; newUrl = trimEmptyHash(newUrl); $location.$$parse(newUrl); $location.$$state = newState; defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, newState, oldState).defaultPrevented; // if the location was changed by a `$locationChangeStart` handler then stop // processing this location change if ($location.absUrl() !== newUrl) return; if (defaultPrevented) { $location.$$parse(oldUrl); $location.$$state = oldState; setBrowserUrlWithFallback(oldUrl, false, oldState); } else { initializing = false; afterLocationChange(oldUrl, oldState); } }); if (!$rootScope.$$phase) $rootScope.$digest(); }); // update browser $rootScope.$watch(function $locationWatch() { if (initializing || $location.$$urlUpdatedByLocation) { $location.$$urlUpdatedByLocation = false; var oldUrl = trimEmptyHash($browser.url()); var newUrl = trimEmptyHash($location.absUrl()); var oldState = $browser.state(); var currentReplace = $location.$$replace; var urlOrStateChanged = oldUrl !== newUrl || ($location.$$html5 && $sniffer.history && oldState !== $location.$$state); if (initializing || urlOrStateChanged) { initializing = false; $rootScope.$evalAsync(function() { var newUrl = $location.absUrl(); var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, $location.$$state, oldState).defaultPrevented; // if the location was changed by a `$locationChangeStart` handler then stop // processing this location change if ($location.absUrl() !== newUrl) return; if (defaultPrevented) { $location.$$parse(oldUrl); $location.$$state = oldState; } else { if (urlOrStateChanged) { setBrowserUrlWithFallback(newUrl, currentReplace, oldState === $location.$$state ? null : $location.$$state); } afterLocationChange(oldUrl, oldState); } }); } } $location.$$replace = false; // we don't need to return anything because $evalAsync will make the digest loop dirty when // there is a change }); return $location; function afterLocationChange(oldUrl, oldState) { $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl, $location.$$state, oldState); } }]; } /** * @ngdoc service * @name $log * @requires $window * * @description * Simple service for logging. Default implementation safely writes the message * into the browser's console (if present). * * The main purpose of this service is to simplify debugging and troubleshooting. * * To reveal the location of the calls to `$log` in the JavaScript console, * you can "blackbox" the AngularJS source in your browser: * * [Mozilla description of blackboxing](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Black_box_a_source). * [Chrome description of blackboxing](https://developer.chrome.com/devtools/docs/blackboxing). * * Note: Not all browsers support blackboxing. * * The default is to log `debug` messages. You can use * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this. * * @example angular.module('logExample', []) .controller('LogController', ['$scope', '$log', function($scope, $log) { $scope.$log = $log; $scope.message = 'Hello World!'; }]);

Reload this page with open console, enter text and hit the log button...

*/ /** * @ngdoc provider * @name $logProvider * @this * * @description * Use the `$logProvider` to configure how the application logs messages */ function $LogProvider() { var debug = true, self = this; /** * @ngdoc method * @name $logProvider#debugEnabled * @description * @param {boolean=} flag enable or disable debug level messages * @returns {*} current value if used as getter or itself (chaining) if used as setter */ this.debugEnabled = function(flag) { if (isDefined(flag)) { debug = flag; return this; } else { return debug; } }; this.$get = ['$window', function($window) { // Support: IE 9-11, Edge 12-14+ // IE/Edge display errors in such a way that it requires the user to click in 4 places // to see the stack trace. There is no way to feature-detect it so there's a chance // of the user agent sniffing to go wrong but since it's only about logging, this shouldn't // break apps. Other browsers display errors in a sensible way and some of them map stack // traces along source maps if available so it makes sense to let browsers display it // as they want. var formatStackTrace = msie || /\bEdge\//.test($window.navigator && $window.navigator.userAgent); return { /** * @ngdoc method * @name $log#log * * @description * Write a log message */ log: consoleLog('log'), /** * @ngdoc method * @name $log#info * * @description * Write an information message */ info: consoleLog('info'), /** * @ngdoc method * @name $log#warn * * @description * Write a warning message */ warn: consoleLog('warn'), /** * @ngdoc method * @name $log#error * * @description * Write an error message */ error: consoleLog('error'), /** * @ngdoc method * @name $log#debug * * @description * Write a debug message */ debug: (function() { var fn = consoleLog('debug'); return function() { if (debug) { fn.apply(self, arguments); } }; })() }; function formatError(arg) { if (isError(arg)) { if (arg.stack && formatStackTrace) { arg = (arg.message && arg.stack.indexOf(arg.message) === -1) ? 'Error: ' + arg.message + '\n' + arg.stack : arg.stack; } else if (arg.sourceURL) { arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line; } } return arg; } function consoleLog(type) { var console = $window.console || {}, logFn = console[type] || console.log || noop; return function() { var args = []; forEach(arguments, function(arg) { args.push(formatError(arg)); }); // Support: IE 9 only // console methods don't inherit from Function.prototype in IE 9 so we can't // call `logFn.apply(console, args)` directly. return Function.prototype.apply.call(logFn, console, args); }; } }]; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Any commits to this file should be reviewed with security in mind. * * Changes to this file can potentially create security vulnerabilities. * * An approval from 2 Core members with history of modifying * * this file is required. * * * * Does the change somehow allow for arbitrary javascript to be executed? * * Or allows for someone to change the prototype of built-in objects? * * Or gives undesired access to variables likes document or window? * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var $parseMinErr = minErr('$parse'); var objectValueOf = {}.constructor.prototype.valueOf; // Sandboxing Angular Expressions // ------------------------------ // Angular expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by // various means such as obtaining a reference to native JS functions like the Function constructor. // // As an example, consider the following Angular expression: // // {}.toString.constructor('alert("evil JS code")') // // It is important to realize that if you create an expression from a string that contains user provided // content then it is possible that your application contains a security vulnerability to an XSS style attack. // // See https://docs.angularjs.org/guide/security function getStringValue(name) { // Property names must be strings. This means that non-string objects cannot be used // as keys in an object. Any non-string object, including a number, is typecasted // into a string via the toString method. // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names // // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it // to a string. It's not always possible. If `name` is an object and its `toString` method is // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown: // // TypeError: Cannot convert object to primitive value // // For performance reasons, we don't catch this error here and allow it to propagate up the call // stack. Note that you'll get the same error in JavaScript if you try to access a property using // such a 'broken' object as a key. return name + ''; } var OPERATORS = createMap(); forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; }); var ESCAPE = {'n':'\n', 'f':'\f', 'r':'\r', 't':'\t', 'v':'\v', '\'':'\'', '"':'"'}; ///////////////////////////////////////// /** * @constructor */ var Lexer = function Lexer(options) { this.options = options; }; Lexer.prototype = { constructor: Lexer, lex: function(text) { this.text = text; this.index = 0; this.tokens = []; while (this.index < this.text.length) { var ch = this.text.charAt(this.index); if (ch === '"' || ch === '\'') { this.readString(ch); } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) { this.readNumber(); } else if (this.isIdentifierStart(this.peekMultichar())) { this.readIdent(); } else if (this.is(ch, '(){}[].,;:?')) { this.tokens.push({index: this.index, text: ch}); this.index++; } else if (this.isWhitespace(ch)) { this.index++; } else { var ch2 = ch + this.peek(); var ch3 = ch2 + this.peek(2); var op1 = OPERATORS[ch]; var op2 = OPERATORS[ch2]; var op3 = OPERATORS[ch3]; if (op1 || op2 || op3) { var token = op3 ? ch3 : (op2 ? ch2 : ch); this.tokens.push({index: this.index, text: token, operator: true}); this.index += token.length; } else { this.throwError('Unexpected next character ', this.index, this.index + 1); } } } return this.tokens; }, is: function(ch, chars) { return chars.indexOf(ch) !== -1; }, peek: function(i) { var num = i || 1; return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false; }, isNumber: function(ch) { return ('0' <= ch && ch <= '9') && typeof ch === 'string'; }, isWhitespace: function(ch) { // IE treats non-breaking space as \u00A0 return (ch === ' ' || ch === '\r' || ch === '\t' || ch === '\n' || ch === '\v' || ch === '\u00A0'); }, isIdentifierStart: function(ch) { return this.options.isIdentifierStart ? this.options.isIdentifierStart(ch, this.codePointAt(ch)) : this.isValidIdentifierStart(ch); }, isValidIdentifierStart: function(ch) { return ('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || '_' === ch || ch === '$'); }, isIdentifierContinue: function(ch) { return this.options.isIdentifierContinue ? this.options.isIdentifierContinue(ch, this.codePointAt(ch)) : this.isValidIdentifierContinue(ch); }, isValidIdentifierContinue: function(ch, cp) { return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch); }, codePointAt: function(ch) { if (ch.length === 1) return ch.charCodeAt(0); // eslint-disable-next-line no-bitwise return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00; }, peekMultichar: function() { var ch = this.text.charAt(this.index); var peek = this.peek(); if (!peek) { return ch; } var cp1 = ch.charCodeAt(0); var cp2 = peek.charCodeAt(0); if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) { return ch + peek; } return ch; }, isExpOperator: function(ch) { return (ch === '-' || ch === '+' || this.isNumber(ch)); }, throwError: function(error, start, end) { end = end || this.index; var colStr = (isDefined(start) ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']' : ' ' + end); throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].', error, colStr, this.text); }, readNumber: function() { var number = ''; var start = this.index; while (this.index < this.text.length) { var ch = lowercase(this.text.charAt(this.index)); if (ch === '.' || this.isNumber(ch)) { number += ch; } else { var peekCh = this.peek(); if (ch === 'e' && this.isExpOperator(peekCh)) { number += ch; } else if (this.isExpOperator(ch) && peekCh && this.isNumber(peekCh) && number.charAt(number.length - 1) === 'e') { number += ch; } else if (this.isExpOperator(ch) && (!peekCh || !this.isNumber(peekCh)) && number.charAt(number.length - 1) === 'e') { this.throwError('Invalid exponent'); } else { break; } } this.index++; } this.tokens.push({ index: start, text: number, constant: true, value: Number(number) }); }, readIdent: function() { var start = this.index; this.index += this.peekMultichar().length; while (this.index < this.text.length) { var ch = this.peekMultichar(); if (!this.isIdentifierContinue(ch)) { break; } this.index += ch.length; } this.tokens.push({ index: start, text: this.text.slice(start, this.index), identifier: true }); }, readString: function(quote) { var start = this.index; this.index++; var string = ''; var rawString = quote; var escape = false; while (this.index < this.text.length) { var ch = this.text.charAt(this.index); rawString += ch; if (escape) { if (ch === 'u') { var hex = this.text.substring(this.index + 1, this.index + 5); if (!hex.match(/[\da-f]{4}/i)) { this.throwError('Invalid unicode escape [\\u' + hex + ']'); } this.index += 4; string += String.fromCharCode(parseInt(hex, 16)); } else { var rep = ESCAPE[ch]; string = string + (rep || ch); } escape = false; } else if (ch === '\\') { escape = true; } else if (ch === quote) { this.index++; this.tokens.push({ index: start, text: rawString, constant: true, value: string }); return; } else { string += ch; } this.index++; } this.throwError('Unterminated quote', start); } }; var AST = function AST(lexer, options) { this.lexer = lexer; this.options = options; }; AST.Program = 'Program'; AST.ExpressionStatement = 'ExpressionStatement'; AST.AssignmentExpression = 'AssignmentExpression'; AST.ConditionalExpression = 'ConditionalExpression'; AST.LogicalExpression = 'LogicalExpression'; AST.BinaryExpression = 'BinaryExpression'; AST.UnaryExpression = 'UnaryExpression'; AST.CallExpression = 'CallExpression'; AST.MemberExpression = 'MemberExpression'; AST.Identifier = 'Identifier'; AST.Literal = 'Literal'; AST.ArrayExpression = 'ArrayExpression'; AST.Property = 'Property'; AST.ObjectExpression = 'ObjectExpression'; AST.ThisExpression = 'ThisExpression'; AST.LocalsExpression = 'LocalsExpression'; // Internal use only AST.NGValueParameter = 'NGValueParameter'; AST.prototype = { ast: function(text) { this.text = text; this.tokens = this.lexer.lex(text); var value = this.program(); if (this.tokens.length !== 0) { this.throwError('is an unexpected token', this.tokens[0]); } return value; }, program: function() { var body = []; while (true) { if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']')) body.push(this.expressionStatement()); if (!this.expect(';')) { return { type: AST.Program, body: body}; } } }, expressionStatement: function() { return { type: AST.ExpressionStatement, expression: this.filterChain() }; }, filterChain: function() { var left = this.expression(); while (this.expect('|')) { left = this.filter(left); } return left; }, expression: function() { return this.assignment(); }, assignment: function() { var result = this.ternary(); if (this.expect('=')) { if (!isAssignable(result)) { throw $parseMinErr('lval', 'Trying to assign a value to a non l-value'); } result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='}; } return result; }, ternary: function() { var test = this.logicalOR(); var alternate; var consequent; if (this.expect('?')) { alternate = this.expression(); if (this.consume(':')) { consequent = this.expression(); return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent}; } } return test; }, logicalOR: function() { var left = this.logicalAND(); while (this.expect('||')) { left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() }; } return left; }, logicalAND: function() { var left = this.equality(); while (this.expect('&&')) { left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()}; } return left; }, equality: function() { var left = this.relational(); var token; while ((token = this.expect('==','!=','===','!=='))) { left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() }; } return left; }, relational: function() { var left = this.additive(); var token; while ((token = this.expect('<', '>', '<=', '>='))) { left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() }; } return left; }, additive: function() { var left = this.multiplicative(); var token; while ((token = this.expect('+','-'))) { left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() }; } return left; }, multiplicative: function() { var left = this.unary(); var token; while ((token = this.expect('*','/','%'))) { left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() }; } return left; }, unary: function() { var token; if ((token = this.expect('+', '-', '!'))) { return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() }; } else { return this.primary(); } }, primary: function() { var primary; if (this.expect('(')) { primary = this.filterChain(); this.consume(')'); } else if (this.expect('[')) { primary = this.arrayDeclaration(); } else if (this.expect('{')) { primary = this.object(); } else if (this.selfReferential.hasOwnProperty(this.peek().text)) { primary = copy(this.selfReferential[this.consume().text]); } else if (this.options.literals.hasOwnProperty(this.peek().text)) { primary = { type: AST.Literal, value: this.options.literals[this.consume().text]}; } else if (this.peek().identifier) { primary = this.identifier(); } else if (this.peek().constant) { primary = this.constant(); } else { this.throwError('not a primary expression', this.peek()); } var next; while ((next = this.expect('(', '[', '.'))) { if (next.text === '(') { primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() }; this.consume(')'); } else if (next.text === '[') { primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true }; this.consume(']'); } else if (next.text === '.') { primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false }; } else { this.throwError('IMPOSSIBLE'); } } return primary; }, filter: function(baseExpression) { var args = [baseExpression]; var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true}; while (this.expect(':')) { args.push(this.expression()); } return result; }, parseArguments: function() { var args = []; if (this.peekToken().text !== ')') { do { args.push(this.filterChain()); } while (this.expect(',')); } return args; }, identifier: function() { var token = this.consume(); if (!token.identifier) { this.throwError('is not a valid identifier', token); } return { type: AST.Identifier, name: token.text }; }, constant: function() { // TODO check that it is a constant return { type: AST.Literal, value: this.consume().value }; }, arrayDeclaration: function() { var elements = []; if (this.peekToken().text !== ']') { do { if (this.peek(']')) { // Support trailing commas per ES5.1. break; } elements.push(this.expression()); } while (this.expect(',')); } this.consume(']'); return { type: AST.ArrayExpression, elements: elements }; }, object: function() { var properties = [], property; if (this.peekToken().text !== '}') { do { if (this.peek('}')) { // Support trailing commas per ES5.1. break; } property = {type: AST.Property, kind: 'init'}; if (this.peek().constant) { property.key = this.constant(); property.computed = false; this.consume(':'); property.value = this.expression(); } else if (this.peek().identifier) { property.key = this.identifier(); property.computed = false; if (this.peek(':')) { this.consume(':'); property.value = this.expression(); } else { property.value = property.key; } } else if (this.peek('[')) { this.consume('['); property.key = this.expression(); this.consume(']'); property.computed = true; this.consume(':'); property.value = this.expression(); } else { this.throwError('invalid key', this.peek()); } properties.push(property); } while (this.expect(',')); } this.consume('}'); return {type: AST.ObjectExpression, properties: properties }; }, throwError: function(msg, token) { throw $parseMinErr('syntax', 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].', token.text, msg, (token.index + 1), this.text, this.text.substring(token.index)); }, consume: function(e1) { if (this.tokens.length === 0) { throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); } var token = this.expect(e1); if (!token) { this.throwError('is unexpected, expecting [' + e1 + ']', this.peek()); } return token; }, peekToken: function() { if (this.tokens.length === 0) { throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); } return this.tokens[0]; }, peek: function(e1, e2, e3, e4) { return this.peekAhead(0, e1, e2, e3, e4); }, peekAhead: function(i, e1, e2, e3, e4) { if (this.tokens.length > i) { var token = this.tokens[i]; var t = token.text; if (t === e1 || t === e2 || t === e3 || t === e4 || (!e1 && !e2 && !e3 && !e4)) { return token; } } return false; }, expect: function(e1, e2, e3, e4) { var token = this.peek(e1, e2, e3, e4); if (token) { this.tokens.shift(); return token; } return false; }, selfReferential: { 'this': {type: AST.ThisExpression }, '$locals': {type: AST.LocalsExpression } } }; function ifDefined(v, d) { return typeof v !== 'undefined' ? v : d; } function plusFn(l, r) { if (typeof l === 'undefined') return r; if (typeof r === 'undefined') return l; return l + r; } function isStateless($filter, filterName) { var fn = $filter(filterName); return !fn.$stateful; } var PURITY_ABSOLUTE = 1; var PURITY_RELATIVE = 2; // Detect nodes which could depend on non-shallow state of objects function isPure(node, parentIsPure) { switch (node.type) { // Computed members might invoke a stateful toString() case AST.MemberExpression: if (node.computed) { return false; } break; // Unary always convert to primative case AST.UnaryExpression: return PURITY_ABSOLUTE; // The binary + operator can invoke a stateful toString(). case AST.BinaryExpression: return node.operator !== '+' ? PURITY_ABSOLUTE : false; // Functions / filters probably read state from within objects case AST.CallExpression: return false; } return (undefined === parentIsPure) ? PURITY_RELATIVE : parentIsPure; } function findConstantAndWatchExpressions(ast, $filter, parentIsPure) { var allConstants; var argsToWatch; var isStatelessFilter; var astIsPure = ast.isPure = isPure(ast, parentIsPure); switch (ast.type) { case AST.Program: allConstants = true; forEach(ast.body, function(expr) { findConstantAndWatchExpressions(expr.expression, $filter, astIsPure); allConstants = allConstants && expr.expression.constant; }); ast.constant = allConstants; break; case AST.Literal: ast.constant = true; ast.toWatch = []; break; case AST.UnaryExpression: findConstantAndWatchExpressions(ast.argument, $filter, astIsPure); ast.constant = ast.argument.constant; ast.toWatch = ast.argument.toWatch; break; case AST.BinaryExpression: findConstantAndWatchExpressions(ast.left, $filter, astIsPure); findConstantAndWatchExpressions(ast.right, $filter, astIsPure); ast.constant = ast.left.constant && ast.right.constant; ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch); break; case AST.LogicalExpression: findConstantAndWatchExpressions(ast.left, $filter, astIsPure); findConstantAndWatchExpressions(ast.right, $filter, astIsPure); ast.constant = ast.left.constant && ast.right.constant; ast.toWatch = ast.constant ? [] : [ast]; break; case AST.ConditionalExpression: findConstantAndWatchExpressions(ast.test, $filter, astIsPure); findConstantAndWatchExpressions(ast.alternate, $filter, astIsPure); findConstantAndWatchExpressions(ast.consequent, $filter, astIsPure); ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant; ast.toWatch = ast.constant ? [] : [ast]; break; case AST.Identifier: ast.constant = false; ast.toWatch = [ast]; break; case AST.MemberExpression: findConstantAndWatchExpressions(ast.object, $filter, astIsPure); if (ast.computed) { findConstantAndWatchExpressions(ast.property, $filter, astIsPure); } ast.constant = ast.object.constant && (!ast.computed || ast.property.constant); ast.toWatch = ast.constant ? [] : [ast]; break; case AST.CallExpression: isStatelessFilter = ast.filter ? isStateless($filter, ast.callee.name) : false; allConstants = isStatelessFilter; argsToWatch = []; forEach(ast.arguments, function(expr) { findConstantAndWatchExpressions(expr, $filter, astIsPure); allConstants = allConstants && expr.constant; argsToWatch.push.apply(argsToWatch, expr.toWatch); }); ast.constant = allConstants; ast.toWatch = isStatelessFilter ? argsToWatch : [ast]; break; case AST.AssignmentExpression: findConstantAndWatchExpressions(ast.left, $filter, astIsPure); findConstantAndWatchExpressions(ast.right, $filter, astIsPure); ast.constant = ast.left.constant && ast.right.constant; ast.toWatch = [ast]; break; case AST.ArrayExpression: allConstants = true; argsToWatch = []; forEach(ast.elements, function(expr) { findConstantAndWatchExpressions(expr, $filter, astIsPure); allConstants = allConstants && expr.constant; argsToWatch.push.apply(argsToWatch, expr.toWatch); }); ast.constant = allConstants; ast.toWatch = argsToWatch; break; case AST.ObjectExpression: allConstants = true; argsToWatch = []; forEach(ast.properties, function(property) { findConstantAndWatchExpressions(property.value, $filter, astIsPure); allConstants = allConstants && property.value.constant; argsToWatch.push.apply(argsToWatch, property.value.toWatch); if (property.computed) { //`{[key]: value}` implicitly does `key.toString()` which may be non-pure findConstantAndWatchExpressions(property.key, $filter, /*parentIsPure=*/false); allConstants = allConstants && property.key.constant; argsToWatch.push.apply(argsToWatch, property.key.toWatch); } }); ast.constant = allConstants; ast.toWatch = argsToWatch; break; case AST.ThisExpression: ast.constant = false; ast.toWatch = []; break; case AST.LocalsExpression: ast.constant = false; ast.toWatch = []; break; } } function getInputs(body) { if (body.length !== 1) return; var lastExpression = body[0].expression; var candidate = lastExpression.toWatch; if (candidate.length !== 1) return candidate; return candidate[0] !== lastExpression ? candidate : undefined; } function isAssignable(ast) { return ast.type === AST.Identifier || ast.type === AST.MemberExpression; } function assignableAST(ast) { if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) { return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='}; } } function isLiteral(ast) { return ast.body.length === 0 || ast.body.length === 1 && ( ast.body[0].expression.type === AST.Literal || ast.body[0].expression.type === AST.ArrayExpression || ast.body[0].expression.type === AST.ObjectExpression); } function isConstant(ast) { return ast.constant; } function ASTCompiler($filter) { this.$filter = $filter; } ASTCompiler.prototype = { compile: function(ast) { var self = this; this.state = { nextId: 0, filters: {}, fn: {vars: [], body: [], own: {}}, assign: {vars: [], body: [], own: {}}, inputs: [] }; findConstantAndWatchExpressions(ast, self.$filter); var extra = ''; var assignable; this.stage = 'assign'; if ((assignable = assignableAST(ast))) { this.state.computing = 'assign'; var result = this.nextId(); this.recurse(assignable, result); this.return_(result); extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l'); } var toWatch = getInputs(ast.body); self.stage = 'inputs'; forEach(toWatch, function(watch, key) { var fnKey = 'fn' + key; self.state[fnKey] = {vars: [], body: [], own: {}}; self.state.computing = fnKey; var intoId = self.nextId(); self.recurse(watch, intoId); self.return_(intoId); self.state.inputs.push({name: fnKey, isPure: watch.isPure}); watch.watchId = key; }); this.state.computing = 'fn'; this.stage = 'main'; this.recurse(ast); var fnString = // The build and minification steps remove the string "use strict" from the code, but this is done using a regex. // This is a workaround for this until we do a better job at only removing the prefix only when we should. '"' + this.USE + ' ' + this.STRICT + '";\n' + this.filterPrefix() + 'var fn=' + this.generateFunction('fn', 's,l,a,i') + extra + this.watchFns() + 'return fn;'; // eslint-disable-next-line no-new-func var fn = (new Function('$filter', 'getStringValue', 'ifDefined', 'plus', fnString))( this.$filter, getStringValue, ifDefined, plusFn); this.state = this.stage = undefined; return fn; }, USE: 'use', STRICT: 'strict', watchFns: function() { var result = []; var inputs = this.state.inputs; var self = this; forEach(inputs, function(input) { result.push('var ' + input.name + '=' + self.generateFunction(input.name, 's')); if (input.isPure) { result.push(input.name, '.isPure=' + JSON.stringify(input.isPure) + ';'); } }); if (inputs.length) { result.push('fn.inputs=[' + inputs.map(function(i) { return i.name; }).join(',') + '];'); } return result.join(''); }, generateFunction: function(name, params) { return 'function(' + params + '){' + this.varsPrefix(name) + this.body(name) + '};'; }, filterPrefix: function() { var parts = []; var self = this; forEach(this.state.filters, function(id, filter) { parts.push(id + '=$filter(' + self.escape(filter) + ')'); }); if (parts.length) return 'var ' + parts.join(',') + ';'; return ''; }, varsPrefix: function(section) { return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : ''; }, body: function(section) { return this.state[section].body.join(''); }, recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) { var left, right, self = this, args, expression, computed; recursionFn = recursionFn || noop; if (!skipWatchIdCheck && isDefined(ast.watchId)) { intoId = intoId || this.nextId(); this.if_('i', this.lazyAssign(intoId, this.computedMember('i', ast.watchId)), this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true) ); return; } switch (ast.type) { case AST.Program: forEach(ast.body, function(expression, pos) { self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; }); if (pos !== ast.body.length - 1) { self.current().body.push(right, ';'); } else { self.return_(right); } }); break; case AST.Literal: expression = this.escape(ast.value); this.assign(intoId, expression); recursionFn(intoId || expression); break; case AST.UnaryExpression: this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; }); expression = ast.operator + '(' + this.ifDefined(right, 0) + ')'; this.assign(intoId, expression); recursionFn(expression); break; case AST.BinaryExpression: this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; }); this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; }); if (ast.operator === '+') { expression = this.plus(left, right); } else if (ast.operator === '-') { expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0); } else { expression = '(' + left + ')' + ast.operator + '(' + right + ')'; } this.assign(intoId, expression); recursionFn(expression); break; case AST.LogicalExpression: intoId = intoId || this.nextId(); self.recurse(ast.left, intoId); self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId)); recursionFn(intoId); break; case AST.ConditionalExpression: intoId = intoId || this.nextId(); self.recurse(ast.test, intoId); self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId)); recursionFn(intoId); break; case AST.Identifier: intoId = intoId || this.nextId(); if (nameId) { nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s'); nameId.computed = false; nameId.name = ast.name; } self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)), function() { self.if_(self.stage === 'inputs' || 's', function() { if (create && create !== 1) { self.if_( self.isNull(self.nonComputedMember('s', ast.name)), self.lazyAssign(self.nonComputedMember('s', ast.name), '{}')); } self.assign(intoId, self.nonComputedMember('s', ast.name)); }); }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name)) ); recursionFn(intoId); break; case AST.MemberExpression: left = nameId && (nameId.context = this.nextId()) || this.nextId(); intoId = intoId || this.nextId(); self.recurse(ast.object, left, undefined, function() { self.if_(self.notNull(left), function() { if (ast.computed) { right = self.nextId(); self.recurse(ast.property, right); self.getStringValue(right); if (create && create !== 1) { self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}')); } expression = self.computedMember(left, right); self.assign(intoId, expression); if (nameId) { nameId.computed = true; nameId.name = right; } } else { if (create && create !== 1) { self.if_(self.isNull(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}')); } expression = self.nonComputedMember(left, ast.property.name); self.assign(intoId, expression); if (nameId) { nameId.computed = false; nameId.name = ast.property.name; } } }, function() { self.assign(intoId, 'undefined'); }); recursionFn(intoId); }, !!create); break; case AST.CallExpression: intoId = intoId || this.nextId(); if (ast.filter) { right = self.filter(ast.callee.name); args = []; forEach(ast.arguments, function(expr) { var argument = self.nextId(); self.recurse(expr, argument); args.push(argument); }); expression = right + '(' + args.join(',') + ')'; self.assign(intoId, expression); recursionFn(intoId); } else { right = self.nextId(); left = {}; args = []; self.recurse(ast.callee, right, left, function() { self.if_(self.notNull(right), function() { forEach(ast.arguments, function(expr) { self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) { args.push(argument); }); }); if (left.name) { expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')'; } else { expression = right + '(' + args.join(',') + ')'; } self.assign(intoId, expression); }, function() { self.assign(intoId, 'undefined'); }); recursionFn(intoId); }); } break; case AST.AssignmentExpression: right = this.nextId(); left = {}; this.recurse(ast.left, undefined, left, function() { self.if_(self.notNull(left.context), function() { self.recurse(ast.right, right); expression = self.member(left.context, left.name, left.computed) + ast.operator + right; self.assign(intoId, expression); recursionFn(intoId || expression); }); }, 1); break; case AST.ArrayExpression: args = []; forEach(ast.elements, function(expr) { self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) { args.push(argument); }); }); expression = '[' + args.join(',') + ']'; this.assign(intoId, expression); recursionFn(intoId || expression); break; case AST.ObjectExpression: args = []; computed = false; forEach(ast.properties, function(property) { if (property.computed) { computed = true; } }); if (computed) { intoId = intoId || this.nextId(); this.assign(intoId, '{}'); forEach(ast.properties, function(property) { if (property.computed) { left = self.nextId(); self.recurse(property.key, left); } else { left = property.key.type === AST.Identifier ? property.key.name : ('' + property.key.value); } right = self.nextId(); self.recurse(property.value, right); self.assign(self.member(intoId, left, property.computed), right); }); } else { forEach(ast.properties, function(property) { self.recurse(property.value, ast.constant ? undefined : self.nextId(), undefined, function(expr) { args.push(self.escape( property.key.type === AST.Identifier ? property.key.name : ('' + property.key.value)) + ':' + expr); }); }); expression = '{' + args.join(',') + '}'; this.assign(intoId, expression); } recursionFn(intoId || expression); break; case AST.ThisExpression: this.assign(intoId, 's'); recursionFn(intoId || 's'); break; case AST.LocalsExpression: this.assign(intoId, 'l'); recursionFn(intoId || 'l'); break; case AST.NGValueParameter: this.assign(intoId, 'v'); recursionFn(intoId || 'v'); break; } }, getHasOwnProperty: function(element, property) { var key = element + '.' + property; var own = this.current().own; if (!own.hasOwnProperty(key)) { own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')'); } return own[key]; }, assign: function(id, value) { if (!id) return; this.current().body.push(id, '=', value, ';'); return id; }, filter: function(filterName) { if (!this.state.filters.hasOwnProperty(filterName)) { this.state.filters[filterName] = this.nextId(true); } return this.state.filters[filterName]; }, ifDefined: function(id, defaultValue) { return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')'; }, plus: function(left, right) { return 'plus(' + left + ',' + right + ')'; }, return_: function(id) { this.current().body.push('return ', id, ';'); }, if_: function(test, alternate, consequent) { if (test === true) { alternate(); } else { var body = this.current().body; body.push('if(', test, '){'); alternate(); body.push('}'); if (consequent) { body.push('else{'); consequent(); body.push('}'); } } }, not: function(expression) { return '!(' + expression + ')'; }, isNull: function(expression) { return expression + '==null'; }, notNull: function(expression) { return expression + '!=null'; }, nonComputedMember: function(left, right) { var SAFE_IDENTIFIER = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/; var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g; if (SAFE_IDENTIFIER.test(right)) { return left + '.' + right; } else { return left + '["' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '"]'; } }, computedMember: function(left, right) { return left + '[' + right + ']'; }, member: function(left, right, computed) { if (computed) return this.computedMember(left, right); return this.nonComputedMember(left, right); }, getStringValue: function(item) { this.assign(item, 'getStringValue(' + item + ')'); }, lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) { var self = this; return function() { self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck); }; }, lazyAssign: function(id, value) { var self = this; return function() { self.assign(id, value); }; }, stringEscapeRegex: /[^ a-zA-Z0-9]/g, stringEscapeFn: function(c) { return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4); }, escape: function(value) { if (isString(value)) return '\'' + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + '\''; if (isNumber(value)) return value.toString(); if (value === true) return 'true'; if (value === false) return 'false'; if (value === null) return 'null'; if (typeof value === 'undefined') return 'undefined'; throw $parseMinErr('esc', 'IMPOSSIBLE'); }, nextId: function(skip, init) { var id = 'v' + (this.state.nextId++); if (!skip) { this.current().vars.push(id + (init ? '=' + init : '')); } return id; }, current: function() { return this.state[this.state.computing]; } }; function ASTInterpreter($filter) { this.$filter = $filter; } ASTInterpreter.prototype = { compile: function(ast) { var self = this; findConstantAndWatchExpressions(ast, self.$filter); var assignable; var assign; if ((assignable = assignableAST(ast))) { assign = this.recurse(assignable); } var toWatch = getInputs(ast.body); var inputs; if (toWatch) { inputs = []; forEach(toWatch, function(watch, key) { var input = self.recurse(watch); input.isPure = watch.isPure; watch.input = input; inputs.push(input); watch.watchId = key; }); } var expressions = []; forEach(ast.body, function(expression) { expressions.push(self.recurse(expression.expression)); }); var fn = ast.body.length === 0 ? noop : ast.body.length === 1 ? expressions[0] : function(scope, locals) { var lastValue; forEach(expressions, function(exp) { lastValue = exp(scope, locals); }); return lastValue; }; if (assign) { fn.assign = function(scope, value, locals) { return assign(scope, locals, value); }; } if (inputs) { fn.inputs = inputs; } return fn; }, recurse: function(ast, context, create) { var left, right, self = this, args; if (ast.input) { return this.inputs(ast.input, ast.watchId); } switch (ast.type) { case AST.Literal: return this.value(ast.value, context); case AST.UnaryExpression: right = this.recurse(ast.argument); return this['unary' + ast.operator](right, context); case AST.BinaryExpression: left = this.recurse(ast.left); right = this.recurse(ast.right); return this['binary' + ast.operator](left, right, context); case AST.LogicalExpression: left = this.recurse(ast.left); right = this.recurse(ast.right); return this['binary' + ast.operator](left, right, context); case AST.ConditionalExpression: return this['ternary?:']( this.recurse(ast.test), this.recurse(ast.alternate), this.recurse(ast.consequent), context ); case AST.Identifier: return self.identifier(ast.name, context, create); case AST.MemberExpression: left = this.recurse(ast.object, false, !!create); if (!ast.computed) { right = ast.property.name; } if (ast.computed) right = this.recurse(ast.property); return ast.computed ? this.computedMember(left, right, context, create) : this.nonComputedMember(left, right, context, create); case AST.CallExpression: args = []; forEach(ast.arguments, function(expr) { args.push(self.recurse(expr)); }); if (ast.filter) right = this.$filter(ast.callee.name); if (!ast.filter) right = this.recurse(ast.callee, true); return ast.filter ? function(scope, locals, assign, inputs) { var values = []; for (var i = 0; i < args.length; ++i) { values.push(args[i](scope, locals, assign, inputs)); } var value = right.apply(undefined, values, inputs); return context ? {context: undefined, name: undefined, value: value} : value; } : function(scope, locals, assign, inputs) { var rhs = right(scope, locals, assign, inputs); var value; if (rhs.value != null) { var values = []; for (var i = 0; i < args.length; ++i) { values.push(args[i](scope, locals, assign, inputs)); } value = rhs.value.apply(rhs.context, values); } return context ? {value: value} : value; }; case AST.AssignmentExpression: left = this.recurse(ast.left, true, 1); right = this.recurse(ast.right); return function(scope, locals, assign, inputs) { var lhs = left(scope, locals, assign, inputs); var rhs = right(scope, locals, assign, inputs); lhs.context[lhs.name] = rhs; return context ? {value: rhs} : rhs; }; case AST.ArrayExpression: args = []; forEach(ast.elements, function(expr) { args.push(self.recurse(expr)); }); return function(scope, locals, assign, inputs) { var value = []; for (var i = 0; i < args.length; ++i) { value.push(args[i](scope, locals, assign, inputs)); } return context ? {value: value} : value; }; case AST.ObjectExpression: args = []; forEach(ast.properties, function(property) { if (property.computed) { args.push({key: self.recurse(property.key), computed: true, value: self.recurse(property.value) }); } else { args.push({key: property.key.type === AST.Identifier ? property.key.name : ('' + property.key.value), computed: false, value: self.recurse(property.value) }); } }); return function(scope, locals, assign, inputs) { var value = {}; for (var i = 0; i < args.length; ++i) { if (args[i].computed) { value[args[i].key(scope, locals, assign, inputs)] = args[i].value(scope, locals, assign, inputs); } else { value[args[i].key] = args[i].value(scope, locals, assign, inputs); } } return context ? {value: value} : value; }; case AST.ThisExpression: return function(scope) { return context ? {value: scope} : scope; }; case AST.LocalsExpression: return function(scope, locals) { return context ? {value: locals} : locals; }; case AST.NGValueParameter: return function(scope, locals, assign) { return context ? {value: assign} : assign; }; } }, 'unary+': function(argument, context) { return function(scope, locals, assign, inputs) { var arg = argument(scope, locals, assign, inputs); if (isDefined(arg)) { arg = +arg; } else { arg = 0; } return context ? {value: arg} : arg; }; }, 'unary-': function(argument, context) { return function(scope, locals, assign, inputs) { var arg = argument(scope, locals, assign, inputs); if (isDefined(arg)) { arg = -arg; } else { arg = -0; } return context ? {value: arg} : arg; }; }, 'unary!': function(argument, context) { return function(scope, locals, assign, inputs) { var arg = !argument(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary+': function(left, right, context) { return function(scope, locals, assign, inputs) { var lhs = left(scope, locals, assign, inputs); var rhs = right(scope, locals, assign, inputs); var arg = plusFn(lhs, rhs); return context ? {value: arg} : arg; }; }, 'binary-': function(left, right, context) { return function(scope, locals, assign, inputs) { var lhs = left(scope, locals, assign, inputs); var rhs = right(scope, locals, assign, inputs); var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0); return context ? {value: arg} : arg; }; }, 'binary*': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary/': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary%': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary===': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary!==': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary==': function(left, right, context) { return function(scope, locals, assign, inputs) { // eslint-disable-next-line eqeqeq var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary!=': function(left, right, context) { return function(scope, locals, assign, inputs) { // eslint-disable-next-line eqeqeq var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary<': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary>': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary<=': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary>=': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary&&': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'binary||': function(left, right, context) { return function(scope, locals, assign, inputs) { var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, 'ternary?:': function(test, alternate, consequent, context) { return function(scope, locals, assign, inputs) { var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs); return context ? {value: arg} : arg; }; }, value: function(value, context) { return function() { return context ? {context: undefined, name: undefined, value: value} : value; }; }, identifier: function(name, context, create) { return function(scope, locals, assign, inputs) { var base = locals && (name in locals) ? locals : scope; if (create && create !== 1 && base && base[name] == null) { base[name] = {}; } var value = base ? base[name] : undefined; if (context) { return {context: base, name: name, value: value}; } else { return value; } }; }, computedMember: function(left, right, context, create) { return function(scope, locals, assign, inputs) { var lhs = left(scope, locals, assign, inputs); var rhs; var value; if (lhs != null) { rhs = right(scope, locals, assign, inputs); rhs = getStringValue(rhs); if (create && create !== 1) { if (lhs && !(lhs[rhs])) { lhs[rhs] = {}; } } value = lhs[rhs]; } if (context) { return {context: lhs, name: rhs, value: value}; } else { return value; } }; }, nonComputedMember: function(left, right, context, create) { return function(scope, locals, assign, inputs) { var lhs = left(scope, locals, assign, inputs); if (create && create !== 1) { if (lhs && lhs[right] == null) { lhs[right] = {}; } } var value = lhs != null ? lhs[right] : undefined; if (context) { return {context: lhs, name: right, value: value}; } else { return value; } }; }, inputs: function(input, watchId) { return function(scope, value, locals, inputs) { if (inputs) return inputs[watchId]; return input(scope, value, locals); }; } }; /** * @constructor */ function Parser(lexer, $filter, options) { this.ast = new AST(lexer, options); this.astCompiler = options.csp ? new ASTInterpreter($filter) : new ASTCompiler($filter); } Parser.prototype = { constructor: Parser, parse: function(text) { var ast = this.ast.ast(text); var fn = this.astCompiler.compile(ast); fn.literal = isLiteral(ast); fn.constant = isConstant(ast); return fn; } }; function getValueOf(value) { return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value); } /////////////////////////////////// /** * @ngdoc service * @name $parse * @kind function * * @description * * Converts Angular {@link guide/expression expression} into a function. * * ```js * var getter = $parse('user.name'); * var setter = getter.assign; * var context = {user:{name:'angular'}}; * var locals = {user:{name:'local'}}; * * expect(getter(context)).toEqual('angular'); * setter(context, 'newValue'); * expect(context.user.name).toEqual('newValue'); * expect(getter(context, locals)).toEqual('local'); * ``` * * * @param {string} expression String expression to compile. * @returns {function(context, locals)} a function which represents the compiled expression: * * * `context` – `{object}` – an object against which any expressions embedded in the strings * are evaluated against (typically a scope object). * * `locals` – `{object=}` – local variables context object, useful for overriding values in * `context`. * * The returned function also has the following properties: * * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript * literal. * * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript * constant literals. * * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be * set to a function to change its value on the given context. * */ /** * @ngdoc provider * @name $parseProvider * @this * * @description * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse} * service. */ function $ParseProvider() { var cache = createMap(); var literals = { 'true': true, 'false': false, 'null': null, 'undefined': undefined }; var identStart, identContinue; /** * @ngdoc method * @name $parseProvider#addLiteral * @description * * Configure $parse service to add literal values that will be present as literal at expressions. * * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name. * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`. * **/ this.addLiteral = function(literalName, literalValue) { literals[literalName] = literalValue; }; /** * @ngdoc method * @name $parseProvider#setIdentifierFns * * @description * * Allows defining the set of characters that are allowed in Angular expressions. The function * `identifierStart` will get called to know if a given character is a valid character to be the * first character for an identifier. The function `identifierContinue` will get called to know if * a given character is a valid character to be a follow-up identifier character. The functions * `identifierStart` and `identifierContinue` will receive as arguments the single character to be * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in * mind that the `string` parameter can be two characters long depending on the character * representation. It is expected for the function to return `true` or `false`, whether that * character is allowed or not. * * Since this function will be called extensively, keep the implementation of these functions fast, * as the performance of these functions have a direct impact on the expressions parsing speed. * * @param {function=} identifierStart The function that will decide whether the given character is * a valid identifier start character. * @param {function=} identifierContinue The function that will decide whether the given character is * a valid identifier continue character. */ this.setIdentifierFns = function(identifierStart, identifierContinue) { identStart = identifierStart; identContinue = identifierContinue; return this; }; this.$get = ['$filter', function($filter) { var noUnsafeEval = csp().noUnsafeEval; var $parseOptions = { csp: noUnsafeEval, literals: copy(literals), isIdentifierStart: isFunction(identStart) && identStart, isIdentifierContinue: isFunction(identContinue) && identContinue }; return $parse; function $parse(exp, interceptorFn) { var parsedExpression, oneTime, cacheKey; switch (typeof exp) { case 'string': exp = exp.trim(); cacheKey = exp; parsedExpression = cache[cacheKey]; if (!parsedExpression) { if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { oneTime = true; exp = exp.substring(2); } var lexer = new Lexer($parseOptions); var parser = new Parser(lexer, $filter, $parseOptions); parsedExpression = parser.parse(exp); if (parsedExpression.constant) { parsedExpression.$$watchDelegate = constantWatchDelegate; } else if (oneTime) { parsedExpression.$$watchDelegate = parsedExpression.literal ? oneTimeLiteralWatchDelegate : oneTimeWatchDelegate; } else if (parsedExpression.inputs) { parsedExpression.$$watchDelegate = inputsWatchDelegate; } cache[cacheKey] = parsedExpression; } return addInterceptor(parsedExpression, interceptorFn); case 'function': return addInterceptor(exp, interceptorFn); default: return addInterceptor(noop, interceptorFn); } } function expressionInputDirtyCheck(newValue, oldValueOfValue, compareObjectIdentity) { if (newValue == null || oldValueOfValue == null) { // null/undefined return newValue === oldValueOfValue; } if (typeof newValue === 'object') { // attempt to convert the value to a primitive type // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can // be cheaply dirty-checked newValue = getValueOf(newValue); if (typeof newValue === 'object' && !compareObjectIdentity) { // objects/arrays are not supported - deep-watching them would be too expensive return false; } // fall-through to the primitive equality check } //Primitive or NaN // eslint-disable-next-line no-self-compare return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue); } function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) { var inputExpressions = parsedExpression.inputs; var lastResult; if (inputExpressions.length === 1) { var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails inputExpressions = inputExpressions[0]; return scope.$watch(function expressionInputWatch(scope) { var newInputValue = inputExpressions(scope); if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, inputExpressions.isPure)) { lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]); oldInputValueOf = newInputValue && getValueOf(newInputValue); } return lastResult; }, listener, objectEquality, prettyPrintExpression); } var oldInputValueOfValues = []; var oldInputValues = []; for (var i = 0, ii = inputExpressions.length; i < ii; i++) { oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails oldInputValues[i] = null; } return scope.$watch(function expressionInputsWatch(scope) { var changed = false; for (var i = 0, ii = inputExpressions.length; i < ii; i++) { var newInputValue = inputExpressions[i](scope); if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], inputExpressions[i].isPure))) { oldInputValues[i] = newInputValue; oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue); } } if (changed) { lastResult = parsedExpression(scope, undefined, undefined, oldInputValues); } return lastResult; }, listener, objectEquality, prettyPrintExpression); } function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) { var unwatch, lastValue; if (parsedExpression.inputs) { unwatch = inputsWatchDelegate(scope, oneTimeListener, objectEquality, parsedExpression, prettyPrintExpression); } else { unwatch = scope.$watch(oneTimeWatch, oneTimeListener, objectEquality); } return unwatch; function oneTimeWatch(scope) { return parsedExpression(scope); } function oneTimeListener(value, old, scope) { lastValue = value; if (isFunction(listener)) { listener(value, old, scope); } if (isDefined(value)) { scope.$$postDigest(function() { if (isDefined(lastValue)) { unwatch(); } }); } } } function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) { var unwatch, lastValue; unwatch = scope.$watch(function oneTimeWatch(scope) { return parsedExpression(scope); }, function oneTimeListener(value, old, scope) { lastValue = value; if (isFunction(listener)) { listener(value, old, scope); } if (isAllDefined(value)) { scope.$$postDigest(function() { if (isAllDefined(lastValue)) unwatch(); }); } }, objectEquality); return unwatch; function isAllDefined(value) { var allDefined = true; forEach(value, function(val) { if (!isDefined(val)) allDefined = false; }); return allDefined; } } function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) { var unwatch = scope.$watch(function constantWatch(scope) { unwatch(); return parsedExpression(scope); }, listener, objectEquality); return unwatch; } function addInterceptor(parsedExpression, interceptorFn) { if (!interceptorFn) return parsedExpression; var watchDelegate = parsedExpression.$$watchDelegate; var useInputs = false; var regularWatch = watchDelegate !== oneTimeLiteralWatchDelegate && watchDelegate !== oneTimeWatchDelegate; var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) { var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs); return interceptorFn(value, scope, locals); } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) { var value = parsedExpression(scope, locals, assign, inputs); var result = interceptorFn(value, scope, locals); // we only return the interceptor's result if the // initial value is defined (for bind-once) return isDefined(value) ? result : value; }; // Propagate $$watchDelegates other then inputsWatchDelegate useInputs = !parsedExpression.inputs; if (watchDelegate && watchDelegate !== inputsWatchDelegate) { fn.$$watchDelegate = watchDelegate; fn.inputs = parsedExpression.inputs; } else if (!interceptorFn.$stateful) { // Treat interceptor like filters - assume non-stateful by default and use the inputsWatchDelegate fn.$$watchDelegate = inputsWatchDelegate; fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression]; } if (fn.inputs) { fn.inputs = fn.inputs.map(function(e) { // Remove the isPure flag of inputs when it is not absolute because they are now wrapped in a // potentially non-pure interceptor function. if (e.isPure === PURITY_RELATIVE) { return function depurifier(s) { return e(s); }; } return e; }); } return fn; } }]; } /** * @ngdoc service * @name $q * @requires $rootScope * * @description * A service that helps you run functions asynchronously, and use their return values (or exceptions) * when they are done processing. * * This is a [Promises/A+](https://promisesaplus.com/)-compliant implementation of promises/deferred * objects inspired by [Kris Kowal's Q](https://github.com/kriskowal/q). * * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred * implementations, and the other which resembles ES6 (ES2015) promises to some degree. * * # $q constructor * * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver` * function as the first argument. This is similar to the native Promise implementation from ES6, * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). * * While the constructor-style use is supported, not all of the supporting methods from ES6 promises are * available yet. * * It can be used like so: * * ```js * // for the purpose of this example let's assume that variables `$q` and `okToGreet` * // are available in the current lexical scope (they could have been injected or passed in). * * function asyncGreet(name) { * // perform some asynchronous operation, resolve or reject the promise when appropriate. * return $q(function(resolve, reject) { * setTimeout(function() { * if (okToGreet(name)) { * resolve('Hello, ' + name + '!'); * } else { * reject('Greeting ' + name + ' is not allowed.'); * } * }, 1000); * }); * } * * var promise = asyncGreet('Robin Hood'); * promise.then(function(greeting) { * alert('Success: ' + greeting); * }, function(reason) { * alert('Failed: ' + reason); * }); * ``` * * Note: progress/notify callbacks are not currently supported via the ES6-style interface. * * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise. * * However, the more traditional CommonJS-style usage is still available, and documented below. * * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an * interface for interacting with an object that represents the result of an action that is * performed asynchronously, and may or may not be finished at any given point in time. * * From the perspective of dealing with error handling, deferred and promise APIs are to * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming. * * ```js * // for the purpose of this example let's assume that variables `$q` and `okToGreet` * // are available in the current lexical scope (they could have been injected or passed in). * * function asyncGreet(name) { * var deferred = $q.defer(); * * setTimeout(function() { * deferred.notify('About to greet ' + name + '.'); * * if (okToGreet(name)) { * deferred.resolve('Hello, ' + name + '!'); * } else { * deferred.reject('Greeting ' + name + ' is not allowed.'); * } * }, 1000); * * return deferred.promise; * } * * var promise = asyncGreet('Robin Hood'); * promise.then(function(greeting) { * alert('Success: ' + greeting); * }, function(reason) { * alert('Failed: ' + reason); * }, function(update) { * alert('Got notification: ' + update); * }); * ``` * * At first it might not be obvious why this extra complexity is worth the trouble. The payoff * comes in the way of guarantees that promise and deferred APIs make, see * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md. * * Additionally the promise api allows for composition that is very hard to do with the * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach. * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the * section on serial or parallel joining of promises. * * # The Deferred API * * A new instance of deferred is constructed by calling `$q.defer()`. * * The purpose of the deferred object is to expose the associated Promise instance as well as APIs * that can be used for signaling the successful or unsuccessful completion, as well as the status * of the task. * * **Methods** * * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection * constructed via `$q.reject`, the promise will be rejected instead. * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to * resolving it with a rejection constructed via `$q.reject`. * - `notify(value)` - provides updates on the status of the promise's execution. This may be called * multiple times before the promise is either resolved or rejected. * * **Properties** * * - promise – `{Promise}` – promise object associated with this deferred. * * * # The Promise API * * A new promise instance is created when a deferred instance is created and can be retrieved by * calling `deferred.promise`. * * The purpose of the promise object is to allow for interested parties to get access to the result * of the deferred task when it completes. * * **Methods** * * - `then(successCallback, [errorCallback], [notifyCallback])` – regardless of when the promise was or * will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously * as soon as the result is available. The callbacks are called with a single argument: the result * or rejection reason. Additionally, the notify callback may be called zero or more times to * provide a progress indication, before the promise is resolved or rejected. * * This method *returns a new promise* which is resolved or rejected via the return value of the * `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved * with the value which is resolved in that promise using * [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)). * It also notifies via the return value of the `notifyCallback` method. The promise cannot be * resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback * arguments are optional. * * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)` * * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise, * but to do so without modifying the final value. This is useful to release resources or do some * clean-up that needs to be done whether the promise was rejected or resolved. See the [full * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for * more information. * * # Chaining promises * * Because calling the `then` method of a promise returns a new derived promise, it is easily * possible to create a chain of promises: * * ```js * promiseB = promiseA.then(function(result) { * return result + 1; * }); * * // promiseB will be resolved immediately after promiseA is resolved and its value * // will be the result of promiseA incremented by 1 * ``` * * It is possible to create chains of any length and since a promise can be resolved with another * promise (which will defer its resolution further), it is possible to pause/defer resolution of * the promises at any point in the chain. This makes it possible to implement powerful APIs like * $http's response interceptors. * * * # Differences between Kris Kowal's Q and $q * * There are two main differences: * * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation * mechanism in angular, which means faster propagation of resolution or rejection into your * models and avoiding unnecessary browser repaints, which would result in flickering UI. * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains * all the important functionality needed for common async tasks. * * # Testing * * ```js * it('should simulate promise', inject(function($q, $rootScope) { * var deferred = $q.defer(); * var promise = deferred.promise; * var resolvedValue; * * promise.then(function(value) { resolvedValue = value; }); * expect(resolvedValue).toBeUndefined(); * * // Simulate resolving of promise * deferred.resolve(123); * // Note that the 'then' function does not get called synchronously. * // This is because we want the promise API to always be async, whether or not * // it got called synchronously or asynchronously. * expect(resolvedValue).toBeUndefined(); * * // Propagate promise resolution to 'then' functions using $apply(). * $rootScope.$apply(); * expect(resolvedValue).toEqual(123); * })); * ``` * * @param {function(function, function)} resolver Function which is responsible for resolving or * rejecting the newly created promise. The first parameter is a function which resolves the * promise, the second parameter is a function which rejects the promise. * * @returns {Promise} The newly created promise. */ /** * @ngdoc provider * @name $qProvider * @this * * @description */ function $QProvider() { var errorOnUnhandledRejections = true; this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { return qFactory(function(callback) { $rootScope.$evalAsync(callback); }, $exceptionHandler, errorOnUnhandledRejections); }]; /** * @ngdoc method * @name $qProvider#errorOnUnhandledRejections * @kind function * * @description * Retrieves or overrides whether to generate an error when a rejected promise is not handled. * This feature is enabled by default. * * @param {boolean=} value Whether to generate an error when a rejected promise is not handled. * @returns {boolean|ng.$qProvider} Current value when called without a new value or self for * chaining otherwise. */ this.errorOnUnhandledRejections = function(value) { if (isDefined(value)) { errorOnUnhandledRejections = value; return this; } else { return errorOnUnhandledRejections; } }; } /** @this */ function $$QProvider() { var errorOnUnhandledRejections = true; this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) { return qFactory(function(callback) { $browser.defer(callback); }, $exceptionHandler, errorOnUnhandledRejections); }]; this.errorOnUnhandledRejections = function(value) { if (isDefined(value)) { errorOnUnhandledRejections = value; return this; } else { return errorOnUnhandledRejections; } }; } /** * Constructs a promise manager. * * @param {function(function)} nextTick Function for executing functions in the next turn. * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for * debugging purposes. * @param {boolean=} errorOnUnhandledRejections Whether an error should be generated on unhandled * promises rejections. * @returns {object} Promise manager. */ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { var $qMinErr = minErr('$q', TypeError); var queueSize = 0; var checkQueue = []; /** * @ngdoc method * @name ng.$q#defer * @kind function * * @description * Creates a `Deferred` object which represents a task which will finish in the future. * * @returns {Deferred} Returns a new instance of deferred. */ function defer() { return new Deferred(); } function Deferred() { var promise = this.promise = new Promise(); //Non prototype methods necessary to support unbound execution :/ this.resolve = function(val) { resolvePromise(promise, val); }; this.reject = function(reason) { rejectPromise(promise, reason); }; this.notify = function(progress) { notifyPromise(promise, progress); }; } function Promise() { this.$$state = { status: 0 }; } extend(Promise.prototype, { then: function(onFulfilled, onRejected, progressBack) { if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) { return this; } var result = new Promise(); this.$$state.pending = this.$$state.pending || []; this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]); if (this.$$state.status > 0) scheduleProcessQueue(this.$$state); return result; }, 'catch': function(callback) { return this.then(null, callback); }, 'finally': function(callback, progressBack) { return this.then(function(value) { return handleCallback(value, resolve, callback); }, function(error) { return handleCallback(error, reject, callback); }, progressBack); } }); function processQueue(state) { var fn, promise, pending; pending = state.pending; state.processScheduled = false; state.pending = undefined; try { for (var i = 0, ii = pending.length; i < ii; ++i) { markQStateExceptionHandled(state); promise = pending[i][0]; fn = pending[i][state.status]; try { if (isFunction(fn)) { resolvePromise(promise, fn(state.value)); } else if (state.status === 1) { resolvePromise(promise, state.value); } else { rejectPromise(promise, state.value); } } catch (e) { rejectPromise(promise, e); } } } finally { --queueSize; if (errorOnUnhandledRejections && queueSize === 0) { nextTick(processChecks); } } } function processChecks() { // eslint-disable-next-line no-unmodified-loop-condition while (!queueSize && checkQueue.length) { var toCheck = checkQueue.shift(); if (!isStateExceptionHandled(toCheck)) { markQStateExceptionHandled(toCheck); var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value); if (isError(toCheck.value)) { exceptionHandler(toCheck.value, errorMessage); } else { exceptionHandler(errorMessage); } } } } function scheduleProcessQueue(state) { if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !isStateExceptionHandled(state)) { if (queueSize === 0 && checkQueue.length === 0) { nextTick(processChecks); } checkQueue.push(state); } if (state.processScheduled || !state.pending) return; state.processScheduled = true; ++queueSize; nextTick(function() { processQueue(state); }); } function resolvePromise(promise, val) { if (promise.$$state.status) return; if (val === promise) { $$reject(promise, $qMinErr( 'qcycle', 'Expected promise to be resolved with value other than itself \'{0}\'', val)); } else { $$resolve(promise, val); } } function $$resolve(promise, val) { var then; var done = false; try { if (isObject(val) || isFunction(val)) then = val.then; if (isFunction(then)) { promise.$$state.status = -1; then.call(val, doResolve, doReject, doNotify); } else { promise.$$state.value = val; promise.$$state.status = 1; scheduleProcessQueue(promise.$$state); } } catch (e) { doReject(e); } function doResolve(val) { if (done) return; done = true; $$resolve(promise, val); } function doReject(val) { if (done) return; done = true; $$reject(promise, val); } function doNotify(progress) { notifyPromise(promise, progress); } } function rejectPromise(promise, reason) { if (promise.$$state.status) return; $$reject(promise, reason); } function $$reject(promise, reason) { promise.$$state.value = reason; promise.$$state.status = 2; scheduleProcessQueue(promise.$$state); } function notifyPromise(promise, progress) { var callbacks = promise.$$state.pending; if ((promise.$$state.status <= 0) && callbacks && callbacks.length) { nextTick(function() { var callback, result; for (var i = 0, ii = callbacks.length; i < ii; i++) { result = callbacks[i][0]; callback = callbacks[i][3]; try { notifyPromise(result, isFunction(callback) ? callback(progress) : progress); } catch (e) { exceptionHandler(e); } } }); } } /** * @ngdoc method * @name $q#reject * @kind function * * @description * Creates a promise that is resolved as rejected with the specified `reason`. This api should be * used to forward rejection in a chain of promises. If you are dealing with the last promise in * a promise chain, you don't need to worry about it. * * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via * a promise error callback and you want to forward the error to the promise derived from the * current promise, you have to "rethrow" the error by returning a rejection constructed via * `reject`. * * ```js * promiseB = promiseA.then(function(result) { * // success: do something and resolve promiseB * // with the old or a new result * return result; * }, function(reason) { * // error: handle the error if possible and * // resolve promiseB with newPromiseOrValue, * // otherwise forward the rejection to promiseB * if (canHandle(reason)) { * // handle the error and recover * return newPromiseOrValue; * } * return $q.reject(reason); * }); * ``` * * @param {*} reason Constant, message, exception or an object representing the rejection reason. * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`. */ function reject(reason) { var result = new Promise(); rejectPromise(result, reason); return result; } function handleCallback(value, resolver, callback) { var callbackOutput = null; try { if (isFunction(callback)) callbackOutput = callback(); } catch (e) { return reject(e); } if (isPromiseLike(callbackOutput)) { return callbackOutput.then(function() { return resolver(value); }, reject); } else { return resolver(value); } } /** * @ngdoc method * @name $q#when * @kind function * * @description * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. * This is useful when you are dealing with an object that might or might not be a promise, or if * the promise comes from a source that can't be trusted. * * @param {*} value Value or a promise * @param {Function=} successCallback * @param {Function=} errorCallback * @param {Function=} progressCallback * @returns {Promise} Returns a promise of the passed value or promise */ function when(value, callback, errback, progressBack) { var result = new Promise(); resolvePromise(result, value); return result.then(callback, errback, progressBack); } /** * @ngdoc method * @name $q#resolve * @kind function * * @description * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6. * * @param {*} value Value or a promise * @param {Function=} successCallback * @param {Function=} errorCallback * @param {Function=} progressCallback * @returns {Promise} Returns a promise of the passed value or promise */ var resolve = when; /** * @ngdoc method * @name $q#all * @kind function * * @description * Combines multiple promises into a single promise that is resolved when all of the input * promises are resolved. * * @param {Array.|Object.} promises An array or hash of promises. * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values, * each value corresponding to the promise at the same index/key in the `promises` array/hash. * If any of the promises is resolved with a rejection, this resulting promise will be rejected * with the same rejection value. */ function all(promises) { var result = new Promise(), counter = 0, results = isArray(promises) ? [] : {}; forEach(promises, function(promise, key) { counter++; when(promise).then(function(value) { results[key] = value; if (!(--counter)) resolvePromise(result, results); }, function(reason) { rejectPromise(result, reason); }); }); if (counter === 0) { resolvePromise(result, results); } return result; } /** * @ngdoc method * @name $q#race * @kind function * * @description * Returns a promise that resolves or rejects as soon as one of those promises * resolves or rejects, with the value or reason from that promise. * * @param {Array.|Object.} promises An array or hash of promises. * @returns {Promise} a promise that resolves or rejects as soon as one of the `promises` * resolves or rejects, with the value or reason from that promise. */ function race(promises) { var deferred = defer(); forEach(promises, function(promise) { when(promise).then(deferred.resolve, deferred.reject); }); return deferred.promise; } function $Q(resolver) { if (!isFunction(resolver)) { throw $qMinErr('norslvr', 'Expected resolverFn, got \'{0}\'', resolver); } var promise = new Promise(); function resolveFn(value) { resolvePromise(promise, value); } function rejectFn(reason) { rejectPromise(promise, reason); } resolver(resolveFn, rejectFn); return promise; } // Let's make the instanceof operator work for promises, so that // `new $q(fn) instanceof $q` would evaluate to true. $Q.prototype = Promise.prototype; $Q.defer = defer; $Q.reject = reject; $Q.when = when; $Q.resolve = resolve; $Q.all = all; $Q.race = race; return $Q; } function isStateExceptionHandled(state) { return !!state.pur; } function markQStateExceptionHandled(state) { state.pur = true; } function markQExceptionHandled(q) { markQStateExceptionHandled(q.$$state); } /** @this */ function $$RAFProvider() { //rAF this.$get = ['$window', '$timeout', function($window, $timeout) { var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame; var cancelAnimationFrame = $window.cancelAnimationFrame || $window.webkitCancelAnimationFrame || $window.webkitCancelRequestAnimationFrame; var rafSupported = !!requestAnimationFrame; var raf = rafSupported ? function(fn) { var id = requestAnimationFrame(fn); return function() { cancelAnimationFrame(id); }; } : function(fn) { var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666 return function() { $timeout.cancel(timer); }; }; raf.supported = rafSupported; return raf; }]; } /** * DESIGN NOTES * * The design decisions behind the scope are heavily favored for speed and memory consumption. * * The typical use of scope is to watch the expressions, which most of the time return the same * value as last time so we optimize the operation. * * Closures construction is expensive in terms of speed as well as memory: * - No closures, instead use prototypical inheritance for API * - Internal state needs to be stored on scope directly, which means that private state is * exposed as $$____ properties * * Loop operations are optimized by using while(count--) { ... } * - This means that in order to keep the same order of execution as addition we have to add * items to the array at the beginning (unshift) instead of at the end (push) * * Child scopes are created and removed often * - Using an array would be slow since inserts in the middle are expensive; so we use linked lists * * There are fewer watches than observers. This is why you don't want the observer to be implemented * in the same way as watch. Watch requires return of the initialization function which is expensive * to construct. */ /** * @ngdoc provider * @name $rootScopeProvider * @description * * Provider for the $rootScope service. */ /** * @ngdoc method * @name $rootScopeProvider#digestTtl * @description * * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and * assuming that the model is unstable. * * The current default is 10 iterations. * * In complex applications it's possible that the dependencies between `$watch`s will result in * several digest iterations. However if an application needs more than the default 10 digest * iterations for its model to stabilize then you should investigate what is causing the model to * continuously change during the digest. * * Increasing the TTL could have performance implications, so you should not change it without * proper justification. * * @param {number} limit The number of digest iterations. */ /** * @ngdoc service * @name $rootScope * @this * * @description * * Every application has a single root {@link ng.$rootScope.Scope scope}. * All other scopes are descendant scopes of the root scope. Scopes provide separation * between the model and the view, via a mechanism for watching the model for changes. * They also provide event emission/broadcast and subscription facility. See the * {@link guide/scope developer guide on scopes}. */ function $RootScopeProvider() { var TTL = 10; var $rootScopeMinErr = minErr('$rootScope'); var lastDirtyWatch = null; var applyAsyncId = null; this.digestTtl = function(value) { if (arguments.length) { TTL = value; } return TTL; }; function createChildScopeClass(parent) { function ChildScope() { this.$$watchers = this.$$nextSibling = this.$$childHead = this.$$childTail = null; this.$$listeners = {}; this.$$listenerCount = {}; this.$$watchersCount = 0; this.$id = nextUid(); this.$$ChildScope = null; } ChildScope.prototype = parent; return ChildScope; } this.$get = ['$exceptionHandler', '$parse', '$browser', function($exceptionHandler, $parse, $browser) { function destroyChildScope($event) { $event.currentScope.$$destroyed = true; } function cleanUpScope($scope) { // Support: IE 9 only if (msie === 9) { // There is a memory leak in IE9 if all child scopes are not disconnected // completely when a scope is destroyed. So this code will recurse up through // all this scopes children // // See issue https://github.com/angular/angular.js/issues/10706 if ($scope.$$childHead) { cleanUpScope($scope.$$childHead); } if ($scope.$$nextSibling) { cleanUpScope($scope.$$nextSibling); } } // The code below works around IE9 and V8's memory leaks // // See: // - https://code.google.com/p/v8/issues/detail?id=2073#c26 // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909 // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451 $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead = $scope.$$childTail = $scope.$root = $scope.$$watchers = null; } /** * @ngdoc type * @name $rootScope.Scope * * @description * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the * {@link auto.$injector $injector}. Child scopes are created using the * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for * an in-depth introduction and usage examples. * * * # Inheritance * A scope can inherit from a parent scope, as in this example: * ```js var parent = $rootScope; var child = parent.$new(); parent.salutation = "Hello"; expect(child.salutation).toEqual('Hello'); child.salutation = "Welcome"; expect(child.salutation).toEqual('Welcome'); expect(parent.salutation).toEqual('Hello'); * ``` * * When interacting with `Scope` in tests, additional helper methods are available on the * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional * details. * * * @param {Object.=} providers Map of service factory which need to be * provided for the current scope. Defaults to {@link ng}. * @param {Object.=} instanceCache Provides pre-instantiated services which should * append/override services provided by `providers`. This is handy * when unit-testing and having the need to override a default * service. * @returns {Object} Newly created scope. * */ function Scope() { this.$id = nextUid(); this.$$phase = this.$parent = this.$$watchers = this.$$nextSibling = this.$$prevSibling = this.$$childHead = this.$$childTail = null; this.$root = this; this.$$destroyed = false; this.$$listeners = {}; this.$$listenerCount = {}; this.$$watchersCount = 0; this.$$isolateBindings = null; } /** * @ngdoc property * @name $rootScope.Scope#$id * * @description * Unique scope ID (monotonically increasing) useful for debugging. */ /** * @ngdoc property * @name $rootScope.Scope#$parent * * @description * Reference to the parent scope. */ /** * @ngdoc property * @name $rootScope.Scope#$root * * @description * Reference to the root scope. */ Scope.prototype = { constructor: Scope, /** * @ngdoc method * @name $rootScope.Scope#$new * @kind function * * @description * Creates a new child {@link ng.$rootScope.Scope scope}. * * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event. * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}. * * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is * desired for the scope and its child scopes to be permanently detached from the parent and * thus stop participating in model change detection and listener notification by invoking. * * @param {boolean} isolate If true, then the scope does not prototypically inherit from the * parent scope. The scope is isolated, as it can not see parent scope properties. * When creating widgets, it is useful for the widget to not accidentally read parent * state. * * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent` * of the newly created scope. Defaults to `this` scope if not provided. * This is used when creating a transclude scope to correctly place it * in the scope hierarchy while maintaining the correct prototypical * inheritance. * * @returns {Object} The newly created child scope. * */ $new: function(isolate, parent) { var child; parent = parent || this; if (isolate) { child = new Scope(); child.$root = this.$root; } else { // Only create a child scope class if somebody asks for one, // but cache it to allow the VM to optimize lookups. if (!this.$$ChildScope) { this.$$ChildScope = createChildScopeClass(this); } child = new this.$$ChildScope(); } child.$parent = parent; child.$$prevSibling = parent.$$childTail; if (parent.$$childHead) { parent.$$childTail.$$nextSibling = child; parent.$$childTail = child; } else { parent.$$childHead = parent.$$childTail = child; } // When the new scope is not isolated or we inherit from `this`, and // the parent scope is destroyed, the property `$$destroyed` is inherited // prototypically. In all other cases, this property needs to be set // when the parent scope is destroyed. // The listener needs to be added after the parent is set if (isolate || parent !== this) child.$on('$destroy', destroyChildScope); return child; }, /** * @ngdoc method * @name $rootScope.Scope#$watch * @kind function * * @description * Registers a `listener` callback to be executed whenever the `watchExpression` changes. * * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest * $digest()} and should return the value that will be watched. (`watchExpression` should not change * its value when executed multiple times with the same input because it may be executed multiple * times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be * [idempotent](http://en.wikipedia.org/wiki/Idempotence).) * - The `listener` is called only when the value from the current `watchExpression` and the * previous call to `watchExpression` are not equal (with the exception of the initial run, * see below). Inequality is determined according to reference inequality, * [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators) * via the `!==` Javascript operator, unless `objectEquality == true` * (see next point) * - When `objectEquality == true`, inequality of the `watchExpression` is determined * according to the {@link angular.equals} function. To save the value of the object for * later comparison, the {@link angular.copy} function is used. This therefore means that * watching complex objects will have adverse memory and performance implications. * - This should not be used to watch for changes in objects that are * or contain [File](https://developer.mozilla.org/docs/Web/API/File) objects due to limitations with {@link angular.copy `angular.copy`}. * - The watch `listener` may change the model, which may trigger other `listener`s to fire. * This is achieved by rerunning the watchers until no changes are detected. The rerun * iteration limit is 10 to prevent an infinite loop deadlock. * * * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called, * you can register a `watchExpression` function with no `listener`. (Be prepared for * multiple calls to your `watchExpression` because it will execute multiple times in a * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.) * * After a watcher is registered with the scope, the `listener` fn is called asynchronously * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the * watcher. In rare cases, this is undesirable because the listener is called when the result * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the * listener was called due to initialization. * * * * # Example * ```js // let's assume that scope was dependency injected as the $rootScope var scope = $rootScope; scope.name = 'misko'; scope.counter = 0; expect(scope.counter).toEqual(0); scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; }); expect(scope.counter).toEqual(0); scope.$digest(); // the listener is always called during the first $digest loop after it was registered expect(scope.counter).toEqual(1); scope.$digest(); // but now it will not be called unless the value changes expect(scope.counter).toEqual(1); scope.name = 'adam'; scope.$digest(); expect(scope.counter).toEqual(2); // Using a function as a watchExpression var food; scope.foodCounter = 0; expect(scope.foodCounter).toEqual(0); scope.$watch( // This function returns the value being watched. It is called for each turn of the $digest loop function() { return food; }, // This is the change listener, called when the value returned from the above function changes function(newValue, oldValue) { if ( newValue !== oldValue ) { // Only increment the counter if the value changed scope.foodCounter = scope.foodCounter + 1; } } ); // No digest has been run so the counter will be zero expect(scope.foodCounter).toEqual(0); // Run the digest but since food has not changed count will still be zero scope.$digest(); expect(scope.foodCounter).toEqual(0); // Update food and run digest. Now the counter will increment food = 'cheeseburger'; scope.$digest(); expect(scope.foodCounter).toEqual(1); * ``` * * * * @param {(function()|string)} watchExpression Expression that is evaluated on each * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers * a call to the `listener`. * * - `string`: Evaluated as {@link guide/expression expression} * - `function(scope)`: called with current `scope` as a parameter. * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value * of `watchExpression` changes. * * - `newVal` contains the current value of the `watchExpression` * - `oldVal` contains the previous value of the `watchExpression` * - `scope` refers to the current scope * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of * comparing for reference equality. * @returns {function()} Returns a deregistration function for this listener. */ $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) { var get = $parse(watchExp); if (get.$$watchDelegate) { return get.$$watchDelegate(this, listener, objectEquality, get, watchExp); } var scope = this, array = scope.$$watchers, watcher = { fn: listener, last: initWatchVal, get: get, exp: prettyPrintExpression || watchExp, eq: !!objectEquality }; lastDirtyWatch = null; if (!isFunction(listener)) { watcher.fn = noop; } if (!array) { array = scope.$$watchers = []; array.$$digestWatchIndex = -1; } // we use unshift since we use a while loop in $digest for speed. // the while loop reads in reverse order. array.unshift(watcher); array.$$digestWatchIndex++; incrementWatchersCount(this, 1); return function deregisterWatch() { var index = arrayRemove(array, watcher); if (index >= 0) { incrementWatchersCount(scope, -1); if (index < array.$$digestWatchIndex) { array.$$digestWatchIndex--; } } lastDirtyWatch = null; }; }, /** * @ngdoc method * @name $rootScope.Scope#$watchGroup * @kind function * * @description * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`. * If any one expression in the collection changes the `listener` is executed. * * - The items in the `watchExpressions` array are observed via the standard `$watch` operation. Their return * values are examined for changes on every call to `$digest`. * - The `listener` is called whenever any expression in the `watchExpressions` array changes. * * `$watchGroup` is more performant than watching each expression individually, and should be * used when the listener does not need to know which expression has changed. * If the listener needs to know which expression has changed, * {@link ng.$rootScope.Scope#$watch $watch()} or * {@link ng.$rootScope.Scope#$watchCollection $watchCollection()} should be used. * * @param {Array.} watchExpressions Array of expressions that will be individually * watched using {@link ng.$rootScope.Scope#$watch $watch()} * * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any * expression in `watchExpressions` changes * The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching * those of `watchExpression` * and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching * those of `watchExpression`. * * Note that `newValues` and `oldValues` reflect the differences in each **individual** * expression, and not the difference of the values between each call of the listener. * That means the difference between `newValues` and `oldValues` cannot be used to determine * which expression has changed / remained stable: * * ```js * * $scope.$watchGroup(['v1', 'v2'], function(newValues, oldValues) { * console.log(newValues, oldValues); * }); * * // newValues, oldValues initially * // [undefined, undefined], [undefined, undefined] * * $scope.v1 = 'a'; * $scope.v2 = 'a'; * * // ['a', 'a'], [undefined, undefined] * * $scope.v2 = 'b' * * // v1 hasn't changed since it became `'a'`, therefore its oldValue is still `undefined` * // ['a', 'b'], [undefined, 'a'] * * ``` * * The `scope` refers to the current scope. * @returns {function()} Returns a de-registration function for all listeners. */ $watchGroup: function(watchExpressions, listener) { var oldValues = new Array(watchExpressions.length); var newValues = new Array(watchExpressions.length); var deregisterFns = []; var self = this; var changeReactionScheduled = false; var firstRun = true; if (!watchExpressions.length) { // No expressions means we call the listener ASAP var shouldCall = true; self.$evalAsync(function() { if (shouldCall) listener(newValues, newValues, self); }); return function deregisterWatchGroup() { shouldCall = false; }; } if (watchExpressions.length === 1) { // Special case size of one return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) { newValues[0] = value; oldValues[0] = oldValue; listener(newValues, (value === oldValue) ? newValues : oldValues, scope); }); } forEach(watchExpressions, function(expr, i) { var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) { newValues[i] = value; oldValues[i] = oldValue; if (!changeReactionScheduled) { changeReactionScheduled = true; self.$evalAsync(watchGroupAction); } }); deregisterFns.push(unwatchFn); }); function watchGroupAction() { changeReactionScheduled = false; if (firstRun) { firstRun = false; listener(newValues, newValues, self); } else { listener(newValues, oldValues, self); } } return function deregisterWatchGroup() { while (deregisterFns.length) { deregisterFns.shift()(); } }; }, /** * @ngdoc method * @name $rootScope.Scope#$watchCollection * @kind function * * @description * Shallow watches the properties of an object and fires whenever any of the properties change * (for arrays, this implies watching the array items; for object maps, this implies watching * the properties). If a change is detected, the `listener` callback is fired. * * - The `obj` collection is observed via standard $watch operation and is examined on every * call to $digest() to see if any items have been added, removed, or moved. * - The `listener` is called whenever anything within the `obj` has changed. Examples include * adding, removing, and moving items belonging to an object or array. * * * # Example * ```js $scope.names = ['igor', 'matias', 'misko', 'james']; $scope.dataCount = 4; $scope.$watchCollection('names', function(newNames, oldNames) { $scope.dataCount = newNames.length; }); expect($scope.dataCount).toEqual(4); $scope.$digest(); //still at 4 ... no changes expect($scope.dataCount).toEqual(4); $scope.names.pop(); $scope.$digest(); //now there's been a change expect($scope.dataCount).toEqual(3); * ``` * * * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The * expression value should evaluate to an object or an array which is observed on each * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the * collection will trigger a call to the `listener`. * * @param {function(newCollection, oldCollection, scope)} listener a callback function called * when a change is detected. * - The `newCollection` object is the newly modified data obtained from the `obj` expression * - The `oldCollection` object is a copy of the former collection data. * Due to performance considerations, the`oldCollection` value is computed only if the * `listener` function declares two or more arguments. * - The `scope` argument refers to the current scope. * * @returns {function()} Returns a de-registration function for this listener. When the * de-registration function is executed, the internal watch operation is terminated. */ $watchCollection: function(obj, listener) { $watchCollectionInterceptor.$stateful = true; var self = this; // the current value, updated on each dirty-check run var newValue; // a shallow copy of the newValue from the last dirty-check run, // updated to match newValue during dirty-check run var oldValue; // a shallow copy of the newValue from when the last change happened var veryOldValue; // only track veryOldValue if the listener is asking for it var trackVeryOldValue = (listener.length > 1); var changeDetected = 0; var changeDetector = $parse(obj, $watchCollectionInterceptor); var internalArray = []; var internalObject = {}; var initRun = true; var oldLength = 0; function $watchCollectionInterceptor(_value) { newValue = _value; var newLength, key, bothNaN, newItem, oldItem; // If the new value is undefined, then return undefined as the watch may be a one-time watch if (isUndefined(newValue)) return; if (!isObject(newValue)) { // if primitive if (oldValue !== newValue) { oldValue = newValue; changeDetected++; } } else if (isArrayLike(newValue)) { if (oldValue !== internalArray) { // we are transitioning from something which was not an array into array. oldValue = internalArray; oldLength = oldValue.length = 0; changeDetected++; } newLength = newValue.length; if (oldLength !== newLength) { // if lengths do not match we need to trigger change notification changeDetected++; oldValue.length = oldLength = newLength; } // copy the items to oldValue and look for changes. for (var i = 0; i < newLength; i++) { oldItem = oldValue[i]; newItem = newValue[i]; // eslint-disable-next-line no-self-compare bothNaN = (oldItem !== oldItem) && (newItem !== newItem); if (!bothNaN && (oldItem !== newItem)) { changeDetected++; oldValue[i] = newItem; } } } else { if (oldValue !== internalObject) { // we are transitioning from something which was not an object into object. oldValue = internalObject = {}; oldLength = 0; changeDetected++; } // copy the items to oldValue and look for changes. newLength = 0; for (key in newValue) { if (hasOwnProperty.call(newValue, key)) { newLength++; newItem = newValue[key]; oldItem = oldValue[key]; if (key in oldValue) { // eslint-disable-next-line no-self-compare bothNaN = (oldItem !== oldItem) && (newItem !== newItem); if (!bothNaN && (oldItem !== newItem)) { changeDetected++; oldValue[key] = newItem; } } else { oldLength++; oldValue[key] = newItem; changeDetected++; } } } if (oldLength > newLength) { // we used to have more keys, need to find them and destroy them. changeDetected++; for (key in oldValue) { if (!hasOwnProperty.call(newValue, key)) { oldLength--; delete oldValue[key]; } } } } return changeDetected; } function $watchCollectionAction() { if (initRun) { initRun = false; listener(newValue, newValue, self); } else { listener(newValue, veryOldValue, self); } // make a copy for the next time a collection is changed if (trackVeryOldValue) { if (!isObject(newValue)) { //primitive veryOldValue = newValue; } else if (isArrayLike(newValue)) { veryOldValue = new Array(newValue.length); for (var i = 0; i < newValue.length; i++) { veryOldValue[i] = newValue[i]; } } else { // if object veryOldValue = {}; for (var key in newValue) { if (hasOwnProperty.call(newValue, key)) { veryOldValue[key] = newValue[key]; } } } } } return this.$watch(changeDetector, $watchCollectionAction); }, /** * @ngdoc method * @name $rootScope.Scope#$digest * @kind function * * @description * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} * until no more listeners are firing. This means that it is possible to get into an infinite * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of * iterations exceeds 10. * * Usually, you don't call `$digest()` directly in * {@link ng.directive:ngController controllers} or in * {@link ng.$compileProvider#directive directives}. * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`. * * If you want to be notified whenever `$digest()` is called, * you can register a `watchExpression` function with * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`. * * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. * * # Example * ```js var scope = ...; scope.name = 'misko'; scope.counter = 0; expect(scope.counter).toEqual(0); scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; }); expect(scope.counter).toEqual(0); scope.$digest(); // the listener is always called during the first $digest loop after it was registered expect(scope.counter).toEqual(1); scope.$digest(); // but now it will not be called unless the value changes expect(scope.counter).toEqual(1); scope.name = 'adam'; scope.$digest(); expect(scope.counter).toEqual(2); * ``` * */ $digest: function() { var watch, value, last, fn, get, watchers, dirty, ttl = TTL, next, current, target = this, watchLog = [], logIdx, asyncTask; beginPhase('$digest'); // Check for changes to browser url that happened in sync before the call to $digest $browser.$$checkUrlChange(); if (this === $rootScope && applyAsyncId !== null) { // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then // cancel the scheduled $apply and flush the queue of expressions to be evaluated. $browser.defer.cancel(applyAsyncId); flushApplyAsync(); } lastDirtyWatch = null; do { // "while dirty" loop dirty = false; current = target; // It's safe for asyncQueuePosition to be a local variable here because this loop can't // be reentered recursively. Calling $digest from a function passed to $evalAsync would // lead to a '$digest already in progress' error. for (var asyncQueuePosition = 0; asyncQueuePosition < asyncQueue.length; asyncQueuePosition++) { try { asyncTask = asyncQueue[asyncQueuePosition]; fn = asyncTask.fn; fn(asyncTask.scope, asyncTask.locals); } catch (e) { $exceptionHandler(e); } lastDirtyWatch = null; } asyncQueue.length = 0; traverseScopesLoop: do { // "traverse the scopes" loop if ((watchers = current.$$watchers)) { // process our watches watchers.$$digestWatchIndex = watchers.length; while (watchers.$$digestWatchIndex--) { try { watch = watchers[watchers.$$digestWatchIndex]; // Most common watches are on primitives, in which case we can short // circuit it with === operator, only when === fails do we use .equals if (watch) { get = watch.get; if ((value = get(current)) !== (last = watch.last) && !(watch.eq ? equals(value, last) : (isNumberNaN(value) && isNumberNaN(last)))) { dirty = true; lastDirtyWatch = watch; watch.last = watch.eq ? copy(value, null) : value; fn = watch.fn; fn(value, ((last === initWatchVal) ? value : last), current); if (ttl < 5) { logIdx = 4 - ttl; if (!watchLog[logIdx]) watchLog[logIdx] = []; watchLog[logIdx].push({ msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp, newVal: value, oldVal: last }); } } else if (watch === lastDirtyWatch) { // If the most recently dirty watcher is now clean, short circuit since the remaining watchers // have already been tested. dirty = false; break traverseScopesLoop; } } } catch (e) { $exceptionHandler(e); } } } // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $broadcast if (!(next = ((current.$$watchersCount && current.$$childHead) || (current !== target && current.$$nextSibling)))) { while (current !== target && !(next = current.$$nextSibling)) { current = current.$parent; } } } while ((current = next)); // `break traverseScopesLoop;` takes us to here if ((dirty || asyncQueue.length) && !(ttl--)) { clearPhase(); throw $rootScopeMinErr('infdig', '{0} $digest() iterations reached. Aborting!\n' + 'Watchers fired in the last 5 iterations: {1}', TTL, watchLog); } } while (dirty || asyncQueue.length); clearPhase(); // postDigestQueuePosition isn't local here because this loop can be reentered recursively. while (postDigestQueuePosition < postDigestQueue.length) { try { postDigestQueue[postDigestQueuePosition++](); } catch (e) { $exceptionHandler(e); } } postDigestQueue.length = postDigestQueuePosition = 0; // Check for changes to browser url that happened during the $digest // (for which no event is fired; e.g. via `history.pushState()`) $browser.$$checkUrlChange(); }, /** * @ngdoc event * @name $rootScope.Scope#$destroy * @eventType broadcast on scope being destroyed * * @description * Broadcasted when a scope and its children are being destroyed. * * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to * clean up DOM bindings before an element is removed from the DOM. */ /** * @ngdoc method * @name $rootScope.Scope#$destroy * @kind function * * @description * Removes the current scope (and all of its children) from the parent scope. Removal implies * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer * propagate to the current scope and its children. Removal also implies that the current * scope is eligible for garbage collection. * * The `$destroy()` is usually used by directives such as * {@link ng.directive:ngRepeat ngRepeat} for managing the * unrolling of the loop. * * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope. * Application code can register a `$destroy` event handler that will give it a chance to * perform any necessary cleanup. * * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to * clean up DOM bindings before an element is removed from the DOM. */ $destroy: function() { // We can't destroy a scope that has been already destroyed. if (this.$$destroyed) return; var parent = this.$parent; this.$broadcast('$destroy'); this.$$destroyed = true; if (this === $rootScope) { //Remove handlers attached to window when $rootScope is removed $browser.$$applicationDestroyed(); } incrementWatchersCount(this, -this.$$watchersCount); for (var eventName in this.$$listenerCount) { decrementListenerCount(this, this.$$listenerCount[eventName], eventName); } // sever all the references to parent scopes (after this cleanup, the current scope should // not be retained by any of our references and should be eligible for garbage collection) if (parent && parent.$$childHead === this) parent.$$childHead = this.$$nextSibling; if (parent && parent.$$childTail === this) parent.$$childTail = this.$$prevSibling; if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling; // Disable listeners, watchers and apply/digest methods this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop; this.$on = this.$watch = this.$watchGroup = function() { return noop; }; this.$$listeners = {}; // Disconnect the next sibling to prevent `cleanUpScope` destroying those too this.$$nextSibling = null; cleanUpScope(this); }, /** * @ngdoc method * @name $rootScope.Scope#$eval * @kind function * * @description * Executes the `expression` on the current scope and returns the result. Any exceptions in * the expression are propagated (uncaught). This is useful when evaluating Angular * expressions. * * # Example * ```js var scope = ng.$rootScope.Scope(); scope.a = 1; scope.b = 2; expect(scope.$eval('a+b')).toEqual(3); expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3); * ``` * * @param {(string|function())=} expression An angular expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with the current `scope` parameter. * * @param {(object)=} locals Local variables object, useful for overriding values in scope. * @returns {*} The result of evaluating the expression. */ $eval: function(expr, locals) { return $parse(expr)(this, locals); }, /** * @ngdoc method * @name $rootScope.Scope#$evalAsync * @kind function * * @description * Executes the expression on the current scope at a later point in time. * * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only * that: * * - it will execute after the function that scheduled the evaluation (preferably before DOM * rendering). * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after * `expression` execution. * * Any exceptions from the execution of the expression are forwarded to the * {@link ng.$exceptionHandler $exceptionHandler} service. * * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle * will be scheduled. However, it is encouraged to always call code that changes the model * from within an `$apply` call. That includes code evaluated via `$evalAsync`. * * @param {(string|function())=} expression An angular expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with the current `scope` parameter. * * @param {(object)=} locals Local variables object, useful for overriding values in scope. */ $evalAsync: function(expr, locals) { // if we are outside of an $digest loop and this is the first time we are scheduling async // task also schedule async auto-flush if (!$rootScope.$$phase && !asyncQueue.length) { $browser.defer(function() { if (asyncQueue.length) { $rootScope.$digest(); } }); } asyncQueue.push({scope: this, fn: $parse(expr), locals: locals}); }, $$postDigest: function(fn) { postDigestQueue.push(fn); }, /** * @ngdoc method * @name $rootScope.Scope#$apply * @kind function * * @description * `$apply()` is used to execute an expression in angular from outside of the angular * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). * Because we are calling into the angular framework we need to perform proper scope life * cycle of {@link ng.$exceptionHandler exception handling}, * {@link ng.$rootScope.Scope#$digest executing watches}. * * ## Life cycle * * # Pseudo-Code of `$apply()` * ```js function $apply(expr) { try { return $eval(expr); } catch (e) { $exceptionHandler(e); } finally { $root.$digest(); } } * ``` * * * Scope's `$apply()` method transitions through the following stages: * * 1. The {@link guide/expression expression} is executed using the * {@link ng.$rootScope.Scope#$eval $eval()} method. * 2. Any exceptions from the execution of the expression are forwarded to the * {@link ng.$exceptionHandler $exceptionHandler} service. * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. * * * @param {(string|function())=} exp An angular expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with current `scope` parameter. * * @returns {*} The result of evaluating the expression. */ $apply: function(expr) { try { beginPhase('$apply'); try { return this.$eval(expr); } finally { clearPhase(); } } catch (e) { $exceptionHandler(e); } finally { try { $rootScope.$digest(); } catch (e) { $exceptionHandler(e); // eslint-disable-next-line no-unsafe-finally throw e; } } }, /** * @ngdoc method * @name $rootScope.Scope#$applyAsync * @kind function * * @description * Schedule the invocation of $apply to occur at a later time. The actual time difference * varies across browsers, but is typically around ~10 milliseconds. * * This can be used to queue up multiple expressions which need to be evaluated in the same * digest. * * @param {(string|function())=} exp An angular expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with current `scope` parameter. */ $applyAsync: function(expr) { var scope = this; if (expr) { applyAsyncQueue.push($applyAsyncExpression); } expr = $parse(expr); scheduleApplyAsync(); function $applyAsyncExpression() { scope.$eval(expr); } }, /** * @ngdoc method * @name $rootScope.Scope#$on * @kind function * * @description * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for * discussion of event life cycle. * * The event listener function format is: `function(event, args...)`. The `event` object * passed into the listener has the following attributes: * * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or * `$broadcast`-ed. * - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the * event propagates through the scope hierarchy, this property is set to null. * - `name` - `{string}`: name of the event. * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel * further event propagation (available only for events that were `$emit`-ed). * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag * to true. * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called. * * @param {string} name Event name to listen on. * @param {function(event, ...args)} listener Function to call when the event is emitted. * @returns {function()} Returns a deregistration function for this listener. */ $on: function(name, listener) { var namedListeners = this.$$listeners[name]; if (!namedListeners) { this.$$listeners[name] = namedListeners = []; } namedListeners.push(listener); var current = this; do { if (!current.$$listenerCount[name]) { current.$$listenerCount[name] = 0; } current.$$listenerCount[name]++; } while ((current = current.$parent)); var self = this; return function() { var indexOfListener = namedListeners.indexOf(listener); if (indexOfListener !== -1) { namedListeners[indexOfListener] = null; decrementListenerCount(self, 1, name); } }; }, /** * @ngdoc method * @name $rootScope.Scope#$emit * @kind function * * @description * Dispatches an event `name` upwards through the scope hierarchy notifying the * registered {@link ng.$rootScope.Scope#$on} listeners. * * The event life cycle starts at the scope on which `$emit` was called. All * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get * notified. Afterwards, the event traverses upwards toward the root scope and calls all * registered listeners along the way. The event will stop propagating if one of the listeners * cancels it. * * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * * @param {string} name Event name to emit. * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}). */ $emit: function(name, args) { var empty = [], namedListeners, scope = this, stopPropagation = false, event = { name: name, targetScope: scope, stopPropagation: function() {stopPropagation = true;}, preventDefault: function() { event.defaultPrevented = true; }, defaultPrevented: false }, listenerArgs = concat([event], arguments, 1), i, length; do { namedListeners = scope.$$listeners[name] || empty; event.currentScope = scope; for (i = 0, length = namedListeners.length; i < length; i++) { // if listeners were deregistered, defragment the array if (!namedListeners[i]) { namedListeners.splice(i, 1); i--; length--; continue; } try { //allow all listeners attached to the current scope to run namedListeners[i].apply(null, listenerArgs); } catch (e) { $exceptionHandler(e); } } //if any listener on the current scope stops propagation, prevent bubbling if (stopPropagation) { event.currentScope = null; return event; } //traverse upwards scope = scope.$parent; } while (scope); event.currentScope = null; return event; }, /** * @ngdoc method * @name $rootScope.Scope#$broadcast * @kind function * * @description * Dispatches an event `name` downwards to all child scopes (and their children) notifying the * registered {@link ng.$rootScope.Scope#$on} listeners. * * The event life cycle starts at the scope on which `$broadcast` was called. All * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get * notified. Afterwards, the event propagates to all direct and indirect scopes of the current * scope and calls all registered listeners along the way. The event cannot be canceled. * * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * * @param {string} name Event name to broadcast. * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} */ $broadcast: function(name, args) { var target = this, current = target, next = target, event = { name: name, targetScope: target, preventDefault: function() { event.defaultPrevented = true; }, defaultPrevented: false }; if (!target.$$listenerCount[name]) return event; var listenerArgs = concat([event], arguments, 1), listeners, i, length; //down while you can, then up and next sibling or up and next sibling until back at root while ((current = next)) { event.currentScope = current; listeners = current.$$listeners[name] || []; for (i = 0, length = listeners.length; i < length; i++) { // if listeners were deregistered, defragment the array if (!listeners[i]) { listeners.splice(i, 1); i--; length--; continue; } try { listeners[i].apply(null, listenerArgs); } catch (e) { $exceptionHandler(e); } } // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $digest // (though it differs due to having the extra check for $$listenerCount) if (!(next = ((current.$$listenerCount[name] && current.$$childHead) || (current !== target && current.$$nextSibling)))) { while (current !== target && !(next = current.$$nextSibling)) { current = current.$parent; } } } event.currentScope = null; return event; } }; var $rootScope = new Scope(); //The internal queues. Expose them on the $rootScope for debugging/testing purposes. var asyncQueue = $rootScope.$$asyncQueue = []; var postDigestQueue = $rootScope.$$postDigestQueue = []; var applyAsyncQueue = $rootScope.$$applyAsyncQueue = []; var postDigestQueuePosition = 0; return $rootScope; function beginPhase(phase) { if ($rootScope.$$phase) { throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase); } $rootScope.$$phase = phase; } function clearPhase() { $rootScope.$$phase = null; } function incrementWatchersCount(current, count) { do { current.$$watchersCount += count; } while ((current = current.$parent)); } function decrementListenerCount(current, count, name) { do { current.$$listenerCount[name] -= count; if (current.$$listenerCount[name] === 0) { delete current.$$listenerCount[name]; } } while ((current = current.$parent)); } /** * function used as an initial value for watchers. * because it's unique we can easily tell it apart from other values */ function initWatchVal() {} function flushApplyAsync() { while (applyAsyncQueue.length) { try { applyAsyncQueue.shift()(); } catch (e) { $exceptionHandler(e); } } applyAsyncId = null; } function scheduleApplyAsync() { if (applyAsyncId === null) { applyAsyncId = $browser.defer(function() { $rootScope.$apply(flushApplyAsync); }); } } }]; } /** * @ngdoc service * @name $rootElement * * @description * The root element of Angular application. This is either the element where {@link * ng.directive:ngApp ngApp} was declared or the element passed into * {@link angular.bootstrap}. The element represents the root element of application. It is also the * location where the application's {@link auto.$injector $injector} service gets * published, and can be retrieved using `$rootElement.injector()`. */ // the implementation is in angular.bootstrap /** * @this * @description * Private service to sanitize uris for links and images. Used by $compile and $sanitize. */ function $$SanitizeUriProvider() { var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/; /** * @description * Retrieves or overrides the default regular expression that is used for whitelisting of safe * urls during a[href] sanitization. * * The sanitization is a security measure aimed at prevent XSS attacks via html links. * * Any url about to be assigned to a[href] via data-binding is first normalized and turned into * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` * regular expression. If a match is found, the original url is written into the dom. Otherwise, * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. * * @param {RegExp=} regexp New regexp to whitelist urls with. * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for * chaining otherwise. */ this.aHrefSanitizationWhitelist = function(regexp) { if (isDefined(regexp)) { aHrefSanitizationWhitelist = regexp; return this; } return aHrefSanitizationWhitelist; }; /** * @description * Retrieves or overrides the default regular expression that is used for whitelisting of safe * urls during img[src] sanitization. * * The sanitization is a security measure aimed at prevent XSS attacks via html links. * * Any url about to be assigned to img[src] via data-binding is first normalized and turned into * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` * regular expression. If a match is found, the original url is written into the dom. Otherwise, * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. * * @param {RegExp=} regexp New regexp to whitelist urls with. * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for * chaining otherwise. */ this.imgSrcSanitizationWhitelist = function(regexp) { if (isDefined(regexp)) { imgSrcSanitizationWhitelist = regexp; return this; } return imgSrcSanitizationWhitelist; }; this.$get = function() { return function sanitizeUri(uri, isImage) { var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; var normalizedVal; normalizedVal = urlResolve(uri).href; if (normalizedVal !== '' && !normalizedVal.match(regex)) { return 'unsafe:' + normalizedVal; } return uri; }; }; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Any commits to this file should be reviewed with security in mind. * * Changes to this file can potentially create security vulnerabilities. * * An approval from 2 Core members with history of modifying * * this file is required. * * * * Does the change somehow allow for arbitrary javascript to be executed? * * Or allows for someone to change the prototype of built-in objects? * * Or gives undesired access to variables likes document or window? * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* exported $SceProvider, $SceDelegateProvider */ var $sceMinErr = minErr('$sce'); var SCE_CONTEXTS = { // HTML is used when there's HTML rendered (e.g. ng-bind-html, iframe srcdoc binding). HTML: 'html', // Style statements or stylesheets. Currently unused in AngularJS. CSS: 'css', // An URL used in a context where it does not refer to a resource that loads code. Currently // unused in AngularJS. URL: 'url', // RESOURCE_URL is a subtype of URL used where the referred-to resource could be interpreted as // code. (e.g. ng-include, script src binding, templateUrl) RESOURCE_URL: 'resourceUrl', // Script. Currently unused in AngularJS. JS: 'js' }; // Helper functions follow. var UNDERSCORE_LOWERCASE_REGEXP = /_([a-z])/g; function snakeToCamel(name) { return name .replace(UNDERSCORE_LOWERCASE_REGEXP, fnCamelCaseReplace); } function adjustMatcher(matcher) { if (matcher === 'self') { return matcher; } else if (isString(matcher)) { // Strings match exactly except for 2 wildcards - '*' and '**'. // '*' matches any character except those from the set ':/.?&'. // '**' matches any character (like .* in a RegExp). // More than 2 *'s raises an error as it's ill defined. if (matcher.indexOf('***') > -1) { throw $sceMinErr('iwcard', 'Illegal sequence *** in string matcher. String: {0}', matcher); } matcher = escapeForRegexp(matcher). replace(/\\\*\\\*/g, '.*'). replace(/\\\*/g, '[^:/.?&;]*'); return new RegExp('^' + matcher + '$'); } else if (isRegExp(matcher)) { // The only other type of matcher allowed is a Regexp. // Match entire URL / disallow partial matches. // Flags are reset (i.e. no global, ignoreCase or multiline) return new RegExp('^' + matcher.source + '$'); } else { throw $sceMinErr('imatcher', 'Matchers may only be "self", string patterns or RegExp objects'); } } function adjustMatchers(matchers) { var adjustedMatchers = []; if (isDefined(matchers)) { forEach(matchers, function(matcher) { adjustedMatchers.push(adjustMatcher(matcher)); }); } return adjustedMatchers; } /** * @ngdoc service * @name $sceDelegate * @kind function * * @description * * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict * Contextual Escaping (SCE)} services to AngularJS. * * For an overview of this service and the functionnality it provides in AngularJS, see the main * page for {@link ng.$sce SCE}. The current page is targeted for developers who need to alter how * SCE works in their application, which shouldn't be needed in most cases. * *
* AngularJS strongly relies on contextual escaping for the security of bindings: disabling or * modifying this might cause cross site scripting (XSS) vulnerabilities. For libraries owners, * changes to this service will also influence users, so be extra careful and document your changes. *
* * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things * work because `$sce` delegates to `$sceDelegate` for these operations. * * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service. * * The default instance of `$sceDelegate` should work out of the box with little pain. While you * can override it completely to change the behavior of `$sce`, the common case would * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist * $sceDelegateProvider.resourceUrlWhitelist} and {@link * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} */ /** * @ngdoc provider * @name $sceDelegateProvider * @this * * @description * * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate * $sceDelegate service}, used as a delegate for {@link ng.$sce Strict Contextual Escaping (SCE)}. * * The `$sceDelegateProvider` allows one to get/set the whitelists and blacklists used to ensure * that the URLs used for sourcing AngularJS templates and other script-running URLs are safe (all * places that use the `$sce.RESOURCE_URL` context). See * {@link ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} * and * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}, * * For the general details about this service in Angular, read the main page for {@link ng.$sce * Strict Contextual Escaping (SCE)}. * * **Example**: Consider the following case.
* * - your app is hosted at url `http://myapp.example.com/` * - but some of your templates are hosted on other domains you control such as * `http://srv01.assets.example.com/`, `http://srv02.assets.example.com/`, etc. * - and you have an open redirect at `http://myapp.example.com/clickThru?...`. * * Here is what a secure configuration for this scenario might look like: * * ``` * angular.module('myApp', []).config(function($sceDelegateProvider) { * $sceDelegateProvider.resourceUrlWhitelist([ * // Allow same origin resource loads. * 'self', * // Allow loading from our assets domain. Notice the difference between * and **. * 'http://srv*.assets.example.com/**' * ]); * * // The blacklist overrides the whitelist so the open redirect here is blocked. * $sceDelegateProvider.resourceUrlBlacklist([ * 'http://myapp.example.com/clickThru**' * ]); * }); * ``` * Note that an empty whitelist will block every resource URL from being loaded, and will require * you to manually mark each one as trusted with `$sce.trustAsResourceUrl`. However, templates * requested by {@link ng.$templateRequest $templateRequest} that are present in * {@link ng.$templateCache $templateCache} will not go through this check. If you have a mechanism * to populate your templates in that cache at config time, then it is a good idea to remove 'self' * from that whitelist. This helps to mitigate the security impact of certain types of issues, like * for instance attacker-controlled `ng-includes`. */ function $SceDelegateProvider() { this.SCE_CONTEXTS = SCE_CONTEXTS; // Resource URLs can also be trusted by policy. var resourceUrlWhitelist = ['self'], resourceUrlBlacklist = []; /** * @ngdoc method * @name $sceDelegateProvider#resourceUrlWhitelist * @kind function * * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value * provided. This must be an array or null. A snapshot of this array is used so further * changes to the array are ignored. * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items * allowed in this array. * * @return {Array} The currently set whitelist array. * * @description * Sets/Gets the whitelist of trusted resource URLs. * * The **default value** when no whitelist has been explicitly set is `['self']` allowing only * same origin resource requests. * *
* **Note:** the default whitelist of 'self' is not recommended if your app shares its origin * with other apps! It is a good idea to limit it to only your application's directory. *
*/ this.resourceUrlWhitelist = function(value) { if (arguments.length) { resourceUrlWhitelist = adjustMatchers(value); } return resourceUrlWhitelist; }; /** * @ngdoc method * @name $sceDelegateProvider#resourceUrlBlacklist * @kind function * * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value * provided. This must be an array or null. A snapshot of this array is used so further * changes to the array are ignored.

* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items * allowed in this array.

* The typical usage for the blacklist is to **block * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as * these would otherwise be trusted but actually return content from the redirected domain. *

* Finally, **the blacklist overrides the whitelist** and has the final say. * * @return {Array} The currently set blacklist array. * * @description * Sets/Gets the blacklist of trusted resource URLs. * * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there * is no blacklist.) */ this.resourceUrlBlacklist = function(value) { if (arguments.length) { resourceUrlBlacklist = adjustMatchers(value); } return resourceUrlBlacklist; }; this.$get = ['$injector', function($injector) { var htmlSanitizer = function htmlSanitizer(html) { throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); }; if ($injector.has('$sanitize')) { htmlSanitizer = $injector.get('$sanitize'); } function matchUrl(matcher, parsedUrl) { if (matcher === 'self') { return urlIsSameOrigin(parsedUrl); } else { // definitely a regex. See adjustMatchers() return !!matcher.exec(parsedUrl.href); } } function isResourceUrlAllowedByPolicy(url) { var parsedUrl = urlResolve(url.toString()); var i, n, allowed = false; // Ensure that at least one item from the whitelist allows this url. for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) { if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) { allowed = true; break; } } if (allowed) { // Ensure that no item from the blacklist blocked this url. for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) { if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) { allowed = false; break; } } } return allowed; } function generateHolderType(Base) { var holderType = function TrustedValueHolderType(trustedValue) { this.$$unwrapTrustedValue = function() { return trustedValue; }; }; if (Base) { holderType.prototype = new Base(); } holderType.prototype.valueOf = function sceValueOf() { return this.$$unwrapTrustedValue(); }; holderType.prototype.toString = function sceToString() { return this.$$unwrapTrustedValue().toString(); }; return holderType; } var trustedValueHolderBase = generateHolderType(), byType = {}; byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase); byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase); byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase); byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase); byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]); /** * @ngdoc method * @name $sceDelegate#trustAs * * @description * Returns a trusted representation of the parameter for the specified context. This trusted * object will later on be used as-is, without any security check, by bindings or directives * that require this security context. * For instance, marking a string as trusted for the `$sce.HTML` context will entirely bypass * the potential `$sanitize` call in corresponding `$sce.HTML` bindings or directives, such as * `ng-bind-html`. Note that in most cases you won't need to call this function: if you have the * sanitizer loaded, passing the value itself will render all the HTML that does not pose a * security risk. * * See {@link ng.$sceDelegate#getTrusted getTrusted} for the function that will consume those * trusted values, and {@link ng.$sce $sce} for general documentation about strict contextual * escaping. * * @param {string} type The context in which this value is safe for use, e.g. `$sce.URL`, * `$sce.RESOURCE_URL`, `$sce.HTML`, `$sce.JS` or `$sce.CSS`. * * @param {*} value The value that should be considered trusted. * @return {*} A trusted representation of value, that can be used in the given context. */ function trustAs(type, trustedValue) { var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null); if (!Constructor) { throw $sceMinErr('icontext', 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}', type, trustedValue); } if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') { return trustedValue; } // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting // mutable objects, we ensure here that the value passed in is actually a string. if (typeof trustedValue !== 'string') { throw $sceMinErr('itype', 'Attempted to trust a non-string value in a content requiring a string: Context: {0}', type); } return new Constructor(trustedValue); } /** * @ngdoc method * @name $sceDelegate#valueOf * * @description * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. * * If the passed parameter is not a value that had been returned by {@link * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, it must be returned as-is. * * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} * call or anything else. * @return {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns * `value` unchanged. */ function valueOf(maybeTrusted) { if (maybeTrusted instanceof trustedValueHolderBase) { return maybeTrusted.$$unwrapTrustedValue(); } else { return maybeTrusted; } } /** * @ngdoc method * @name $sceDelegate#getTrusted * * @description * Takes any input, and either returns a value that's safe to use in the specified context, or * throws an exception. * * In practice, there are several cases. When given a string, this function runs checks * and sanitization to make it safe without prior assumptions. When given the result of a {@link * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call, it returns the originally supplied * value if that value's context is valid for this call's context. Finally, this function can * also throw when there is no way to turn `maybeTrusted` in a safe value (e.g., no sanitization * is available or possible.) * * @param {string} type The context in which this value is to be used (such as `$sce.HTML`). * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs * `$sceDelegate.trustAs`} call, or anything else (which will not be considered trusted.) * @return {*} A version of the value that's safe to use in the given context, or throws an * exception if this is impossible. */ function getTrusted(type, maybeTrusted) { if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') { return maybeTrusted; } var constructor = (byType.hasOwnProperty(type) ? byType[type] : null); // If maybeTrusted is a trusted class instance or subclass instance, then unwrap and return // as-is. if (constructor && maybeTrusted instanceof constructor) { return maybeTrusted.$$unwrapTrustedValue(); } // Otherwise, if we get here, then we may either make it safe, or throw an exception. This // depends on the context: some are sanitizatible (HTML), some use whitelists (RESOURCE_URL), // some are impossible to do (JS). This step isn't implemented for CSS and URL, as AngularJS // has no corresponding sinks. if (type === SCE_CONTEXTS.RESOURCE_URL) { // RESOURCE_URL uses a whitelist. if (isResourceUrlAllowedByPolicy(maybeTrusted)) { return maybeTrusted; } else { throw $sceMinErr('insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}', maybeTrusted.toString()); } } else if (type === SCE_CONTEXTS.HTML) { // htmlSanitizer throws its own error when no sanitizer is available. return htmlSanitizer(maybeTrusted); } // Default error when the $sce service has no way to make the input safe. throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); } return { trustAs: trustAs, getTrusted: getTrusted, valueOf: valueOf }; }]; } /** * @ngdoc provider * @name $sceProvider * @this * * @description * * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service. * - enable/disable Strict Contextual Escaping (SCE) in a module * - override the default implementation with a custom delegate * * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}. */ /** * @ngdoc service * @name $sce * @kind function * * @description * * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. * * # Strict Contextual Escaping * * Strict Contextual Escaping (SCE) is a mode in which AngularJS constrains bindings to only render * trusted values. Its goal is to assist in writing code in a way that (a) is secure by default, and * (b) makes auditing for security vulnerabilities such as XSS, clickjacking, etc. a lot easier. * * ## Overview * * To systematically block XSS security bugs, AngularJS treats all values as untrusted by default in * HTML or sensitive URL bindings. When binding untrusted values, AngularJS will automatically * run security checks on them (sanitizations, whitelists, depending on context), or throw when it * cannot guarantee the security of the result. That behavior depends strongly on contexts: HTML * can be sanitized, but template URLs cannot, for instance. * * To illustrate this, consider the `ng-bind-html` directive. It renders its value directly as HTML: * we call that the *context*. When given an untrusted input, AngularJS will attempt to sanitize it * before rendering if a sanitizer is available, and throw otherwise. To bypass sanitization and * render the input as-is, you will need to mark it as trusted for that context before attempting * to bind it. * * As of version 1.2, AngularJS ships with SCE enabled by default. * * ## In practice * * Here's an example of a binding in a privileged context: * * ``` * *

* ``` * * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE * disabled, this application allows the user to render arbitrary HTML into the DIV, which would * be an XSS security bug. In a more realistic example, one may be rendering user comments, blog * articles, etc. via bindings. (HTML is just one example of a context where rendering user * controlled input creates security vulnerabilities.) * * For the case of HTML, you might use a library, either on the client side, or on the server side, * to sanitize unsafe HTML before binding to the value and rendering it in the document. * * How would you ensure that every place that used these types of bindings was bound to a value that * was sanitized by your library (or returned as safe for rendering by your server?) How can you * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some * properties/fields and forgot to update the binding to the sanitized value? * * To be secure by default, AngularJS makes sure bindings go through that sanitization, or * any similar validation process, unless there's a good reason to trust the given value in this * context. That trust is formalized with a function call. This means that as a developer, you * can assume all untrusted bindings are safe. Then, to audit your code for binding security issues, * you just need to ensure the values you mark as trusted indeed are safe - because they were * received from your server, sanitized by your library, etc. You can organize your codebase to * help with this - perhaps allowing only the files in a specific directory to do this. * Ensuring that the internal API exposed by that code doesn't markup arbitrary values as safe then * becomes a more manageable task. * * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to * build the trusted versions of your values. * * ## How does it work? * * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted * $sce.getTrusted(context, value)} rather than to the value directly. Think of this function as * a way to enforce the required security context in your data sink. Directives use {@link * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs * the {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. Also, * when binding without directives, AngularJS will understand the context of your bindings * automatically. * * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly * simplified): * * ``` * var ngBindHtmlDirective = ['$sce', function($sce) { * return function(scope, element, attr) { * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) { * element.html(value || ''); * }); * }; * }]; * ``` * * ## Impact on loading templates * * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as * `templateUrl`'s specified by {@link guide/directive directives}. * * By default, Angular only loads templates from the same domain and protocol as the application * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value. * * *Please note*: * The browser's * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/) * policy apply in addition to this and may further restrict whether the template is successfully * loaded. This means that without the right CORS policy, loading templates from a different domain * won't work on all browsers. Also, loading templates from `file://` URL does not work on some * browsers. * * ## This feels like too much overhead * * It's important to remember that SCE only applies to interpolation expressions. * * If your expressions are constant literals, they're automatically trusted and you don't need to * call `$sce.trustAs` on them (e.g. * `
`) just works. The `$sceDelegate` will * also use the `$sanitize` service if it is available when binding untrusted values to * `$sce.HTML` context. AngularJS provides an implementation in `angular-sanitize.js`, and if you * wish to use it, you will also need to depend on the {@link ngSanitize `ngSanitize`} module in * your application. * * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load * templates in `ng-include` from your application's domain without having to even know about SCE. * It blocks loading templates from other domains or loading templates over http from an https * served document. You can change these by setting your own custom {@link * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs. * * This significantly reduces the overhead. It is far easier to pay the small overhead and have an * application that's secure and can be audited to verify that with much more ease than bolting * security onto an application later. * * * ## What trusted context types are supported? * * | Context | Notes | * |---------------------|----------------| * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered, and the {@link ngSanitize.$sanitize $sanitize} service is available (implemented by the {@link ngSanitize ngSanitize} module) this will sanitize the value instead of throwing an error. | * | `$sce.CSS` | For CSS that's safe to source into the application. Currently, no bindings require this context. Feel free to use it in your own directives. | * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`
Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does (it's not just the URL that matters, but also what is at the end of it), and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently, no bindings require this context. Feel free to use it in your own directives. | * * * Be aware that `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them * through {@link ng.$sce#getTrusted $sce.getTrusted}. There's no CSS-, URL-, or JS-context bindings * in AngularJS currently, so their corresponding `$sce.trustAs` functions aren't useful yet. This * might evolve. * * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist}
* * Each element in these arrays must be one of the following: * * - **'self'** * - The special **string**, `'self'`, can be used to match against all URLs of the **same * domain** as the application document using the **same protocol**. * - **String** (except the special value `'self'`) * - The string is matched against the full *normalized / absolute URL* of the resource * being tested (substring matches are not good enough.) * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters * match themselves. * - `*`: matches zero or more occurrences of any character other than one of the following 6 * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'. It's a useful wildcard for use * in a whitelist. * - `**`: matches zero or more occurrences of *any* character. As such, it's not * appropriate for use in a scheme, domain, etc. as it would match too much. (e.g. * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might * not have been the intention.) Its usage at the very end of the path is ok. (e.g. * http://foo.example.com/templates/**). * - **RegExp** (*see caveat below*) * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax * (and all the inevitable escaping) makes them *harder to maintain*. It's easy to * accidentally introduce a bug when one updates a complex expression (imho, all regexes should * have good test coverage). For instance, the use of `.` in the regex is correct only in a * small number of cases. A `.` character in the regex used when matching the scheme or a * subdomain could be matched against a `:` or literal `.` that was likely not intended. It * is highly recommended to use the string patterns and only fall back to regular expressions * as a last resort. * - The regular expression must be an instance of RegExp (i.e. not a string.) It is * matched against the **entire** *normalized / absolute URL* of the resource being tested * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags * present on the RegExp (such as multiline, global, ignoreCase) are ignored. * - If you are generating your JavaScript from some other templating engine (not * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)), * remember to escape your regular expression (and be aware that you might need more than * one level of escaping depending on your templating engine and the way you interpolated * the value.) Do make use of your platform's escaping mechanism as it might be good * enough before coding your own. E.g. Ruby has * [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape) * and Python has [re.escape](http://docs.python.org/library/re.html#re.escape). * Javascript lacks a similar built in function for escaping. Take a look at Google * Closure library's [goog.string.regExpEscape(s)]( * http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962). * * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. * * ## Show me an example using SCE. * * * *
*

* User comments
* By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when * $sanitize is available. If $sanitize isn't available, this results in an error instead of an * exploit. *
*
* {{userComment.name}}: * *
*
*
*
*
* * * angular.module('mySceApp', ['ngSanitize']) * .controller('AppController', ['$http', '$templateCache', '$sce', * function AppController($http, $templateCache, $sce) { * var self = this; * $http.get('test_data.json', {cache: $templateCache}).then(function(response) { * self.userComments = response.data; * }); * self.explicitlyTrustedHtml = $sce.trustAsHtml( * 'Hover over this text.'); * }]); * * * * [ * { "name": "Alice", * "htmlComment": * "Is anyone reading this?" * }, * { "name": "Bob", * "htmlComment": "Yes! Am I the only other one?" * } * ] * * * * describe('SCE doc demo', function() { * it('should sanitize untrusted values', function() { * expect(element.all(by.css('.htmlComment')).first().getAttribute('innerHTML')) * .toBe('Is anyone reading this?'); * }); * * it('should NOT sanitize explicitly trusted values', function() { * expect(element(by.id('explicitlyTrustedHtml')).getAttribute('innerHTML')).toBe( * 'Hover over this text.'); * }); * }); * *
* * * * ## Can I disable SCE completely? * * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits * for little coding overhead. It will be much harder to take an SCE disabled application and * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE * for cases where you have a lot of existing code that was written before SCE was introduced and * you're migrating them a module at a time. Also do note that this is an app-wide setting, so if * you are writing a library, you will cause security bugs applications using it. * * That said, here's how you can completely disable SCE: * * ``` * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) { * // Completely disable SCE. For demonstration purposes only! * // Do not use in new projects or libraries. * $sceProvider.enabled(false); * }); * ``` * */ function $SceProvider() { var enabled = true; /** * @ngdoc method * @name $sceProvider#enabled * @kind function * * @param {boolean=} value If provided, then enables/disables SCE application-wide. * @return {boolean} True if SCE is enabled, false otherwise. * * @description * Enables/disables SCE and returns the current value. */ this.enabled = function(value) { if (arguments.length) { enabled = !!value; } return enabled; }; /* Design notes on the default implementation for SCE. * * The API contract for the SCE delegate * ------------------------------------- * The SCE delegate object must provide the following 3 methods: * * - trustAs(contextEnum, value) * This method is used to tell the SCE service that the provided value is OK to use in the * contexts specified by contextEnum. It must return an object that will be accepted by * getTrusted() for a compatible contextEnum and return this value. * * - valueOf(value) * For values that were not produced by trustAs(), return them as is. For values that were * produced by trustAs(), return the corresponding input value to trustAs. Basically, if * trustAs is wrapping the given values into some type, this operation unwraps it when given * such a value. * * - getTrusted(contextEnum, value) * This function should return the a value that is safe to use in the context specified by * contextEnum or throw and exception otherwise. * * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be * opaque or wrapped in some holder object. That happens to be an implementation detail. For * instance, an implementation could maintain a registry of all trusted objects by context. In * such a case, trustAs() would return the same object that was passed in. getTrusted() would * return the same object passed in if it was found in the registry under a compatible context or * throw an exception otherwise. An implementation might only wrap values some of the time based * on some criteria. getTrusted() might return a value and not throw an exception for special * constants or objects even if not wrapped. All such implementations fulfill this contract. * * * A note on the inheritance model for SCE contexts * ------------------------------------------------ * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This * is purely an implementation details. * * The contract is simply this: * * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value) * will also succeed. * * Inheritance happens to capture this in a natural way. In some future, we may not use * inheritance anymore. That is OK because no code outside of sce.js and sceSpecs.js would need to * be aware of this detail. */ this.$get = ['$parse', '$sceDelegate', function( $parse, $sceDelegate) { // Support: IE 9-11 only // Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow // the "expression(javascript expression)" syntax which is insecure. if (enabled && msie < 8) { throw $sceMinErr('iequirks', 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' + 'mode. You can fix this by adding the text to the top of your HTML ' + 'document. See http://docs.angularjs.org/api/ng.$sce for more information.'); } var sce = shallowCopy(SCE_CONTEXTS); /** * @ngdoc method * @name $sce#isEnabled * @kind function * * @return {Boolean} True if SCE is enabled, false otherwise. If you want to set the value, you * have to do it at module config time on {@link ng.$sceProvider $sceProvider}. * * @description * Returns a boolean indicating if SCE is enabled. */ sce.isEnabled = function() { return enabled; }; sce.trustAs = $sceDelegate.trustAs; sce.getTrusted = $sceDelegate.getTrusted; sce.valueOf = $sceDelegate.valueOf; if (!enabled) { sce.trustAs = sce.getTrusted = function(type, value) { return value; }; sce.valueOf = identity; } /** * @ngdoc method * @name $sce#parseAs * * @description * Converts Angular {@link guide/expression expression} into a function. This is like {@link * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, * *result*)} * * @param {string} type The SCE context in which this result will be used. * @param {string} expression String expression to compile. * @return {function(context, locals)} A function which represents the compiled expression: * * * `context` – `{object}` – an object against which any expressions embedded in the * strings are evaluated against (typically a scope object). * * `locals` – `{object=}` – local variables context object, useful for overriding values * in `context`. */ sce.parseAs = function sceParseAs(type, expr) { var parsed = $parse(expr); if (parsed.literal && parsed.constant) { return parsed; } else { return $parse(expr, function(value) { return sce.getTrusted(type, value); }); } }; /** * @ngdoc method * @name $sce#trustAs * * @description * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, returns a * wrapped object that represents your value, and the trust you have in its safety for the given * context. AngularJS can then use that value as-is in bindings of the specified secure context. * This is used in bindings for `ng-bind-html`, `ng-include`, and most `src` attribute * interpolations. See {@link ng.$sce $sce} for strict contextual escaping. * * @param {string} type The context in which this value is safe for use, e.g. `$sce.URL`, * `$sce.RESOURCE_URL`, `$sce.HTML`, `$sce.JS` or `$sce.CSS`. * * @param {*} value The value that that should be considered trusted. * @return {*} A wrapped version of value that can be used as a trusted variant of your `value` * in the context you specified. */ /** * @ngdoc method * @name $sce#trustAsHtml * * @description * Shorthand method. `$sce.trustAsHtml(value)` → * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`} * * @param {*} value The value to mark as trusted for `$sce.HTML` context. * @return {*} A wrapped version of value that can be used as a trusted variant of your `value` * in `$sce.HTML` context (like `ng-bind-html`). */ /** * @ngdoc method * @name $sce#trustAsCss * * @description * Shorthand method. `$sce.trustAsCss(value)` → * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.CSS, value)`} * * @param {*} value The value to mark as trusted for `$sce.CSS` context. * @return {*} A wrapped version of value that can be used as a trusted variant * of your `value` in `$sce.CSS` context. This context is currently unused, so there are * almost no reasons to use this function so far. */ /** * @ngdoc method * @name $sce#trustAsUrl * * @description * Shorthand method. `$sce.trustAsUrl(value)` → * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`} * * @param {*} value The value to mark as trusted for `$sce.URL` context. * @return {*} A wrapped version of value that can be used as a trusted variant of your `value` * in `$sce.URL` context. That context is currently unused, so there are almost no reasons * to use this function so far. */ /** * @ngdoc method * @name $sce#trustAsResourceUrl * * @description * Shorthand method. `$sce.trustAsResourceUrl(value)` → * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} * * @param {*} value The value to mark as trusted for `$sce.RESOURCE_URL` context. * @return {*} A wrapped version of value that can be used as a trusted variant of your `value` * in `$sce.RESOURCE_URL` context (template URLs in `ng-include`, most `src` attribute * bindings, ...) */ /** * @ngdoc method * @name $sce#trustAsJs * * @description * Shorthand method. `$sce.trustAsJs(value)` → * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`} * * @param {*} value The value to mark as trusted for `$sce.JS` context. * @return {*} A wrapped version of value that can be used as a trusted variant of your `value` * in `$sce.JS` context. That context is currently unused, so there are almost no reasons to * use this function so far. */ /** * @ngdoc method * @name $sce#getTrusted * * @description * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, * takes any input, and either returns a value that's safe to use in the specified context, * or throws an exception. This function is aware of trusted values created by the `trustAs` * function and its shorthands, and when contexts are appropriate, returns the unwrapped value * as-is. Finally, this function can also throw when there is no way to turn `maybeTrusted` in a * safe value (e.g., no sanitization is available or possible.) * * @param {string} type The context in which this value is to be used. * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs * `$sce.trustAs`} call, or anything else (which will not be considered trusted.) * @return {*} A version of the value that's safe to use in the given context, or throws an * exception if this is impossible. */ /** * @ngdoc method * @name $sce#getTrustedHtml * * @description * Shorthand method. `$sce.getTrustedHtml(value)` → * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @return {*} The return value of `$sce.getTrusted($sce.HTML, value)` */ /** * @ngdoc method * @name $sce#getTrustedCss * * @description * Shorthand method. `$sce.getTrustedCss(value)` → * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @return {*} The return value of `$sce.getTrusted($sce.CSS, value)` */ /** * @ngdoc method * @name $sce#getTrustedUrl * * @description * Shorthand method. `$sce.getTrustedUrl(value)` → * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @return {*} The return value of `$sce.getTrusted($sce.URL, value)` */ /** * @ngdoc method * @name $sce#getTrustedResourceUrl * * @description * Shorthand method. `$sce.getTrustedResourceUrl(value)` → * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} * * @param {*} value The value to pass to `$sceDelegate.getTrusted`. * @return {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` */ /** * @ngdoc method * @name $sce#getTrustedJs * * @description * Shorthand method. `$sce.getTrustedJs(value)` → * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @return {*} The return value of `$sce.getTrusted($sce.JS, value)` */ /** * @ngdoc method * @name $sce#parseAsHtml * * @description * Shorthand method. `$sce.parseAsHtml(expression string)` → * {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`} * * @param {string} expression String expression to compile. * @return {function(context, locals)} A function which represents the compiled expression: * * * `context` – `{object}` – an object against which any expressions embedded in the * strings are evaluated against (typically a scope object). * * `locals` – `{object=}` – local variables context object, useful for overriding values * in `context`. */ /** * @ngdoc method * @name $sce#parseAsCss * * @description * Shorthand method. `$sce.parseAsCss(value)` → * {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`} * * @param {string} expression String expression to compile. * @return {function(context, locals)} A function which represents the compiled expression: * * * `context` – `{object}` – an object against which any expressions embedded in the * strings are evaluated against (typically a scope object). * * `locals` – `{object=}` – local variables context object, useful for overriding values * in `context`. */ /** * @ngdoc method * @name $sce#parseAsUrl * * @description * Shorthand method. `$sce.parseAsUrl(value)` → * {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`} * * @param {string} expression String expression to compile. * @return {function(context, locals)} A function which represents the compiled expression: * * * `context` – `{object}` – an object against which any expressions embedded in the * strings are evaluated against (typically a scope object). * * `locals` – `{object=}` – local variables context object, useful for overriding values * in `context`. */ /** * @ngdoc method * @name $sce#parseAsResourceUrl * * @description * Shorthand method. `$sce.parseAsResourceUrl(value)` → * {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`} * * @param {string} expression String expression to compile. * @return {function(context, locals)} A function which represents the compiled expression: * * * `context` – `{object}` – an object against which any expressions embedded in the * strings are evaluated against (typically a scope object). * * `locals` – `{object=}` – local variables context object, useful for overriding values * in `context`. */ /** * @ngdoc method * @name $sce#parseAsJs * * @description * Shorthand method. `$sce.parseAsJs(value)` → * {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`} * * @param {string} expression String expression to compile. * @return {function(context, locals)} A function which represents the compiled expression: * * * `context` – `{object}` – an object against which any expressions embedded in the * strings are evaluated against (typically a scope object). * * `locals` – `{object=}` – local variables context object, useful for overriding values * in `context`. */ // Shorthand delegations. var parse = sce.parseAs, getTrusted = sce.getTrusted, trustAs = sce.trustAs; forEach(SCE_CONTEXTS, function(enumValue, name) { var lName = lowercase(name); sce[snakeToCamel('parse_as_' + lName)] = function(expr) { return parse(enumValue, expr); }; sce[snakeToCamel('get_trusted_' + lName)] = function(value) { return getTrusted(enumValue, value); }; sce[snakeToCamel('trust_as_' + lName)] = function(value) { return trustAs(enumValue, value); }; }); return sce; }]; } /* exported $SnifferProvider */ /** * !!! This is an undocumented "private" service !!! * * @name $sniffer * @requires $window * @requires $document * @this * * @property {boolean} history Does the browser support html5 history api ? * @property {boolean} transitions Does the browser support CSS transition events ? * @property {boolean} animations Does the browser support CSS animation events ? * * @description * This is very simple implementation of testing browser's features. */ function $SnifferProvider() { this.$get = ['$window', '$document', function($window, $document) { var eventSupport = {}, // Chrome Packaged Apps are not allowed to access `history.pushState`. // If not sandboxed, they can be detected by the presence of `chrome.app.runtime` // (see https://developer.chrome.com/apps/api_index). If sandboxed, they can be detected by // the presence of an extension runtime ID and the absence of other Chrome runtime APIs // (see https://developer.chrome.com/apps/manifest/sandbox). // (NW.js apps have access to Chrome APIs, but do support `history`.) isNw = $window.nw && $window.nw.process, isChromePackagedApp = !isNw && $window.chrome && ($window.chrome.app && $window.chrome.app.runtime || !$window.chrome.app && $window.chrome.runtime && $window.chrome.runtime.id), hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState, android = toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]), boxee = /Boxee/i.test(($window.navigator || {}).userAgent), document = $document[0] || {}, bodyStyle = document.body && document.body.style, transitions = false, animations = false; if (bodyStyle) { // Support: Android <5, Blackberry Browser 10, default Chrome in Android 4.4.x // Mentioned browsers need a -webkit- prefix for transitions & animations. transitions = !!('transition' in bodyStyle || 'webkitTransition' in bodyStyle); animations = !!('animation' in bodyStyle || 'webkitAnimation' in bodyStyle); } return { // Android has history.pushState, but it does not update location correctly // so let's not use the history API at all. // http://code.google.com/p/android/issues/detail?id=17471 // https://github.com/angular/angular.js/issues/904 // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has // so let's not use the history API also // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined history: !!(hasHistoryPushState && !(android < 4) && !boxee), hasEvent: function(event) { // Support: IE 9-11 only // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have // it. In particular the event is not fired when backspace or delete key are pressed or // when cut operation is performed. // IE10+ implements 'input' event but it erroneously fires under various situations, // e.g. when placeholder changes, or a form is focused. if (event === 'input' && msie) return false; if (isUndefined(eventSupport[event])) { var divElm = document.createElement('div'); eventSupport[event] = 'on' + event in divElm; } return eventSupport[event]; }, csp: csp(), transitions: transitions, animations: animations, android: android }; }]; } var $templateRequestMinErr = minErr('$compile'); /** * @ngdoc provider * @name $templateRequestProvider * @this * * @description * Used to configure the options passed to the {@link $http} service when making a template request. * * For example, it can be used for specifying the "Accept" header that is sent to the server, when * requesting a template. */ function $TemplateRequestProvider() { var httpOptions; /** * @ngdoc method * @name $templateRequestProvider#httpOptions * @description * The options to be passed to the {@link $http} service when making the request. * You can use this to override options such as the "Accept" header for template requests. * * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the * options if not overridden here. * * @param {string=} value new value for the {@link $http} options. * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter. */ this.httpOptions = function(val) { if (val) { httpOptions = val; return this; } return httpOptions; }; /** * @ngdoc service * @name $templateRequest * * @description * The `$templateRequest` service runs security checks then downloads the provided template using * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted * when `tpl` is of type string and `$templateCache` has the matching entry. * * If you want to pass custom options to the `$http` service, such as setting the Accept header you * can configure this via {@link $templateRequestProvider#httpOptions}. * * @param {string|TrustedResourceUrl} tpl The HTTP request template URL * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty * * @return {Promise} a promise for the HTTP response data of the given URL. * * @property {number} totalPendingRequests total amount of pending template requests being downloaded. */ this.$get = ['$exceptionHandler', '$templateCache', '$http', '$q', '$sce', function($exceptionHandler, $templateCache, $http, $q, $sce) { function handleRequestFn(tpl, ignoreRequestError) { handleRequestFn.totalPendingRequests++; // We consider the template cache holds only trusted templates, so // there's no need to go through whitelisting again for keys that already // are included in there. This also makes Angular accept any script // directive, no matter its name. However, we still need to unwrap trusted // types. if (!isString(tpl) || isUndefined($templateCache.get(tpl))) { tpl = $sce.getTrustedResourceUrl(tpl); } var transformResponse = $http.defaults && $http.defaults.transformResponse; if (isArray(transformResponse)) { transformResponse = transformResponse.filter(function(transformer) { return transformer !== defaultHttpResponseTransform; }); } else if (transformResponse === defaultHttpResponseTransform) { transformResponse = null; } return $http.get(tpl, extend({ cache: $templateCache, transformResponse: transformResponse }, httpOptions)) .finally(function() { handleRequestFn.totalPendingRequests--; }) .then(function(response) { $templateCache.put(tpl, response.data); return response.data; }, handleError); function handleError(resp) { if (!ignoreRequestError) { resp = $templateRequestMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})', tpl, resp.status, resp.statusText); $exceptionHandler(resp); } return $q.reject(resp); } } handleRequestFn.totalPendingRequests = 0; return handleRequestFn; } ]; } /** @this */ function $$TestabilityProvider() { this.$get = ['$rootScope', '$browser', '$location', function($rootScope, $browser, $location) { /** * @name $testability * * @description * The private $$testability service provides a collection of methods for use when debugging * or by automated test and debugging tools. */ var testability = {}; /** * @name $$testability#findBindings * * @description * Returns an array of elements that are bound (via ng-bind or {{}}) * to expressions matching the input. * * @param {Element} element The element root to search from. * @param {string} expression The binding expression to match. * @param {boolean} opt_exactMatch If true, only returns exact matches * for the expression. Filters and whitespace are ignored. */ testability.findBindings = function(element, expression, opt_exactMatch) { var bindings = element.getElementsByClassName('ng-binding'); var matches = []; forEach(bindings, function(binding) { var dataBinding = angular.element(binding).data('$binding'); if (dataBinding) { forEach(dataBinding, function(bindingName) { if (opt_exactMatch) { var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)'); if (matcher.test(bindingName)) { matches.push(binding); } } else { if (bindingName.indexOf(expression) !== -1) { matches.push(binding); } } }); } }); return matches; }; /** * @name $$testability#findModels * * @description * Returns an array of elements that are two-way found via ng-model to * expressions matching the input. * * @param {Element} element The element root to search from. * @param {string} expression The model expression to match. * @param {boolean} opt_exactMatch If true, only returns exact matches * for the expression. */ testability.findModels = function(element, expression, opt_exactMatch) { var prefixes = ['ng-', 'data-ng-', 'ng\\:']; for (var p = 0; p < prefixes.length; ++p) { var attributeEquals = opt_exactMatch ? '=' : '*='; var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]'; var elements = element.querySelectorAll(selector); if (elements.length) { return elements; } } }; /** * @name $$testability#getLocation * * @description * Shortcut for getting the location in a browser agnostic way. Returns * the path, search, and hash. (e.g. /path?a=b#hash) */ testability.getLocation = function() { return $location.url(); }; /** * @name $$testability#setLocation * * @description * Shortcut for navigating to a location without doing a full page reload. * * @param {string} url The location url (path, search and hash, * e.g. /path?a=b#hash) to go to. */ testability.setLocation = function(url) { if (url !== $location.url()) { $location.url(url); $rootScope.$digest(); } }; /** * @name $$testability#whenStable * * @description * Calls the callback when $timeout and $http requests are completed. * * @param {function} callback */ testability.whenStable = function(callback) { $browser.notifyWhenNoOutstandingRequests(callback); }; return testability; }]; } /** @this */ function $TimeoutProvider() { this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler', function($rootScope, $browser, $q, $$q, $exceptionHandler) { var deferreds = {}; /** * @ngdoc service * @name $timeout * * @description * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch * block and delegates any exceptions to * {@link ng.$exceptionHandler $exceptionHandler} service. * * The return value of calling `$timeout` is a promise, which will be resolved when * the delay has passed and the timeout function, if provided, is executed. * * To cancel a timeout request, call `$timeout.cancel(promise)`. * * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to * synchronously flush the queue of deferred functions. * * If you only want a promise that will be resolved after some specified delay * then you can call `$timeout` without the `fn` function. * * @param {function()=} fn A function, whose execution should be delayed. * @param {number=} [delay=0] Delay in milliseconds. * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. * @param {...*=} Pass additional parameters to the executed function. * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise * will be resolved with the return value of the `fn` function. * */ function timeout(fn, delay, invokeApply) { if (!isFunction(fn)) { invokeApply = delay; delay = fn; fn = noop; } var args = sliceArgs(arguments, 3), skipApply = (isDefined(invokeApply) && !invokeApply), deferred = (skipApply ? $$q : $q).defer(), promise = deferred.promise, timeoutId; timeoutId = $browser.defer(function() { try { deferred.resolve(fn.apply(null, args)); } catch (e) { deferred.reject(e); $exceptionHandler(e); } finally { delete deferreds[promise.$$timeoutId]; } if (!skipApply) $rootScope.$apply(); }, delay); promise.$$timeoutId = timeoutId; deferreds[timeoutId] = deferred; return promise; } /** * @ngdoc method * @name $timeout#cancel * * @description * Cancels a task associated with the `promise`. As a result of this, the promise will be * resolved with a rejection. * * @param {Promise=} promise Promise returned by the `$timeout` function. * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully * canceled. */ timeout.cancel = function(promise) { if (promise && promise.$$timeoutId in deferreds) { // Timeout cancels should not report an unhandled promise. markQExceptionHandled(deferreds[promise.$$timeoutId].promise); deferreds[promise.$$timeoutId].reject('canceled'); delete deferreds[promise.$$timeoutId]; return $browser.defer.cancel(promise.$$timeoutId); } return false; }; return timeout; }]; } // NOTE: The usage of window and document instead of $window and $document here is // deliberate. This service depends on the specific behavior of anchor nodes created by the // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and // cause us to break tests. In addition, when the browser resolves a URL for XHR, it // doesn't know about mocked locations and resolves URLs to the real document - which is // exactly the behavior needed here. There is little value is mocking these out for this // service. var urlParsingNode = window.document.createElement('a'); var originUrl = urlResolve(window.location.href); /** * * Implementation Notes for non-IE browsers * ---------------------------------------- * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM, * results both in the normalizing and parsing of the URL. Normalizing means that a relative * URL will be resolved into an absolute URL in the context of the application document. * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related * properties are all populated to reflect the normalized URL. This approach has wide * compatibility - Safari 1+, Mozilla 1+ etc. See * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html * * Implementation Notes for IE * --------------------------- * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other * browsers. However, the parsed components will not be set if the URL assigned did not specify * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We * work around that by performing the parsing in a 2nd step by taking a previously normalized * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the * properties such as protocol, hostname, port, etc. * * References: * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html * http://url.spec.whatwg.org/#urlutils * https://github.com/angular/angular.js/pull/2902 * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ * * @kind function * @param {string} url The URL to be parsed. * @description Normalizes and parses a URL. * @returns {object} Returns the normalized URL as a dictionary. * * | member name | Description | * |---------------|----------------| * | href | A normalized version of the provided URL if it was not an absolute URL | * | protocol | The protocol including the trailing colon | * | host | The host and port (if the port is non-default) of the normalizedUrl | * | search | The search params, minus the question mark | * | hash | The hash string, minus the hash symbol * | hostname | The hostname * | port | The port, without ":" * | pathname | The pathname, beginning with "/" * */ function urlResolve(url) { var href = url; // Support: IE 9-11 only if (msie) { // Normalize before parse. Refer Implementation Notes on why this is // done in two steps on IE. urlParsingNode.setAttribute('href', href); href = urlParsingNode.href; } urlParsingNode.setAttribute('href', href); // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils return { href: urlParsingNode.href, protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', host: urlParsingNode.host, search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', hostname: urlParsingNode.hostname, port: urlParsingNode.port, pathname: (urlParsingNode.pathname.charAt(0) === '/') ? urlParsingNode.pathname : '/' + urlParsingNode.pathname }; } /** * Parse a request URL and determine whether this is a same-origin request as the application document. * * @param {string|object} requestUrl The url of the request as a string that will be resolved * or a parsed URL object. * @returns {boolean} Whether the request is for the same origin as the application document. */ function urlIsSameOrigin(requestUrl) { var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; return (parsed.protocol === originUrl.protocol && parsed.host === originUrl.host); } /** * @ngdoc service * @name $window * @this * * @description * A reference to the browser's `window` object. While `window` * is globally available in JavaScript, it causes testability problems, because * it is a global variable. In angular we always refer to it through the * `$window` service, so it may be overridden, removed or mocked for testing. * * Expressions, like the one defined for the `ngClick` directive in the example * below, are evaluated with respect to the current scope. Therefore, there is * no risk of inadvertently coding in a dependency on a global value in such an * expression. * * @example
it('should display the greeting in the input box', function() { element(by.model('greeting')).sendKeys('Hello, E2E Tests'); // If we click the button it will block the test runner // element(':button').click(); });
*/ function $WindowProvider() { this.$get = valueFn(window); } /** * @name $$cookieReader * @requires $document * * @description * This is a private service for reading cookies used by $http and ngCookies * * @return {Object} a key/value map of the current cookies */ function $$CookieReader($document) { var rawDocument = $document[0] || {}; var lastCookies = {}; var lastCookieString = ''; function safeGetCookie(rawDocument) { try { return rawDocument.cookie || ''; } catch (e) { return ''; } } function safeDecodeURIComponent(str) { try { return decodeURIComponent(str); } catch (e) { return str; } } return function() { var cookieArray, cookie, i, index, name; var currentCookieString = safeGetCookie(rawDocument); if (currentCookieString !== lastCookieString) { lastCookieString = currentCookieString; cookieArray = lastCookieString.split('; '); lastCookies = {}; for (i = 0; i < cookieArray.length; i++) { cookie = cookieArray[i]; index = cookie.indexOf('='); if (index > 0) { //ignore nameless cookies name = safeDecodeURIComponent(cookie.substring(0, index)); // the first value that is seen for a cookie is the most // specific one. values for the same cookie name that // follow are for less specific paths. if (isUndefined(lastCookies[name])) { lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1)); } } } } return lastCookies; }; } $$CookieReader.$inject = ['$document']; /** @this */ function $$CookieReaderProvider() { this.$get = $$CookieReader; } /* global currencyFilter: true, dateFilter: true, filterFilter: true, jsonFilter: true, limitToFilter: true, lowercaseFilter: true, numberFilter: true, orderByFilter: true, uppercaseFilter: true, */ /** * @ngdoc provider * @name $filterProvider * @description * * Filters are just functions which transform input to an output. However filters need to be * Dependency Injected. To achieve this a filter definition consists of a factory function which is * annotated with dependencies and is responsible for creating a filter function. * *
* **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). *
* * ```js * // Filter registration * function MyModule($provide, $filterProvider) { * // create a service to demonstrate injection (not always needed) * $provide.value('greet', function(name){ * return 'Hello ' + name + '!'; * }); * * // register a filter factory which uses the * // greet service to demonstrate DI. * $filterProvider.register('greet', function(greet){ * // return the filter function which uses the greet service * // to generate salutation * return function(text) { * // filters need to be forgiving so check input validity * return text && greet(text) || text; * }; * }); * } * ``` * * The filter function is registered with the `$injector` under the filter name suffix with * `Filter`. * * ```js * it('should be the same instance', inject( * function($filterProvider) { * $filterProvider.register('reverse', function(){ * return ...; * }); * }, * function($filter, reverseFilter) { * expect($filter('reverse')).toBe(reverseFilter); * }); * ``` * * * For more information about how angular filters work, and how to create your own filters, see * {@link guide/filter Filters} in the Angular Developer Guide. */ /** * @ngdoc service * @name $filter * @kind function * @description * Filters are used for formatting data displayed to the user. * * They can be used in view templates, controllers or services.Angular comes * with a collection of [built-in filters](api/ng/filter), but it is easy to * define your own as well. * * The general syntax in templates is as follows: * * ```html * {{ expression [| filter_name[:parameter_value] ... ] }} * ``` * * @param {String} name Name of the filter function to retrieve * @return {Function} the filter function * @example

{{ originalText }}

{{ filteredText }}

angular.module('filterExample', []) .controller('MainCtrl', function($scope, $filter) { $scope.originalText = 'hello'; $scope.filteredText = $filter('uppercase')($scope.originalText); });
*/ $FilterProvider.$inject = ['$provide']; /** @this */ function $FilterProvider($provide) { var suffix = 'Filter'; /** * @ngdoc method * @name $filterProvider#register * @param {string|Object} name Name of the filter function, or an object map of filters where * the keys are the filter names and the values are the filter factories. * *
* **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). *
* @param {Function} factory If the first argument was a string, a factory function for the filter to be registered. * @returns {Object} Registered filter instance, or if a map of filters was provided then a map * of the registered filter instances. */ function register(name, factory) { if (isObject(name)) { var filters = {}; forEach(name, function(filter, key) { filters[key] = register(key, filter); }); return filters; } else { return $provide.factory(name + suffix, factory); } } this.register = register; this.$get = ['$injector', function($injector) { return function(name) { return $injector.get(name + suffix); }; }]; //////////////////////////////////////// /* global currencyFilter: false, dateFilter: false, filterFilter: false, jsonFilter: false, limitToFilter: false, lowercaseFilter: false, numberFilter: false, orderByFilter: false, uppercaseFilter: false */ register('currency', currencyFilter); register('date', dateFilter); register('filter', filterFilter); register('json', jsonFilter); register('limitTo', limitToFilter); register('lowercase', lowercaseFilter); register('number', numberFilter); register('orderBy', orderByFilter); register('uppercase', uppercaseFilter); } /** * @ngdoc filter * @name filter * @kind function * * @description * Selects a subset of items from `array` and returns it as a new array. * * @param {Array} array The source array. *
* **Note**: If the array contains objects that reference themselves, filtering is not possible. *
* @param {string|Object|function()} expression The predicate to be used for selecting items from * `array`. * * Can be one of: * * - `string`: The string is used for matching against the contents of the `array`. All strings or * objects with string properties in `array` that match this string will be returned. This also * applies to nested object properties. * The predicate can be negated by prefixing the string with `!`. * * - `Object`: A pattern object can be used to filter specific properties on objects contained * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items * which have property `name` containing "M" and property `phone` containing "1". A special * property name (`$` by default) can be used (e.g. as in `{$: "text"}`) to accept a match * against any property of the object or its nested object properties. That's equivalent to the * simple substring match with a `string` as described above. The special property name can be * overwritten, using the `anyPropertyKey` parameter. * The predicate can be negated by prefixing the string with `!`. * For example `{name: "!M"}` predicate will return an array of items which have property `name` * not containing "M". * * Note that a named property will match properties on the same level only, while the special * `$` property will match properties on the same level or deeper. E.g. an array item like * `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but * **will** be matched by `{$: 'John'}`. * * - `function(value, index, array)`: A predicate function can be used to write arbitrary filters. * The function is called for each element of the array, with the element, its index, and * the entire array itself as arguments. * * The final result is an array of those elements that the predicate returned true for. * * @param {function(actual, expected)|true|false} [comparator] Comparator which is used in * determining if values retrieved using `expression` (when it is not a function) should be * considered a match based on the expected value (from the filter expression) and actual * value (from the object in the array). * * Can be one of: * * - `function(actual, expected)`: * The function will be given the object value and the predicate value to compare and * should return true if both values should be considered equal. * * - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`. * This is essentially strict comparison of expected and actual. * * - `false`: A short hand for a function which will look for a substring match in a case * insensitive way. Primitive values are converted to strings. Objects are not compared against * primitives, unless they have a custom `toString` method (e.g. `Date` objects). * * * Defaults to `false`. * * @param {string} [anyPropertyKey] The special property name that matches against any property. * By default `$`. * * @example
NamePhone
{{friend.name}} {{friend.phone}}





NamePhone
{{friendObj.name}} {{friendObj.phone}}
var expectFriendNames = function(expectedNames, key) { element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) { arr.forEach(function(wd, i) { expect(wd.getText()).toMatch(expectedNames[i]); }); }); }; it('should search across all fields when filtering with a string', function() { var searchText = element(by.model('searchText')); searchText.clear(); searchText.sendKeys('m'); expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend'); searchText.clear(); searchText.sendKeys('76'); expectFriendNames(['John', 'Julie'], 'friend'); }); it('should search in specific fields when filtering with a predicate object', function() { var searchAny = element(by.model('search.$')); searchAny.clear(); searchAny.sendKeys('i'); expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj'); }); it('should use a equal comparison when comparator is true', function() { var searchName = element(by.model('search.name')); var strict = element(by.model('strict')); searchName.clear(); searchName.sendKeys('Julie'); strict.click(); expectFriendNames(['Julie'], 'friendObj'); });
*/ function filterFilter() { return function(array, expression, comparator, anyPropertyKey) { if (!isArrayLike(array)) { if (array == null) { return array; } else { throw minErr('filter')('notarray', 'Expected array but received: {0}', array); } } anyPropertyKey = anyPropertyKey || '$'; var expressionType = getTypeForFilter(expression); var predicateFn; var matchAgainstAnyProp; switch (expressionType) { case 'function': predicateFn = expression; break; case 'boolean': case 'null': case 'number': case 'string': matchAgainstAnyProp = true; // falls through case 'object': predicateFn = createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp); break; default: return array; } return Array.prototype.filter.call(array, predicateFn); }; } // Helper functions for `filterFilter` function createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp) { var shouldMatchPrimitives = isObject(expression) && (anyPropertyKey in expression); var predicateFn; if (comparator === true) { comparator = equals; } else if (!isFunction(comparator)) { comparator = function(actual, expected) { if (isUndefined(actual)) { // No substring matching against `undefined` return false; } if ((actual === null) || (expected === null)) { // No substring matching against `null`; only match against `null` return actual === expected; } if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) { // Should not compare primitives against objects, unless they have custom `toString` method return false; } actual = lowercase('' + actual); expected = lowercase('' + expected); return actual.indexOf(expected) !== -1; }; } predicateFn = function(item) { if (shouldMatchPrimitives && !isObject(item)) { return deepCompare(item, expression[anyPropertyKey], comparator, anyPropertyKey, false); } return deepCompare(item, expression, comparator, anyPropertyKey, matchAgainstAnyProp); }; return predicateFn; } function deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstAnyProp, dontMatchWholeObject) { var actualType = getTypeForFilter(actual); var expectedType = getTypeForFilter(expected); if ((expectedType === 'string') && (expected.charAt(0) === '!')) { return !deepCompare(actual, expected.substring(1), comparator, anyPropertyKey, matchAgainstAnyProp); } else if (isArray(actual)) { // In case `actual` is an array, consider it a match // if ANY of it's items matches `expected` return actual.some(function(item) { return deepCompare(item, expected, comparator, anyPropertyKey, matchAgainstAnyProp); }); } switch (actualType) { case 'object': var key; if (matchAgainstAnyProp) { for (key in actual) { // Under certain, rare, circumstances, key may not be a string and `charAt` will be undefined // See: https://github.com/angular/angular.js/issues/15644 if (key.charAt && (key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) { return true; } } return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, anyPropertyKey, false); } else if (expectedType === 'object') { for (key in expected) { var expectedVal = expected[key]; if (isFunction(expectedVal) || isUndefined(expectedVal)) { continue; } var matchAnyProperty = key === anyPropertyKey; var actualVal = matchAnyProperty ? actual : actual[key]; if (!deepCompare(actualVal, expectedVal, comparator, anyPropertyKey, matchAnyProperty, matchAnyProperty)) { return false; } } return true; } else { return comparator(actual, expected); } case 'function': return false; default: return comparator(actual, expected); } } // Used for easily differentiating between `null` and actual `object` function getTypeForFilter(val) { return (val === null) ? 'null' : typeof val; } var MAX_DIGITS = 22; var DECIMAL_SEP = '.'; var ZERO_CHAR = '0'; /** * @ngdoc filter * @name currency * @kind function * * @description * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default * symbol for current locale is used. * * @param {number} amount Input to filter. * @param {string=} symbol Currency symbol or identifier to be displayed. * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale * @returns {string} Formatted number. * * * @example

default currency symbol ($): {{amount | currency}}
custom currency identifier (USD$): {{amount | currency:"USD$"}}
no fractions (0): {{amount | currency:"USD$":0}}
it('should init with 1234.56', function() { expect(element(by.id('currency-default')).getText()).toBe('$1,234.56'); expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56'); expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235'); }); it('should update', function() { if (browser.params.browser === 'safari') { // Safari does not understand the minus key. See // https://github.com/angular/protractor/issues/481 return; } element(by.model('amount')).clear(); element(by.model('amount')).sendKeys('-1234'); expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00'); expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00'); expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234'); });
*/ currencyFilter.$inject = ['$locale']; function currencyFilter($locale) { var formats = $locale.NUMBER_FORMATS; return function(amount, currencySymbol, fractionSize) { if (isUndefined(currencySymbol)) { currencySymbol = formats.CURRENCY_SYM; } if (isUndefined(fractionSize)) { fractionSize = formats.PATTERNS[1].maxFrac; } // if null or undefined pass it through return (amount == null) ? amount : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize). replace(/\u00A4/g, currencySymbol); }; } /** * @ngdoc filter * @name number * @kind function * * @description * Formats a number as text. * * If the input is null or undefined, it will just be returned. * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively. * If the input is not a number an empty string is returned. * * * @param {number|string} number Number to format. * @param {(number|string)=} fractionSize Number of decimal places to round the number to. * If this is not provided then the fraction size is computed from the current locale's number * formatting pattern. In the case of the default locale, it will be 3. * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current * locale (e.g., in the en_US locale it will have "." as the decimal separator and * include "," group separators after each third digit). * * @example

Default formatting: {{val | number}}
No fractions: {{val | number:0}}
Negative number: {{-val | number:4}}
it('should format numbers', function() { expect(element(by.id('number-default')).getText()).toBe('1,234.568'); expect(element(by.binding('val | number:0')).getText()).toBe('1,235'); expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679'); }); it('should update', function() { element(by.model('val')).clear(); element(by.model('val')).sendKeys('3374.333'); expect(element(by.id('number-default')).getText()).toBe('3,374.333'); expect(element(by.binding('val | number:0')).getText()).toBe('3,374'); expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330'); });
*/ numberFilter.$inject = ['$locale']; function numberFilter($locale) { var formats = $locale.NUMBER_FORMATS; return function(number, fractionSize) { // if null or undefined pass it through return (number == null) ? number : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize); }; } /** * Parse a number (as a string) into three components that can be used * for formatting the number. * * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/) * * @param {string} numStr The number to parse * @return {object} An object describing this number, containing the following keys: * - d : an array of digits containing leading zeros as necessary * - i : the number of the digits in `d` that are to the left of the decimal point * - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d` * */ function parse(numStr) { var exponent = 0, digits, numberOfIntegerDigits; var i, j, zeros; // Decimal point? if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) { numStr = numStr.replace(DECIMAL_SEP, ''); } // Exponential form? if ((i = numStr.search(/e/i)) > 0) { // Work out the exponent. if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i; numberOfIntegerDigits += +numStr.slice(i + 1); numStr = numStr.substring(0, i); } else if (numberOfIntegerDigits < 0) { // There was no decimal point or exponent so it is an integer. numberOfIntegerDigits = numStr.length; } // Count the number of leading zeros. for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) { /* empty */ } if (i === (zeros = numStr.length)) { // The digits are all zero. digits = [0]; numberOfIntegerDigits = 1; } else { // Count the number of trailing zeros zeros--; while (numStr.charAt(zeros) === ZERO_CHAR) zeros--; // Trailing zeros are insignificant so ignore them numberOfIntegerDigits -= i; digits = []; // Convert string to array of digits without leading/trailing zeros. for (j = 0; i <= zeros; i++, j++) { digits[j] = +numStr.charAt(i); } } // If the number overflows the maximum allowed digits then use an exponent. if (numberOfIntegerDigits > MAX_DIGITS) { digits = digits.splice(0, MAX_DIGITS - 1); exponent = numberOfIntegerDigits - 1; numberOfIntegerDigits = 1; } return { d: digits, e: exponent, i: numberOfIntegerDigits }; } /** * Round the parsed number to the specified number of decimal places * This function changed the parsedNumber in-place */ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) { var digits = parsedNumber.d; var fractionLen = digits.length - parsedNumber.i; // determine fractionSize if it is not specified; `+fractionSize` converts it to a number fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize; // The index of the digit to where rounding is to occur var roundAt = fractionSize + parsedNumber.i; var digit = digits[roundAt]; if (roundAt > 0) { // Drop fractional digits beyond `roundAt` digits.splice(Math.max(parsedNumber.i, roundAt)); // Set non-fractional digits beyond `roundAt` to 0 for (var j = roundAt; j < digits.length; j++) { digits[j] = 0; } } else { // We rounded to zero so reset the parsedNumber fractionLen = Math.max(0, fractionLen); parsedNumber.i = 1; digits.length = Math.max(1, roundAt = fractionSize + 1); digits[0] = 0; for (var i = 1; i < roundAt; i++) digits[i] = 0; } if (digit >= 5) { if (roundAt - 1 < 0) { for (var k = 0; k > roundAt; k--) { digits.unshift(0); parsedNumber.i++; } digits.unshift(1); parsedNumber.i++; } else { digits[roundAt - 1]++; } } // Pad out with zeros to get the required fraction length for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0); // Do any carrying, e.g. a digit was rounded up to 10 var carry = digits.reduceRight(function(carry, d, i, digits) { d = d + carry; digits[i] = d % 10; return Math.floor(d / 10); }, 0); if (carry) { digits.unshift(carry); parsedNumber.i++; } } /** * Format a number into a string * @param {number} number The number to format * @param {{ * minFrac, // the minimum number of digits required in the fraction part of the number * maxFrac, // the maximum number of digits required in the fraction part of the number * gSize, // number of digits in each group of separated digits * lgSize, // number of digits in the last group of digits before the decimal separator * negPre, // the string to go in front of a negative number (e.g. `-` or `(`)) * posPre, // the string to go in front of a positive number * negSuf, // the string to go after a negative number (e.g. `)`) * posSuf // the string to go after a positive number * }} pattern * @param {string} groupSep The string to separate groups of number (e.g. `,`) * @param {string} decimalSep The string to act as the decimal separator (e.g. `.`) * @param {[type]} fractionSize The size of the fractional part of the number * @return {string} The number formatted as a string */ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { if (!(isString(number) || isNumber(number)) || isNaN(number)) return ''; var isInfinity = !isFinite(number); var isZero = false; var numStr = Math.abs(number) + '', formattedText = '', parsedNumber; if (isInfinity) { formattedText = '\u221e'; } else { parsedNumber = parse(numStr); roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac); var digits = parsedNumber.d; var integerLen = parsedNumber.i; var exponent = parsedNumber.e; var decimals = []; isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true); // pad zeros for small numbers while (integerLen < 0) { digits.unshift(0); integerLen++; } // extract decimals digits if (integerLen > 0) { decimals = digits.splice(integerLen, digits.length); } else { decimals = digits; digits = [0]; } // format the integer digits with grouping separators var groups = []; if (digits.length >= pattern.lgSize) { groups.unshift(digits.splice(-pattern.lgSize, digits.length).join('')); } while (digits.length > pattern.gSize) { groups.unshift(digits.splice(-pattern.gSize, digits.length).join('')); } if (digits.length) { groups.unshift(digits.join('')); } formattedText = groups.join(groupSep); // append the decimal digits if (decimals.length) { formattedText += decimalSep + decimals.join(''); } if (exponent) { formattedText += 'e+' + exponent; } } if (number < 0 && !isZero) { return pattern.negPre + formattedText + pattern.negSuf; } else { return pattern.posPre + formattedText + pattern.posSuf; } } function padNumber(num, digits, trim, negWrap) { var neg = ''; if (num < 0 || (negWrap && num <= 0)) { if (negWrap) { num = -num + 1; } else { num = -num; neg = '-'; } } num = '' + num; while (num.length < digits) num = ZERO_CHAR + num; if (trim) { num = num.substr(num.length - digits); } return neg + num; } function dateGetter(name, size, offset, trim, negWrap) { offset = offset || 0; return function(date) { var value = date['get' + name](); if (offset > 0 || value > -offset) { value += offset; } if (value === 0 && offset === -12) value = 12; return padNumber(value, size, trim, negWrap); }; } function dateStrGetter(name, shortForm, standAlone) { return function(date, formats) { var value = date['get' + name](); var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : ''); var get = uppercase(propPrefix + name); return formats[get][value]; }; } function timeZoneGetter(date, formats, offset) { var zone = -1 * offset; var paddedZone = (zone >= 0) ? '+' : ''; paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2); return paddedZone; } function getFirstThursdayOfYear(year) { // 0 = index of January var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay(); // 4 = index of Thursday (+1 to account for 1st = 5) // 11 = index of *next* Thursday (+1 account for 1st = 12) return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst); } function getThursdayThisWeek(datetime) { return new Date(datetime.getFullYear(), datetime.getMonth(), // 4 = index of Thursday datetime.getDate() + (4 - datetime.getDay())); } function weekGetter(size) { return function(date) { var firstThurs = getFirstThursdayOfYear(date.getFullYear()), thisThurs = getThursdayThisWeek(date); var diff = +thisThurs - +firstThurs, result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week return padNumber(result, size); }; } function ampmGetter(date, formats) { return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]; } function eraGetter(date, formats) { return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1]; } function longEraGetter(date, formats) { return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1]; } var DATE_FORMATS = { yyyy: dateGetter('FullYear', 4, 0, false, true), yy: dateGetter('FullYear', 2, 0, true, true), y: dateGetter('FullYear', 1, 0, false, true), MMMM: dateStrGetter('Month'), MMM: dateStrGetter('Month', true), MM: dateGetter('Month', 2, 1), M: dateGetter('Month', 1, 1), LLLL: dateStrGetter('Month', false, true), dd: dateGetter('Date', 2), d: dateGetter('Date', 1), HH: dateGetter('Hours', 2), H: dateGetter('Hours', 1), hh: dateGetter('Hours', 2, -12), h: dateGetter('Hours', 1, -12), mm: dateGetter('Minutes', 2), m: dateGetter('Minutes', 1), ss: dateGetter('Seconds', 2), s: dateGetter('Seconds', 1), // while ISO 8601 requires fractions to be prefixed with `.` or `,` // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions sss: dateGetter('Milliseconds', 3), EEEE: dateStrGetter('Day'), EEE: dateStrGetter('Day', true), a: ampmGetter, Z: timeZoneGetter, ww: weekGetter(2), w: weekGetter(1), G: eraGetter, GG: eraGetter, GGG: eraGetter, GGGG: longEraGetter }; var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))([\s\S]*)/, NUMBER_STRING = /^-?\d+$/; /** * @ngdoc filter * @name date * @kind function * * @description * Formats `date` to a string based on the requested `format`. * * `format` string can be composed of the following elements: * * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) * * `'MMMM'`: Month in year (January-December) * * `'MMM'`: Month in year (Jan-Dec) * * `'MM'`: Month in year, padded (01-12) * * `'M'`: Month in year (1-12) * * `'LLLL'`: Stand-alone month in year (January-December) * * `'dd'`: Day in month, padded (01-31) * * `'d'`: Day in month (1-31) * * `'EEEE'`: Day in Week,(Sunday-Saturday) * * `'EEE'`: Day in Week, (Sun-Sat) * * `'HH'`: Hour in day, padded (00-23) * * `'H'`: Hour in day (0-23) * * `'hh'`: Hour in AM/PM, padded (01-12) * * `'h'`: Hour in AM/PM, (1-12) * * `'mm'`: Minute in hour, padded (00-59) * * `'m'`: Minute in hour (0-59) * * `'ss'`: Second in minute, padded (00-59) * * `'s'`: Second in minute (0-59) * * `'sss'`: Millisecond in second, padded (000-999) * * `'a'`: AM/PM marker * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) * * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year * * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year * * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD') * * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini') * * `format` string can also be one of the following predefined * {@link guide/i18n localizable formats}: * * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale * (e.g. Sep 3, 2010 12:05:08 PM) * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 PM) * * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US locale * (e.g. Friday, September 3, 2010) * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010) * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010) * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10) * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM) * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM) * * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g. * `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence * (e.g. `"h 'o''clock'"`). * * Any other characters in the `format` string will be output as-is. * * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is * specified in the string input, the time is considered to be in the local timezone. * @param {string=} format Formatting rules (see Description). If not specified, * `mediumDate` is used. * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the * continental US time zone abbreviations, but for general use, use a time zone offset, for * example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian) * If not specified, the timezone of the browser will be used. * @returns {string} Formatted string or the input if input is not recognized as date/millis. * * @example {{1288323623006 | date:'medium'}}: {{1288323623006 | date:'medium'}}
{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}: {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}: {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}: {{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}
it('should format date', function() { expect(element(by.binding("1288323623006 | date:'medium'")).getText()). toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/); expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()). toMatch(/2010-10-2\d \d{2}:\d{2}:\d{2} (-|\+)?\d{4}/); expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()). toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/); expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()). toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/); });
*/ dateFilter.$inject = ['$locale']; function dateFilter($locale) { var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; // 1 2 3 4 5 6 7 8 9 10 11 function jsonStringToDate(string) { var match; if ((match = string.match(R_ISO8601_STR))) { var date = new Date(0), tzHour = 0, tzMin = 0, dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear, timeSetter = match[8] ? date.setUTCHours : date.setHours; if (match[9]) { tzHour = toInt(match[9] + match[10]); tzMin = toInt(match[9] + match[11]); } dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3])); var h = toInt(match[4] || 0) - tzHour; var m = toInt(match[5] || 0) - tzMin; var s = toInt(match[6] || 0); var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000); timeSetter.call(date, h, m, s, ms); return date; } return string; } return function(date, format, timezone) { var text = '', parts = [], fn, match; format = format || 'mediumDate'; format = $locale.DATETIME_FORMATS[format] || format; if (isString(date)) { date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date); } if (isNumber(date)) { date = new Date(date); } if (!isDate(date) || !isFinite(date.getTime())) { return date; } while (format) { match = DATE_FORMATS_SPLIT.exec(format); if (match) { parts = concat(parts, match, 1); format = parts.pop(); } else { parts.push(format); format = null; } } var dateTimezoneOffset = date.getTimezoneOffset(); if (timezone) { dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset); date = convertTimezoneToLocal(date, timezone, true); } forEach(parts, function(value) { fn = DATE_FORMATS[value]; text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset) : value === '\'\'' ? '\'' : value.replace(/(^'|'$)/g, '').replace(/''/g, '\''); }); return text; }; } /** * @ngdoc filter * @name json * @kind function * * @description * Allows you to convert a JavaScript object into JSON string. * * This filter is mostly useful for debugging. When using the double curly {{value}} notation * the binding is automatically converted to JSON. * * @param {*} object Any JavaScript object (including arrays and primitive types) to filter. * @param {number=} spacing The number of spaces to use per indentation, defaults to 2. * @returns {string} JSON string. * * * @example
{{ {'name':'value'} | json }}
{{ {'name':'value'} | json:4 }}
it('should jsonify filtered objects', function() { expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n {2}"name": ?"value"\n}/); expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n {4}"name": ?"value"\n}/); });
* */ function jsonFilter() { return function(object, spacing) { if (isUndefined(spacing)) { spacing = 2; } return toJson(object, spacing); }; } /** * @ngdoc filter * @name lowercase * @kind function * @description * Converts string to lowercase. * * See the {@link ng.uppercase uppercase filter documentation} for a functionally identical example. * * @see angular.lowercase */ var lowercaseFilter = valueFn(lowercase); /** * @ngdoc filter * @name uppercase * @kind function * @description * Converts string to uppercase. * @example

{{title}}

{{title | uppercase}}

*/ var uppercaseFilter = valueFn(uppercase); /** * @ngdoc filter * @name limitTo * @kind function * * @description * Creates a new array or string containing only a specified number of elements. The elements are * taken from either the beginning or the end of the source array, string or number, as specified by * the value and sign (positive or negative) of `limit`. Other array-like objects are also supported * (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input, * it is converted to a string. * * @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited. * @param {string|number} limit - The length of the returned array or string. If the `limit` number * is positive, `limit` number of items from the beginning of the source array/string are copied. * If the number is negative, `limit` number of items from the end of the source array/string * are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined, * the input will be returned unchanged. * @param {(string|number)=} begin - Index at which to begin limitation. As a negative index, * `begin` indicates an offset from the end of `input`. Defaults to `0`. * @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had * less than `limit` elements. * * @example

Output numbers: {{ numbers | limitTo:numLimit }}

Output letters: {{ letters | limitTo:letterLimit }}

Output long number: {{ longNumber | limitTo:longNumberLimit }}

var numLimitInput = element(by.model('numLimit')); var letterLimitInput = element(by.model('letterLimit')); var longNumberLimitInput = element(by.model('longNumberLimit')); var limitedNumbers = element(by.binding('numbers | limitTo:numLimit')); var limitedLetters = element(by.binding('letters | limitTo:letterLimit')); var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit')); it('should limit the number array to first three items', function() { expect(numLimitInput.getAttribute('value')).toBe('3'); expect(letterLimitInput.getAttribute('value')).toBe('3'); expect(longNumberLimitInput.getAttribute('value')).toBe('3'); expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]'); expect(limitedLetters.getText()).toEqual('Output letters: abc'); expect(limitedLongNumber.getText()).toEqual('Output long number: 234'); }); // There is a bug in safari and protractor that doesn't like the minus key // it('should update the output when -3 is entered', function() { // numLimitInput.clear(); // numLimitInput.sendKeys('-3'); // letterLimitInput.clear(); // letterLimitInput.sendKeys('-3'); // longNumberLimitInput.clear(); // longNumberLimitInput.sendKeys('-3'); // expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]'); // expect(limitedLetters.getText()).toEqual('Output letters: ghi'); // expect(limitedLongNumber.getText()).toEqual('Output long number: 342'); // }); it('should not exceed the maximum size of input array', function() { numLimitInput.clear(); numLimitInput.sendKeys('100'); letterLimitInput.clear(); letterLimitInput.sendKeys('100'); longNumberLimitInput.clear(); longNumberLimitInput.sendKeys('100'); expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]'); expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi'); expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342'); });
*/ function limitToFilter() { return function(input, limit, begin) { if (Math.abs(Number(limit)) === Infinity) { limit = Number(limit); } else { limit = toInt(limit); } if (isNumberNaN(limit)) return input; if (isNumber(input)) input = input.toString(); if (!isArrayLike(input)) return input; begin = (!begin || isNaN(begin)) ? 0 : toInt(begin); begin = (begin < 0) ? Math.max(0, input.length + begin) : begin; if (limit >= 0) { return sliceFn(input, begin, begin + limit); } else { if (begin === 0) { return sliceFn(input, limit, input.length); } else { return sliceFn(input, Math.max(0, begin + limit), begin); } } }; } function sliceFn(input, begin, end) { if (isString(input)) return input.slice(begin, end); return slice.call(input, begin, end); } /** * @ngdoc filter * @name orderBy * @kind function * * @description * Returns an array containing the items from the specified `collection`, ordered by a `comparator` * function based on the values computed using the `expression` predicate. * * For example, `[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'` would result in * `[{id: 'bar'}, {id: 'foo'}]`. * * The `collection` can be an Array or array-like object (e.g. NodeList, jQuery object, TypedArray, * String, etc). * * The `expression` can be a single predicate, or a list of predicates each serving as a tie-breaker * for the preceding one. The `expression` is evaluated against each item and the output is used * for comparing with other items. * * You can change the sorting order by setting `reverse` to `true`. By default, items are sorted in * ascending order. * * The comparison is done using the `comparator` function. If none is specified, a default, built-in * comparator is used (see below for details - in a nutshell, it compares numbers numerically and * strings alphabetically). * * ### Under the hood * * Ordering the specified `collection` happens in two phases: * * 1. All items are passed through the predicate (or predicates), and the returned values are saved * along with their type (`string`, `number` etc). For example, an item `{label: 'foo'}`, passed * through a predicate that extracts the value of the `label` property, would be transformed to: * ``` * { * value: 'foo', * type: 'string', * index: ... * } * ``` * 2. The comparator function is used to sort the items, based on the derived values, types and * indices. * * If you use a custom comparator, it will be called with pairs of objects of the form * `{value: ..., type: '...', index: ...}` and is expected to return `0` if the objects are equal * (as far as the comparator is concerned), `-1` if the 1st one should be ranked higher than the * second, or `1` otherwise. * * In order to ensure that the sorting will be deterministic across platforms, if none of the * specified predicates can distinguish between two items, `orderBy` will automatically introduce a * dummy predicate that returns the item's index as `value`. * (If you are using a custom comparator, make sure it can handle this predicate as well.) * * If a custom comparator still can't distinguish between two items, then they will be sorted based * on their index using the built-in comparator. * * Finally, in an attempt to simplify things, if a predicate returns an object as the extracted * value for an item, `orderBy` will try to convert that object to a primitive value, before passing * it to the comparator. The following rules govern the conversion: * * 1. If the object has a `valueOf()` method that returns a primitive, its return value will be * used instead.
* (If the object has a `valueOf()` method that returns another object, then the returned object * will be used in subsequent steps.) * 2. If the object has a custom `toString()` method (i.e. not the one inherited from `Object`) that * returns a primitive, its return value will be used instead.
* (If the object has a `toString()` method that returns another object, then the returned object * will be used in subsequent steps.) * 3. No conversion; the object itself is used. * * ### The default comparator * * The default, built-in comparator should be sufficient for most usecases. In short, it compares * numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to * using their index in the original collection, and sorts values of different types by type. * * More specifically, it follows these steps to determine the relative order of items: * * 1. If the compared values are of different types, compare the types themselves alphabetically. * 2. If both values are of type `string`, compare them alphabetically in a case- and * locale-insensitive way. * 3. If both values are objects, compare their indices instead. * 4. Otherwise, return: * - `0`, if the values are equal (by strict equality comparison, i.e. using `===`). * - `-1`, if the 1st value is "less than" the 2nd value (compared using the `<` operator). * - `1`, otherwise. * * **Note:** If you notice numbers not being sorted as expected, make sure they are actually being * saved as numbers and not strings. * **Note:** For the purpose of sorting, `null` values are treated as the string `'null'` (i.e. * `type: 'string'`, `value: 'null'`). This may cause unexpected sort order relative to * other values. * * @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort. * @param {(Function|string|Array.)=} expression - A predicate (or list of * predicates) to be used by the comparator to determine the order of elements. * * Can be one of: * * - `Function`: A getter function. This function will be called with each item as argument and * the return value will be used for sorting. * - `string`: An Angular expression. This expression will be evaluated against each item and the * result will be used for sorting. For example, use `'label'` to sort by a property called * `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label` * property.
* (The result of a constant expression is interpreted as a property name to be used for * comparison. For example, use `'"special name"'` (note the extra pair of quotes) to sort by a * property called `special name`.)
* An expression can be optionally prefixed with `+` or `-` to control the sorting direction, * ascending or descending. For example, `'+label'` or `'-label'`. If no property is provided, * (e.g. `'+'` or `'-'`), the collection element itself is used in comparisons. * - `Array`: An array of function and/or string predicates. If a predicate cannot determine the * relative order of two items, the next predicate is used as a tie-breaker. * * **Note:** If the predicate is missing or empty then it defaults to `'+'`. * * @param {boolean=} reverse - If `true`, reverse the sorting order. * @param {(Function)=} comparator - The comparator function used to determine the relative order of * value pairs. If omitted, the built-in comparator will be used. * * @returns {Array} - The sorted array. * * * @example * ### Ordering a table with `ngRepeat` * * The example below demonstrates a simple {@link ngRepeat ngRepeat}, where the data is sorted by * age in descending order (expression is set to `'-age'`). The `comparator` is not set, which means * it defaults to the built-in comparator. *
Name Phone Number Age
{{friend.name}} {{friend.phone}} {{friend.age}}
angular.module('orderByExample1', []) .controller('ExampleController', ['$scope', function($scope) { $scope.friends = [ {name: 'John', phone: '555-1212', age: 10}, {name: 'Mary', phone: '555-9876', age: 19}, {name: 'Mike', phone: '555-4321', age: 21}, {name: 'Adam', phone: '555-5678', age: 35}, {name: 'Julie', phone: '555-8765', age: 29} ]; }]); .friends { border-collapse: collapse; } .friends th { border-bottom: 1px solid; } .friends td, .friends th { border-left: 1px solid; padding: 5px 10px; } .friends td:first-child, .friends th:first-child { border-left: none; } // Element locators var names = element.all(by.repeater('friends').column('friend.name')); it('should sort friends by age in reverse order', function() { expect(names.get(0).getText()).toBe('Adam'); expect(names.get(1).getText()).toBe('Julie'); expect(names.get(2).getText()).toBe('Mike'); expect(names.get(3).getText()).toBe('Mary'); expect(names.get(4).getText()).toBe('John'); });
*
* * @example * ### Changing parameters dynamically * * All parameters can be changed dynamically. The next example shows how you can make the columns of * a table sortable, by binding the `expression` and `reverse` parameters to scope properties. *
Sort by = {{propertyName}}; reverse = {{reverse}}


{{friend.name}} {{friend.phone}} {{friend.age}}
angular.module('orderByExample2', []) .controller('ExampleController', ['$scope', function($scope) { var friends = [ {name: 'John', phone: '555-1212', age: 10}, {name: 'Mary', phone: '555-9876', age: 19}, {name: 'Mike', phone: '555-4321', age: 21}, {name: 'Adam', phone: '555-5678', age: 35}, {name: 'Julie', phone: '555-8765', age: 29} ]; $scope.propertyName = 'age'; $scope.reverse = true; $scope.friends = friends; $scope.sortBy = function(propertyName) { $scope.reverse = ($scope.propertyName === propertyName) ? !$scope.reverse : false; $scope.propertyName = propertyName; }; }]); .friends { border-collapse: collapse; } .friends th { border-bottom: 1px solid; } .friends td, .friends th { border-left: 1px solid; padding: 5px 10px; } .friends td:first-child, .friends th:first-child { border-left: none; } .sortorder:after { content: '\25b2'; // BLACK UP-POINTING TRIANGLE } .sortorder.reverse:after { content: '\25bc'; // BLACK DOWN-POINTING TRIANGLE } // Element locators var unsortButton = element(by.partialButtonText('unsorted')); var nameHeader = element(by.partialButtonText('Name')); var phoneHeader = element(by.partialButtonText('Phone')); var ageHeader = element(by.partialButtonText('Age')); var firstName = element(by.repeater('friends').column('friend.name').row(0)); var lastName = element(by.repeater('friends').column('friend.name').row(4)); it('should sort friends by some property, when clicking on the column header', function() { expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); phoneHeader.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Mary'); nameHeader.click(); expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('Mike'); ageHeader.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Adam'); }); it('should sort friends in reverse order, when clicking on the same column', function() { expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); ageHeader.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Adam'); ageHeader.click(); expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); }); it('should restore the original order, when clicking "Set to unsorted"', function() { expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); unsortButton.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Julie'); });
*
* * @example * ### Using `orderBy` inside a controller * * It is also possible to call the `orderBy` filter manually, by injecting `orderByFilter`, and * calling it with the desired parameters. (Alternatively, you could inject the `$filter` factory * and retrieve the `orderBy` filter with `$filter('orderBy')`.) *
Sort by = {{propertyName}}; reverse = {{reverse}}


{{friend.name}} {{friend.phone}} {{friend.age}}
angular.module('orderByExample3', []) .controller('ExampleController', ['$scope', 'orderByFilter', function($scope, orderBy) { var friends = [ {name: 'John', phone: '555-1212', age: 10}, {name: 'Mary', phone: '555-9876', age: 19}, {name: 'Mike', phone: '555-4321', age: 21}, {name: 'Adam', phone: '555-5678', age: 35}, {name: 'Julie', phone: '555-8765', age: 29} ]; $scope.propertyName = 'age'; $scope.reverse = true; $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse); $scope.sortBy = function(propertyName) { $scope.reverse = (propertyName !== null && $scope.propertyName === propertyName) ? !$scope.reverse : false; $scope.propertyName = propertyName; $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse); }; }]); .friends { border-collapse: collapse; } .friends th { border-bottom: 1px solid; } .friends td, .friends th { border-left: 1px solid; padding: 5px 10px; } .friends td:first-child, .friends th:first-child { border-left: none; } .sortorder:after { content: '\25b2'; // BLACK UP-POINTING TRIANGLE } .sortorder.reverse:after { content: '\25bc'; // BLACK DOWN-POINTING TRIANGLE } // Element locators var unsortButton = element(by.partialButtonText('unsorted')); var nameHeader = element(by.partialButtonText('Name')); var phoneHeader = element(by.partialButtonText('Phone')); var ageHeader = element(by.partialButtonText('Age')); var firstName = element(by.repeater('friends').column('friend.name').row(0)); var lastName = element(by.repeater('friends').column('friend.name').row(4)); it('should sort friends by some property, when clicking on the column header', function() { expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); phoneHeader.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Mary'); nameHeader.click(); expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('Mike'); ageHeader.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Adam'); }); it('should sort friends in reverse order, when clicking on the same column', function() { expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); ageHeader.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Adam'); ageHeader.click(); expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); }); it('should restore the original order, when clicking "Set to unsorted"', function() { expect(firstName.getText()).toBe('Adam'); expect(lastName.getText()).toBe('John'); unsortButton.click(); expect(firstName.getText()).toBe('John'); expect(lastName.getText()).toBe('Julie'); });
*
* * @example * ### Using a custom comparator * * If you have very specific requirements about the way items are sorted, you can pass your own * comparator function. For example, you might need to compare some strings in a locale-sensitive * way. (When specifying a custom comparator, you also need to pass a value for the `reverse` * argument - passing `false` retains the default sorting order, i.e. ascending.) *

Locale-sensitive Comparator

Name Favorite Letter
{{friend.name}} {{friend.favoriteLetter}}

Default Comparator

Name Favorite Letter
{{friend.name}} {{friend.favoriteLetter}}
angular.module('orderByExample4', []) .controller('ExampleController', ['$scope', function($scope) { $scope.friends = [ {name: 'John', favoriteLetter: 'Ä'}, {name: 'Mary', favoriteLetter: 'Ü'}, {name: 'Mike', favoriteLetter: 'Ö'}, {name: 'Adam', favoriteLetter: 'H'}, {name: 'Julie', favoriteLetter: 'Z'} ]; $scope.localeSensitiveComparator = function(v1, v2) { // If we don't get strings, just compare by index if (v1.type !== 'string' || v2.type !== 'string') { return (v1.index < v2.index) ? -1 : 1; } // Compare strings alphabetically, taking locale into account return v1.value.localeCompare(v2.value); }; }]); .friends-container { display: inline-block; margin: 0 30px; } .friends { border-collapse: collapse; } .friends th { border-bottom: 1px solid; } .friends td, .friends th { border-left: 1px solid; padding: 5px 10px; } .friends td:first-child, .friends th:first-child { border-left: none; } // Element locators var container = element(by.css('.custom-comparator')); var names = container.all(by.repeater('friends').column('friend.name')); it('should sort friends by favorite letter (in correct alphabetical order)', function() { expect(names.get(0).getText()).toBe('John'); expect(names.get(1).getText()).toBe('Adam'); expect(names.get(2).getText()).toBe('Mike'); expect(names.get(3).getText()).toBe('Mary'); expect(names.get(4).getText()).toBe('Julie'); });
* */ orderByFilter.$inject = ['$parse']; function orderByFilter($parse) { return function(array, sortPredicate, reverseOrder, compareFn) { if (array == null) return array; if (!isArrayLike(array)) { throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array); } if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; } if (sortPredicate.length === 0) { sortPredicate = ['+']; } var predicates = processPredicates(sortPredicate); var descending = reverseOrder ? -1 : 1; // Define the `compare()` function. Use a default comparator if none is specified. var compare = isFunction(compareFn) ? compareFn : defaultCompare; // The next three lines are a version of a Swartzian Transform idiom from Perl // (sometimes called the Decorate-Sort-Undecorate idiom) // See https://en.wikipedia.org/wiki/Schwartzian_transform var compareValues = Array.prototype.map.call(array, getComparisonObject); compareValues.sort(doComparison); array = compareValues.map(function(item) { return item.value; }); return array; function getComparisonObject(value, index) { // NOTE: We are adding an extra `tieBreaker` value based on the element's index. // This will be used to keep the sort stable when none of the input predicates can // distinguish between two elements. return { value: value, tieBreaker: {value: index, type: 'number', index: index}, predicateValues: predicates.map(function(predicate) { return getPredicateValue(predicate.get(value), index); }) }; } function doComparison(v1, v2) { for (var i = 0, ii = predicates.length; i < ii; i++) { var result = compare(v1.predicateValues[i], v2.predicateValues[i]); if (result) { return result * predicates[i].descending * descending; } } return (compare(v1.tieBreaker, v2.tieBreaker) || defaultCompare(v1.tieBreaker, v2.tieBreaker)) * descending; } }; function processPredicates(sortPredicates) { return sortPredicates.map(function(predicate) { var descending = 1, get = identity; if (isFunction(predicate)) { get = predicate; } else if (isString(predicate)) { if ((predicate.charAt(0) === '+' || predicate.charAt(0) === '-')) { descending = predicate.charAt(0) === '-' ? -1 : 1; predicate = predicate.substring(1); } if (predicate !== '') { get = $parse(predicate); if (get.constant) { var key = get(); get = function(value) { return value[key]; }; } } } return {get: get, descending: descending}; }); } function isPrimitive(value) { switch (typeof value) { case 'number': /* falls through */ case 'boolean': /* falls through */ case 'string': return true; default: return false; } } function objectValue(value) { // If `valueOf` is a valid function use that if (isFunction(value.valueOf)) { value = value.valueOf(); if (isPrimitive(value)) return value; } // If `toString` is a valid function and not the one from `Object.prototype` use that if (hasCustomToString(value)) { value = value.toString(); if (isPrimitive(value)) return value; } return value; } function getPredicateValue(value, index) { var type = typeof value; if (value === null) { type = 'string'; value = 'null'; } else if (type === 'object') { value = objectValue(value); } return {value: value, type: type, index: index}; } function defaultCompare(v1, v2) { var result = 0; var type1 = v1.type; var type2 = v2.type; if (type1 === type2) { var value1 = v1.value; var value2 = v2.value; if (type1 === 'string') { // Compare strings case-insensitively value1 = value1.toLowerCase(); value2 = value2.toLowerCase(); } else if (type1 === 'object') { // For basic objects, use the position of the object // in the collection instead of the value if (isObject(value1)) value1 = v1.index; if (isObject(value2)) value2 = v2.index; } if (value1 !== value2) { result = value1 < value2 ? -1 : 1; } } else { result = type1 < type2 ? -1 : 1; } return result; } } function ngDirective(directive) { if (isFunction(directive)) { directive = { link: directive }; } directive.restrict = directive.restrict || 'AC'; return valueFn(directive); } /** * @ngdoc directive * @name a * @restrict E * * @description * Modifies the default behavior of the html a tag so that the default action is prevented when * the href attribute is empty. * * For dynamically creating `href` attributes for a tags, see the {@link ng.ngHref `ngHref`} directive. */ var htmlAnchorDirective = valueFn({ restrict: 'E', compile: function(element, attr) { if (!attr.href && !attr.xlinkHref) { return function(scope, element) { // If the linked element is not an anchor tag anymore, do nothing if (element[0].nodeName.toLowerCase() !== 'a') return; // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute. var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ? 'xlink:href' : 'href'; element.on('click', function(event) { // if we have no href url, then don't navigate anywhere. if (!element.attr(href)) { event.preventDefault(); } }); }; } } }); /** * @ngdoc directive * @name ngHref * @restrict A * @priority 99 * * @description * Using Angular markup like `{{hash}}` in an href attribute will * make the link go to the wrong URL if the user clicks it before * Angular has a chance to replace the `{{hash}}` markup with its * value. Until Angular replaces the markup the link will be broken * and will most likely return a 404 error. The `ngHref` directive * solves this problem. * * The wrong way to write it: * ```html * link1 * ``` * * The correct way to write it: * ```html * link1 * ``` * * @element A * @param {template} ngHref any string which can contain `{{}}` markup. * * @example * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes * in links and their different behaviors:
link 1 (link, don't reload)
link 2 (link, don't reload)
link 3 (link, reload!)
anchor (link, don't reload)
anchor (no link)
link (link, change location)
it('should execute ng-click but not reload when href without value', function() { element(by.id('link-1')).click(); expect(element(by.model('value')).getAttribute('value')).toEqual('1'); expect(element(by.id('link-1')).getAttribute('href')).toBe(''); }); it('should execute ng-click but not reload when href empty string', function() { element(by.id('link-2')).click(); expect(element(by.model('value')).getAttribute('value')).toEqual('2'); expect(element(by.id('link-2')).getAttribute('href')).toBe(''); }); it('should execute ng-click and change url when ng-href specified', function() { expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/); element(by.id('link-3')).click(); // At this point, we navigate away from an Angular page, so we need // to use browser.driver to get the base webdriver. browser.wait(function() { return browser.driver.getCurrentUrl().then(function(url) { return url.match(/\/123$/); }); }, 5000, 'page should navigate to /123'); }); it('should execute ng-click but not reload when href empty string and name specified', function() { element(by.id('link-4')).click(); expect(element(by.model('value')).getAttribute('value')).toEqual('4'); expect(element(by.id('link-4')).getAttribute('href')).toBe(''); }); it('should execute ng-click but not reload when no href but name specified', function() { element(by.id('link-5')).click(); expect(element(by.model('value')).getAttribute('value')).toEqual('5'); expect(element(by.id('link-5')).getAttribute('href')).toBe(null); }); it('should only change url when only ng-href', function() { element(by.model('value')).clear(); element(by.model('value')).sendKeys('6'); expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/); element(by.id('link-6')).click(); // At this point, we navigate away from an Angular page, so we need // to use browser.driver to get the base webdriver. browser.wait(function() { return browser.driver.getCurrentUrl().then(function(url) { return url.match(/\/6$/); }); }, 5000, 'page should navigate to /6'); });
*/ /** * @ngdoc directive * @name ngSrc * @restrict A * @priority 99 * * @description * Using Angular markup like `{{hash}}` in a `src` attribute doesn't * work right: The browser will fetch from the URL with the literal * text `{{hash}}` until Angular replaces the expression inside * `{{hash}}`. The `ngSrc` directive solves this problem. * * The buggy way to write it: * ```html * Description * ``` * * The correct way to write it: * ```html * Description * ``` * * @element IMG * @param {template} ngSrc any string which can contain `{{}}` markup. */ /** * @ngdoc directive * @name ngSrcset * @restrict A * @priority 99 * * @description * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't * work right: The browser will fetch from the URL with the literal * text `{{hash}}` until Angular replaces the expression inside * `{{hash}}`. The `ngSrcset` directive solves this problem. * * The buggy way to write it: * ```html * Description * ``` * * The correct way to write it: * ```html * Description * ``` * * @element IMG * @param {template} ngSrcset any string which can contain `{{}}` markup. */ /** * @ngdoc directive * @name ngDisabled * @restrict A * @priority 100 * * @description * * This directive sets the `disabled` attribute on the element (typically a form control, * e.g. `input`, `button`, `select` etc.) if the * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy. * * A special directive is necessary because we cannot use interpolation inside the `disabled` * attribute. See the {@link guide/interpolation interpolation guide} for more info. * * @example
it('should toggle button', function() { expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy(); element(by.model('checked')).click(); expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy(); });
* * @element INPUT * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy, * then the `disabled` attribute will be set on the element */ /** * @ngdoc directive * @name ngChecked * @restrict A * @priority 100 * * @description * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy. * * Note that this directive should not be used together with {@link ngModel `ngModel`}, * as this can lead to unexpected behavior. * * A special directive is necessary because we cannot use interpolation inside the `checked` * attribute. See the {@link guide/interpolation interpolation guide} for more info. * * @example
it('should check both checkBoxes', function() { expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy(); element(by.model('master')).click(); expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy(); });
* * @element INPUT * @param {expression} ngChecked If the {@link guide/expression expression} is truthy, * then the `checked` attribute will be set on the element */ /** * @ngdoc directive * @name ngReadonly * @restrict A * @priority 100 * * @description * * Sets the `readonly` attribute on the element, if the expression inside `ngReadonly` is truthy. * Note that `readonly` applies only to `input` elements with specific types. [See the input docs on * MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) for more information. * * A special directive is necessary because we cannot use interpolation inside the `readonly` * attribute. See the {@link guide/interpolation interpolation guide} for more info. * * @example
it('should toggle readonly attr', function() { expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy(); element(by.model('checked')).click(); expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy(); });
* * @element INPUT * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy, * then special attribute "readonly" will be set on the element */ /** * @ngdoc directive * @name ngSelected * @restrict A * @priority 100 * * @description * * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy. * * A special directive is necessary because we cannot use interpolation inside the `selected` * attribute. See the {@link guide/interpolation interpolation guide} for more info. * *
* **Note:** `ngSelected` does not interact with the `select` and `ngModel` directives, it only * sets the `selected` attribute on the element. If you are using `ngModel` on the select, you * should not use `ngSelected` on the options, as `ngModel` will set the select value and * selected options. *
* * @example
it('should select Greetings!', function() { expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy(); element(by.model('selected')).click(); expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy(); });
* * @element OPTION * @param {expression} ngSelected If the {@link guide/expression expression} is truthy, * then special attribute "selected" will be set on the element */ /** * @ngdoc directive * @name ngOpen * @restrict A * @priority 100 * * @description * * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy. * * A special directive is necessary because we cannot use interpolation inside the `open` * attribute. See the {@link guide/interpolation interpolation guide} for more info. * * ## A note about browser compatibility * * Internet Explorer and Edge do not support the `details` element, it is * recommended to use {@link ng.ngShow} and {@link ng.ngHide} instead. * * @example
List
  • Apple
  • Orange
  • Durian
it('should toggle open', function() { expect(element(by.id('details')).getAttribute('open')).toBeFalsy(); element(by.model('open')).click(); expect(element(by.id('details')).getAttribute('open')).toBeTruthy(); });
* * @element DETAILS * @param {expression} ngOpen If the {@link guide/expression expression} is truthy, * then special attribute "open" will be set on the element */ var ngAttributeAliasDirectives = {}; // boolean attrs are evaluated forEach(BOOLEAN_ATTR, function(propName, attrName) { // binding to multiple is not supported if (propName === 'multiple') return; function defaultLinkFn(scope, element, attr) { scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) { attr.$set(attrName, !!value); }); } var normalized = directiveNormalize('ng-' + attrName); var linkFn = defaultLinkFn; if (propName === 'checked') { linkFn = function(scope, element, attr) { // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input if (attr.ngModel !== attr[normalized]) { defaultLinkFn(scope, element, attr); } }; } ngAttributeAliasDirectives[normalized] = function() { return { restrict: 'A', priority: 100, link: linkFn }; }; }); // aliased input attrs are evaluated forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) { ngAttributeAliasDirectives[ngAttr] = function() { return { priority: 100, link: function(scope, element, attr) { //special case ngPattern when a literal regular expression value //is used as the expression (this way we don't have to watch anything). if (ngAttr === 'ngPattern' && attr.ngPattern.charAt(0) === '/') { var match = attr.ngPattern.match(REGEX_STRING_REGEXP); if (match) { attr.$set('ngPattern', new RegExp(match[1], match[2])); return; } } scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) { attr.$set(ngAttr, value); }); } }; }; }); // ng-src, ng-srcset, ng-href are interpolated forEach(['src', 'srcset', 'href'], function(attrName) { var normalized = directiveNormalize('ng-' + attrName); ngAttributeAliasDirectives[normalized] = function() { return { priority: 99, // it needs to run after the attributes are interpolated link: function(scope, element, attr) { var propName = attrName, name = attrName; if (attrName === 'href' && toString.call(element.prop('href')) === '[object SVGAnimatedString]') { name = 'xlinkHref'; attr.$attr[name] = 'xlink:href'; propName = null; } attr.$observe(normalized, function(value) { if (!value) { if (attrName === 'href') { attr.$set(name, null); } return; } attr.$set(name, value); // Support: IE 9-11 only // On IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need // to set the property as well to achieve the desired effect. // We use attr[attrName] value since $set can sanitize the url. if (msie && propName) element.prop(propName, attr[name]); }); } }; }; }); /* global -nullFormCtrl, -PENDING_CLASS, -SUBMITTED_CLASS */ var nullFormCtrl = { $addControl: noop, $$renameControl: nullFormRenameControl, $removeControl: noop, $setValidity: noop, $setDirty: noop, $setPristine: noop, $setSubmitted: noop }, PENDING_CLASS = 'ng-pending', SUBMITTED_CLASS = 'ng-submitted'; function nullFormRenameControl(control, name) { control.$name = name; } /** * @ngdoc type * @name form.FormController * * @property {boolean} $pristine True if user has not interacted with the form yet. * @property {boolean} $dirty True if user has already interacted with the form. * @property {boolean} $valid True if all of the containing forms and controls are valid. * @property {boolean} $invalid True if at least one containing control or form is invalid. * @property {boolean} $submitted True if user has submitted the form even if its invalid. * * @property {Object} $pending An object hash, containing references to controls or forms with * pending validators, where: * * - keys are validations tokens (error names). * - values are arrays of controls or forms that have a pending validator for the given error name. * * See {@link form.FormController#$error $error} for a list of built-in validation tokens. * * @property {Object} $error An object hash, containing references to controls or forms with failing * validators, where: * * - keys are validation tokens (error names), * - values are arrays of controls or forms that have a failing validator for the given error name. * * Built-in validation tokens: * - `email` * - `max` * - `maxlength` * - `min` * - `minlength` * - `number` * - `pattern` * - `required` * - `url` * - `date` * - `datetimelocal` * - `time` * - `week` * - `month` * * @description * `FormController` keeps track of all its controls and nested forms as well as the state of them, * such as being valid/invalid or dirty/pristine. * * Each {@link ng.directive:form form} directive creates an instance * of `FormController`. * */ //asks for $scope to fool the BC controller module FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate']; function FormController($element, $attrs, $scope, $animate, $interpolate) { this.$$controls = []; // init state this.$error = {}; this.$$success = {}; this.$pending = undefined; this.$name = $interpolate($attrs.name || $attrs.ngForm || '')($scope); this.$dirty = false; this.$pristine = true; this.$valid = true; this.$invalid = false; this.$submitted = false; this.$$parentForm = nullFormCtrl; this.$$element = $element; this.$$animate = $animate; setupValidity(this); } FormController.prototype = { /** * @ngdoc method * @name form.FormController#$rollbackViewValue * * @description * Rollback all form controls pending updates to the `$modelValue`. * * Updates may be pending by a debounced event or because the input is waiting for a some future * event defined in `ng-model-options`. This method is typically needed by the reset button of * a form that uses `ng-model-options` to pend updates. */ $rollbackViewValue: function() { forEach(this.$$controls, function(control) { control.$rollbackViewValue(); }); }, /** * @ngdoc method * @name form.FormController#$commitViewValue * * @description * Commit all form controls pending updates to the `$modelValue`. * * Updates may be pending by a debounced event or because the input is waiting for a some future * event defined in `ng-model-options`. This method is rarely needed as `NgModelController` * usually handles calling this in response to input events. */ $commitViewValue: function() { forEach(this.$$controls, function(control) { control.$commitViewValue(); }); }, /** * @ngdoc method * @name form.FormController#$addControl * @param {object} control control object, either a {@link form.FormController} or an * {@link ngModel.NgModelController} * * @description * Register a control with the form. Input elements using ngModelController do this automatically * when they are linked. * * Note that the current state of the control will not be reflected on the new parent form. This * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine` * state. * * However, if the method is used programmatically, for example by adding dynamically created controls, * or controls that have been previously removed without destroying their corresponding DOM element, * it's the developers responsibility to make sure the current state propagates to the parent form. * * For example, if an input control is added that is already `$dirty` and has `$error` properties, * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form. */ $addControl: function(control) { // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored // and not added to the scope. Now we throw an error. assertNotHasOwnProperty(control.$name, 'input'); this.$$controls.push(control); if (control.$name) { this[control.$name] = control; } control.$$parentForm = this; }, // Private API: rename a form control $$renameControl: function(control, newName) { var oldName = control.$name; if (this[oldName] === control) { delete this[oldName]; } this[newName] = control; control.$name = newName; }, /** * @ngdoc method * @name form.FormController#$removeControl * @param {object} control control object, either a {@link form.FormController} or an * {@link ngModel.NgModelController} * * @description * Deregister a control from the form. * * Input elements using ngModelController do this automatically when they are destroyed. * * Note that only the removed control's validation state (`$errors`etc.) will be removed from the * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be * different from case to case. For example, removing the only `$dirty` control from a form may or * may not mean that the form is still `$dirty`. */ $removeControl: function(control) { if (control.$name && this[control.$name] === control) { delete this[control.$name]; } forEach(this.$pending, function(value, name) { // eslint-disable-next-line no-invalid-this this.$setValidity(name, null, control); }, this); forEach(this.$error, function(value, name) { // eslint-disable-next-line no-invalid-this this.$setValidity(name, null, control); }, this); forEach(this.$$success, function(value, name) { // eslint-disable-next-line no-invalid-this this.$setValidity(name, null, control); }, this); arrayRemove(this.$$controls, control); control.$$parentForm = nullFormCtrl; }, /** * @ngdoc method * @name form.FormController#$setDirty * * @description * Sets the form to a dirty state. * * This method can be called to add the 'ng-dirty' class and set the form to a dirty * state (ng-dirty class). This method will also propagate to parent forms. */ $setDirty: function() { this.$$animate.removeClass(this.$$element, PRISTINE_CLASS); this.$$animate.addClass(this.$$element, DIRTY_CLASS); this.$dirty = true; this.$pristine = false; this.$$parentForm.$setDirty(); }, /** * @ngdoc method * @name form.FormController#$setPristine * * @description * Sets the form to its pristine state. * * This method sets the form's `$pristine` state to true, the `$dirty` state to false, removes * the `ng-dirty` class and adds the `ng-pristine` class. Additionally, it sets the `$submitted` * state to false. * * This method will also propagate to all the controls contained in this form. * * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after * saving or resetting it. */ $setPristine: function() { this.$$animate.setClass(this.$$element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS); this.$dirty = false; this.$pristine = true; this.$submitted = false; forEach(this.$$controls, function(control) { control.$setPristine(); }); }, /** * @ngdoc method * @name form.FormController#$setUntouched * * @description * Sets the form to its untouched state. * * This method can be called to remove the 'ng-touched' class and set the form controls to their * untouched state (ng-untouched class). * * Setting a form controls back to their untouched state is often useful when setting the form * back to its pristine state. */ $setUntouched: function() { forEach(this.$$controls, function(control) { control.$setUntouched(); }); }, /** * @ngdoc method * @name form.FormController#$setSubmitted * * @description * Sets the form to its submitted state. */ $setSubmitted: function() { this.$$animate.addClass(this.$$element, SUBMITTED_CLASS); this.$submitted = true; this.$$parentForm.$setSubmitted(); } }; /** * @ngdoc method * @name form.FormController#$setValidity * * @description * Change the validity state of the form, and notify the parent form (if any). * * Application developers will rarely need to call this method directly. It is used internally, by * {@link ngModel.NgModelController#$setValidity NgModelController.$setValidity()}, to propagate a * control's validity state to the parent `FormController`. * * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be * assigned to either `$error[validationErrorKey]` or `$pending[validationErrorKey]` (for * unfulfilled `$asyncValidators`), so that it is available for data-binding. The * `validationErrorKey` should be in camelCase and will get converted into dash-case for * class name. Example: `myError` will result in `ng-valid-my-error` and * `ng-invalid-my-error` classes and can be bound to as `{{ someForm.$error.myError }}`. * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending * (undefined), or skipped (null). Pending is used for unfulfilled `$asyncValidators`. * Skipped is used by AngularJS when validators do not run because of parse errors and when * `$asyncValidators` do not run because any of the `$validators` failed. * @param {NgModelController | FormController} controller - The controller whose validity state is * triggering the change. */ addSetValidityMethod({ clazz: FormController, set: function(object, property, controller) { var list = object[property]; if (!list) { object[property] = [controller]; } else { var index = list.indexOf(controller); if (index === -1) { list.push(controller); } } }, unset: function(object, property, controller) { var list = object[property]; if (!list) { return; } arrayRemove(list, controller); if (list.length === 0) { delete object[property]; } } }); /** * @ngdoc directive * @name ngForm * @restrict EAC * * @description * Nestable alias of {@link ng.directive:form `form`} directive. HTML * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a * sub-group of controls needs to be determined. * * Note: the purpose of `ngForm` is to group controls, * but not to be a replacement for the `
` tag with all of its capabilities * (e.g. posting to the server, ...). * * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into * related scope, under this name. * */ /** * @ngdoc directive * @name form * @restrict E * * @description * Directive that instantiates * {@link form.FormController FormController}. * * If the `name` attribute is specified, the form controller is published onto the current scope under * this name. * * # Alias: {@link ng.directive:ngForm `ngForm`} * * In Angular, forms can be nested. This means that the outer form is valid when all of the child * forms are valid as well. However, browsers do not allow nesting of `` elements, so * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group * of controls needs to be determined. * * # CSS classes * - `ng-valid` is set if the form is valid. * - `ng-invalid` is set if the form is invalid. * - `ng-pending` is set if the form is pending. * - `ng-pristine` is set if the form is pristine. * - `ng-dirty` is set if the form is dirty. * - `ng-submitted` is set if the form was submitted. * * Keep in mind that ngAnimate can detect each of these classes when added and removed. * * * # Submitting a form and preventing the default action * * Since the role of forms in client-side Angular applications is different than in classical * roundtrip apps, it is desirable for the browser not to translate the form submission into a full * page reload that sends the data to the server. Instead some javascript logic should be triggered * to handle the form submission in an application-specific way. * * For this reason, Angular prevents the default action (form submission to the server) unless the * `` element has an `action` attribute specified. * * You can use one of the following two ways to specify what javascript method should be called when * a form is submitted: * * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element * - {@link ng.directive:ngClick ngClick} directive on the first * button or input field of type submit (input[type=submit]) * * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit} * or {@link ng.directive:ngClick ngClick} directives. * This is because of the following form submission rules in the HTML specification: * * - If a form has only one input field then hitting enter in this field triggers form submit * (`ngSubmit`) * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter * doesn't trigger submit * - if a form has one or more input fields and one or more buttons or input[type=submit] then * hitting enter in any of the input fields will trigger the click handler on the *first* button or * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`) * * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` * to have access to the updated model. * * ## Animation Hooks * * Animations in ngForm are triggered when any of the associated CSS classes are added and removed. * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any * other validations that are performed within the form. Animations in ngForm are similar to how * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well * as JS animations. * * The following example shows a simple way to utilize CSS transitions to style a form element * that has been rendered as invalid after it has been validated: * *
 * //be sure to include ngAnimate as a module to hook into more
 * //advanced animations
 * .my-form {
 *   transition:0.5s linear all;
 *   background: white;
 * }
 * .my-form.ng-invalid {
 *   background: red;
 *   color:white;
 * }
 * 
* * @example userType: Required!
userType = {{userType}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
it('should initialize to model', function() { var userType = element(by.binding('userType')); var valid = element(by.binding('myForm.input.$valid')); expect(userType.getText()).toContain('guest'); expect(valid.getText()).toContain('true'); }); it('should be invalid if empty', function() { var userType = element(by.binding('userType')); var valid = element(by.binding('myForm.input.$valid')); var userInput = element(by.model('userType')); userInput.clear(); userInput.sendKeys(''); expect(userType.getText()).toEqual('userType ='); expect(valid.getText()).toContain('false'); });
* * @param {string=} name Name of the form. If specified, the form controller will be published into * related scope, under this name. */ var formDirectiveFactory = function(isNgForm) { return ['$timeout', '$parse', function($timeout, $parse) { var formDirective = { name: 'form', restrict: isNgForm ? 'EAC' : 'E', require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form controller: FormController, compile: function ngFormCompile(formElement, attr) { // Setup initial state of the control formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS); var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false); return { pre: function ngFormPreLink(scope, formElement, attr, ctrls) { var controller = ctrls[0]; // if `action` attr is not present on the form, prevent the default action (submission) if (!('action' in attr)) { // we can't use jq events because if a form is destroyed during submission the default // action is not prevented. see #1238 // // IE 9 is not affected because it doesn't fire a submit event and try to do a full // page reload if the form was destroyed by submission of the form via a click handler // on a button in the form. Looks like an IE9 specific bug. var handleFormSubmission = function(event) { scope.$apply(function() { controller.$commitViewValue(); controller.$setSubmitted(); }); event.preventDefault(); }; formElement[0].addEventListener('submit', handleFormSubmission); // unregister the preventDefault listener so that we don't not leak memory but in a // way that will achieve the prevention of the default action. formElement.on('$destroy', function() { $timeout(function() { formElement[0].removeEventListener('submit', handleFormSubmission); }, 0, false); }); } var parentFormCtrl = ctrls[1] || controller.$$parentForm; parentFormCtrl.$addControl(controller); var setter = nameAttr ? getSetter(controller.$name) : noop; if (nameAttr) { setter(scope, controller); attr.$observe(nameAttr, function(newValue) { if (controller.$name === newValue) return; setter(scope, undefined); controller.$$parentForm.$$renameControl(controller, newValue); setter = getSetter(controller.$name); setter(scope, controller); }); } formElement.on('$destroy', function() { controller.$$parentForm.$removeControl(controller); setter(scope, undefined); extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards }); } }; } }; return formDirective; function getSetter(expression) { if (expression === '') { //create an assignable expression, so forms with an empty name can be renamed later return $parse('this[""]').assign; } return $parse(expression).assign || noop; } }]; }; var formDirective = formDirectiveFactory(); var ngFormDirective = formDirectiveFactory(true); // helper methods function setupValidity(instance) { instance.$$classCache = {}; instance.$$classCache[INVALID_CLASS] = !(instance.$$classCache[VALID_CLASS] = instance.$$element.hasClass(VALID_CLASS)); } function addSetValidityMethod(context) { var clazz = context.clazz, set = context.set, unset = context.unset; clazz.prototype.$setValidity = function(validationErrorKey, state, controller) { if (isUndefined(state)) { createAndSet(this, '$pending', validationErrorKey, controller); } else { unsetAndCleanup(this, '$pending', validationErrorKey, controller); } if (!isBoolean(state)) { unset(this.$error, validationErrorKey, controller); unset(this.$$success, validationErrorKey, controller); } else { if (state) { unset(this.$error, validationErrorKey, controller); set(this.$$success, validationErrorKey, controller); } else { set(this.$error, validationErrorKey, controller); unset(this.$$success, validationErrorKey, controller); } } if (this.$pending) { cachedToggleClass(this, PENDING_CLASS, true); this.$valid = this.$invalid = undefined; toggleValidationCss(this, '', null); } else { cachedToggleClass(this, PENDING_CLASS, false); this.$valid = isObjectEmpty(this.$error); this.$invalid = !this.$valid; toggleValidationCss(this, '', this.$valid); } // re-read the state as the set/unset methods could have // combined state in this.$error[validationError] (used for forms), // where setting/unsetting only increments/decrements the value, // and does not replace it. var combinedState; if (this.$pending && this.$pending[validationErrorKey]) { combinedState = undefined; } else if (this.$error[validationErrorKey]) { combinedState = false; } else if (this.$$success[validationErrorKey]) { combinedState = true; } else { combinedState = null; } toggleValidationCss(this, validationErrorKey, combinedState); this.$$parentForm.$setValidity(validationErrorKey, combinedState, this); }; function createAndSet(ctrl, name, value, controller) { if (!ctrl[name]) { ctrl[name] = {}; } set(ctrl[name], value, controller); } function unsetAndCleanup(ctrl, name, value, controller) { if (ctrl[name]) { unset(ctrl[name], value, controller); } if (isObjectEmpty(ctrl[name])) { ctrl[name] = undefined; } } function cachedToggleClass(ctrl, className, switchValue) { if (switchValue && !ctrl.$$classCache[className]) { ctrl.$$animate.addClass(ctrl.$$element, className); ctrl.$$classCache[className] = true; } else if (!switchValue && ctrl.$$classCache[className]) { ctrl.$$animate.removeClass(ctrl.$$element, className); ctrl.$$classCache[className] = false; } } function toggleValidationCss(ctrl, validationErrorKey, isValid) { validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : ''; cachedToggleClass(ctrl, VALID_CLASS + validationErrorKey, isValid === true); cachedToggleClass(ctrl, INVALID_CLASS + validationErrorKey, isValid === false); } } function isObjectEmpty(obj) { if (obj) { for (var prop in obj) { if (obj.hasOwnProperty(prop)) { return false; } } } return true; } /* global VALID_CLASS: false, INVALID_CLASS: false, PRISTINE_CLASS: false, DIRTY_CLASS: false, ngModelMinErr: false */ // Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231 var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/; // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987) // Note: We are being more lenient, because browsers are too. // 1. Scheme // 2. Slashes // 3. Username // 4. Password // 5. Hostname // 6. Port // 7. Path // 8. Query // 9. Fragment // 1111111111111111 222 333333 44444 55555555555555555555555 666 77777777 8888888 999 var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i; // eslint-disable-next-line max-len var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/; var NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/; var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/; var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/; var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/; var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown'; var PARTIAL_VALIDATION_TYPES = createMap(); forEach('date,datetime-local,month,time,week'.split(','), function(type) { PARTIAL_VALIDATION_TYPES[type] = true; }); var inputType = { /** * @ngdoc input * @name input[text] * * @description * Standard HTML text input with angular data binding, inherited by most of the `input` elements. * * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} required Adds `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than * minlength. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of * any length. * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} * does not match a RegExp found by evaluating the Angular expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to * `new RegExp('^abc$')`.
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. * This parameter is ignored for input[type=password] controls, which will never trim the * input. * * @example
Required! Single word only!
text = {{example.text}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
var text = element(by.binding('example.text')); var valid = element(by.binding('myForm.input.$valid')); var input = element(by.model('example.text')); it('should initialize to model', function() { expect(text.getText()).toContain('guest'); expect(valid.getText()).toContain('true'); }); it('should be invalid if empty', function() { input.clear(); input.sendKeys(''); expect(text.getText()).toEqual('text ='); expect(valid.getText()).toContain('false'); }); it('should be invalid if multi word', function() { input.clear(); input.sendKeys('hello world'); expect(valid.getText()).toContain('false'); });
*/ 'text': textInputType, /** * @ngdoc input * @name input[date] * * @description * Input with date validation and transformation. In browsers that do not yet support * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601 * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many * modern browsers do not yet support this input type, it is important to provide cues to users on the * expected input format via a placeholder or label. * * The model must always be a Date object, otherwise Angular will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a * valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute * (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5 * constraint validation. * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be * a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute * (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5 * constraint validation. * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
Required! Not a valid date!
value = {{example.value | date: "yyyy-MM-dd"}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
var value = element(by.binding('example.value | date: "yyyy-MM-dd"')); var valid = element(by.binding('myForm.input.$valid')); // currently protractor/webdriver does not support // sending keys to all known HTML5 input controls // for various browsers (see https://github.com/angular/protractor/issues/562). function setInput(val) { // set the value of the element and force validation. var scr = "var ipt = document.getElementById('exampleInput'); " + "ipt.value = '" + val + "';" + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; browser.executeScript(scr); } it('should initialize to model', function() { expect(value.getText()).toContain('2013-10-22'); expect(valid.getText()).toContain('myForm.input.$valid = true'); }); it('should be invalid if empty', function() { setInput(''); expect(value.getText()).toEqual('value ='); expect(valid.getText()).toContain('myForm.input.$valid = false'); }); it('should be invalid if over max', function() { setInput('2015-01-01'); expect(value.getText()).toContain(''); expect(valid.getText()).toContain('myForm.input.$valid = false'); });
*/ 'date': createDateInputType('date', DATE_REGEXP, createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']), 'yyyy-MM-dd'), /** * @ngdoc input * @name input[datetime-local] * * @description * Input with datetime validation and transformation. In browsers that do not yet support * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. * * The model must always be a Date object, otherwise Angular will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation * inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`). * Note that `min` will also add native HTML5 constraint validation. * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation * inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`). * Note that `max` will also add native HTML5 constraint validation. * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
Required! Not a valid date!
value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"')); var valid = element(by.binding('myForm.input.$valid')); // currently protractor/webdriver does not support // sending keys to all known HTML5 input controls // for various browsers (https://github.com/angular/protractor/issues/562). function setInput(val) { // set the value of the element and force validation. var scr = "var ipt = document.getElementById('exampleInput'); " + "ipt.value = '" + val + "';" + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; browser.executeScript(scr); } it('should initialize to model', function() { expect(value.getText()).toContain('2010-12-28T14:57:00'); expect(valid.getText()).toContain('myForm.input.$valid = true'); }); it('should be invalid if empty', function() { setInput(''); expect(value.getText()).toEqual('value ='); expect(valid.getText()).toContain('myForm.input.$valid = false'); }); it('should be invalid if over max', function() { setInput('2015-01-01T23:59:00'); expect(value.getText()).toContain(''); expect(valid.getText()).toContain('myForm.input.$valid = false'); });
*/ 'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP, createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']), 'yyyy-MM-ddTHH:mm:ss.sss'), /** * @ngdoc input * @name input[time] * * @description * Input with time validation and transformation. In browsers that do not yet support * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`. * * The model must always be a Date object, otherwise Angular will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this * attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add * native HTML5 constraint validation. * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this * attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add * native HTML5 constraint validation. * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the * `ngMin` expression evaluates to. Note that it does not set the `min` attribute. * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the * `ngMax` expression evaluates to. Note that it does not set the `max` attribute. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
Required! Not a valid date!
value = {{example.value | date: "HH:mm:ss"}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
var value = element(by.binding('example.value | date: "HH:mm:ss"')); var valid = element(by.binding('myForm.input.$valid')); // currently protractor/webdriver does not support // sending keys to all known HTML5 input controls // for various browsers (https://github.com/angular/protractor/issues/562). function setInput(val) { // set the value of the element and force validation. var scr = "var ipt = document.getElementById('exampleInput'); " + "ipt.value = '" + val + "';" + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; browser.executeScript(scr); } it('should initialize to model', function() { expect(value.getText()).toContain('14:57:00'); expect(valid.getText()).toContain('myForm.input.$valid = true'); }); it('should be invalid if empty', function() { setInput(''); expect(value.getText()).toEqual('value ='); expect(valid.getText()).toContain('myForm.input.$valid = false'); }); it('should be invalid if over max', function() { setInput('23:59:00'); expect(value.getText()).toContain(''); expect(valid.getText()).toContain('myForm.input.$valid = false'); });
*/ 'time': createDateInputType('time', TIME_REGEXP, createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']), 'HH:mm:ss.sss'), /** * @ngdoc input * @name input[week] * * @description * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * week format (yyyy-W##), for example: `2013-W02`. * * The model must always be a Date object, otherwise Angular will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this * attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add * native HTML5 constraint validation. * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this * attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add * native HTML5 constraint validation. * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
Required! Not a valid date!
value = {{example.value | date: "yyyy-Www"}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
var value = element(by.binding('example.value | date: "yyyy-Www"')); var valid = element(by.binding('myForm.input.$valid')); // currently protractor/webdriver does not support // sending keys to all known HTML5 input controls // for various browsers (https://github.com/angular/protractor/issues/562). function setInput(val) { // set the value of the element and force validation. var scr = "var ipt = document.getElementById('exampleInput'); " + "ipt.value = '" + val + "';" + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; browser.executeScript(scr); } it('should initialize to model', function() { expect(value.getText()).toContain('2013-W01'); expect(valid.getText()).toContain('myForm.input.$valid = true'); }); it('should be invalid if empty', function() { setInput(''); expect(value.getText()).toEqual('value ='); expect(valid.getText()).toContain('myForm.input.$valid = false'); }); it('should be invalid if over max', function() { setInput('2015-W01'); expect(value.getText()).toContain(''); expect(valid.getText()).toContain('myForm.input.$valid = false'); });
*/ 'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'), /** * @ngdoc input * @name input[month] * * @description * Input with month validation and transformation. In browsers that do not yet support * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * month format (yyyy-MM), for example: `2009-01`. * * The model must always be a Date object, otherwise Angular will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * If the model is not set to the first of the month, the next view to model update will set it * to the first of the month. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this * attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add * native HTML5 constraint validation. * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this * attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add * native HTML5 constraint validation. * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
Required! Not a valid month!
value = {{example.value | date: "yyyy-MM"}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
var value = element(by.binding('example.value | date: "yyyy-MM"')); var valid = element(by.binding('myForm.input.$valid')); // currently protractor/webdriver does not support // sending keys to all known HTML5 input controls // for various browsers (https://github.com/angular/protractor/issues/562). function setInput(val) { // set the value of the element and force validation. var scr = "var ipt = document.getElementById('exampleInput'); " + "ipt.value = '" + val + "';" + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; browser.executeScript(scr); } it('should initialize to model', function() { expect(value.getText()).toContain('2013-10'); expect(valid.getText()).toContain('myForm.input.$valid = true'); }); it('should be invalid if empty', function() { setInput(''); expect(value.getText()).toEqual('value ='); expect(valid.getText()).toContain('myForm.input.$valid = false'); }); it('should be invalid if over max', function() { setInput('2015-01'); expect(value.getText()).toContain(''); expect(valid.getText()).toContain('myForm.input.$valid = false'); });
*/ 'month': createDateInputType('month', MONTH_REGEXP, createDateParser(MONTH_REGEXP, ['yyyy', 'MM']), 'yyyy-MM'), /** * @ngdoc input * @name input[number] * * @description * Text input with number validation and transformation. Sets the `number` validation * error if not a valid number. * *
* The model must always be of type `number` otherwise Angular will throw an error. * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt} * error docs for more information and an example of how to convert your model if necessary. *
* * ## Issues with HTML5 constraint validation * * In browsers that follow the * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29), * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}. * If a non-number is entered in the input, the browser will report the value as an empty string, * which means the view / model values in `ngModel` and subsequently the scope value * will also be an empty string. * * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * Can be interpolated. * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * Can be interpolated. * @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`, * but does not trigger HTML5 native validation. Takes an expression. * @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`, * but does not trigger HTML5 native validation. Takes an expression. * @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint. * Can be interpolated. * @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint, * but does not trigger HTML5 native validation. Takes an expression. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than * minlength. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of * any length. * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} * does not match a RegExp found by evaluating the Angular expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to * `new RegExp('^abc$')`.
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
Required! Not valid number!
value = {{example.value}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
var value = element(by.binding('example.value')); var valid = element(by.binding('myForm.input.$valid')); var input = element(by.model('example.value')); it('should initialize to model', function() { expect(value.getText()).toContain('12'); expect(valid.getText()).toContain('true'); }); it('should be invalid if empty', function() { input.clear(); input.sendKeys(''); expect(value.getText()).toEqual('value ='); expect(valid.getText()).toContain('false'); }); it('should be invalid if over max', function() { input.clear(); input.sendKeys('123'); expect(value.getText()).toEqual('value ='); expect(valid.getText()).toContain('false'); });
*/ 'number': numberInputType, /** * @ngdoc input * @name input[url] * * @description * Text input with URL validation. Sets the `url` validation error key if the content is not a * valid URL. * *
* **Note:** `input[url]` uses a regex to validate urls that is derived from the regex * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify * the built-in validators (see the {@link guide/forms Forms guide}) *
* * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than * minlength. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of * any length. * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} * does not match a RegExp found by evaluating the Angular expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to * `new RegExp('^abc$')`.
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
var text = element(by.binding('url.text')); var valid = element(by.binding('myForm.input.$valid')); var input = element(by.model('url.text')); it('should initialize to model', function() { expect(text.getText()).toContain('http://google.com'); expect(valid.getText()).toContain('true'); }); it('should be invalid if empty', function() { input.clear(); input.sendKeys(''); expect(text.getText()).toEqual('text ='); expect(valid.getText()).toContain('false'); }); it('should be invalid if not url', function() { input.clear(); input.sendKeys('box'); expect(valid.getText()).toContain('false'); });
*/ 'url': urlInputType, /** * @ngdoc input * @name input[email] * * @description * Text input with email validation. Sets the `email` validation error key if not a valid email * address. * *
* **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide}) *
* * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than * minlength. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of * any length. * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} * does not match a RegExp found by evaluating the Angular expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to * `new RegExp('^abc$')`.
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example
Required! Not valid email!
text = {{email.text}}
myForm.input.$valid = {{myForm.input.$valid}}
myForm.input.$error = {{myForm.input.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
myForm.$error.email = {{!!myForm.$error.email}}
var text = element(by.binding('email.text')); var valid = element(by.binding('myForm.input.$valid')); var input = element(by.model('email.text')); it('should initialize to model', function() { expect(text.getText()).toContain('me@example.com'); expect(valid.getText()).toContain('true'); }); it('should be invalid if empty', function() { input.clear(); input.sendKeys(''); expect(text.getText()).toEqual('text ='); expect(valid.getText()).toContain('false'); }); it('should be invalid if not email', function() { input.clear(); input.sendKeys('xxx'); expect(valid.getText()).toContain('false'); });
*/ 'email': emailInputType, /** * @ngdoc input * @name input[radio] * * @description * HTML radio button. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string} value The value to which the `ngModel` expression should be set when selected. * Note that `value` only supports `string` values, i.e. the scope model needs to be a string, * too. Use `ngValue` if you need complex models (`number`, `object`, ...). * @param {string=} name Property name of the form under which the control is published. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio * is selected. Should be used instead of the `value` attribute if you need * a non-string `ngModel` (`boolean`, `array`, ...). * * @example



color = {{color.name | json}}
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
it('should change state', function() { var inputs = element.all(by.model('color.name')); var color = element(by.binding('color.name')); expect(color.getText()).toContain('blue'); inputs.get(0).click(); expect(color.getText()).toContain('red'); inputs.get(1).click(); expect(color.getText()).toContain('green'); });
*/ 'radio': radioInputType, /** * @ngdoc input * @name input[range] * * @description * Native range input with validation and transformation. * * The model for the range input must always be a `Number`. * * IE9 and other browsers that do not support the `range` type fall back * to a text input without any default values for `min`, `max` and `step`. Model binding, * validation and number parsing are nevertheless supported. * * Browsers that support range (latest Chrome, Safari, Firefox, Edge) treat `input[range]` * in a way that never allows the input to hold an invalid value. That means: * - any non-numerical value is set to `(max + min) / 2`. * - any numerical value that is less than the current min val, or greater than the current max val * is set to the min / max val respectively. * - additionally, the current `step` is respected, so the nearest value that satisfies a step * is used. * * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range)) * for more info. * * This has the following consequences for Angular: * * Since the element value should always reflect the current model value, a range input * will set the bound ngModel expression to the value that the browser has set for the * input element. For example, in the following input ``, * if the application sets `model.value = null`, the browser will set the input to `'50'`. * Angular will then set the model to `50`, to prevent input and model value being out of sync. * * That means the model for range will immediately be set to `50` after `ngModel` has been * initialized. It also means a range input can never have the required error. * * This does not only affect changes to the model value, but also to the values of the `min`, * `max`, and `step` attributes. When these change in a way that will cause the browser to modify * the input value, Angular will also update the model value. * * Automatic value adjustment also means that a range input element can never have the `required`, * `min`, or `max` errors. * * However, `step` is currently only fully implemented by Firefox. Other browsers have problems * when the step value changes dynamically - they do not adjust the element value correctly, but * instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step` * error on the input, and set the model to `undefined`. * * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do * not set the `min` and `max` attributes, which means that the browser won't automatically adjust * the input value based on their values, and will always assume min = 0, max = 100, and step = 1. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation to ensure that the value entered is greater * than `min`. Can be interpolated. * @param {string=} max Sets the `max` validation to ensure that the value entered is less than `max`. * Can be interpolated. * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step` * Can be interpolated. * @param {string=} ngChange Angular expression to be executed when the ngModel value changes due * to user interaction with the input element. * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the * element. **Note** : `ngChecked` should not be used alongside `ngModel`. * Checkout {@link ng.directive:ngChecked ngChecked} for usage. * * @example
Model as range:
Model as number:
Min:
Max:
value = {{value}}
myForm.range.$valid = {{myForm.range.$valid}}
myForm.range.$error = {{myForm.range.$error}}
* ## Range Input with ngMin & ngMax attributes * @example
Model as range:
Model as number:
Min:
Max:
value = {{value}}
myForm.range.$valid = {{myForm.range.$valid}}
myForm.range.$error = {{myForm.range.$error}}
*/ 'range': rangeInputType, /** * @ngdoc input * @name input[checkbox] * * @description * HTML checkbox. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {expression=} ngTrueValue The value to which the expression should be set when selected. * @param {expression=} ngFalseValue The value to which the expression should be set when not selected. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * * @example


value1 = {{checkboxModel.value1}}
value2 = {{checkboxModel.value2}}
it('should change state', function() { var value1 = element(by.binding('checkboxModel.value1')); var value2 = element(by.binding('checkboxModel.value2')); expect(value1.getText()).toContain('true'); expect(value2.getText()).toContain('YES'); element(by.model('checkboxModel.value1')).click(); element(by.model('checkboxModel.value2')).click(); expect(value1.getText()).toContain('false'); expect(value2.getText()).toContain('NO'); });
*/ 'checkbox': checkboxInputType, 'hidden': noop, 'button': noop, 'submit': noop, 'reset': noop, 'file': noop }; function stringBasedInputType(ctrl) { ctrl.$formatters.push(function(value) { return ctrl.$isEmpty(value) ? value : value.toString(); }); } function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { baseInputType(scope, element, attr, ctrl, $sniffer, $browser); stringBasedInputType(ctrl); } function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { var type = lowercase(element[0].type); // In composition mode, users are still inputting intermediate text buffer, // hold the listener until composition is done. // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent if (!$sniffer.android) { var composing = false; element.on('compositionstart', function() { composing = true; }); element.on('compositionend', function() { composing = false; listener(); }); } var timeout; var listener = function(ev) { if (timeout) { $browser.defer.cancel(timeout); timeout = null; } if (composing) return; var value = element.val(), event = ev && ev.type; // By default we will trim the value // If the attribute ng-trim exists we will avoid trimming // If input type is 'password', the value is never trimmed if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) { value = trim(value); } // If a control is suffering from bad input (due to native validators), browsers discard its // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the // control's value is the same empty value twice in a row. if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) { ctrl.$setViewValue(value, event); } }; // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the // input event on backspace, delete or cut if ($sniffer.hasEvent('input')) { element.on('input', listener); } else { var deferListener = function(ev, input, origValue) { if (!timeout) { timeout = $browser.defer(function() { timeout = null; if (!input || input.value !== origValue) { listener(ev); } }); } }; element.on('keydown', /** @this */ function(event) { var key = event.keyCode; // ignore // command modifiers arrows if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; deferListener(event, this, this.value); }); // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it if ($sniffer.hasEvent('paste')) { element.on('paste cut', deferListener); } } // if user paste into input using mouse on older browser // or form autocomplete on newer browser, we need "change" event to catch it element.on('change', listener); // Some native input types (date-family) have the ability to change validity without // firing any input/change events. // For these event types, when native validators are present and the browser supports the type, // check for validity changes on various DOM events. if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) { element.on(PARTIAL_VALIDATION_EVENTS, /** @this */ function(ev) { if (!timeout) { var validity = this[VALIDITY_STATE_PROPERTY]; var origBadInput = validity.badInput; var origTypeMismatch = validity.typeMismatch; timeout = $browser.defer(function() { timeout = null; if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) { listener(ev); } }); } }); } ctrl.$render = function() { // Workaround for Firefox validation #12102. var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue; if (element.val() !== value) { element.val(value); } }; } function weekParser(isoWeek, existingDate) { if (isDate(isoWeek)) { return isoWeek; } if (isString(isoWeek)) { WEEK_REGEXP.lastIndex = 0; var parts = WEEK_REGEXP.exec(isoWeek); if (parts) { var year = +parts[1], week = +parts[2], hours = 0, minutes = 0, seconds = 0, milliseconds = 0, firstThurs = getFirstThursdayOfYear(year), addDays = (week - 1) * 7; if (existingDate) { hours = existingDate.getHours(); minutes = existingDate.getMinutes(); seconds = existingDate.getSeconds(); milliseconds = existingDate.getMilliseconds(); } return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds); } } return NaN; } function createDateParser(regexp, mapping) { return function(iso, date) { var parts, map; if (isDate(iso)) { return iso; } if (isString(iso)) { // When a date is JSON'ified to wraps itself inside of an extra // set of double quotes. This makes the date parsing code unable // to match the date string and parse it as a date. if (iso.charAt(0) === '"' && iso.charAt(iso.length - 1) === '"') { iso = iso.substring(1, iso.length - 1); } if (ISO_DATE_REGEXP.test(iso)) { return new Date(iso); } regexp.lastIndex = 0; parts = regexp.exec(iso); if (parts) { parts.shift(); if (date) { map = { yyyy: date.getFullYear(), MM: date.getMonth() + 1, dd: date.getDate(), HH: date.getHours(), mm: date.getMinutes(), ss: date.getSeconds(), sss: date.getMilliseconds() / 1000 }; } else { map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 }; } forEach(parts, function(part, index) { if (index < mapping.length) { map[mapping[index]] = +part; } }); return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0); } } return NaN; }; } function createDateInputType(type, regexp, parseDate, format) { return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) { badInputChecker(scope, element, attr, ctrl); baseInputType(scope, element, attr, ctrl, $sniffer, $browser); var timezone = ctrl && ctrl.$options.getOption('timezone'); var previousDate; ctrl.$$parserName = type; ctrl.$parsers.push(function(value) { if (ctrl.$isEmpty(value)) return null; if (regexp.test(value)) { // Note: We cannot read ctrl.$modelValue, as there might be a different // parser/formatter in the processing chain so that the model // contains some different data format! var parsedDate = parseDate(value, previousDate); if (timezone) { parsedDate = convertTimezoneToLocal(parsedDate, timezone); } return parsedDate; } return undefined; }); ctrl.$formatters.push(function(value) { if (value && !isDate(value)) { throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value); } if (isValidDate(value)) { previousDate = value; if (previousDate && timezone) { previousDate = convertTimezoneToLocal(previousDate, timezone, true); } return $filter('date')(value, format, timezone); } else { previousDate = null; return ''; } }); if (isDefined(attr.min) || attr.ngMin) { var minVal; ctrl.$validators.min = function(value) { return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal; }; attr.$observe('min', function(val) { minVal = parseObservedDateValue(val); ctrl.$validate(); }); } if (isDefined(attr.max) || attr.ngMax) { var maxVal; ctrl.$validators.max = function(value) { return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal; }; attr.$observe('max', function(val) { maxVal = parseObservedDateValue(val); ctrl.$validate(); }); } function isValidDate(value) { // Invalid Date: getTime() returns NaN return value && !(value.getTime && value.getTime() !== value.getTime()); } function parseObservedDateValue(val) { return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val; } }; } function badInputChecker(scope, element, attr, ctrl) { var node = element[0]; var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity); if (nativeValidation) { ctrl.$parsers.push(function(value) { var validity = element.prop(VALIDITY_STATE_PROPERTY) || {}; return validity.badInput || validity.typeMismatch ? undefined : value; }); } } function numberFormatterParser(ctrl) { ctrl.$$parserName = 'number'; ctrl.$parsers.push(function(value) { if (ctrl.$isEmpty(value)) return null; if (NUMBER_REGEXP.test(value)) return parseFloat(value); return undefined; }); ctrl.$formatters.push(function(value) { if (!ctrl.$isEmpty(value)) { if (!isNumber(value)) { throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value); } value = value.toString(); } return value; }); } function parseNumberAttrVal(val) { if (isDefined(val) && !isNumber(val)) { val = parseFloat(val); } return !isNumberNaN(val) ? val : undefined; } function isNumberInteger(num) { // See http://stackoverflow.com/questions/14636536/how-to-check-if-a-variable-is-an-integer-in-javascript#14794066 // (minus the assumption that `num` is a number) // eslint-disable-next-line no-bitwise return (num | 0) === num; } function countDecimals(num) { var numString = num.toString(); var decimalSymbolIndex = numString.indexOf('.'); if (decimalSymbolIndex === -1) { if (-1 < num && num < 1) { // It may be in the exponential notation format (`1e-X`) var match = /e-(\d+)$/.exec(numString); if (match) { return Number(match[1]); } } return 0; } return numString.length - decimalSymbolIndex - 1; } function isValidForStep(viewValue, stepBase, step) { // At this point `stepBase` and `step` are expected to be non-NaN values // and `viewValue` is expected to be a valid stringified number. var value = Number(viewValue); var isNonIntegerValue = !isNumberInteger(value); var isNonIntegerStepBase = !isNumberInteger(stepBase); var isNonIntegerStep = !isNumberInteger(step); // Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or // `0.5 % 0.1 !== 0`), we need to convert all numbers to integers. if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) { var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0; var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0; var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0; var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals); var multiplier = Math.pow(10, decimalCount); value = value * multiplier; stepBase = stepBase * multiplier; step = step * multiplier; if (isNonIntegerValue) value = Math.round(value); if (isNonIntegerStepBase) stepBase = Math.round(stepBase); if (isNonIntegerStep) step = Math.round(step); } return (value - stepBase) % step === 0; } function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { badInputChecker(scope, element, attr, ctrl); numberFormatterParser(ctrl); baseInputType(scope, element, attr, ctrl, $sniffer, $browser); var minVal; var maxVal; if (isDefined(attr.min) || attr.ngMin) { ctrl.$validators.min = function(value) { return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal; }; attr.$observe('min', function(val) { minVal = parseNumberAttrVal(val); // TODO(matsko): implement validateLater to reduce number of validations ctrl.$validate(); }); } if (isDefined(attr.max) || attr.ngMax) { ctrl.$validators.max = function(value) { return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal; }; attr.$observe('max', function(val) { maxVal = parseNumberAttrVal(val); // TODO(matsko): implement validateLater to reduce number of validations ctrl.$validate(); }); } if (isDefined(attr.step) || attr.ngStep) { var stepVal; ctrl.$validators.step = function(modelValue, viewValue) { return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) || isValidForStep(viewValue, minVal || 0, stepVal); }; attr.$observe('step', function(val) { stepVal = parseNumberAttrVal(val); // TODO(matsko): implement validateLater to reduce number of validations ctrl.$validate(); }); } } function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) { badInputChecker(scope, element, attr, ctrl); numberFormatterParser(ctrl); baseInputType(scope, element, attr, ctrl, $sniffer, $browser); var supportsRange = ctrl.$$hasNativeValidators && element[0].type === 'range', minVal = supportsRange ? 0 : undefined, maxVal = supportsRange ? 100 : undefined, stepVal = supportsRange ? 1 : undefined, validity = element[0].validity, hasMinAttr = isDefined(attr.min), hasMaxAttr = isDefined(attr.max), hasStepAttr = isDefined(attr.step); var originalRender = ctrl.$render; ctrl.$render = supportsRange && isDefined(validity.rangeUnderflow) && isDefined(validity.rangeOverflow) ? //Browsers that implement range will set these values automatically, but reading the adjusted values after //$render would cause the min / max validators to be applied with the wrong value function rangeRender() { originalRender(); ctrl.$setViewValue(element.val()); } : originalRender; if (hasMinAttr) { ctrl.$validators.min = supportsRange ? // Since all browsers set the input to a valid value, we don't need to check validity function noopMinValidator() { return true; } : // non-support browsers validate the min val function minValidator(modelValue, viewValue) { return ctrl.$isEmpty(viewValue) || isUndefined(minVal) || viewValue >= minVal; }; setInitialValueAndObserver('min', minChange); } if (hasMaxAttr) { ctrl.$validators.max = supportsRange ? // Since all browsers set the input to a valid value, we don't need to check validity function noopMaxValidator() { return true; } : // non-support browsers validate the max val function maxValidator(modelValue, viewValue) { return ctrl.$isEmpty(viewValue) || isUndefined(maxVal) || viewValue <= maxVal; }; setInitialValueAndObserver('max', maxChange); } if (hasStepAttr) { ctrl.$validators.step = supportsRange ? function nativeStepValidator() { // Currently, only FF implements the spec on step change correctly (i.e. adjusting the // input element value to a valid value). It's possible that other browsers set the stepMismatch // validity error instead, so we can at least report an error in that case. return !validity.stepMismatch; } : // ngStep doesn't set the setp attr, so the browser doesn't adjust the input value as setting step would function stepValidator(modelValue, viewValue) { return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) || isValidForStep(viewValue, minVal || 0, stepVal); }; setInitialValueAndObserver('step', stepChange); } function setInitialValueAndObserver(htmlAttrName, changeFn) { // interpolated attributes set the attribute value only after a digest, but we need the // attribute value when the input is first rendered, so that the browser can adjust the // input value based on the min/max value element.attr(htmlAttrName, attr[htmlAttrName]); attr.$observe(htmlAttrName, changeFn); } function minChange(val) { minVal = parseNumberAttrVal(val); // ignore changes before model is initialized if (isNumberNaN(ctrl.$modelValue)) { return; } if (supportsRange) { var elVal = element.val(); // IE11 doesn't set the el val correctly if the minVal is greater than the element value if (minVal > elVal) { elVal = minVal; element.val(elVal); } ctrl.$setViewValue(elVal); } else { // TODO(matsko): implement validateLater to reduce number of validations ctrl.$validate(); } } function maxChange(val) { maxVal = parseNumberAttrVal(val); // ignore changes before model is initialized if (isNumberNaN(ctrl.$modelValue)) { return; } if (supportsRange) { var elVal = element.val(); // IE11 doesn't set the el val correctly if the maxVal is less than the element value if (maxVal < elVal) { element.val(maxVal); // IE11 and Chrome don't set the value to the minVal when max < min elVal = maxVal < minVal ? minVal : maxVal; } ctrl.$setViewValue(elVal); } else { // TODO(matsko): implement validateLater to reduce number of validations ctrl.$validate(); } } function stepChange(val) { stepVal = parseNumberAttrVal(val); // ignore changes before model is initialized if (isNumberNaN(ctrl.$modelValue)) { return; } // Some browsers don't adjust the input value correctly, but set the stepMismatch error if (supportsRange && ctrl.$viewValue !== element.val()) { ctrl.$setViewValue(element.val()); } else { // TODO(matsko): implement validateLater to reduce number of validations ctrl.$validate(); } } } function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) { // Note: no badInputChecker here by purpose as `url` is only a validation // in browsers, i.e. we can always read out input.value even if it is not valid! baseInputType(scope, element, attr, ctrl, $sniffer, $browser); stringBasedInputType(ctrl); ctrl.$$parserName = 'url'; ctrl.$validators.url = function(modelValue, viewValue) { var value = modelValue || viewValue; return ctrl.$isEmpty(value) || URL_REGEXP.test(value); }; } function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) { // Note: no badInputChecker here by purpose as `url` is only a validation // in browsers, i.e. we can always read out input.value even if it is not valid! baseInputType(scope, element, attr, ctrl, $sniffer, $browser); stringBasedInputType(ctrl); ctrl.$$parserName = 'email'; ctrl.$validators.email = function(modelValue, viewValue) { var value = modelValue || viewValue; return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value); }; } function radioInputType(scope, element, attr, ctrl) { var doTrim = !attr.ngTrim || trim(attr.ngTrim) !== 'false'; // make the name unique, if not defined if (isUndefined(attr.name)) { element.attr('name', nextUid()); } var listener = function(ev) { var value; if (element[0].checked) { value = attr.value; if (doTrim) { value = trim(value); } ctrl.$setViewValue(value, ev && ev.type); } }; element.on('click', listener); ctrl.$render = function() { var value = attr.value; if (doTrim) { value = trim(value); } element[0].checked = (value === ctrl.$viewValue); }; attr.$observe('value', ctrl.$render); } function parseConstantExpr($parse, context, name, expression, fallback) { var parseFn; if (isDefined(expression)) { parseFn = $parse(expression); if (!parseFn.constant) { throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' + '`{1}`.', name, expression); } return parseFn(context); } return fallback; } function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) { var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true); var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false); var listener = function(ev) { ctrl.$setViewValue(element[0].checked, ev && ev.type); }; element.on('click', listener); ctrl.$render = function() { element[0].checked = ctrl.$viewValue; }; // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false` // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert // it to a boolean. ctrl.$isEmpty = function(value) { return value === false; }; ctrl.$formatters.push(function(value) { return equals(value, trueValue); }); ctrl.$parsers.push(function(value) { return value ? trueValue : falseValue; }); } /** * @ngdoc directive * @name textarea * @restrict E * * @description * HTML textarea element control with angular data-binding. The data-binding and validation * properties of this element are exactly the same as those of the * {@link ng.directive:input input element}. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than * minlength. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any * length. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} * does not match a RegExp found by evaluating the Angular expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to * `new RegExp('^abc$')`.
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. * @param {string=} ngChange Angular expression to be executed when input changes due to user * interaction with the input element. * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. * * @knownIssue * * When specifying the `placeholder` attribute of ` *
{{ list | json }}
* * * it("should split the text by newlines", function() { * var listInput = element(by.model('list')); * var output = element(by.binding('list | json')); * listInput.sendKeys('abc\ndef\nghi'); * expect(output.getText()).toContain('[\n "abc",\n "def",\n "ghi"\n]'); * }); * * * * @element input * @param {string=} ngList optional delimiter that should be used to split the value. */ var ngListDirective = function() { return { restrict: 'A', priority: 100, require: 'ngModel', link: function(scope, element, attr, ctrl) { var ngList = attr.ngList || ', '; var trimValues = attr.ngTrim !== 'false'; var separator = trimValues ? trim(ngList) : ngList; var parse = function(viewValue) { // If the viewValue is invalid (say required but empty) it will be `undefined` if (isUndefined(viewValue)) return; var list = []; if (viewValue) { forEach(viewValue.split(separator), function(value) { if (value) list.push(trimValues ? trim(value) : value); }); } return list; }; ctrl.$parsers.push(parse); ctrl.$formatters.push(function(value) { if (isArray(value)) { return value.join(ngList); } return undefined; }); // Override the standard $isEmpty because an empty array means the input is empty. ctrl.$isEmpty = function(value) { return !value || !value.length; }; } }; }; /* global VALID_CLASS: true, INVALID_CLASS: true, PRISTINE_CLASS: true, DIRTY_CLASS: true, UNTOUCHED_CLASS: true, TOUCHED_CLASS: true, PENDING_CLASS: true, addSetValidityMethod: true, setupValidity: true, defaultModelOptions: false */ var VALID_CLASS = 'ng-valid', INVALID_CLASS = 'ng-invalid', PRISTINE_CLASS = 'ng-pristine', DIRTY_CLASS = 'ng-dirty', UNTOUCHED_CLASS = 'ng-untouched', TOUCHED_CLASS = 'ng-touched', EMPTY_CLASS = 'ng-empty', NOT_EMPTY_CLASS = 'ng-not-empty'; var ngModelMinErr = minErr('ngModel'); /** * @ngdoc type * @name ngModel.NgModelController * * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue * is set. * * @property {*} $modelValue The value in the model that the control is bound to. * * @property {Array.} $parsers Array of functions to execute, as a pipeline, whenever * the control updates the ngModelController with a new {@link ngModel.NgModelController#$viewValue `$viewValue`} from the DOM, usually via user input. See {@link ngModel.NgModelController#$setViewValue `$setViewValue()`} for a detailed lifecycle explanation. Note that the `$parsers` are not called when the bound ngModel expression changes programmatically. The functions are called in array order, each passing its return value through to the next. The last return value is forwarded to the {@link ngModel.NgModelController#$validators `$validators`} collection. Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue `$viewValue`}. Returning `undefined` from a parser means a parse error occurred. In that case, no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel` will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is set to `true`. The parse error is stored in `ngModel.$error.parse`. This simple example shows a parser that would convert text input value to lowercase: * ```js * function parse(value) { * if (value) { * return value.toLowerCase(); * } * } * ngModelController.$parsers.push(parse); * ``` * * @property {Array.} $formatters Array of functions to execute, as a pipeline, whenever the bound ngModel expression changes programmatically. The `$formatters` are not called when the value of the control is changed by user interaction. Formatters are used to format / convert the {@link ngModel.NgModelController#$modelValue `$modelValue`} for display in the control. The functions are called in reverse array order, each passing the value through to the next. The last return value is used as the actual DOM value. This simple example shows a formatter that would convert the model value to uppercase: * ```js * function format(value) { * if (value) { * return value.toUpperCase(); * } * } * ngModel.$formatters.push(format); * ``` * * @property {Object.} $validators A collection of validators that are applied * whenever the model value changes. The key value within the object refers to the name of the * validator while the function refers to the validation operation. The validation operation is * provided with the model value as an argument and must return a true or false value depending * on the response of that validation. * * ```js * ngModel.$validators.validCharacters = function(modelValue, viewValue) { * var value = modelValue || viewValue; * return /[0-9]+/.test(value) && * /[a-z]+/.test(value) && * /[A-Z]+/.test(value) && * /\W+/.test(value); * }; * ``` * * @property {Object.} $asyncValidators A collection of validations that are expected to * perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided * is expected to return a promise when it is run during the model validation process. Once the promise * is delivered then the validation status will be set to true when fulfilled and false when rejected. * When the asynchronous validators are triggered, each of the validators will run in parallel and the model * value will only be updated once all validators have been fulfilled. As long as an asynchronous validator * is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators * will only run once all synchronous validators have passed. * * Please note that if $http is used then it is important that the server returns a success HTTP response code * in order to fulfill the validation and a status level of `4xx` in order to reject the validation. * * ```js * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) { * var value = modelValue || viewValue; * * // Lookup user by username * return $http.get('/api/users/' + value). * then(function resolved() { * //username exists, this means validation fails * return $q.reject('exists'); * }, function rejected() { * //username does not exist, therefore this validation passes * return true; * }); * }; * ``` * * @property {Array.} $viewChangeListeners Array of functions to execute whenever the * view value has changed. It is called with no arguments, and its return value is ignored. * This can be used in place of additional $watches against the model value. * * @property {Object} $error An object hash with all failing validator ids as keys. * @property {Object} $pending An object hash with all pending validator ids as keys. * * @property {boolean} $untouched True if control has not lost focus yet. * @property {boolean} $touched True if control has lost focus. * @property {boolean} $pristine True if user has not interacted with the control yet. * @property {boolean} $dirty True if user has already interacted with the control. * @property {boolean} $valid True if there is no error. * @property {boolean} $invalid True if at least one error on the control. * @property {string} $name The name attribute of the control. * * @description * * `NgModelController` provides API for the {@link ngModel `ngModel`} directive. * The controller contains services for data-binding, validation, CSS updates, and value formatting * and parsing. It purposefully does not contain any logic which deals with DOM rendering or * listening to DOM events. * Such DOM related logic should be provided by other directives which make use of * `NgModelController` for data-binding to control elements. * Angular provides this DOM logic for most {@link input `input`} elements. * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example * custom control example} that uses `ngModelController` to bind to `contenteditable` elements. * * @example * ### Custom Control Example * This example shows how to use `NgModelController` with a custom control to achieve * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`) * collaborate together to achieve the desired result. * * `contenteditable` is an HTML5 attribute, which tells the browser to let the element * contents be edited in place by the user. * * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize} * module to automatically remove "bad" content like inline event listener (e.g. ``). * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks * that content using the `$sce` service. * * [contenteditable] { border: 1px solid black; background-color: white; min-height: 20px; } .ng-invalid { border: 1px solid red; } angular.module('customControl', ['ngSanitize']). directive('contenteditable', ['$sce', function($sce) { return { restrict: 'A', // only activate on element attribute require: '?ngModel', // get a hold of NgModelController link: function(scope, element, attrs, ngModel) { if (!ngModel) return; // do nothing if no ng-model // Specify how UI should be updated ngModel.$render = function() { element.html($sce.getTrustedHtml(ngModel.$viewValue || '')); }; // Listen for change events to enable binding element.on('blur keyup change', function() { scope.$evalAsync(read); }); read(); // initialize // Write data to the model function read() { var html = element.html(); // When we clear the content editable the browser leaves a
behind // If strip-br attribute is provided then we strip this out if (attrs.stripBr && html === '
') { html = ''; } ngModel.$setViewValue(html); } } }; }]);
Change me!
Required!
it('should data-bind and become invalid', function() { if (browser.params.browser === 'safari' || browser.params.browser === 'firefox') { // SafariDriver can't handle contenteditable // and Firefox driver can't clear contenteditables very well return; } var contentEditable = element(by.css('[contenteditable]')); var content = 'Change me!'; expect(contentEditable.getText()).toEqual(content); contentEditable.clear(); contentEditable.sendKeys(protractor.Key.BACK_SPACE); expect(contentEditable.getText()).toEqual(''); expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/); }); *
* * */ NgModelController.$inject = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$q', '$interpolate']; function NgModelController($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $q, $interpolate) { this.$viewValue = Number.NaN; this.$modelValue = Number.NaN; this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity. this.$validators = {}; this.$asyncValidators = {}; this.$parsers = []; this.$formatters = []; this.$viewChangeListeners = []; this.$untouched = true; this.$touched = false; this.$pristine = true; this.$dirty = false; this.$valid = true; this.$invalid = false; this.$error = {}; // keep invalid keys here this.$$success = {}; // keep valid keys here this.$pending = undefined; // keep pending keys here this.$name = $interpolate($attr.name || '', false)($scope); this.$$parentForm = nullFormCtrl; this.$options = defaultModelOptions; this.$$parsedNgModel = $parse($attr.ngModel); this.$$parsedNgModelAssign = this.$$parsedNgModel.assign; this.$$ngModelGet = this.$$parsedNgModel; this.$$ngModelSet = this.$$parsedNgModelAssign; this.$$pendingDebounce = null; this.$$parserValid = undefined; this.$$currentValidationRunId = 0; // https://github.com/angular/angular.js/issues/15833 // Prevent `$$scope` from being iterated over by `copy` when NgModelController is deep watched Object.defineProperty(this, '$$scope', {value: $scope}); this.$$attr = $attr; this.$$element = $element; this.$$animate = $animate; this.$$timeout = $timeout; this.$$parse = $parse; this.$$q = $q; this.$$exceptionHandler = $exceptionHandler; setupValidity(this); setupModelWatcher(this); } NgModelController.prototype = { $$initGetterSetters: function() { if (this.$options.getOption('getterSetter')) { var invokeModelGetter = this.$$parse(this.$$attr.ngModel + '()'), invokeModelSetter = this.$$parse(this.$$attr.ngModel + '($$$p)'); this.$$ngModelGet = function($scope) { var modelValue = this.$$parsedNgModel($scope); if (isFunction(modelValue)) { modelValue = invokeModelGetter($scope); } return modelValue; }; this.$$ngModelSet = function($scope, newValue) { if (isFunction(this.$$parsedNgModel($scope))) { invokeModelSetter($scope, {$$$p: newValue}); } else { this.$$parsedNgModelAssign($scope, newValue); } }; } else if (!this.$$parsedNgModel.assign) { throw ngModelMinErr('nonassign', 'Expression \'{0}\' is non-assignable. Element: {1}', this.$$attr.ngModel, startingTag(this.$$element)); } }, /** * @ngdoc method * @name ngModel.NgModelController#$render * * @description * Called when the view needs to be updated. It is expected that the user of the ng-model * directive will implement this method. * * The `$render()` method is invoked in the following situations: * * * `$rollbackViewValue()` is called. If we are rolling back the view value to the last * committed value then `$render()` is called to update the input control. * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and * the `$viewValue` are different from last time. * * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue` * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be * invoked if you only change a property on the objects. */ $render: noop, /** * @ngdoc method * @name ngModel.NgModelController#$isEmpty * * @description * This is called when we need to determine if the value of an input is empty. * * For instance, the required directive does this to work out if the input has data or not. * * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`. * * You can override this for input directives whose concept of being empty is different from the * default. The `checkboxInputType` directive does this because in its case a value of `false` * implies empty. * * @param {*} value The value of the input to check for emptiness. * @returns {boolean} True if `value` is "empty". */ $isEmpty: function(value) { // eslint-disable-next-line no-self-compare return isUndefined(value) || value === '' || value === null || value !== value; }, $$updateEmptyClasses: function(value) { if (this.$isEmpty(value)) { this.$$animate.removeClass(this.$$element, NOT_EMPTY_CLASS); this.$$animate.addClass(this.$$element, EMPTY_CLASS); } else { this.$$animate.removeClass(this.$$element, EMPTY_CLASS); this.$$animate.addClass(this.$$element, NOT_EMPTY_CLASS); } }, /** * @ngdoc method * @name ngModel.NgModelController#$setPristine * * @description * Sets the control to its pristine state. * * This method can be called to remove the `ng-dirty` class and set the control to its pristine * state (`ng-pristine` class). A model is considered to be pristine when the control * has not been changed from when first compiled. */ $setPristine: function() { this.$dirty = false; this.$pristine = true; this.$$animate.removeClass(this.$$element, DIRTY_CLASS); this.$$animate.addClass(this.$$element, PRISTINE_CLASS); }, /** * @ngdoc method * @name ngModel.NgModelController#$setDirty * * @description * Sets the control to its dirty state. * * This method can be called to remove the `ng-pristine` class and set the control to its dirty * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed * from when first compiled. */ $setDirty: function() { this.$dirty = true; this.$pristine = false; this.$$animate.removeClass(this.$$element, PRISTINE_CLASS); this.$$animate.addClass(this.$$element, DIRTY_CLASS); this.$$parentForm.$setDirty(); }, /** * @ngdoc method * @name ngModel.NgModelController#$setUntouched * * @description * Sets the control to its untouched state. * * This method can be called to remove the `ng-touched` class and set the control to its * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched * by default, however this function can be used to restore that state if the model has * already been touched by the user. */ $setUntouched: function() { this.$touched = false; this.$untouched = true; this.$$animate.setClass(this.$$element, UNTOUCHED_CLASS, TOUCHED_CLASS); }, /** * @ngdoc method * @name ngModel.NgModelController#$setTouched * * @description * Sets the control to its touched state. * * This method can be called to remove the `ng-untouched` class and set the control to its * touched state (`ng-touched` class). A model is considered to be touched when the user has * first focused the control element and then shifted focus away from the control (blur event). */ $setTouched: function() { this.$touched = true; this.$untouched = false; this.$$animate.setClass(this.$$element, TOUCHED_CLASS, UNTOUCHED_CLASS); }, /** * @ngdoc method * @name ngModel.NgModelController#$rollbackViewValue * * @description * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`, * which may be caused by a pending debounced event or because the input is waiting for some * future event. * * If you have an input that uses `ng-model-options` to set up debounced updates or updates that * depend on special events such as `blur`, there can be a period when the `$viewValue` is out of * sync with the ngModel's `$modelValue`. * * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update * and reset the input to the last committed view value. * * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue` * programmatically before these debounced/future events have resolved/occurred, because Angular's * dirty checking mechanism is not able to tell whether the model has actually changed or not. * * The `$rollbackViewValue()` method should be called before programmatically changing the model of an * input which may have such events pending. This is important in order to make sure that the * input field will be updated with the new model value and any pending operations are cancelled. * * * * angular.module('cancel-update-example', []) * * .controller('CancelUpdateController', ['$scope', function($scope) { * $scope.model = {value1: '', value2: ''}; * * $scope.setEmpty = function(e, value, rollback) { * if (e.keyCode === 27) { * e.preventDefault(); * if (rollback) { * $scope.myForm[value].$rollbackViewValue(); * } * $scope.model[value] = ''; * } * }; * }]); * * *
*

Both of these inputs are only updated if they are blurred. Hitting escape should * empty them. Follow these steps and observe the difference:

*
    *
  1. Type something in the input. You will see that the model is not yet updated
  2. *
  3. Press the Escape key. *
      *
    1. In the first example, nothing happens, because the model is already '', and no * update is detected. If you blur the input, the model will be set to the current view. *
    2. *
    3. In the second example, the pending update is cancelled, and the input is set back * to the last committed view value (''). Blurring the input does nothing. *
    4. *
    *
  4. *
* *
*
*

Without $rollbackViewValue():

* * value1: "{{ model.value1 }}" *
* *
*

With $rollbackViewValue():

* * value2: "{{ model.value2 }}" *
*
*
*
div { display: table-cell; } div:nth-child(1) { padding-right: 30px; } *
*/ $rollbackViewValue: function() { this.$$timeout.cancel(this.$$pendingDebounce); this.$viewValue = this.$$lastCommittedViewValue; this.$render(); }, /** * @ngdoc method * @name ngModel.NgModelController#$validate * * @description * Runs each of the registered validators (first synchronous validators and then * asynchronous validators). * If the validity changes to invalid, the model will be set to `undefined`, * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`. * If the validity changes to valid, it will set the model to the last available valid * `$modelValue`, i.e. either the last parsed value or the last value set from the scope. */ $validate: function() { // ignore $validate before model is initialized if (isNumberNaN(this.$modelValue)) { return; } var viewValue = this.$$lastCommittedViewValue; // Note: we use the $$rawModelValue as $modelValue might have been // set to undefined during a view -> model update that found validation // errors. We can't parse the view here, since that could change // the model although neither viewValue nor the model on the scope changed var modelValue = this.$$rawModelValue; var prevValid = this.$valid; var prevModelValue = this.$modelValue; var allowInvalid = this.$options.getOption('allowInvalid'); var that = this; this.$$runValidators(modelValue, viewValue, function(allValid) { // If there was no change in validity, don't update the model // This prevents changing an invalid modelValue to undefined if (!allowInvalid && prevValid !== allValid) { // Note: Don't check this.$valid here, as we could have // external validators (e.g. calculated on the server), // that just call $setValidity and need the model value // to calculate their validity. that.$modelValue = allValid ? modelValue : undefined; if (that.$modelValue !== prevModelValue) { that.$$writeModelToScope(); } } }); }, $$runValidators: function(modelValue, viewValue, doneCallback) { this.$$currentValidationRunId++; var localValidationRunId = this.$$currentValidationRunId; var that = this; // check parser error if (!processParseErrors()) { validationDone(false); return; } if (!processSyncValidators()) { validationDone(false); return; } processAsyncValidators(); function processParseErrors() { var errorKey = that.$$parserName || 'parse'; if (isUndefined(that.$$parserValid)) { setValidity(errorKey, null); } else { if (!that.$$parserValid) { forEach(that.$validators, function(v, name) { setValidity(name, null); }); forEach(that.$asyncValidators, function(v, name) { setValidity(name, null); }); } // Set the parse error last, to prevent unsetting it, should a $validators key == parserName setValidity(errorKey, that.$$parserValid); return that.$$parserValid; } return true; } function processSyncValidators() { var syncValidatorsValid = true; forEach(that.$validators, function(validator, name) { var result = Boolean(validator(modelValue, viewValue)); syncValidatorsValid = syncValidatorsValid && result; setValidity(name, result); }); if (!syncValidatorsValid) { forEach(that.$asyncValidators, function(v, name) { setValidity(name, null); }); return false; } return true; } function processAsyncValidators() { var validatorPromises = []; var allValid = true; forEach(that.$asyncValidators, function(validator, name) { var promise = validator(modelValue, viewValue); if (!isPromiseLike(promise)) { throw ngModelMinErr('nopromise', 'Expected asynchronous validator to return a promise but got \'{0}\' instead.', promise); } setValidity(name, undefined); validatorPromises.push(promise.then(function() { setValidity(name, true); }, function() { allValid = false; setValidity(name, false); })); }); if (!validatorPromises.length) { validationDone(true); } else { that.$$q.all(validatorPromises).then(function() { validationDone(allValid); }, noop); } } function setValidity(name, isValid) { if (localValidationRunId === that.$$currentValidationRunId) { that.$setValidity(name, isValid); } } function validationDone(allValid) { if (localValidationRunId === that.$$currentValidationRunId) { doneCallback(allValid); } } }, /** * @ngdoc method * @name ngModel.NgModelController#$commitViewValue * * @description * Commit a pending update to the `$modelValue`. * * Updates may be pending by a debounced event or because the input is waiting for a some future * event defined in `ng-model-options`. this method is rarely needed as `NgModelController` * usually handles calling this in response to input events. */ $commitViewValue: function() { var viewValue = this.$viewValue; this.$$timeout.cancel(this.$$pendingDebounce); // If the view value has not changed then we should just exit, except in the case where there is // a native validator on the element. In this case the validation state may have changed even though // the viewValue has stayed empty. if (this.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !this.$$hasNativeValidators)) { return; } this.$$updateEmptyClasses(viewValue); this.$$lastCommittedViewValue = viewValue; // change to dirty if (this.$pristine) { this.$setDirty(); } this.$$parseAndValidate(); }, $$parseAndValidate: function() { var viewValue = this.$$lastCommittedViewValue; var modelValue = viewValue; var that = this; this.$$parserValid = isUndefined(modelValue) ? undefined : true; if (this.$$parserValid) { for (var i = 0; i < this.$parsers.length; i++) { modelValue = this.$parsers[i](modelValue); if (isUndefined(modelValue)) { this.$$parserValid = false; break; } } } if (isNumberNaN(this.$modelValue)) { // this.$modelValue has not been touched yet... this.$modelValue = this.$$ngModelGet(this.$$scope); } var prevModelValue = this.$modelValue; var allowInvalid = this.$options.getOption('allowInvalid'); this.$$rawModelValue = modelValue; if (allowInvalid) { this.$modelValue = modelValue; writeToModelIfNeeded(); } // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date. // This can happen if e.g. $setViewValue is called from inside a parser this.$$runValidators(modelValue, this.$$lastCommittedViewValue, function(allValid) { if (!allowInvalid) { // Note: Don't check this.$valid here, as we could have // external validators (e.g. calculated on the server), // that just call $setValidity and need the model value // to calculate their validity. that.$modelValue = allValid ? modelValue : undefined; writeToModelIfNeeded(); } }); function writeToModelIfNeeded() { if (that.$modelValue !== prevModelValue) { that.$$writeModelToScope(); } } }, $$writeModelToScope: function() { this.$$ngModelSet(this.$$scope, this.$modelValue); forEach(this.$viewChangeListeners, function(listener) { try { listener(); } catch (e) { // eslint-disable-next-line no-invalid-this this.$$exceptionHandler(e); } }, this); }, /** * @ngdoc method * @name ngModel.NgModelController#$setViewValue * * @description * Update the view value. * * This method should be called when a control wants to change the view value; typically, * this is done from within a DOM event handler. For example, the {@link ng.directive:input input} * directive calls it when the value of the input changes and {@link ng.directive:select select} * calls it when an option is selected. * * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers` * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged * value is sent directly for processing through the `$parsers` pipeline. After this, the `$validators` and * `$asyncValidators` are called and the value is applied to `$modelValue`. * Finally, the value is set to the **expression** specified in the `ng-model` attribute and * all the registered change listeners, in the `$viewChangeListeners` list are called. * * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn` * and the `default` trigger is not listed, all those actions will remain pending until one of the * `updateOn` events is triggered on the DOM element. * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions} * directive is used with a custom debounce for this particular event. * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce` * is specified, once the timer runs out. * * When used with standard inputs, the view value will always be a string (which is in some cases * parsed into another type, such as a `Date` object for `input[date]`.) * However, custom controls might also pass objects to this method. In this case, we should make * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not * perform a deep watch of objects, it only looks for a change of identity. If you only change * the property of the object then ngModel will not realize that the object has changed and * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should * not change properties of the copy once it has been passed to `$setViewValue`. * Otherwise you may cause the model value on the scope to change incorrectly. * *
* In any case, the value passed to the method should always reflect the current value * of the control. For example, if you are calling `$setViewValue` for an input element, * you should pass the input DOM value. Otherwise, the control and the scope model become * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change * the control's DOM value in any way. If we want to change the control's DOM value * programmatically, we should update the `ngModel` scope expression. Its new value will be * picked up by the model controller, which will run it through the `$formatters`, `$render` it * to update the DOM, and finally call `$validate` on it. *
* * @param {*} value value from the view. * @param {string} trigger Event that triggered the update. */ $setViewValue: function(value, trigger) { this.$viewValue = value; if (this.$options.getOption('updateOnDefault')) { this.$$debounceViewValueCommit(trigger); } }, $$debounceViewValueCommit: function(trigger) { var debounceDelay = this.$options.getOption('debounce'); if (isNumber(debounceDelay[trigger])) { debounceDelay = debounceDelay[trigger]; } else if (isNumber(debounceDelay['default'])) { debounceDelay = debounceDelay['default']; } this.$$timeout.cancel(this.$$pendingDebounce); var that = this; if (debounceDelay > 0) { // this fails if debounceDelay is an object this.$$pendingDebounce = this.$$timeout(function() { that.$commitViewValue(); }, debounceDelay); } else if (this.$$scope.$root.$$phase) { this.$commitViewValue(); } else { this.$$scope.$apply(function() { that.$commitViewValue(); }); } }, /** * @ngdoc method * * @name ngModel.NgModelController#$overrideModelOptions * * @description * * Override the current model options settings programmatically. * * The previous `ModelOptions` value will not be modified. Instead, a * new `ModelOptions` object will inherit from the previous one overriding * or inheriting settings that are defined in the given parameter. * * See {@link ngModelOptions} for information about what options can be specified * and how model option inheritance works. * * @param {Object} options a hash of settings to override the previous options * */ $overrideModelOptions: function(options) { this.$options = this.$options.createChild(options); } }; function setupModelWatcher(ctrl) { // model -> value // Note: we cannot use a normal scope.$watch as we want to detect the following: // 1. scope value is 'a' // 2. user enters 'b' // 3. ng-change kicks in and reverts scope value to 'a' // -> scope value did not change since the last digest as // ng-change executes in apply phase // 4. view should be changed back to 'a' ctrl.$$scope.$watch(function ngModelWatch(scope) { var modelValue = ctrl.$$ngModelGet(scope); // if scope model value and ngModel value are out of sync // TODO(perf): why not move this to the action fn? if (modelValue !== ctrl.$modelValue && // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator // eslint-disable-next-line no-self-compare (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) ) { ctrl.$modelValue = ctrl.$$rawModelValue = modelValue; ctrl.$$parserValid = undefined; var formatters = ctrl.$formatters, idx = formatters.length; var viewValue = modelValue; while (idx--) { viewValue = formatters[idx](viewValue); } if (ctrl.$viewValue !== viewValue) { ctrl.$$updateEmptyClasses(viewValue); ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue; ctrl.$render(); // It is possible that model and view value have been updated during render ctrl.$$runValidators(ctrl.$modelValue, ctrl.$viewValue, noop); } } return modelValue; }); } /** * @ngdoc method * @name ngModel.NgModelController#$setValidity * * @description * Change the validity state, and notify the form. * * This method can be called within $parsers/$formatters or a custom validation implementation. * However, in most cases it should be sufficient to use the `ngModel.$validators` and * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically. * * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned * to either `$error[validationErrorKey]` or `$pending[validationErrorKey]` * (for unfulfilled `$asyncValidators`), so that it is available for data-binding. * The `validationErrorKey` should be in camelCase and will get converted into dash-case * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error` * classes and can be bound to as `{{ someForm.someControl.$error.myError }}`. * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined), * or skipped (null). Pending is used for unfulfilled `$asyncValidators`. * Skipped is used by Angular when validators do not run because of parse errors and * when `$asyncValidators` do not run because any of the `$validators` failed. */ addSetValidityMethod({ clazz: NgModelController, set: function(object, property) { object[property] = true; }, unset: function(object, property) { delete object[property]; } }); /** * @ngdoc directive * @name ngModel * * @element input * @priority 1 * * @description * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a * property on the scope using {@link ngModel.NgModelController NgModelController}, * which is created and exposed by this directive. * * `ngModel` is responsible for: * * - Binding the view into the model, which other directives such as `input`, `textarea` or `select` * require. * - Providing validation behavior (i.e. required, number, email, url). * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors). * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, * `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations. * - Registering the control with its parent {@link ng.directive:form form}. * * Note: `ngModel` will try to bind to the property given by evaluating the expression on the * current scope. If the property doesn't already exist on this scope, it will be created * implicitly and added to the scope. * * For best practices on using `ngModel`, see: * * - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes) * * For basic examples, how to use `ngModel`, see: * * - {@link ng.directive:input input} * - {@link input[text] text} * - {@link input[checkbox] checkbox} * - {@link input[radio] radio} * - {@link input[number] number} * - {@link input[email] email} * - {@link input[url] url} * - {@link input[date] date} * - {@link input[datetime-local] datetime-local} * - {@link input[time] time} * - {@link input[month] month} * - {@link input[week] week} * - {@link ng.directive:select select} * - {@link ng.directive:textarea textarea} * * # Complex Models (objects or collections) * * By default, `ngModel` watches the model by reference, not value. This is important to know when * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the * object or collection change, `ngModel` will not be notified and so the input will not be re-rendered. * * The model must be assigned an entirely new object or collection before a re-rendering will occur. * * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or * if the select is given the `multiple` attribute. * * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the * first level of the object (or only changing the properties of an item in the collection if it's an array) will still * not trigger a re-rendering of the model. * * # CSS classes * The following CSS classes are added and removed on the associated input/select/textarea element * depending on the validity of the model. * * - `ng-valid`: the model is valid * - `ng-invalid`: the model is invalid * - `ng-valid-[key]`: for each valid key added by `$setValidity` * - `ng-invalid-[key]`: for each invalid key added by `$setValidity` * - `ng-pristine`: the control hasn't been interacted with yet * - `ng-dirty`: the control has been interacted with * - `ng-touched`: the control has been blurred * - `ng-untouched`: the control hasn't been blurred * - `ng-pending`: any `$asyncValidators` are unfulfilled * - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined * by the {@link ngModel.NgModelController#$isEmpty} method * - `ng-not-empty`: the view contains a non-empty value * * Keep in mind that ngAnimate can detect each of these classes when added and removed. * * ## Animation Hooks * * Animations within models are triggered when any of the associated CSS classes are added and removed * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`, * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself. * The animations that are triggered within ngModel are similar to how they work in ngClass and * animations can be hooked into using CSS transitions, keyframes as well as JS animations. * * The following example shows a simple way to utilize CSS transitions to style an input element * that has been rendered as invalid after it has been validated: * *
 * //be sure to include ngAnimate as a module to hook into more
 * //advanced animations
 * .my-input {
 *   transition:0.5s linear all;
 *   background: white;
 * }
 * .my-input.ng-invalid {
 *   background: red;
 *   color:white;
 * }
 * 
* * @example *

Update input to see transitions when valid/invalid. Integer is a valid value.

*
* * ## Binding to a getter/setter * * Sometimes it's helpful to bind `ngModel` to a getter/setter function. A getter/setter is a * function that returns a representation of the model when called with zero arguments, and sets * the internal state of a model when called with an argument. It's sometimes useful to use this * for models that have an internal representation that's different from what the model exposes * to the view. * *
* **Best Practice:** It's best to keep getters fast because Angular is likely to call them more * frequently than other parts of your code. *
* * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to * a `
`, which will enable this behavior for all ``s within it. See * {@link ng.directive:ngModelOptions `ngModelOptions`} for more. * * The following example shows how to use `ngModel` with a getter/setter: * * @example *
user.name = 
angular.module('getterSetterExample', []) .controller('ExampleController', ['$scope', function($scope) { var _name = 'Brian'; $scope.user = { name: function(newName) { // Note that newName can be undefined for two reasons: // 1. Because it is called as a getter and thus called with no arguments // 2. Because the property should actually be set to undefined. This happens e.g. if the // input is invalid return arguments.length ? (_name = newName) : _name; } }; }]); *
*/ var ngModelDirective = ['$rootScope', function($rootScope) { return { restrict: 'A', require: ['ngModel', '^?form', '^?ngModelOptions'], controller: NgModelController, // Prelink needs to run before any input directive // so that we can set the NgModelOptions in NgModelController // before anyone else uses it. priority: 1, compile: function ngModelCompile(element) { // Setup initial state of the control element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS); return { pre: function ngModelPreLink(scope, element, attr, ctrls) { var modelCtrl = ctrls[0], formCtrl = ctrls[1] || modelCtrl.$$parentForm, optionsCtrl = ctrls[2]; if (optionsCtrl) { modelCtrl.$options = optionsCtrl.$options; } modelCtrl.$$initGetterSetters(); // notify others, especially parent forms formCtrl.$addControl(modelCtrl); attr.$observe('name', function(newValue) { if (modelCtrl.$name !== newValue) { modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue); } }); scope.$on('$destroy', function() { modelCtrl.$$parentForm.$removeControl(modelCtrl); }); }, post: function ngModelPostLink(scope, element, attr, ctrls) { var modelCtrl = ctrls[0]; if (modelCtrl.$options.getOption('updateOn')) { element.on(modelCtrl.$options.getOption('updateOn'), function(ev) { modelCtrl.$$debounceViewValueCommit(ev && ev.type); }); } function setTouched() { modelCtrl.$setTouched(); } element.on('blur', function() { if (modelCtrl.$touched) return; if ($rootScope.$$phase) { scope.$evalAsync(setTouched); } else { scope.$apply(setTouched); } }); } }; } }; }]; /* exported defaultModelOptions */ var defaultModelOptions; var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/; /** * @ngdoc type * @name ModelOptions * @description * A container for the options set by the {@link ngModelOptions} directive */ function ModelOptions(options) { this.$$options = options; } ModelOptions.prototype = { /** * @ngdoc method * @name ModelOptions#getOption * @param {string} name the name of the option to retrieve * @returns {*} the value of the option * @description * Returns the value of the given option */ getOption: function(name) { return this.$$options[name]; }, /** * @ngdoc method * @name ModelOptions#createChild * @param {Object} options a hash of options for the new child that will override the parent's options * @return {ModelOptions} a new `ModelOptions` object initialized with the given options. */ createChild: function(options) { var inheritAll = false; // make a shallow copy options = extend({}, options); // Inherit options from the parent if specified by the value `"$inherit"` forEach(options, /* @this */ function(option, key) { if (option === '$inherit') { if (key === '*') { inheritAll = true; } else { options[key] = this.$$options[key]; // `updateOn` is special so we must also inherit the `updateOnDefault` option if (key === 'updateOn') { options.updateOnDefault = this.$$options.updateOnDefault; } } } else { if (key === 'updateOn') { // If the `updateOn` property contains the `default` event then we have to remove // it from the event list and set the `updateOnDefault` flag. options.updateOnDefault = false; options[key] = trim(option.replace(DEFAULT_REGEXP, function() { options.updateOnDefault = true; return ' '; })); } } }, this); if (inheritAll) { // We have a property of the form: `"*": "$inherit"` delete options['*']; defaults(options, this.$$options); } // Finally add in any missing defaults defaults(options, defaultModelOptions.$$options); return new ModelOptions(options); } }; defaultModelOptions = new ModelOptions({ updateOn: '', updateOnDefault: true, debounce: 0, getterSetter: false, allowInvalid: false, timezone: null }); /** * @ngdoc directive * @name ngModelOptions * * @description * This directive allows you to modify the behaviour of {@link ngModel} directives within your * application. You can specify an `ngModelOptions` directive on any element. All {@link ngModel} * directives will use the options of their nearest `ngModelOptions` ancestor. * * The `ngModelOptions` settings are found by evaluating the value of the attribute directive as * an Angular expression. This expression should evaluate to an object, whose properties contain * the settings. For example: `
*
* *
*
* ``` * * the `input` element will have the following settings * * ```js * { allowInvalid: true, updateOn: 'default', debounce: 0 } * ``` * * Notice that the `debounce` setting was not inherited and used the default value instead. * * You can specify that all undefined settings are automatically inherited from an ancestor by * including a property with key of `"*"` and value of `"$inherit"`. * * For example given the following fragment of HTML * * * ```html *
*
* *
*
* ``` * * the `input` element will have the following settings * * ```js * { allowInvalid: true, updateOn: 'default', debounce: 200 } * ``` * * Notice that the `debounce` setting now inherits the value from the outer `
` element. * * If you are creating a reusable component then you should be careful when using `"*": "$inherit"` * since you may inadvertently inherit a setting in the future that changes the behavior of your component. * * * ## Triggering and debouncing model updates * * The `updateOn` and `debounce` properties allow you to specify a custom list of events that will * trigger a model update and/or a debouncing delay so that the actual update only takes place when * a timer expires; this timer will be reset after another change takes place. * * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might * be different from the value in the actual model. This means that if you update the model you * should also invoke {@link ngModel.NgModelController#$rollbackViewValue} on the relevant input field in * order to make sure it is synchronized with the model and that any debounced action is canceled. * * The easiest way to reference the control's {@link ngModel.NgModelController#$rollbackViewValue} * method is by making sure the input is placed inside a form that has a `name` attribute. This is * important because `form` controllers are published to the related scope under the name in their * `name` attribute. * * Any pending changes will take place immediately when an enclosing form is submitted via the * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` * to have access to the updated model. * * The following example shows how to override immediate updates. Changes on the inputs within the * form will update the model only when the control loses focus (blur event). If `escape` key is * pressed while the input field is focused, the value is reset to the value in the current model. * * * *
*
*
*
*
*
user.name = 
*
*
* * angular.module('optionsExample', []) * .controller('ExampleController', ['$scope', function($scope) { * $scope.user = { name: 'say', data: '' }; * * $scope.cancel = function(e) { * if (e.keyCode === 27) { * $scope.userForm.userName.$rollbackViewValue(); * } * }; * }]); * * * var model = element(by.binding('user.name')); * var input = element(by.model('user.name')); * var other = element(by.model('user.data')); * * it('should allow custom events', function() { * input.sendKeys(' hello'); * input.click(); * expect(model.getText()).toEqual('say'); * other.click(); * expect(model.getText()).toEqual('say hello'); * }); * * it('should $rollbackViewValue when model changes', function() { * input.sendKeys(' hello'); * expect(input.getAttribute('value')).toEqual('say hello'); * input.sendKeys(protractor.Key.ESCAPE); * expect(input.getAttribute('value')).toEqual('say'); * other.click(); * expect(model.getText()).toEqual('say'); * }); * *
* * The next example shows how to debounce model changes. Model will be updated only 1 sec after last change. * If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty. * * * *
*
* Name: * *
*
*
user.name = 
*
*
* * angular.module('optionsExample', []) * .controller('ExampleController', ['$scope', function($scope) { * $scope.user = { name: 'say' }; * }]); * *
* * ## Model updates and validation * * The default behaviour in `ngModel` is that the model value is set to `undefined` when the * validation determines that the value is invalid. By setting the `allowInvalid` property to true, * the model will still be updated even if the value is invalid. * * * ## Connecting to the scope * * By setting the `getterSetter` property to true you are telling ngModel that the `ngModel` expression * on the scope refers to a "getter/setter" function rather than the value itself. * * The following example shows how to bind to getter/setters: * * * *
*
* *
*
user.name = 
*
*
* * angular.module('getterSetterExample', []) * .controller('ExampleController', ['$scope', function($scope) { * var _name = 'Brian'; * $scope.user = { * name: function(newName) { * return angular.isDefined(newName) ? (_name = newName) : _name; * } * }; * }]); * *
* * * ## Specifying timezones * * You can specify the timezone that date/time input directives expect by providing its name in the * `timezone` property. * * @param {Object} ngModelOptions options to apply to {@link ngModel} directives on this element and * and its descendents. Valid keys are: * - `updateOn`: string specifying which event should the input be bound to. You can set several * events using an space delimited list. There is a special event called `default` that * matches the default events belonging to the control. * - `debounce`: integer value which contains the debounce model update value in milliseconds. A * value of 0 triggers an immediate update. If an object is supplied instead, you can specify a * custom value for each event. For example: * ``` * ng-model-options="{ * updateOn: 'default blur', * debounce: { 'default': 500, 'blur': 0 } * }" * ``` * - `allowInvalid`: boolean value which indicates that the model can be set with values that did * not validate correctly instead of the default behavior of setting the model to undefined. * - `getterSetter`: boolean value which determines whether or not to treat functions bound to * `ngModel` as getters/setters. * - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for * ``, ``, ... . It understands UTC/GMT and the * continental US time zone abbreviations, but for general use, use a time zone offset, for * example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian) * If not specified, the timezone of the browser will be used. * */ var ngModelOptionsDirective = function() { NgModelOptionsController.$inject = ['$attrs', '$scope']; function NgModelOptionsController($attrs, $scope) { this.$$attrs = $attrs; this.$$scope = $scope; } NgModelOptionsController.prototype = { $onInit: function() { var parentOptions = this.parentCtrl ? this.parentCtrl.$options : defaultModelOptions; var modelOptionsDefinition = this.$$scope.$eval(this.$$attrs.ngModelOptions); this.$options = parentOptions.createChild(modelOptionsDefinition); } }; return { restrict: 'A', // ngModelOptions needs to run before ngModel and input directives priority: 10, require: {parentCtrl: '?^^ngModelOptions'}, bindToController: true, controller: NgModelOptionsController }; }; // shallow copy over values from `src` that are not already specified on `dst` function defaults(dst, src) { forEach(src, function(value, key) { if (!isDefined(dst[key])) { dst[key] = value; } }); } /** * @ngdoc directive * @name ngNonBindable * @restrict AC * @priority 1000 * * @description * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current * DOM element. This is useful if the element contains what appears to be Angular directives and * bindings but which should be ignored by Angular. This could be the case if you have a site that * displays snippets of code, for instance. * * @element ANY * * @example * In this example there are two locations where a simple interpolation binding (`{{}}`) is present, * but the one wrapped in `ngNonBindable` is left alone. * * @example
Normal: {{1 + 2}}
Ignored: {{1 + 2}}
it('should check ng-non-bindable', function() { expect(element(by.binding('1 + 2')).getText()).toContain('3'); expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/); });
*/ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 }); /* exported ngOptionsDirective */ /* global jqLiteRemove */ var ngOptionsMinErr = minErr('ngOptions'); /** * @ngdoc directive * @name ngOptions * @restrict A * * @description * * The `ngOptions` attribute can be used to dynamically generate a list of `` * DOM element. * * `disable`: The result of this expression will be used to disable the rendered ` * *
* *
*
*
* singleSelect = {{data.singleSelect}} * *
*
*
* multipleSelect = {{data.multipleSelect}}
* *
* * * angular.module('staticSelect', []) * .controller('ExampleController', ['$scope', function($scope) { * $scope.data = { * singleSelect: null, * multipleSelect: [], * option1: 'option-1' * }; * * $scope.forceUnknownOption = function() { * $scope.data.singleSelect = 'nonsense'; * }; * }]); * * * * ### Using `ngRepeat` to generate `select` options * * *
*
* * *
*
* model = {{data.model}}
*
*
* * angular.module('ngrepeatSelect', []) * .controller('ExampleController', ['$scope', function($scope) { * $scope.data = { * model: null, * availableOptions: [ * {id: '1', name: 'Option A'}, * {id: '2', name: 'Option B'}, * {id: '3', name: 'Option C'} * ] * }; * }]); * *
* * ### Using `ngValue` to bind the model to an array of objects * * *
*
* * *
*
*
model = {{data.model | json}}

*
*
* * angular.module('ngvalueSelect', []) * .controller('ExampleController', ['$scope', function($scope) { * $scope.data = { * model: null, * availableOptions: [ {value: 'myString', name: 'string'}, {value: 1, name: 'integer'}, {value: true, name: 'boolean'}, {value: null, name: 'null'}, {value: {prop: 'value'}, name: 'object'}, {value: ['a'], name: 'array'} * ] * }; * }]); * *
* * ### Using `select` with `ngOptions` and setting a default value * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples. * * * *
*
* * *
*
* option = {{data.selectedOption}}
*
*
* * angular.module('defaultValueSelect', []) * .controller('ExampleController', ['$scope', function($scope) { * $scope.data = { * availableOptions: [ * {id: '1', name: 'Option A'}, * {id: '2', name: 'Option B'}, * {id: '3', name: 'Option C'} * ], * selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui * }; * }]); * *
* * * ### Binding `select` to a non-string value via `ngModel` parsing / formatting * * * * * {{ model }} * * * angular.module('nonStringSelect', []) * .run(function($rootScope) { * $rootScope.model = { id: 2 }; * }) * .directive('convertToNumber', function() { * return { * require: 'ngModel', * link: function(scope, element, attrs, ngModel) { * ngModel.$parsers.push(function(val) { * return parseInt(val, 10); * }); * ngModel.$formatters.push(function(val) { * return '' + val; * }); * } * }; * }); * * * it('should initialize to model', function() { * expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two'); * }); * * * */ var selectDirective = function() { return { restrict: 'E', require: ['select', '?ngModel'], controller: SelectController, priority: 1, link: { pre: selectPreLink, post: selectPostLink } }; function selectPreLink(scope, element, attr, ctrls) { var selectCtrl = ctrls[0]; var ngModelCtrl = ctrls[1]; // if ngModel is not defined, we don't need to do anything but set the registerOption // function to noop, so options don't get added internally if (!ngModelCtrl) { selectCtrl.registerOption = noop; return; } selectCtrl.ngModelCtrl = ngModelCtrl; // When the selected item(s) changes we delegate getting the value of the select control // to the `readValue` method, which can be changed if the select can have multiple // selected values or if the options are being generated by `ngOptions` element.on('change', function() { selectCtrl.removeUnknownOption(); scope.$apply(function() { ngModelCtrl.$setViewValue(selectCtrl.readValue()); }); }); // If the select allows multiple values then we need to modify how we read and write // values from and to the control; also what it means for the value to be empty and // we have to add an extra watch since ngModel doesn't work well with arrays - it // doesn't trigger rendering if only an item in the array changes. if (attr.multiple) { selectCtrl.multiple = true; // Read value now needs to check each option to see if it is selected selectCtrl.readValue = function readMultipleValue() { var array = []; forEach(element.find('option'), function(option) { if (option.selected && !option.disabled) { var val = option.value; array.push(val in selectCtrl.selectValueMap ? selectCtrl.selectValueMap[val] : val); } }); return array; }; // Write value now needs to set the selected property of each matching option selectCtrl.writeValue = function writeMultipleValue(value) { forEach(element.find('option'), function(option) { var shouldBeSelected = !!value && (includes(value, option.value) || includes(value, selectCtrl.selectValueMap[option.value])); var currentlySelected = option.selected; // Support: IE 9-11 only, Edge 12-15+ // In IE and Edge adding options to the selection via shift+click/UP/DOWN // will de-select already selected options if "selected" on those options was set // more than once (i.e. when the options were already selected) // So we only modify the selected property if necessary. // Note: this behavior cannot be replicated via unit tests because it only shows in the // actual user interface. if (shouldBeSelected !== currentlySelected) { setOptionSelectedStatus(jqLite(option), shouldBeSelected); } }); }; // we have to do it on each watch since ngModel watches reference, but // we need to work of an array, so we need to see if anything was inserted/removed var lastView, lastViewRef = NaN; scope.$watch(function selectMultipleWatch() { if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) { lastView = shallowCopy(ngModelCtrl.$viewValue); ngModelCtrl.$render(); } lastViewRef = ngModelCtrl.$viewValue; }); // If we are a multiple select then value is now a collection // so the meaning of $isEmpty changes ngModelCtrl.$isEmpty = function(value) { return !value || value.length === 0; }; } } function selectPostLink(scope, element, attrs, ctrls) { // if ngModel is not defined, we don't need to do anything var ngModelCtrl = ctrls[1]; if (!ngModelCtrl) return; var selectCtrl = ctrls[0]; // We delegate rendering to the `writeValue` method, which can be changed // if the select can have multiple selected values or if the options are being // generated by `ngOptions`. // This must be done in the postLink fn to prevent $render to be called before // all nodes have been linked correctly. ngModelCtrl.$render = function() { selectCtrl.writeValue(ngModelCtrl.$viewValue); }; } }; // The option directive is purely designed to communicate the existence (or lack of) // of dynamically created (and destroyed) option elements to their containing select // directive via its controller. var optionDirective = ['$interpolate', function($interpolate) { return { restrict: 'E', priority: 100, compile: function(element, attr) { var interpolateValueFn, interpolateTextFn; if (isDefined(attr.ngValue)) { // Will be handled by registerOption } else if (isDefined(attr.value)) { // If the value attribute is defined, check if it contains an interpolation interpolateValueFn = $interpolate(attr.value, true); } else { // If the value attribute is not defined then we fall back to the // text content of the option element, which may be interpolated interpolateTextFn = $interpolate(element.text(), true); if (!interpolateTextFn) { attr.$set('value', element.text()); } } return function(scope, element, attr) { // This is an optimization over using ^^ since we don't want to have to search // all the way to the root of the DOM for every single option element var selectCtrlName = '$selectController', parent = element.parent(), selectCtrl = parent.data(selectCtrlName) || parent.parent().data(selectCtrlName); // in case we are in optgroup if (selectCtrl) { selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn); } }; } }; }]; /** * @ngdoc directive * @name ngRequired * @restrict A * * @description * * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}. * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be * applied to custom controls. * * The directive sets the `required` attribute on the element if the Angular expression inside * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide} * for more info. * * The validator will set the `required` error key to true if the `required` attribute is set and * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based. * * @example * * * *
*
* * *
* *
*
* required error set? = {{form.input.$error.required}}
* model = {{model}} *
*
*
* var required = element(by.binding('form.input.$error.required')); var model = element(by.binding('model')); var input = element(by.id('input')); it('should set the required error', function() { expect(required.getText()).toContain('true'); input.sendKeys('123'); expect(required.getText()).not.toContain('true'); expect(model.getText()).toContain('123'); }); * *
*/ var requiredDirective = function() { return { restrict: 'A', require: '?ngModel', link: function(scope, elm, attr, ctrl) { if (!ctrl) return; attr.required = true; // force truthy in case we are on non input element ctrl.$validators.required = function(modelValue, viewValue) { return !attr.required || !ctrl.$isEmpty(viewValue); }; attr.$observe('required', function() { ctrl.$validate(); }); } }; }; /** * @ngdoc directive * @name ngPattern * * @description * * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}. * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls. * * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} * does not match a RegExp which is obtained by evaluating the Angular expression given in the * `ngPattern` attribute value: * * If the expression evaluates to a RegExp object, then this is used directly. * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. * *
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. *
* *
* **Note:** This directive is also added when the plain `pattern` attribute is used, with two * differences: *
    *
  1. * `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is * not available. *
  2. *
  3. * The `ngPattern` attribute must be an expression, while the `pattern` value must be * interpolated. *
  4. *
*
* * @example * * * *
*
* * *
* *
*
* input valid? = {{form.input.$valid}}
* model = {{model}} *
*
*
* var model = element(by.binding('model')); var input = element(by.id('input')); it('should validate the input with the default pattern', function() { input.sendKeys('aaa'); expect(model.getText()).not.toContain('aaa'); input.clear().then(function() { input.sendKeys('123'); expect(model.getText()).toContain('123'); }); }); * *
*/ var patternDirective = function() { return { restrict: 'A', require: '?ngModel', link: function(scope, elm, attr, ctrl) { if (!ctrl) return; var regexp, patternExp = attr.ngPattern || attr.pattern; attr.$observe('pattern', function(regex) { if (isString(regex) && regex.length > 0) { regex = new RegExp('^' + regex + '$'); } if (regex && !regex.test) { throw minErr('ngPattern')('noregexp', 'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp, regex, startingTag(elm)); } regexp = regex || undefined; ctrl.$validate(); }); ctrl.$validators.pattern = function(modelValue, viewValue) { // HTML5 pattern constraint validates the input value, so we validate the viewValue return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue); }; } }; }; /** * @ngdoc directive * @name ngMaxlength * * @description * * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}. * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls. * * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} * is longer than the integer obtained by evaluating the Angular expression given in the * `ngMaxlength` attribute value. * *
* **Note:** This directive is also added when the plain `maxlength` attribute is used, with two * differences: *
    *
  1. * `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint * validation is not available. *
  2. *
  3. * The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be * interpolated. *
  4. *
*
* * @example * * * *
*
* * *
* *
*
* input valid? = {{form.input.$valid}}
* model = {{model}} *
*
*
* var model = element(by.binding('model')); var input = element(by.id('input')); it('should validate the input with the default maxlength', function() { input.sendKeys('abcdef'); expect(model.getText()).not.toContain('abcdef'); input.clear().then(function() { input.sendKeys('abcde'); expect(model.getText()).toContain('abcde'); }); }); * *
*/ var maxlengthDirective = function() { return { restrict: 'A', require: '?ngModel', link: function(scope, elm, attr, ctrl) { if (!ctrl) return; var maxlength = -1; attr.$observe('maxlength', function(value) { var intVal = toInt(value); maxlength = isNumberNaN(intVal) ? -1 : intVal; ctrl.$validate(); }); ctrl.$validators.maxlength = function(modelValue, viewValue) { return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength); }; } }; }; /** * @ngdoc directive * @name ngMinlength * * @description * * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}. * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls. * * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} * is shorter than the integer obtained by evaluating the Angular expression given in the * `ngMinlength` attribute value. * *
* **Note:** This directive is also added when the plain `minlength` attribute is used, with two * differences: *
    *
  1. * `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint * validation is not available. *
  2. *
  3. * The `ngMinlength` value must be an expression, while the `minlength` value must be * interpolated. *
  4. *
*
* * @example * * * *
*
* * *
* *
*
* input valid? = {{form.input.$valid}}
* model = {{model}} *
*
*
* var model = element(by.binding('model')); var input = element(by.id('input')); it('should validate the input with the default minlength', function() { input.sendKeys('ab'); expect(model.getText()).not.toContain('ab'); input.sendKeys('abc'); expect(model.getText()).toContain('abc'); }); * *
*/ var minlengthDirective = function() { return { restrict: 'A', require: '?ngModel', link: function(scope, elm, attr, ctrl) { if (!ctrl) return; var minlength = 0; attr.$observe('minlength', function(value) { minlength = toInt(value) || 0; ctrl.$validate(); }); ctrl.$validators.minlength = function(modelValue, viewValue) { return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength; }; } }; }; if (window.angular.bootstrap) { // AngularJS is already loaded, so we can return here... if (window.console) { console.log('WARNING: Tried to load angular more than once.'); } return; } // try to bind to jquery now so that one can write jqLite(fn) // but we will rebind on bootstrap again. bindJQuery(); publishExternalAPI(angular); angular.module("ngLocale", [], ["$provide", function($provide) { var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"}; function getDecimals(n) { n = n + ''; var i = n.indexOf('.'); return (i == -1) ? 0 : n.length - i - 1; } function getVF(n, opt_precision) { var v = opt_precision; if (undefined === v) { v = Math.min(getDecimals(n), 3); } var base = Math.pow(10, v); var f = ((n * base) | 0) % base; return {v: v, f: f}; } $provide.value("$locale", { "DATETIME_FORMATS": { "AMPMS": [ "AM", "PM" ], "DAY": [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], "ERANAMES": [ "Before Christ", "Anno Domini" ], "ERAS": [ "BC", "AD" ], "FIRSTDAYOFWEEK": 6, "MONTH": [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], "SHORTDAY": [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], "SHORTMONTH": [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], "STANDALONEMONTH": [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], "WEEKENDRANGE": [ 5, 6 ], "fullDate": "EEEE, MMMM d, y", "longDate": "MMMM d, y", "medium": "MMM d, y h:mm:ss a", "mediumDate": "MMM d, y", "mediumTime": "h:mm:ss a", "short": "M/d/yy h:mm a", "shortDate": "M/d/yy", "shortTime": "h:mm a" }, "NUMBER_FORMATS": { "CURRENCY_SYM": "$", "DECIMAL_SEP": ".", "GROUP_SEP": ",", "PATTERNS": [ { "gSize": 3, "lgSize": 3, "maxFrac": 3, "minFrac": 0, "minInt": 1, "negPre": "-", "negSuf": "", "posPre": "", "posSuf": "" }, { "gSize": 3, "lgSize": 3, "maxFrac": 2, "minFrac": 2, "minInt": 1, "negPre": "-\u00a4", "negSuf": "", "posPre": "\u00a4", "posSuf": "" } ] }, "id": "en-us", "localeID": "en_US", "pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;} }); }]); jqLite(function() { angularInit(window.document, bootstrap); }); })(window); !window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend(''); /** * @license * Lodash * Copyright JS Foundation and other contributors * Released under MIT license * Based on Underscore.js 1.8.3 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ ;(function() { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; /** Used as the semantic version number. */ var VERSION = '4.17.4'; /** Used as the size to enable large array optimizations. */ var LARGE_ARRAY_SIZE = 200; /** Error message constants. */ var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', FUNC_ERROR_TEXT = 'Expected a function'; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED = '__lodash_hash_undefined__'; /** Used as the maximum memoize cache size. */ var MAX_MEMOIZE_SIZE = 500; /** Used as the internal argument placeholder. */ var PLACEHOLDER = '__lodash_placeholder__'; /** Used to compose bitmasks for cloning. */ var CLONE_DEEP_FLAG = 1, CLONE_FLAT_FLAG = 2, CLONE_SYMBOLS_FLAG = 4; /** Used to compose bitmasks for value comparisons. */ var COMPARE_PARTIAL_FLAG = 1, COMPARE_UNORDERED_FLAG = 2; /** Used to compose bitmasks for function metadata. */ var WRAP_BIND_FLAG = 1, WRAP_BIND_KEY_FLAG = 2, WRAP_CURRY_BOUND_FLAG = 4, WRAP_CURRY_FLAG = 8, WRAP_CURRY_RIGHT_FLAG = 16, WRAP_PARTIAL_FLAG = 32, WRAP_PARTIAL_RIGHT_FLAG = 64, WRAP_ARY_FLAG = 128, WRAP_REARG_FLAG = 256, WRAP_FLIP_FLAG = 512; /** Used as default options for `_.truncate`. */ var DEFAULT_TRUNC_LENGTH = 30, DEFAULT_TRUNC_OMISSION = '...'; /** Used to detect hot functions by number of calls within a span of milliseconds. */ var HOT_COUNT = 800, HOT_SPAN = 16; /** Used to indicate the type of lazy iteratees. */ var LAZY_FILTER_FLAG = 1, LAZY_MAP_FLAG = 2, LAZY_WHILE_FLAG = 3; /** Used as references for various `Number` constants. */ var INFINITY = 1 / 0, MAX_SAFE_INTEGER = 9007199254740991, MAX_INTEGER = 1.7976931348623157e+308, NAN = 0 / 0; /** Used as references for the maximum length and index of an array. */ var MAX_ARRAY_LENGTH = 4294967295, MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; /** Used to associate wrap methods with their bit flags. */ var wrapFlags = [ ['ary', WRAP_ARY_FLAG], ['bind', WRAP_BIND_FLAG], ['bindKey', WRAP_BIND_KEY_FLAG], ['curry', WRAP_CURRY_FLAG], ['curryRight', WRAP_CURRY_RIGHT_FLAG], ['flip', WRAP_FLIP_FLAG], ['partial', WRAP_PARTIAL_FLAG], ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], ['rearg', WRAP_REARG_FLAG] ]; /** `Object#toString` result references. */ var argsTag = '[object Arguments]', arrayTag = '[object Array]', asyncTag = '[object AsyncFunction]', boolTag = '[object Boolean]', dateTag = '[object Date]', domExcTag = '[object DOMException]', errorTag = '[object Error]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', mapTag = '[object Map]', numberTag = '[object Number]', nullTag = '[object Null]', objectTag = '[object Object]', promiseTag = '[object Promise]', proxyTag = '[object Proxy]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', symbolTag = '[object Symbol]', undefinedTag = '[object Undefined]', weakMapTag = '[object WeakMap]', weakSetTag = '[object WeakSet]'; var arrayBufferTag = '[object ArrayBuffer]', dataViewTag = '[object DataView]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; /** Used to match empty string literals in compiled template source. */ var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match HTML entities and HTML characters. */ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, reUnescapedHtml = /[&<>"']/g, reHasEscapedHtml = RegExp(reEscapedHtml.source), reHasUnescapedHtml = RegExp(reUnescapedHtml.source); /** Used to match template delimiters. */ var reEscape = /<%-([\s\S]+?)%>/g, reEvaluate = /<%([\s\S]+?)%>/g, reInterpolate = /<%=([\s\S]+?)%>/g; /** Used to match property names within property paths. */ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/, reLeadingDot = /^\./, rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, reHasRegExpChar = RegExp(reRegExpChar.source); /** Used to match leading and trailing whitespace. */ var reTrim = /^\s+|\s+$/g, reTrimStart = /^\s+/, reTrimEnd = /\s+$/; /** Used to match wrap detail comments. */ var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, reSplitDetails = /,? & /; /** Used to match words composed of alphanumeric characters. */ var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; /** Used to match backslashes in property paths. */ var reEscapeChar = /\\(\\)?/g; /** * Used to match * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). */ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; /** Used to match `RegExp` flags from their coerced string values. */ var reFlags = /\w*$/; /** Used to detect bad signed hexadecimal string values. */ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; /** Used to detect binary string values. */ var reIsBinary = /^0b[01]+$/i; /** Used to detect host constructors (Safari). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Used to detect octal string values. */ var reIsOctal = /^0o[0-7]+$/i; /** Used to detect unsigned integer values. */ var reIsUint = /^(?:0|[1-9]\d*)$/; /** Used to match Latin Unicode letters (excluding mathematical operators). */ var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; /** Used to ensure capturing order of template delimiters. */ var reNoMatch = /($^)/; /** Used to match unescaped characters in compiled string literals. */ var reUnescapedString = /['\n\r\u2028\u2029\\]/g; /** Used to compose unicode character classes. */ var rsAstralRange = '\\ud800-\\udfff', rsComboMarksRange = '\\u0300-\\u036f', reComboHalfMarksRange = '\\ufe20-\\ufe2f', rsComboSymbolsRange = '\\u20d0-\\u20ff', rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, rsDingbatRange = '\\u2700-\\u27bf', rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', rsPunctuationRange = '\\u2000-\\u206f', rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', rsVarRange = '\\ufe0e\\ufe0f', rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; /** Used to compose unicode capture groups. */ var rsApos = "['\u2019]", rsAstral = '[' + rsAstralRange + ']', rsBreak = '[' + rsBreakRange + ']', rsCombo = '[' + rsComboRange + ']', rsDigits = '\\d+', rsDingbat = '[' + rsDingbatRange + ']', rsLower = '[' + rsLowerRange + ']', rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', rsFitz = '\\ud83c[\\udffb-\\udfff]', rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', rsNonAstral = '[^' + rsAstralRange + ']', rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', rsUpper = '[' + rsUpperRange + ']', rsZWJ = '\\u200d'; /** Used to compose unicode regexes. */ var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', reOptMod = rsModifier + '?', rsOptVar = '[' + rsVarRange + ']?', rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)', rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)', rsSeq = rsOptVar + reOptMod + rsOptJoin, rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; /** Used to match apostrophes. */ var reApos = RegExp(rsApos, 'g'); /** * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). */ var reComboMark = RegExp(rsCombo, 'g'); /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); /** Used to match complex or compound words. */ var reUnicodeWord = RegExp([ rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, rsUpper + '+' + rsOptContrUpper, rsOrdUpper, rsOrdLower, rsDigits, rsEmoji ].join('|'), 'g'); /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); /** Used to detect strings that need a more robust regexp to match words. */ var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; /** Used to assign default `context` object properties. */ var contextProps = [ 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' ]; /** Used to make template sourceURLs easier to identify. */ var templateCounter = -1; /** Used to identify `toStringTag` values of typed arrays. */ var typedArrayTags = {}; typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; /** Used to identify `toStringTag` values supported by `_.clone`. */ var cloneableTags = {}; cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[mapTag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[setTag] = cloneableTags[stringTag] = cloneableTags[symbolTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false; /** Used to map Latin Unicode letters to basic Latin letters. */ var deburredLetters = { // Latin-1 Supplement block. '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', '\xc7': 'C', '\xe7': 'c', '\xd0': 'D', '\xf0': 'd', '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', '\xd1': 'N', '\xf1': 'n', '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', '\xc6': 'Ae', '\xe6': 'ae', '\xde': 'Th', '\xfe': 'th', '\xdf': 'ss', // Latin Extended-A block. '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', '\u0134': 'J', '\u0135': 'j', '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', '\u0163': 't', '\u0165': 't', '\u0167': 't', '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', '\u0174': 'W', '\u0175': 'w', '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', '\u0132': 'IJ', '\u0133': 'ij', '\u0152': 'Oe', '\u0153': 'oe', '\u0149': "'n", '\u017f': 's' }; /** Used to map characters to HTML entities. */ var htmlEscapes = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; /** Used to map HTML entities to characters. */ var htmlUnescapes = { '&': '&', '<': '<', '>': '>', '"': '"', ''': "'" }; /** Used to escape characters for inclusion in compiled string literals. */ var stringEscapes = { '\\': '\\', "'": "'", '\n': 'n', '\r': 'r', '\u2028': 'u2028', '\u2029': 'u2029' }; /** Built-in method references without a dependency on `root`. */ var freeParseFloat = parseFloat, freeParseInt = parseInt; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Detect free variable `exports`. */ var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; /** Detect free variable `module`. */ var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; /** Detect the popular CommonJS extension `module.exports`. */ var moduleExports = freeModule && freeModule.exports === freeExports; /** Detect free variable `process` from Node.js. */ var freeProcess = moduleExports && freeGlobal.process; /** Used to access faster Node.js helpers. */ var nodeUtil = (function() { try { return freeProcess && freeProcess.binding && freeProcess.binding('util'); } catch (e) {} }()); /* Node.js helper references. */ var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, nodeIsDate = nodeUtil && nodeUtil.isDate, nodeIsMap = nodeUtil && nodeUtil.isMap, nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, nodeIsSet = nodeUtil && nodeUtil.isSet, nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; /*--------------------------------------------------------------------------*/ /** * Adds the key-value `pair` to `map`. * * @private * @param {Object} map The map to modify. * @param {Array} pair The key-value pair to add. * @returns {Object} Returns `map`. */ function addMapEntry(map, pair) { // Don't return `map.set` because it's not chainable in IE 11. map.set(pair[0], pair[1]); return map; } /** * Adds `value` to `set`. * * @private * @param {Object} set The set to modify. * @param {*} value The value to add. * @returns {Object} Returns `set`. */ function addSetEntry(set, value) { // Don't return `set.add` because it's not chainable in IE 11. set.add(value); return set; } /** * A faster alternative to `Function#apply`, this function invokes `func` * with the `this` binding of `thisArg` and the arguments of `args`. * * @private * @param {Function} func The function to invoke. * @param {*} thisArg The `this` binding of `func`. * @param {Array} args The arguments to invoke `func` with. * @returns {*} Returns the result of `func`. */ function apply(func, thisArg, args) { switch (args.length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); case 3: return func.call(thisArg, args[0], args[1], args[2]); } return func.apply(thisArg, args); } /** * A specialized version of `baseAggregator` for arrays. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} setter The function to set `accumulator` values. * @param {Function} iteratee The iteratee to transform keys. * @param {Object} accumulator The initial aggregated object. * @returns {Function} Returns `accumulator`. */ function arrayAggregator(array, setter, iteratee, accumulator) { var index = -1, length = array == null ? 0 : array.length; while (++index < length) { var value = array[index]; setter(accumulator, value, iteratee(value), array); } return accumulator; } /** * A specialized version of `_.forEach` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEach(array, iteratee) { var index = -1, length = array == null ? 0 : array.length; while (++index < length) { if (iteratee(array[index], index, array) === false) { break; } } return array; } /** * A specialized version of `_.forEachRight` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEachRight(array, iteratee) { var length = array == null ? 0 : array.length; while (length--) { if (iteratee(array[length], length, array) === false) { break; } } return array; } /** * A specialized version of `_.every` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if all elements pass the predicate check, * else `false`. */ function arrayEvery(array, predicate) { var index = -1, length = array == null ? 0 : array.length; while (++index < length) { if (!predicate(array[index], index, array)) { return false; } } return true; } /** * A specialized version of `_.filter` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {Array} Returns the new filtered array. */ function arrayFilter(array, predicate) { var index = -1, length = array == null ? 0 : array.length, resIndex = 0, result = []; while (++index < length) { var value = array[index]; if (predicate(value, index, array)) { result[resIndex++] = value; } } return result; } /** * A specialized version of `_.includes` for arrays without support for * specifying an index to search from. * * @private * @param {Array} [array] The array to inspect. * @param {*} target The value to search for. * @returns {boolean} Returns `true` if `target` is found, else `false`. */ function arrayIncludes(array, value) { var length = array == null ? 0 : array.length; return !!length && baseIndexOf(array, value, 0) > -1; } /** * This function is like `arrayIncludes` except that it accepts a comparator. * * @private * @param {Array} [array] The array to inspect. * @param {*} target The value to search for. * @param {Function} comparator The comparator invoked per element. * @returns {boolean} Returns `true` if `target` is found, else `false`. */ function arrayIncludesWith(array, value, comparator) { var index = -1, length = array == null ? 0 : array.length; while (++index < length) { if (comparator(value, array[index])) { return true; } } return false; } /** * A specialized version of `_.map` for arrays without support for iteratee * shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the new mapped array. */ function arrayMap(array, iteratee) { var index = -1, length = array == null ? 0 : array.length, result = Array(length); while (++index < length) { result[index] = iteratee(array[index], index, array); } return result; } /** * Appends the elements of `values` to `array`. * * @private * @param {Array} array The array to modify. * @param {Array} values The values to append. * @returns {Array} Returns `array`. */ function arrayPush(array, values) { var index = -1, length = values.length, offset = array.length; while (++index < length) { array[offset + index] = values[index]; } return array; } /** * A specialized version of `_.reduce` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {boolean} [initAccum] Specify using the first element of `array` as * the initial value. * @returns {*} Returns the accumulated value. */ function arrayReduce(array, iteratee, accumulator, initAccum) { var index = -1, length = array == null ? 0 : array.length; if (initAccum && length) { accumulator = array[++index]; } while (++index < length) { accumulator = iteratee(accumulator, array[index], index, array); } return accumulator; } /** * A specialized version of `_.reduceRight` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {boolean} [initAccum] Specify using the last element of `array` as * the initial value. * @returns {*} Returns the accumulated value. */ function arrayReduceRight(array, iteratee, accumulator, initAccum) { var length = array == null ? 0 : array.length; if (initAccum && length) { accumulator = array[--length]; } while (length--) { accumulator = iteratee(accumulator, array[length], length, array); } return accumulator; } /** * A specialized version of `_.some` for arrays without support for iteratee * shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if any element passes the predicate check, * else `false`. */ function arraySome(array, predicate) { var index = -1, length = array == null ? 0 : array.length; while (++index < length) { if (predicate(array[index], index, array)) { return true; } } return false; } /** * Gets the size of an ASCII `string`. * * @private * @param {string} string The string inspect. * @returns {number} Returns the string size. */ var asciiSize = baseProperty('length'); /** * Converts an ASCII `string` to an array. * * @private * @param {string} string The string to convert. * @returns {Array} Returns the converted array. */ function asciiToArray(string) { return string.split(''); } /** * Splits an ASCII `string` into an array of its words. * * @private * @param {string} The string to inspect. * @returns {Array} Returns the words of `string`. */ function asciiWords(string) { return string.match(reAsciiWord) || []; } /** * The base implementation of methods like `_.findKey` and `_.findLastKey`, * without support for iteratee shorthands, which iterates over `collection` * using `eachFunc`. * * @private * @param {Array|Object} collection The collection to inspect. * @param {Function} predicate The function invoked per iteration. * @param {Function} eachFunc The function to iterate over `collection`. * @returns {*} Returns the found element or its key, else `undefined`. */ function baseFindKey(collection, predicate, eachFunc) { var result; eachFunc(collection, function(value, key, collection) { if (predicate(value, key, collection)) { result = key; return false; } }); return result; } /** * The base implementation of `_.findIndex` and `_.findLastIndex` without * support for iteratee shorthands. * * @private * @param {Array} array The array to inspect. * @param {Function} predicate The function invoked per iteration. * @param {number} fromIndex The index to search from. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {number} Returns the index of the matched value, else `-1`. */ function baseFindIndex(array, predicate, fromIndex, fromRight) { var length = array.length, index = fromIndex + (fromRight ? 1 : -1); while ((fromRight ? index-- : ++index < length)) { if (predicate(array[index], index, array)) { return index; } } return -1; } /** * The base implementation of `_.indexOf` without `fromIndex` bounds checks. * * @private * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} fromIndex The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. */ function baseIndexOf(array, value, fromIndex) { return value === value ? strictIndexOf(array, value, fromIndex) : baseFindIndex(array, baseIsNaN, fromIndex); } /** * This function is like `baseIndexOf` except that it accepts a comparator. * * @private * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} fromIndex The index to search from. * @param {Function} comparator The comparator invoked per element. * @returns {number} Returns the index of the matched value, else `-1`. */ function baseIndexOfWith(array, value, fromIndex, comparator) { var index = fromIndex - 1, length = array.length; while (++index < length) { if (comparator(array[index], value)) { return index; } } return -1; } /** * The base implementation of `_.isNaN` without support for number objects. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. */ function baseIsNaN(value) { return value !== value; } /** * The base implementation of `_.mean` and `_.meanBy` without support for * iteratee shorthands. * * @private * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {number} Returns the mean. */ function baseMean(array, iteratee) { var length = array == null ? 0 : array.length; return length ? (baseSum(array, iteratee) / length) : NAN; } /** * The base implementation of `_.property` without support for deep paths. * * @private * @param {string} key The key of the property to get. * @returns {Function} Returns the new accessor function. */ function baseProperty(key) { return function(object) { return object == null ? undefined : object[key]; }; } /** * The base implementation of `_.propertyOf` without support for deep paths. * * @private * @param {Object} object The object to query. * @returns {Function} Returns the new accessor function. */ function basePropertyOf(object) { return function(key) { return object == null ? undefined : object[key]; }; } /** * The base implementation of `_.reduce` and `_.reduceRight`, without support * for iteratee shorthands, which iterates over `collection` using `eachFunc`. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} accumulator The initial value. * @param {boolean} initAccum Specify using the first or last element of * `collection` as the initial value. * @param {Function} eachFunc The function to iterate over `collection`. * @returns {*} Returns the accumulated value. */ function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { eachFunc(collection, function(value, index, collection) { accumulator = initAccum ? (initAccum = false, value) : iteratee(accumulator, value, index, collection); }); return accumulator; } /** * The base implementation of `_.sortBy` which uses `comparer` to define the * sort order of `array` and replaces criteria objects with their corresponding * values. * * @private * @param {Array} array The array to sort. * @param {Function} comparer The function to define sort order. * @returns {Array} Returns `array`. */ function baseSortBy(array, comparer) { var length = array.length; array.sort(comparer); while (length--) { array[length] = array[length].value; } return array; } /** * The base implementation of `_.sum` and `_.sumBy` without support for * iteratee shorthands. * * @private * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {number} Returns the sum. */ function baseSum(array, iteratee) { var result, index = -1, length = array.length; while (++index < length) { var current = iteratee(array[index]); if (current !== undefined) { result = result === undefined ? current : (result + current); } } return result; } /** * The base implementation of `_.times` without support for iteratee shorthands * or max array length checks. * * @private * @param {number} n The number of times to invoke `iteratee`. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the array of results. */ function baseTimes(n, iteratee) { var index = -1, result = Array(n); while (++index < n) { result[index] = iteratee(index); } return result; } /** * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array * of key-value pairs for `object` corresponding to the property names of `props`. * * @private * @param {Object} object The object to query. * @param {Array} props The property names to get values for. * @returns {Object} Returns the key-value pairs. */ function baseToPairs(object, props) { return arrayMap(props, function(key) { return [key, object[key]]; }); } /** * The base implementation of `_.unary` without support for storing metadata. * * @private * @param {Function} func The function to cap arguments for. * @returns {Function} Returns the new capped function. */ function baseUnary(func) { return function(value) { return func(value); }; } /** * The base implementation of `_.values` and `_.valuesIn` which creates an * array of `object` property values corresponding to the property names * of `props`. * * @private * @param {Object} object The object to query. * @param {Array} props The property names to get values for. * @returns {Object} Returns the array of property values. */ function baseValues(object, props) { return arrayMap(props, function(key) { return object[key]; }); } /** * Checks if a `cache` value for `key` exists. * * @private * @param {Object} cache The cache to query. * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function cacheHas(cache, key) { return cache.has(key); } /** * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol * that is not found in the character symbols. * * @private * @param {Array} strSymbols The string symbols to inspect. * @param {Array} chrSymbols The character symbols to find. * @returns {number} Returns the index of the first unmatched string symbol. */ function charsStartIndex(strSymbols, chrSymbols) { var index = -1, length = strSymbols.length; while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} return index; } /** * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol * that is not found in the character symbols. * * @private * @param {Array} strSymbols The string symbols to inspect. * @param {Array} chrSymbols The character symbols to find. * @returns {number} Returns the index of the last unmatched string symbol. */ function charsEndIndex(strSymbols, chrSymbols) { var index = strSymbols.length; while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} return index; } /** * Gets the number of `placeholder` occurrences in `array`. * * @private * @param {Array} array The array to inspect. * @param {*} placeholder The placeholder to search for. * @returns {number} Returns the placeholder count. */ function countHolders(array, placeholder) { var length = array.length, result = 0; while (length--) { if (array[length] === placeholder) { ++result; } } return result; } /** * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A * letters to basic Latin letters. * * @private * @param {string} letter The matched letter to deburr. * @returns {string} Returns the deburred letter. */ var deburrLetter = basePropertyOf(deburredLetters); /** * Used by `_.escape` to convert characters to HTML entities. * * @private * @param {string} chr The matched character to escape. * @returns {string} Returns the escaped character. */ var escapeHtmlChar = basePropertyOf(htmlEscapes); /** * Used by `_.template` to escape characters for inclusion in compiled string literals. * * @private * @param {string} chr The matched character to escape. * @returns {string} Returns the escaped character. */ function escapeStringChar(chr) { return '\\' + stringEscapes[chr]; } /** * Gets the value at `key` of `object`. * * @private * @param {Object} [object] The object to query. * @param {string} key The key of the property to get. * @returns {*} Returns the property value. */ function getValue(object, key) { return object == null ? undefined : object[key]; } /** * Checks if `string` contains Unicode symbols. * * @private * @param {string} string The string to inspect. * @returns {boolean} Returns `true` if a symbol is found, else `false`. */ function hasUnicode(string) { return reHasUnicode.test(string); } /** * Checks if `string` contains a word composed of Unicode symbols. * * @private * @param {string} string The string to inspect. * @returns {boolean} Returns `true` if a word is found, else `false`. */ function hasUnicodeWord(string) { return reHasUnicodeWord.test(string); } /** * Converts `iterator` to an array. * * @private * @param {Object} iterator The iterator to convert. * @returns {Array} Returns the converted array. */ function iteratorToArray(iterator) { var data, result = []; while (!(data = iterator.next()).done) { result.push(data.value); } return result; } /** * Converts `map` to its key-value pairs. * * @private * @param {Object} map The map to convert. * @returns {Array} Returns the key-value pairs. */ function mapToArray(map) { var index = -1, result = Array(map.size); map.forEach(function(value, key) { result[++index] = [key, value]; }); return result; } /** * Creates a unary function that invokes `func` with its argument transformed. * * @private * @param {Function} func The function to wrap. * @param {Function} transform The argument transform. * @returns {Function} Returns the new function. */ function overArg(func, transform) { return function(arg) { return func(transform(arg)); }; } /** * Replaces all `placeholder` elements in `array` with an internal placeholder * and returns an array of their indexes. * * @private * @param {Array} array The array to modify. * @param {*} placeholder The placeholder to replace. * @returns {Array} Returns the new array of placeholder indexes. */ function replaceHolders(array, placeholder) { var index = -1, length = array.length, resIndex = 0, result = []; while (++index < length) { var value = array[index]; if (value === placeholder || value === PLACEHOLDER) { array[index] = PLACEHOLDER; result[resIndex++] = index; } } return result; } /** * Converts `set` to an array of its values. * * @private * @param {Object} set The set to convert. * @returns {Array} Returns the values. */ function setToArray(set) { var index = -1, result = Array(set.size); set.forEach(function(value) { result[++index] = value; }); return result; } /** * Converts `set` to its value-value pairs. * * @private * @param {Object} set The set to convert. * @returns {Array} Returns the value-value pairs. */ function setToPairs(set) { var index = -1, result = Array(set.size); set.forEach(function(value) { result[++index] = [value, value]; }); return result; } /** * A specialized version of `_.indexOf` which performs strict equality * comparisons of values, i.e. `===`. * * @private * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} fromIndex The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. */ function strictIndexOf(array, value, fromIndex) { var index = fromIndex - 1, length = array.length; while (++index < length) { if (array[index] === value) { return index; } } return -1; } /** * A specialized version of `_.lastIndexOf` which performs strict equality * comparisons of values, i.e. `===`. * * @private * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} fromIndex The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. */ function strictLastIndexOf(array, value, fromIndex) { var index = fromIndex + 1; while (index--) { if (array[index] === value) { return index; } } return index; } /** * Gets the number of symbols in `string`. * * @private * @param {string} string The string to inspect. * @returns {number} Returns the string size. */ function stringSize(string) { return hasUnicode(string) ? unicodeSize(string) : asciiSize(string); } /** * Converts `string` to an array. * * @private * @param {string} string The string to convert. * @returns {Array} Returns the converted array. */ function stringToArray(string) { return hasUnicode(string) ? unicodeToArray(string) : asciiToArray(string); } /** * Used by `_.unescape` to convert HTML entities to characters. * * @private * @param {string} chr The matched character to unescape. * @returns {string} Returns the unescaped character. */ var unescapeHtmlChar = basePropertyOf(htmlUnescapes); /** * Gets the size of a Unicode `string`. * * @private * @param {string} string The string inspect. * @returns {number} Returns the string size. */ function unicodeSize(string) { var result = reUnicode.lastIndex = 0; while (reUnicode.test(string)) { ++result; } return result; } /** * Converts a Unicode `string` to an array. * * @private * @param {string} string The string to convert. * @returns {Array} Returns the converted array. */ function unicodeToArray(string) { return string.match(reUnicode) || []; } /** * Splits a Unicode `string` into an array of its words. * * @private * @param {string} The string to inspect. * @returns {Array} Returns the words of `string`. */ function unicodeWords(string) { return string.match(reUnicodeWord) || []; } /*--------------------------------------------------------------------------*/ /** * Create a new pristine `lodash` function using the `context` object. * * @static * @memberOf _ * @since 1.1.0 * @category Util * @param {Object} [context=root] The context object. * @returns {Function} Returns a new `lodash` function. * @example * * _.mixin({ 'foo': _.constant('foo') }); * * var lodash = _.runInContext(); * lodash.mixin({ 'bar': lodash.constant('bar') }); * * _.isFunction(_.foo); * // => true * _.isFunction(_.bar); * // => false * * lodash.isFunction(lodash.foo); * // => false * lodash.isFunction(lodash.bar); * // => true * * // Create a suped-up `defer` in Node.js. * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; */ var runInContext = (function runInContext(context) { context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); /** Built-in constructor references. */ var Array = context.Array, Date = context.Date, Error = context.Error, Function = context.Function, Math = context.Math, Object = context.Object, RegExp = context.RegExp, String = context.String, TypeError = context.TypeError; /** Used for built-in method references. */ var arrayProto = Array.prototype, funcProto = Function.prototype, objectProto = Object.prototype; /** Used to detect overreaching core-js shims. */ var coreJsData = context['__core-js_shared__']; /** Used to resolve the decompiled source of functions. */ var funcToString = funcProto.toString; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** Used to generate unique IDs. */ var idCounter = 0; /** Used to detect methods masquerading as native. */ var maskSrcKey = (function() { var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); return uid ? ('Symbol(src)_1.' + uid) : ''; }()); /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var nativeObjectToString = objectProto.toString; /** Used to infer the `Object` constructor. */ var objectCtorString = funcToString.call(Object); /** Used to restore the original `_` reference in `_.noConflict`. */ var oldDash = root._; /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); /** Built-in value references. */ var Buffer = moduleExports ? context.Buffer : undefined, Symbol = context.Symbol, Uint8Array = context.Uint8Array, allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, getPrototype = overArg(Object.getPrototypeOf, Object), objectCreate = Object.create, propertyIsEnumerable = objectProto.propertyIsEnumerable, splice = arrayProto.splice, spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, symIterator = Symbol ? Symbol.iterator : undefined, symToStringTag = Symbol ? Symbol.toStringTag : undefined; var defineProperty = (function() { try { var func = getNative(Object, 'defineProperty'); func({}, '', {}); return func; } catch (e) {} }()); /** Mocked built-ins. */ var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, ctxNow = Date && Date.now !== root.Date.now && Date.now, ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeCeil = Math.ceil, nativeFloor = Math.floor, nativeGetSymbols = Object.getOwnPropertySymbols, nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, nativeIsFinite = context.isFinite, nativeJoin = arrayProto.join, nativeKeys = overArg(Object.keys, Object), nativeMax = Math.max, nativeMin = Math.min, nativeNow = Date.now, nativeParseInt = context.parseInt, nativeRandom = Math.random, nativeReverse = arrayProto.reverse; /* Built-in method references that are verified to be native. */ var DataView = getNative(context, 'DataView'), Map = getNative(context, 'Map'), Promise = getNative(context, 'Promise'), Set = getNative(context, 'Set'), WeakMap = getNative(context, 'WeakMap'), nativeCreate = getNative(Object, 'create'); /** Used to store function metadata. */ var metaMap = WeakMap && new WeakMap; /** Used to lookup unminified function names. */ var realNames = {}; /** Used to detect maps, sets, and weakmaps. */ var dataViewCtorString = toSource(DataView), mapCtorString = toSource(Map), promiseCtorString = toSource(Promise), setCtorString = toSource(Set), weakMapCtorString = toSource(WeakMap); /** Used to convert symbols to primitives and strings. */ var symbolProto = Symbol ? Symbol.prototype : undefined, symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, symbolToString = symbolProto ? symbolProto.toString : undefined; /*------------------------------------------------------------------------*/ /** * Creates a `lodash` object which wraps `value` to enable implicit method * chain sequences. Methods that operate on and return arrays, collections, * and functions can be chained together. Methods that retrieve a single value * or may return a primitive value will automatically end the chain sequence * and return the unwrapped value. Otherwise, the value must be unwrapped * with `_#value`. * * Explicit chain sequences, which must be unwrapped with `_#value`, may be * enabled using `_.chain`. * * The execution of chained methods is lazy, that is, it's deferred until * `_#value` is implicitly or explicitly called. * * Lazy evaluation allows several methods to support shortcut fusion. * Shortcut fusion is an optimization to merge iteratee calls; this avoids * the creation of intermediate arrays and can greatly reduce the number of * iteratee executions. Sections of a chain sequence qualify for shortcut * fusion if the section is applied to an array and iteratees accept only * one argument. The heuristic for whether a section qualifies for shortcut * fusion is subject to change. * * Chaining is supported in custom builds as long as the `_#value` method is * directly or indirectly included in the build. * * In addition to lodash methods, wrappers have `Array` and `String` methods. * * The wrapper `Array` methods are: * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` * * The wrapper `String` methods are: * `replace` and `split` * * The wrapper methods that support shortcut fusion are: * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` * * The chainable wrapper methods are: * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, * `zipObject`, `zipObjectDeep`, and `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, * `upperFirst`, `value`, and `words` * * @name _ * @constructor * @category Seq * @param {*} value The value to wrap in a `lodash` instance. * @returns {Object} Returns the new `lodash` wrapper instance. * @example * * function square(n) { * return n * n; * } * * var wrapped = _([1, 2, 3]); * * // Returns an unwrapped value. * wrapped.reduce(_.add); * // => 6 * * // Returns a wrapped value. * var squares = wrapped.map(square); * * _.isArray(squares); * // => false * * _.isArray(squares.value()); * // => true */ function lodash(value) { if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { if (value instanceof LodashWrapper) { return value; } if (hasOwnProperty.call(value, '__wrapped__')) { return wrapperClone(value); } } return new LodashWrapper(value); } /** * The base implementation of `_.create` without support for assigning * properties to the created object. * * @private * @param {Object} proto The object to inherit from. * @returns {Object} Returns the new object. */ var baseCreate = (function() { function object() {} return function(proto) { if (!isObject(proto)) { return {}; } if (objectCreate) { return objectCreate(proto); } object.prototype = proto; var result = new object; object.prototype = undefined; return result; }; }()); /** * The function whose prototype chain sequence wrappers inherit from. * * @private */ function baseLodash() { // No operation performed. } /** * The base constructor for creating `lodash` wrapper objects. * * @private * @param {*} value The value to wrap. * @param {boolean} [chainAll] Enable explicit method chain sequences. */ function LodashWrapper(value, chainAll) { this.__wrapped__ = value; this.__actions__ = []; this.__chain__ = !!chainAll; this.__index__ = 0; this.__values__ = undefined; } /** * By default, the template delimiters used by lodash are like those in * embedded Ruby (ERB) as well as ES2015 template strings. Change the * following template settings to use alternative delimiters. * * @static * @memberOf _ * @type {Object} */ lodash.templateSettings = { /** * Used to detect `data` property values to be HTML-escaped. * * @memberOf _.templateSettings * @type {RegExp} */ 'escape': reEscape, /** * Used to detect code to be evaluated. * * @memberOf _.templateSettings * @type {RegExp} */ 'evaluate': reEvaluate, /** * Used to detect `data` property values to inject. * * @memberOf _.templateSettings * @type {RegExp} */ 'interpolate': reInterpolate, /** * Used to reference the data object in the template text. * * @memberOf _.templateSettings * @type {string} */ 'variable': '', /** * Used to import variables into the compiled template. * * @memberOf _.templateSettings * @type {Object} */ 'imports': { /** * A reference to the `lodash` function. * * @memberOf _.templateSettings.imports * @type {Function} */ '_': lodash } }; // Ensure wrappers are instances of `baseLodash`. lodash.prototype = baseLodash.prototype; lodash.prototype.constructor = lodash; LodashWrapper.prototype = baseCreate(baseLodash.prototype); LodashWrapper.prototype.constructor = LodashWrapper; /*------------------------------------------------------------------------*/ /** * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. * * @private * @constructor * @param {*} value The value to wrap. */ function LazyWrapper(value) { this.__wrapped__ = value; this.__actions__ = []; this.__dir__ = 1; this.__filtered__ = false; this.__iteratees__ = []; this.__takeCount__ = MAX_ARRAY_LENGTH; this.__views__ = []; } /** * Creates a clone of the lazy wrapper object. * * @private * @name clone * @memberOf LazyWrapper * @returns {Object} Returns the cloned `LazyWrapper` object. */ function lazyClone() { var result = new LazyWrapper(this.__wrapped__); result.__actions__ = copyArray(this.__actions__); result.__dir__ = this.__dir__; result.__filtered__ = this.__filtered__; result.__iteratees__ = copyArray(this.__iteratees__); result.__takeCount__ = this.__takeCount__; result.__views__ = copyArray(this.__views__); return result; } /** * Reverses the direction of lazy iteration. * * @private * @name reverse * @memberOf LazyWrapper * @returns {Object} Returns the new reversed `LazyWrapper` object. */ function lazyReverse() { if (this.__filtered__) { var result = new LazyWrapper(this); result.__dir__ = -1; result.__filtered__ = true; } else { result = this.clone(); result.__dir__ *= -1; } return result; } /** * Extracts the unwrapped value from its lazy wrapper. * * @private * @name value * @memberOf LazyWrapper * @returns {*} Returns the unwrapped value. */ function lazyValue() { var array = this.__wrapped__.value(), dir = this.__dir__, isArr = isArray(array), isRight = dir < 0, arrLength = isArr ? array.length : 0, view = getView(0, arrLength, this.__views__), start = view.start, end = view.end, length = end - start, index = isRight ? end : (start - 1), iteratees = this.__iteratees__, iterLength = iteratees.length, resIndex = 0, takeCount = nativeMin(length, this.__takeCount__); if (!isArr || (!isRight && arrLength == length && takeCount == length)) { return baseWrapperValue(array, this.__actions__); } var result = []; outer: while (length-- && resIndex < takeCount) { index += dir; var iterIndex = -1, value = array[index]; while (++iterIndex < iterLength) { var data = iteratees[iterIndex], iteratee = data.iteratee, type = data.type, computed = iteratee(value); if (type == LAZY_MAP_FLAG) { value = computed; } else if (!computed) { if (type == LAZY_FILTER_FLAG) { continue outer; } else { break outer; } } } result[resIndex++] = value; } return result; } // Ensure `LazyWrapper` is an instance of `baseLodash`. LazyWrapper.prototype = baseCreate(baseLodash.prototype); LazyWrapper.prototype.constructor = LazyWrapper; /*------------------------------------------------------------------------*/ /** * Creates a hash object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function Hash(entries) { var index = -1, length = entries == null ? 0 : entries.length; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the hash. * * @private * @name clear * @memberOf Hash */ function hashClear() { this.__data__ = nativeCreate ? nativeCreate(null) : {}; this.size = 0; } /** * Removes `key` and its value from the hash. * * @private * @name delete * @memberOf Hash * @param {Object} hash The hash to modify. * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function hashDelete(key) { var result = this.has(key) && delete this.__data__[key]; this.size -= result ? 1 : 0; return result; } /** * Gets the hash value for `key`. * * @private * @name get * @memberOf Hash * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function hashGet(key) { var data = this.__data__; if (nativeCreate) { var result = data[key]; return result === HASH_UNDEFINED ? undefined : result; } return hasOwnProperty.call(data, key) ? data[key] : undefined; } /** * Checks if a hash value for `key` exists. * * @private * @name has * @memberOf Hash * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function hashHas(key) { var data = this.__data__; return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); } /** * Sets the hash `key` to `value`. * * @private * @name set * @memberOf Hash * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the hash instance. */ function hashSet(key, value) { var data = this.__data__; this.size += this.has(key) ? 0 : 1; data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; return this; } // Add methods to `Hash`. Hash.prototype.clear = hashClear; Hash.prototype['delete'] = hashDelete; Hash.prototype.get = hashGet; Hash.prototype.has = hashHas; Hash.prototype.set = hashSet; /*------------------------------------------------------------------------*/ /** * Creates an list cache object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function ListCache(entries) { var index = -1, length = entries == null ? 0 : entries.length; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the list cache. * * @private * @name clear * @memberOf ListCache */ function listCacheClear() { this.__data__ = []; this.size = 0; } /** * Removes `key` and its value from the list cache. * * @private * @name delete * @memberOf ListCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function listCacheDelete(key) { var data = this.__data__, index = assocIndexOf(data, key); if (index < 0) { return false; } var lastIndex = data.length - 1; if (index == lastIndex) { data.pop(); } else { splice.call(data, index, 1); } --this.size; return true; } /** * Gets the list cache value for `key`. * * @private * @name get * @memberOf ListCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function listCacheGet(key) { var data = this.__data__, index = assocIndexOf(data, key); return index < 0 ? undefined : data[index][1]; } /** * Checks if a list cache value for `key` exists. * * @private * @name has * @memberOf ListCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function listCacheHas(key) { return assocIndexOf(this.__data__, key) > -1; } /** * Sets the list cache `key` to `value`. * * @private * @name set * @memberOf ListCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the list cache instance. */ function listCacheSet(key, value) { var data = this.__data__, index = assocIndexOf(data, key); if (index < 0) { ++this.size; data.push([key, value]); } else { data[index][1] = value; } return this; } // Add methods to `ListCache`. ListCache.prototype.clear = listCacheClear; ListCache.prototype['delete'] = listCacheDelete; ListCache.prototype.get = listCacheGet; ListCache.prototype.has = listCacheHas; ListCache.prototype.set = listCacheSet; /*------------------------------------------------------------------------*/ /** * Creates a map cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function MapCache(entries) { var index = -1, length = entries == null ? 0 : entries.length; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the map. * * @private * @name clear * @memberOf MapCache */ function mapCacheClear() { this.size = 0; this.__data__ = { 'hash': new Hash, 'map': new (Map || ListCache), 'string': new Hash }; } /** * Removes `key` and its value from the map. * * @private * @name delete * @memberOf MapCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function mapCacheDelete(key) { var result = getMapData(this, key)['delete'](key); this.size -= result ? 1 : 0; return result; } /** * Gets the map value for `key`. * * @private * @name get * @memberOf MapCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function mapCacheGet(key) { return getMapData(this, key).get(key); } /** * Checks if a map value for `key` exists. * * @private * @name has * @memberOf MapCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function mapCacheHas(key) { return getMapData(this, key).has(key); } /** * Sets the map `key` to `value`. * * @private * @name set * @memberOf MapCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the map cache instance. */ function mapCacheSet(key, value) { var data = getMapData(this, key), size = data.size; data.set(key, value); this.size += data.size == size ? 0 : 1; return this; } // Add methods to `MapCache`. MapCache.prototype.clear = mapCacheClear; MapCache.prototype['delete'] = mapCacheDelete; MapCache.prototype.get = mapCacheGet; MapCache.prototype.has = mapCacheHas; MapCache.prototype.set = mapCacheSet; /*------------------------------------------------------------------------*/ /** * * Creates an array cache object to store unique values. * * @private * @constructor * @param {Array} [values] The values to cache. */ function SetCache(values) { var index = -1, length = values == null ? 0 : values.length; this.__data__ = new MapCache; while (++index < length) { this.add(values[index]); } } /** * Adds `value` to the array cache. * * @private * @name add * @memberOf SetCache * @alias push * @param {*} value The value to cache. * @returns {Object} Returns the cache instance. */ function setCacheAdd(value) { this.__data__.set(value, HASH_UNDEFINED); return this; } /** * Checks if `value` is in the array cache. * * @private * @name has * @memberOf SetCache * @param {*} value The value to search for. * @returns {number} Returns `true` if `value` is found, else `false`. */ function setCacheHas(value) { return this.__data__.has(value); } // Add methods to `SetCache`. SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; SetCache.prototype.has = setCacheHas; /*------------------------------------------------------------------------*/ /** * Creates a stack cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function Stack(entries) { var data = this.__data__ = new ListCache(entries); this.size = data.size; } /** * Removes all key-value entries from the stack. * * @private * @name clear * @memberOf Stack */ function stackClear() { this.__data__ = new ListCache; this.size = 0; } /** * Removes `key` and its value from the stack. * * @private * @name delete * @memberOf Stack * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function stackDelete(key) { var data = this.__data__, result = data['delete'](key); this.size = data.size; return result; } /** * Gets the stack value for `key`. * * @private * @name get * @memberOf Stack * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function stackGet(key) { return this.__data__.get(key); } /** * Checks if a stack value for `key` exists. * * @private * @name has * @memberOf Stack * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function stackHas(key) { return this.__data__.has(key); } /** * Sets the stack `key` to `value`. * * @private * @name set * @memberOf Stack * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the stack cache instance. */ function stackSet(key, value) { var data = this.__data__; if (data instanceof ListCache) { var pairs = data.__data__; if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { pairs.push([key, value]); this.size = ++data.size; return this; } data = this.__data__ = new MapCache(pairs); } data.set(key, value); this.size = data.size; return this; } // Add methods to `Stack`. Stack.prototype.clear = stackClear; Stack.prototype['delete'] = stackDelete; Stack.prototype.get = stackGet; Stack.prototype.has = stackHas; Stack.prototype.set = stackSet; /*------------------------------------------------------------------------*/ /** * Creates an array of the enumerable property names of the array-like `value`. * * @private * @param {*} value The value to query. * @param {boolean} inherited Specify returning inherited property names. * @returns {Array} Returns the array of property names. */ function arrayLikeKeys(value, inherited) { var isArr = isArray(value), isArg = !isArr && isArguments(value), isBuff = !isArr && !isArg && isBuffer(value), isType = !isArr && !isArg && !isBuff && isTypedArray(value), skipIndexes = isArr || isArg || isBuff || isType, result = skipIndexes ? baseTimes(value.length, String) : [], length = result.length; for (var key in value) { if ((inherited || hasOwnProperty.call(value, key)) && !(skipIndexes && ( // Safari 9 has enumerable `arguments.length` in strict mode. key == 'length' || // Node.js 0.10 has enumerable non-index properties on buffers. (isBuff && (key == 'offset' || key == 'parent')) || // PhantomJS 2 has enumerable non-index properties on typed arrays. (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || // Skip index properties. isIndex(key, length) ))) { result.push(key); } } return result; } /** * A specialized version of `_.sample` for arrays. * * @private * @param {Array} array The array to sample. * @returns {*} Returns the random element. */ function arraySample(array) { var length = array.length; return length ? array[baseRandom(0, length - 1)] : undefined; } /** * A specialized version of `_.sampleSize` for arrays. * * @private * @param {Array} array The array to sample. * @param {number} n The number of elements to sample. * @returns {Array} Returns the random elements. */ function arraySampleSize(array, n) { return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); } /** * A specialized version of `_.shuffle` for arrays. * * @private * @param {Array} array The array to shuffle. * @returns {Array} Returns the new shuffled array. */ function arrayShuffle(array) { return shuffleSelf(copyArray(array)); } /** * This function is like `assignValue` except that it doesn't assign * `undefined` values. * * @private * @param {Object} object The object to modify. * @param {string} key The key of the property to assign. * @param {*} value The value to assign. */ function assignMergeValue(object, key, value) { if ((value !== undefined && !eq(object[key], value)) || (value === undefined && !(key in object))) { baseAssignValue(object, key, value); } } /** * Assigns `value` to `key` of `object` if the existing value is not equivalent * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons. * * @private * @param {Object} object The object to modify. * @param {string} key The key of the property to assign. * @param {*} value The value to assign. */ function assignValue(object, key, value) { var objValue = object[key]; if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || (value === undefined && !(key in object))) { baseAssignValue(object, key, value); } } /** * Gets the index at which the `key` is found in `array` of key-value pairs. * * @private * @param {Array} array The array to inspect. * @param {*} key The key to search for. * @returns {number} Returns the index of the matched value, else `-1`. */ function assocIndexOf(array, key) { var length = array.length; while (length--) { if (eq(array[length][0], key)) { return length; } } return -1; } /** * Aggregates elements of `collection` on `accumulator` with keys transformed * by `iteratee` and values set by `setter`. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} setter The function to set `accumulator` values. * @param {Function} iteratee The iteratee to transform keys. * @param {Object} accumulator The initial aggregated object. * @returns {Function} Returns `accumulator`. */ function baseAggregator(collection, setter, iteratee, accumulator) { baseEach(collection, function(value, key, collection) { setter(accumulator, value, iteratee(value), collection); }); return accumulator; } /** * The base implementation of `_.assign` without support for multiple sources * or `customizer` functions. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @returns {Object} Returns `object`. */ function baseAssign(object, source) { return object && copyObject(source, keys(source), object); } /** * The base implementation of `_.assignIn` without support for multiple sources * or `customizer` functions. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @returns {Object} Returns `object`. */ function baseAssignIn(object, source) { return object && copyObject(source, keysIn(source), object); } /** * The base implementation of `assignValue` and `assignMergeValue` without * value checks. * * @private * @param {Object} object The object to modify. * @param {string} key The key of the property to assign. * @param {*} value The value to assign. */ function baseAssignValue(object, key, value) { if (key == '__proto__' && defineProperty) { defineProperty(object, key, { 'configurable': true, 'enumerable': true, 'value': value, 'writable': true }); } else { object[key] = value; } } /** * The base implementation of `_.at` without support for individual paths. * * @private * @param {Object} object The object to iterate over. * @param {string[]} paths The property paths to pick. * @returns {Array} Returns the picked elements. */ function baseAt(object, paths) { var index = -1, length = paths.length, result = Array(length), skip = object == null; while (++index < length) { result[index] = skip ? undefined : get(object, paths[index]); } return result; } /** * The base implementation of `_.clamp` which doesn't coerce arguments. * * @private * @param {number} number The number to clamp. * @param {number} [lower] The lower bound. * @param {number} upper The upper bound. * @returns {number} Returns the clamped number. */ function baseClamp(number, lower, upper) { if (number === number) { if (upper !== undefined) { number = number <= upper ? number : upper; } if (lower !== undefined) { number = number >= lower ? number : lower; } } return number; } /** * The base implementation of `_.clone` and `_.cloneDeep` which tracks * traversed objects. * * @private * @param {*} value The value to clone. * @param {boolean} bitmask The bitmask flags. * 1 - Deep clone * 2 - Flatten inherited properties * 4 - Clone symbols * @param {Function} [customizer] The function to customize cloning. * @param {string} [key] The key of `value`. * @param {Object} [object] The parent object of `value`. * @param {Object} [stack] Tracks traversed objects and their clone counterparts. * @returns {*} Returns the cloned value. */ function baseClone(value, bitmask, customizer, key, object, stack) { var result, isDeep = bitmask & CLONE_DEEP_FLAG, isFlat = bitmask & CLONE_FLAT_FLAG, isFull = bitmask & CLONE_SYMBOLS_FLAG; if (customizer) { result = object ? customizer(value, key, object, stack) : customizer(value); } if (result !== undefined) { return result; } if (!isObject(value)) { return value; } var isArr = isArray(value); if (isArr) { result = initCloneArray(value); if (!isDeep) { return copyArray(value, result); } } else { var tag = getTag(value), isFunc = tag == funcTag || tag == genTag; if (isBuffer(value)) { return cloneBuffer(value, isDeep); } if (tag == objectTag || tag == argsTag || (isFunc && !object)) { result = (isFlat || isFunc) ? {} : initCloneObject(value); if (!isDeep) { return isFlat ? copySymbolsIn(value, baseAssignIn(result, value)) : copySymbols(value, baseAssign(result, value)); } } else { if (!cloneableTags[tag]) { return object ? value : {}; } result = initCloneByTag(value, tag, baseClone, isDeep); } } // Check for circular references and return its corresponding clone. stack || (stack = new Stack); var stacked = stack.get(value); if (stacked) { return stacked; } stack.set(value, result); var keysFunc = isFull ? (isFlat ? getAllKeysIn : getAllKeys) : (isFlat ? keysIn : keys); var props = isArr ? undefined : keysFunc(value); arrayEach(props || value, function(subValue, key) { if (props) { key = subValue; subValue = value[key]; } // Recursively populate clone (susceptible to call stack limits). assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); }); return result; } /** * The base implementation of `_.conforms` which doesn't clone `source`. * * @private * @param {Object} source The object of property predicates to conform to. * @returns {Function} Returns the new spec function. */ function baseConforms(source) { var props = keys(source); return function(object) { return baseConformsTo(object, source, props); }; } /** * The base implementation of `_.conformsTo` which accepts `props` to check. * * @private * @param {Object} object The object to inspect. * @param {Object} source The object of property predicates to conform to. * @returns {boolean} Returns `true` if `object` conforms, else `false`. */ function baseConformsTo(object, source, props) { var length = props.length; if (object == null) { return !length; } object = Object(object); while (length--) { var key = props[length], predicate = source[key], value = object[key]; if ((value === undefined && !(key in object)) || !predicate(value)) { return false; } } return true; } /** * The base implementation of `_.delay` and `_.defer` which accepts `args` * to provide to `func`. * * @private * @param {Function} func The function to delay. * @param {number} wait The number of milliseconds to delay invocation. * @param {Array} args The arguments to provide to `func`. * @returns {number|Object} Returns the timer id or timeout object. */ function baseDelay(func, wait, args) { if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } return setTimeout(function() { func.apply(undefined, args); }, wait); } /** * The base implementation of methods like `_.difference` without support * for excluding multiple arrays or iteratee shorthands. * * @private * @param {Array} array The array to inspect. * @param {Array} values The values to exclude. * @param {Function} [iteratee] The iteratee invoked per element. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of filtered values. */ function baseDifference(array, values, iteratee, comparator) { var index = -1, includes = arrayIncludes, isCommon = true, length = array.length, result = [], valuesLength = values.length; if (!length) { return result; } if (iteratee) { values = arrayMap(values, baseUnary(iteratee)); } if (comparator) { includes = arrayIncludesWith; isCommon = false; } else if (values.length >= LARGE_ARRAY_SIZE) { includes = cacheHas; isCommon = false; values = new SetCache(values); } outer: while (++index < length) { var value = array[index], computed = iteratee == null ? value : iteratee(value); value = (comparator || value !== 0) ? value : 0; if (isCommon && computed === computed) { var valuesIndex = valuesLength; while (valuesIndex--) { if (values[valuesIndex] === computed) { continue outer; } } result.push(value); } else if (!includes(values, computed, comparator)) { result.push(value); } } return result; } /** * The base implementation of `_.forEach` without support for iteratee shorthands. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array|Object} Returns `collection`. */ var baseEach = createBaseEach(baseForOwn); /** * The base implementation of `_.forEachRight` without support for iteratee shorthands. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array|Object} Returns `collection`. */ var baseEachRight = createBaseEach(baseForOwnRight, true); /** * The base implementation of `_.every` without support for iteratee shorthands. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if all elements pass the predicate check, * else `false` */ function baseEvery(collection, predicate) { var result = true; baseEach(collection, function(value, index, collection) { result = !!predicate(value, index, collection); return result; }); return result; } /** * The base implementation of methods like `_.max` and `_.min` which accepts a * `comparator` to determine the extremum value. * * @private * @param {Array} array The array to iterate over. * @param {Function} iteratee The iteratee invoked per iteration. * @param {Function} comparator The comparator used to compare values. * @returns {*} Returns the extremum value. */ function baseExtremum(array, iteratee, comparator) { var index = -1, length = array.length; while (++index < length) { var value = array[index], current = iteratee(value); if (current != null && (computed === undefined ? (current === current && !isSymbol(current)) : comparator(current, computed) )) { var computed = current, result = value; } } return result; } /** * The base implementation of `_.fill` without an iteratee call guard. * * @private * @param {Array} array The array to fill. * @param {*} value The value to fill `array` with. * @param {number} [start=0] The start position. * @param {number} [end=array.length] The end position. * @returns {Array} Returns `array`. */ function baseFill(array, value, start, end) { var length = array.length; start = toInteger(start); if (start < 0) { start = -start > length ? 0 : (length + start); } end = (end === undefined || end > length) ? length : toInteger(end); if (end < 0) { end += length; } end = start > end ? 0 : toLength(end); while (start < end) { array[start++] = value; } return array; } /** * The base implementation of `_.filter` without support for iteratee shorthands. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {Array} Returns the new filtered array. */ function baseFilter(collection, predicate) { var result = []; baseEach(collection, function(value, index, collection) { if (predicate(value, index, collection)) { result.push(value); } }); return result; } /** * The base implementation of `_.flatten` with support for restricting flattening. * * @private * @param {Array} array The array to flatten. * @param {number} depth The maximum recursion depth. * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. * @param {Array} [result=[]] The initial result value. * @returns {Array} Returns the new flattened array. */ function baseFlatten(array, depth, predicate, isStrict, result) { var index = -1, length = array.length; predicate || (predicate = isFlattenable); result || (result = []); while (++index < length) { var value = array[index]; if (depth > 0 && predicate(value)) { if (depth > 1) { // Recursively flatten arrays (susceptible to call stack limits). baseFlatten(value, depth - 1, predicate, isStrict, result); } else { arrayPush(result, value); } } else if (!isStrict) { result[result.length] = value; } } return result; } /** * The base implementation of `baseForOwn` which iterates over `object` * properties returned by `keysFunc` and invokes `iteratee` for each property. * Iteratee functions may exit iteration early by explicitly returning `false`. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {Function} keysFunc The function to get the keys of `object`. * @returns {Object} Returns `object`. */ var baseFor = createBaseFor(); /** * This function is like `baseFor` except that it iterates over properties * in the opposite order. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {Function} keysFunc The function to get the keys of `object`. * @returns {Object} Returns `object`. */ var baseForRight = createBaseFor(true); /** * The base implementation of `_.forOwn` without support for iteratee shorthands. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Object} Returns `object`. */ function baseForOwn(object, iteratee) { return object && baseFor(object, iteratee, keys); } /** * The base implementation of `_.forOwnRight` without support for iteratee shorthands. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Object} Returns `object`. */ function baseForOwnRight(object, iteratee) { return object && baseForRight(object, iteratee, keys); } /** * The base implementation of `_.functions` which creates an array of * `object` function property names filtered from `props`. * * @private * @param {Object} object The object to inspect. * @param {Array} props The property names to filter. * @returns {Array} Returns the function names. */ function baseFunctions(object, props) { return arrayFilter(props, function(key) { return isFunction(object[key]); }); } /** * The base implementation of `_.get` without support for default values. * * @private * @param {Object} object The object to query. * @param {Array|string} path The path of the property to get. * @returns {*} Returns the resolved value. */ function baseGet(object, path) { path = castPath(path, object); var index = 0, length = path.length; while (object != null && index < length) { object = object[toKey(path[index++])]; } return (index && index == length) ? object : undefined; } /** * The base implementation of `getAllKeys` and `getAllKeysIn` which uses * `keysFunc` and `symbolsFunc` to get the enumerable property names and * symbols of `object`. * * @private * @param {Object} object The object to query. * @param {Function} keysFunc The function to get the keys of `object`. * @param {Function} symbolsFunc The function to get the symbols of `object`. * @returns {Array} Returns the array of property names and symbols. */ function baseGetAllKeys(object, keysFunc, symbolsFunc) { var result = keysFunc(object); return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); } /** * The base implementation of `getTag` without fallbacks for buggy environments. * * @private * @param {*} value The value to query. * @returns {string} Returns the `toStringTag`. */ function baseGetTag(value) { if (value == null) { return value === undefined ? undefinedTag : nullTag; } return (symToStringTag && symToStringTag in Object(value)) ? getRawTag(value) : objectToString(value); } /** * The base implementation of `_.gt` which doesn't coerce arguments. * * @private * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if `value` is greater than `other`, * else `false`. */ function baseGt(value, other) { return value > other; } /** * The base implementation of `_.has` without support for deep paths. * * @private * @param {Object} [object] The object to query. * @param {Array|string} key The key to check. * @returns {boolean} Returns `true` if `key` exists, else `false`. */ function baseHas(object, key) { return object != null && hasOwnProperty.call(object, key); } /** * The base implementation of `_.hasIn` without support for deep paths. * * @private * @param {Object} [object] The object to query. * @param {Array|string} key The key to check. * @returns {boolean} Returns `true` if `key` exists, else `false`. */ function baseHasIn(object, key) { return object != null && key in Object(object); } /** * The base implementation of `_.inRange` which doesn't coerce arguments. * * @private * @param {number} number The number to check. * @param {number} start The start of the range. * @param {number} end The end of the range. * @returns {boolean} Returns `true` if `number` is in the range, else `false`. */ function baseInRange(number, start, end) { return number >= nativeMin(start, end) && number < nativeMax(start, end); } /** * The base implementation of methods like `_.intersection`, without support * for iteratee shorthands, that accepts an array of arrays to inspect. * * @private * @param {Array} arrays The arrays to inspect. * @param {Function} [iteratee] The iteratee invoked per element. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of shared values. */ function baseIntersection(arrays, iteratee, comparator) { var includes = comparator ? arrayIncludesWith : arrayIncludes, length = arrays[0].length, othLength = arrays.length, othIndex = othLength, caches = Array(othLength), maxLength = Infinity, result = []; while (othIndex--) { var array = arrays[othIndex]; if (othIndex && iteratee) { array = arrayMap(array, baseUnary(iteratee)); } maxLength = nativeMin(array.length, maxLength); caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) ? new SetCache(othIndex && array) : undefined; } array = arrays[0]; var index = -1, seen = caches[0]; outer: while (++index < length && result.length < maxLength) { var value = array[index], computed = iteratee ? iteratee(value) : value; value = (comparator || value !== 0) ? value : 0; if (!(seen ? cacheHas(seen, computed) : includes(result, computed, comparator) )) { othIndex = othLength; while (--othIndex) { var cache = caches[othIndex]; if (!(cache ? cacheHas(cache, computed) : includes(arrays[othIndex], computed, comparator)) ) { continue outer; } } if (seen) { seen.push(computed); } result.push(value); } } return result; } /** * The base implementation of `_.invert` and `_.invertBy` which inverts * `object` with values transformed by `iteratee` and set by `setter`. * * @private * @param {Object} object The object to iterate over. * @param {Function} setter The function to set `accumulator` values. * @param {Function} iteratee The iteratee to transform values. * @param {Object} accumulator The initial inverted object. * @returns {Function} Returns `accumulator`. */ function baseInverter(object, setter, iteratee, accumulator) { baseForOwn(object, function(value, key, object) { setter(accumulator, iteratee(value), key, object); }); return accumulator; } /** * The base implementation of `_.invoke` without support for individual * method arguments. * * @private * @param {Object} object The object to query. * @param {Array|string} path The path of the method to invoke. * @param {Array} args The arguments to invoke the method with. * @returns {*} Returns the result of the invoked method. */ function baseInvoke(object, path, args) { path = castPath(path, object); object = parent(object, path); var func = object == null ? object : object[toKey(last(path))]; return func == null ? undefined : apply(func, object, args); } /** * The base implementation of `_.isArguments`. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an `arguments` object, */ function baseIsArguments(value) { return isObjectLike(value) && baseGetTag(value) == argsTag; } /** * The base implementation of `_.isArrayBuffer` without Node.js optimizations. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. */ function baseIsArrayBuffer(value) { return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; } /** * The base implementation of `_.isDate` without Node.js optimizations. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a date object, else `false`. */ function baseIsDate(value) { return isObjectLike(value) && baseGetTag(value) == dateTag; } /** * The base implementation of `_.isEqual` which supports partial comparisons * and tracks traversed objects. * * @private * @param {*} value The value to compare. * @param {*} other The other value to compare. * @param {boolean} bitmask The bitmask flags. * 1 - Unordered comparison * 2 - Partial comparison * @param {Function} [customizer] The function to customize comparisons. * @param {Object} [stack] Tracks traversed `value` and `other` objects. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. */ function baseIsEqual(value, other, bitmask, customizer, stack) { if (value === other) { return true; } if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { return value !== value && other !== other; } return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); } /** * A specialized version of `baseIsEqual` for arrays and objects which performs * deep comparisons and tracks traversed objects enabling objects with circular * references to be compared. * * @private * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. * @param {Function} customizer The function to customize comparisons. * @param {Function} equalFunc The function to determine equivalents of values. * @param {Object} [stack] Tracks traversed `object` and `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { var objIsArr = isArray(object), othIsArr = isArray(other), objTag = objIsArr ? arrayTag : getTag(object), othTag = othIsArr ? arrayTag : getTag(other); objTag = objTag == argsTag ? objectTag : objTag; othTag = othTag == argsTag ? objectTag : othTag; var objIsObj = objTag == objectTag, othIsObj = othTag == objectTag, isSameTag = objTag == othTag; if (isSameTag && isBuffer(object)) { if (!isBuffer(other)) { return false; } objIsArr = true; objIsObj = false; } if (isSameTag && !objIsObj) { stack || (stack = new Stack); return (objIsArr || isTypedArray(object)) ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); } if (!(bitmask & COMPARE_PARTIAL_FLAG)) { var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); if (objIsWrapped || othIsWrapped) { var objUnwrapped = objIsWrapped ? object.value() : object, othUnwrapped = othIsWrapped ? other.value() : other; stack || (stack = new Stack); return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); } } if (!isSameTag) { return false; } stack || (stack = new Stack); return equalObjects(object, other, bitmask, customizer, equalFunc, stack); } /** * The base implementation of `_.isMap` without Node.js optimizations. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a map, else `false`. */ function baseIsMap(value) { return isObjectLike(value) && getTag(value) == mapTag; } /** * The base implementation of `_.isMatch` without support for iteratee shorthands. * * @private * @param {Object} object The object to inspect. * @param {Object} source The object of property values to match. * @param {Array} matchData The property names, values, and compare flags to match. * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if `object` is a match, else `false`. */ function baseIsMatch(object, source, matchData, customizer) { var index = matchData.length, length = index, noCustomizer = !customizer; if (object == null) { return !length; } object = Object(object); while (index--) { var data = matchData[index]; if ((noCustomizer && data[2]) ? data[1] !== object[data[0]] : !(data[0] in object) ) { return false; } } while (++index < length) { data = matchData[index]; var key = data[0], objValue = object[key], srcValue = data[1]; if (noCustomizer && data[2]) { if (objValue === undefined && !(key in object)) { return false; } } else { var stack = new Stack; if (customizer) { var result = customizer(objValue, srcValue, key, object, source, stack); } if (!(result === undefined ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) : result )) { return false; } } } return true; } /** * The base implementation of `_.isNative` without bad shim checks. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a native function, * else `false`. */ function baseIsNative(value) { if (!isObject(value) || isMasked(value)) { return false; } var pattern = isFunction(value) ? reIsNative : reIsHostCtor; return pattern.test(toSource(value)); } /** * The base implementation of `_.isRegExp` without Node.js optimizations. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. */ function baseIsRegExp(value) { return isObjectLike(value) && baseGetTag(value) == regexpTag; } /** * The base implementation of `_.isSet` without Node.js optimizations. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a set, else `false`. */ function baseIsSet(value) { return isObjectLike(value) && getTag(value) == setTag; } /** * The base implementation of `_.isTypedArray` without Node.js optimizations. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. */ function baseIsTypedArray(value) { return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; } /** * The base implementation of `_.iteratee`. * * @private * @param {*} [value=_.identity] The value to convert to an iteratee. * @returns {Function} Returns the iteratee. */ function baseIteratee(value) { // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. if (typeof value == 'function') { return value; } if (value == null) { return identity; } if (typeof value == 'object') { return isArray(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value); } return property(value); } /** * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. */ function baseKeys(object) { if (!isPrototype(object)) { return nativeKeys(object); } var result = []; for (var key in Object(object)) { if (hasOwnProperty.call(object, key) && key != 'constructor') { result.push(key); } } return result; } /** * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. */ function baseKeysIn(object) { if (!isObject(object)) { return nativeKeysIn(object); } var isProto = isPrototype(object), result = []; for (var key in object) { if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { result.push(key); } } return result; } /** * The base implementation of `_.lt` which doesn't coerce arguments. * * @private * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if `value` is less than `other`, * else `false`. */ function baseLt(value, other) { return value < other; } /** * The base implementation of `_.map` without support for iteratee shorthands. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the new mapped array. */ function baseMap(collection, iteratee) { var index = -1, result = isArrayLike(collection) ? Array(collection.length) : []; baseEach(collection, function(value, key, collection) { result[++index] = iteratee(value, key, collection); }); return result; } /** * The base implementation of `_.matches` which doesn't clone `source`. * * @private * @param {Object} source The object of property values to match. * @returns {Function} Returns the new spec function. */ function baseMatches(source) { var matchData = getMatchData(source); if (matchData.length == 1 && matchData[0][2]) { return matchesStrictComparable(matchData[0][0], matchData[0][1]); } return function(object) { return object === source || baseIsMatch(object, source, matchData); }; } /** * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. * * @private * @param {string} path The path of the property to get. * @param {*} srcValue The value to match. * @returns {Function} Returns the new spec function. */ function baseMatchesProperty(path, srcValue) { if (isKey(path) && isStrictComparable(srcValue)) { return matchesStrictComparable(toKey(path), srcValue); } return function(object) { var objValue = get(object, path); return (objValue === undefined && objValue === srcValue) ? hasIn(object, path) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); }; } /** * The base implementation of `_.merge` without support for multiple sources. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @param {number} srcIndex The index of `source`. * @param {Function} [customizer] The function to customize merged values. * @param {Object} [stack] Tracks traversed source values and their merged * counterparts. */ function baseMerge(object, source, srcIndex, customizer, stack) { if (object === source) { return; } baseFor(source, function(srcValue, key) { if (isObject(srcValue)) { stack || (stack = new Stack); baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); } else { var newValue = customizer ? customizer(object[key], srcValue, (key + ''), object, source, stack) : undefined; if (newValue === undefined) { newValue = srcValue; } assignMergeValue(object, key, newValue); } }, keysIn); } /** * A specialized version of `baseMerge` for arrays and objects which performs * deep merges and tracks traversed objects enabling objects with circular * references to be merged. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @param {string} key The key of the value to merge. * @param {number} srcIndex The index of `source`. * @param {Function} mergeFunc The function to merge values. * @param {Function} [customizer] The function to customize assigned values. * @param {Object} [stack] Tracks traversed source values and their merged * counterparts. */ function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { var objValue = object[key], srcValue = source[key], stacked = stack.get(srcValue); if (stacked) { assignMergeValue(object, key, stacked); return; } var newValue = customizer ? customizer(objValue, srcValue, (key + ''), object, source, stack) : undefined; var isCommon = newValue === undefined; if (isCommon) { var isArr = isArray(srcValue), isBuff = !isArr && isBuffer(srcValue), isTyped = !isArr && !isBuff && isTypedArray(srcValue); newValue = srcValue; if (isArr || isBuff || isTyped) { if (isArray(objValue)) { newValue = objValue; } else if (isArrayLikeObject(objValue)) { newValue = copyArray(objValue); } else if (isBuff) { isCommon = false; newValue = cloneBuffer(srcValue, true); } else if (isTyped) { isCommon = false; newValue = cloneTypedArray(srcValue, true); } else { newValue = []; } } else if (isPlainObject(srcValue) || isArguments(srcValue)) { newValue = objValue; if (isArguments(objValue)) { newValue = toPlainObject(objValue); } else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { newValue = initCloneObject(srcValue); } } else { isCommon = false; } } if (isCommon) { // Recursively merge objects and arrays (susceptible to call stack limits). stack.set(srcValue, newValue); mergeFunc(newValue, srcValue, srcIndex, customizer, stack); stack['delete'](srcValue); } assignMergeValue(object, key, newValue); } /** * The base implementation of `_.nth` which doesn't coerce arguments. * * @private * @param {Array} array The array to query. * @param {number} n The index of the element to return. * @returns {*} Returns the nth element of `array`. */ function baseNth(array, n) { var length = array.length; if (!length) { return; } n += n < 0 ? length : 0; return isIndex(n, length) ? array[n] : undefined; } /** * The base implementation of `_.orderBy` without param guards. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. * @param {string[]} orders The sort orders of `iteratees`. * @returns {Array} Returns the new sorted array. */ function baseOrderBy(collection, iteratees, orders) { var index = -1; iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); var result = baseMap(collection, function(value, key, collection) { var criteria = arrayMap(iteratees, function(iteratee) { return iteratee(value); }); return { 'criteria': criteria, 'index': ++index, 'value': value }; }); return baseSortBy(result, function(object, other) { return compareMultiple(object, other, orders); }); } /** * The base implementation of `_.pick` without support for individual * property identifiers. * * @private * @param {Object} object The source object. * @param {string[]} paths The property paths to pick. * @returns {Object} Returns the new object. */ function basePick(object, paths) { return basePickBy(object, paths, function(value, path) { return hasIn(object, path); }); } /** * The base implementation of `_.pickBy` without support for iteratee shorthands. * * @private * @param {Object} object The source object. * @param {string[]} paths The property paths to pick. * @param {Function} predicate The function invoked per property. * @returns {Object} Returns the new object. */ function basePickBy(object, paths, predicate) { var index = -1, length = paths.length, result = {}; while (++index < length) { var path = paths[index], value = baseGet(object, path); if (predicate(value, path)) { baseSet(result, castPath(path, object), value); } } return result; } /** * A specialized version of `baseProperty` which supports deep paths. * * @private * @param {Array|string} path The path of the property to get. * @returns {Function} Returns the new accessor function. */ function basePropertyDeep(path) { return function(object) { return baseGet(object, path); }; } /** * The base implementation of `_.pullAllBy` without support for iteratee * shorthands. * * @private * @param {Array} array The array to modify. * @param {Array} values The values to remove. * @param {Function} [iteratee] The iteratee invoked per element. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns `array`. */ function basePullAll(array, values, iteratee, comparator) { var indexOf = comparator ? baseIndexOfWith : baseIndexOf, index = -1, length = values.length, seen = array; if (array === values) { values = copyArray(values); } if (iteratee) { seen = arrayMap(array, baseUnary(iteratee)); } while (++index < length) { var fromIndex = 0, value = values[index], computed = iteratee ? iteratee(value) : value; while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { if (seen !== array) { splice.call(seen, fromIndex, 1); } splice.call(array, fromIndex, 1); } } return array; } /** * The base implementation of `_.pullAt` without support for individual * indexes or capturing the removed elements. * * @private * @param {Array} array The array to modify. * @param {number[]} indexes The indexes of elements to remove. * @returns {Array} Returns `array`. */ function basePullAt(array, indexes) { var length = array ? indexes.length : 0, lastIndex = length - 1; while (length--) { var index = indexes[length]; if (length == lastIndex || index !== previous) { var previous = index; if (isIndex(index)) { splice.call(array, index, 1); } else { baseUnset(array, index); } } } return array; } /** * The base implementation of `_.random` without support for returning * floating-point numbers. * * @private * @param {number} lower The lower bound. * @param {number} upper The upper bound. * @returns {number} Returns the random number. */ function baseRandom(lower, upper) { return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); } /** * The base implementation of `_.range` and `_.rangeRight` which doesn't * coerce arguments. * * @private * @param {number} start The start of the range. * @param {number} end The end of the range. * @param {number} step The value to increment or decrement by. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {Array} Returns the range of numbers. */ function baseRange(start, end, step, fromRight) { var index = -1, length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), result = Array(length); while (length--) { result[fromRight ? length : ++index] = start; start += step; } return result; } /** * The base implementation of `_.repeat` which doesn't coerce arguments. * * @private * @param {string} string The string to repeat. * @param {number} n The number of times to repeat the string. * @returns {string} Returns the repeated string. */ function baseRepeat(string, n) { var result = ''; if (!string || n < 1 || n > MAX_SAFE_INTEGER) { return result; } // Leverage the exponentiation by squaring algorithm for a faster repeat. // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. do { if (n % 2) { result += string; } n = nativeFloor(n / 2); if (n) { string += string; } } while (n); return result; } /** * The base implementation of `_.rest` which doesn't validate or coerce arguments. * * @private * @param {Function} func The function to apply a rest parameter to. * @param {number} [start=func.length-1] The start position of the rest parameter. * @returns {Function} Returns the new function. */ function baseRest(func, start) { return setToString(overRest(func, start, identity), func + ''); } /** * The base implementation of `_.sample`. * * @private * @param {Array|Object} collection The collection to sample. * @returns {*} Returns the random element. */ function baseSample(collection) { return arraySample(values(collection)); } /** * The base implementation of `_.sampleSize` without param guards. * * @private * @param {Array|Object} collection The collection to sample. * @param {number} n The number of elements to sample. * @returns {Array} Returns the random elements. */ function baseSampleSize(collection, n) { var array = values(collection); return shuffleSelf(array, baseClamp(n, 0, array.length)); } /** * The base implementation of `_.set`. * * @private * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to set. * @param {*} value The value to set. * @param {Function} [customizer] The function to customize path creation. * @returns {Object} Returns `object`. */ function baseSet(object, path, value, customizer) { if (!isObject(object)) { return object; } path = castPath(path, object); var index = -1, length = path.length, lastIndex = length - 1, nested = object; while (nested != null && ++index < length) { var key = toKey(path[index]), newValue = value; if (index != lastIndex) { var objValue = nested[key]; newValue = customizer ? customizer(objValue, key, nested) : undefined; if (newValue === undefined) { newValue = isObject(objValue) ? objValue : (isIndex(path[index + 1]) ? [] : {}); } } assignValue(nested, key, newValue); nested = nested[key]; } return object; } /** * The base implementation of `setData` without support for hot loop shorting. * * @private * @param {Function} func The function to associate metadata with. * @param {*} data The metadata. * @returns {Function} Returns `func`. */ var baseSetData = !metaMap ? identity : function(func, data) { metaMap.set(func, data); return func; }; /** * The base implementation of `setToString` without support for hot loop shorting. * * @private * @param {Function} func The function to modify. * @param {Function} string The `toString` result. * @returns {Function} Returns `func`. */ var baseSetToString = !defineProperty ? identity : function(func, string) { return defineProperty(func, 'toString', { 'configurable': true, 'enumerable': false, 'value': constant(string), 'writable': true }); }; /** * The base implementation of `_.shuffle`. * * @private * @param {Array|Object} collection The collection to shuffle. * @returns {Array} Returns the new shuffled array. */ function baseShuffle(collection) { return shuffleSelf(values(collection)); } /** * The base implementation of `_.slice` without an iteratee call guard. * * @private * @param {Array} array The array to slice. * @param {number} [start=0] The start position. * @param {number} [end=array.length] The end position. * @returns {Array} Returns the slice of `array`. */ function baseSlice(array, start, end) { var index = -1, length = array.length; if (start < 0) { start = -start > length ? 0 : (length + start); } end = end > length ? length : end; if (end < 0) { end += length; } length = start > end ? 0 : ((end - start) >>> 0); start >>>= 0; var result = Array(length); while (++index < length) { result[index] = array[index + start]; } return result; } /** * The base implementation of `_.some` without support for iteratee shorthands. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if any element passes the predicate check, * else `false`. */ function baseSome(collection, predicate) { var result; baseEach(collection, function(value, index, collection) { result = predicate(value, index, collection); return !result; }); return !!result; } /** * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which * performs a binary search of `array` to determine the index at which `value` * should be inserted into `array` in order to maintain its sort order. * * @private * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. * @param {boolean} [retHighest] Specify returning the highest qualified index. * @returns {number} Returns the index at which `value` should be inserted * into `array`. */ function baseSortedIndex(array, value, retHighest) { var low = 0, high = array == null ? low : array.length; if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { while (low < high) { var mid = (low + high) >>> 1, computed = array[mid]; if (computed !== null && !isSymbol(computed) && (retHighest ? (computed <= value) : (computed < value))) { low = mid + 1; } else { high = mid; } } return high; } return baseSortedIndexBy(array, value, identity, retHighest); } /** * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` * which invokes `iteratee` for `value` and each element of `array` to compute * their sort ranking. The iteratee is invoked with one argument; (value). * * @private * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. * @param {Function} iteratee The iteratee invoked per element. * @param {boolean} [retHighest] Specify returning the highest qualified index. * @returns {number} Returns the index at which `value` should be inserted * into `array`. */ function baseSortedIndexBy(array, value, iteratee, retHighest) { value = iteratee(value); var low = 0, high = array == null ? 0 : array.length, valIsNaN = value !== value, valIsNull = value === null, valIsSymbol = isSymbol(value), valIsUndefined = value === undefined; while (low < high) { var mid = nativeFloor((low + high) / 2), computed = iteratee(array[mid]), othIsDefined = computed !== undefined, othIsNull = computed === null, othIsReflexive = computed === computed, othIsSymbol = isSymbol(computed); if (valIsNaN) { var setLow = retHighest || othIsReflexive; } else if (valIsUndefined) { setLow = othIsReflexive && (retHighest || othIsDefined); } else if (valIsNull) { setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); } else if (valIsSymbol) { setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); } else if (othIsNull || othIsSymbol) { setLow = false; } else { setLow = retHighest ? (computed <= value) : (computed < value); } if (setLow) { low = mid + 1; } else { high = mid; } } return nativeMin(high, MAX_ARRAY_INDEX); } /** * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without * support for iteratee shorthands. * * @private * @param {Array} array The array to inspect. * @param {Function} [iteratee] The iteratee invoked per element. * @returns {Array} Returns the new duplicate free array. */ function baseSortedUniq(array, iteratee) { var index = -1, length = array.length, resIndex = 0, result = []; while (++index < length) { var value = array[index], computed = iteratee ? iteratee(value) : value; if (!index || !eq(computed, seen)) { var seen = computed; result[resIndex++] = value === 0 ? 0 : value; } } return result; } /** * The base implementation of `_.toNumber` which doesn't ensure correct * conversions of binary, hexadecimal, or octal string values. * * @private * @param {*} value The value to process. * @returns {number} Returns the number. */ function baseToNumber(value) { if (typeof value == 'number') { return value; } if (isSymbol(value)) { return NAN; } return +value; } /** * The base implementation of `_.toString` which doesn't convert nullish * values to empty strings. * * @private * @param {*} value The value to process. * @returns {string} Returns the string. */ function baseToString(value) { // Exit early for strings to avoid a performance hit in some environments. if (typeof value == 'string') { return value; } if (isArray(value)) { // Recursively convert values (susceptible to call stack limits). return arrayMap(value, baseToString) + ''; } if (isSymbol(value)) { return symbolToString ? symbolToString.call(value) : ''; } var result = (value + ''); return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; } /** * The base implementation of `_.uniqBy` without support for iteratee shorthands. * * @private * @param {Array} array The array to inspect. * @param {Function} [iteratee] The iteratee invoked per element. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new duplicate free array. */ function baseUniq(array, iteratee, comparator) { var index = -1, includes = arrayIncludes, length = array.length, isCommon = true, result = [], seen = result; if (comparator) { isCommon = false; includes = arrayIncludesWith; } else if (length >= LARGE_ARRAY_SIZE) { var set = iteratee ? null : createSet(array); if (set) { return setToArray(set); } isCommon = false; includes = cacheHas; seen = new SetCache; } else { seen = iteratee ? [] : result; } outer: while (++index < length) { var value = array[index], computed = iteratee ? iteratee(value) : value; value = (comparator || value !== 0) ? value : 0; if (isCommon && computed === computed) { var seenIndex = seen.length; while (seenIndex--) { if (seen[seenIndex] === computed) { continue outer; } } if (iteratee) { seen.push(computed); } result.push(value); } else if (!includes(seen, computed, comparator)) { if (seen !== result) { seen.push(computed); } result.push(value); } } return result; } /** * The base implementation of `_.unset`. * * @private * @param {Object} object The object to modify. * @param {Array|string} path The property path to unset. * @returns {boolean} Returns `true` if the property is deleted, else `false`. */ function baseUnset(object, path) { path = castPath(path, object); object = parent(object, path); return object == null || delete object[toKey(last(path))]; } /** * The base implementation of `_.update`. * * @private * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to update. * @param {Function} updater The function to produce the updated value. * @param {Function} [customizer] The function to customize path creation. * @returns {Object} Returns `object`. */ function baseUpdate(object, path, updater, customizer) { return baseSet(object, path, updater(baseGet(object, path)), customizer); } /** * The base implementation of methods like `_.dropWhile` and `_.takeWhile` * without support for iteratee shorthands. * * @private * @param {Array} array The array to query. * @param {Function} predicate The function invoked per iteration. * @param {boolean} [isDrop] Specify dropping elements instead of taking them. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {Array} Returns the slice of `array`. */ function baseWhile(array, predicate, isDrop, fromRight) { var length = array.length, index = fromRight ? length : -1; while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {} return isDrop ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); } /** * The base implementation of `wrapperValue` which returns the result of * performing a sequence of actions on the unwrapped `value`, where each * successive action is supplied the return value of the previous. * * @private * @param {*} value The unwrapped value. * @param {Array} actions Actions to perform to resolve the unwrapped value. * @returns {*} Returns the resolved value. */ function baseWrapperValue(value, actions) { var result = value; if (result instanceof LazyWrapper) { result = result.value(); } return arrayReduce(actions, function(result, action) { return action.func.apply(action.thisArg, arrayPush([result], action.args)); }, result); } /** * The base implementation of methods like `_.xor`, without support for * iteratee shorthands, that accepts an array of arrays to inspect. * * @private * @param {Array} arrays The arrays to inspect. * @param {Function} [iteratee] The iteratee invoked per element. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of values. */ function baseXor(arrays, iteratee, comparator) { var length = arrays.length; if (length < 2) { return length ? baseUniq(arrays[0]) : []; } var index = -1, result = Array(length); while (++index < length) { var array = arrays[index], othIndex = -1; while (++othIndex < length) { if (othIndex != index) { result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); } } } return baseUniq(baseFlatten(result, 1), iteratee, comparator); } /** * This base implementation of `_.zipObject` which assigns values using `assignFunc`. * * @private * @param {Array} props The property identifiers. * @param {Array} values The property values. * @param {Function} assignFunc The function to assign values. * @returns {Object} Returns the new object. */ function baseZipObject(props, values, assignFunc) { var index = -1, length = props.length, valsLength = values.length, result = {}; while (++index < length) { var value = index < valsLength ? values[index] : undefined; assignFunc(result, props[index], value); } return result; } /** * Casts `value` to an empty array if it's not an array like object. * * @private * @param {*} value The value to inspect. * @returns {Array|Object} Returns the cast array-like object. */ function castArrayLikeObject(value) { return isArrayLikeObject(value) ? value : []; } /** * Casts `value` to `identity` if it's not a function. * * @private * @param {*} value The value to inspect. * @returns {Function} Returns cast function. */ function castFunction(value) { return typeof value == 'function' ? value : identity; } /** * Casts `value` to a path array if it's not one. * * @private * @param {*} value The value to inspect. * @param {Object} [object] The object to query keys on. * @returns {Array} Returns the cast property path array. */ function castPath(value, object) { if (isArray(value)) { return value; } return isKey(value, object) ? [value] : stringToPath(toString(value)); } /** * A `baseRest` alias which can be replaced with `identity` by module * replacement plugins. * * @private * @type {Function} * @param {Function} func The function to apply a rest parameter to. * @returns {Function} Returns the new function. */ var castRest = baseRest; /** * Casts `array` to a slice if it's needed. * * @private * @param {Array} array The array to inspect. * @param {number} start The start position. * @param {number} [end=array.length] The end position. * @returns {Array} Returns the cast slice. */ function castSlice(array, start, end) { var length = array.length; end = end === undefined ? length : end; return (!start && end >= length) ? array : baseSlice(array, start, end); } /** * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). * * @private * @param {number|Object} id The timer id or timeout object of the timer to clear. */ var clearTimeout = ctxClearTimeout || function(id) { return root.clearTimeout(id); }; /** * Creates a clone of `buffer`. * * @private * @param {Buffer} buffer The buffer to clone. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Buffer} Returns the cloned buffer. */ function cloneBuffer(buffer, isDeep) { if (isDeep) { return buffer.slice(); } var length = buffer.length, result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); buffer.copy(result); return result; } /** * Creates a clone of `arrayBuffer`. * * @private * @param {ArrayBuffer} arrayBuffer The array buffer to clone. * @returns {ArrayBuffer} Returns the cloned array buffer. */ function cloneArrayBuffer(arrayBuffer) { var result = new arrayBuffer.constructor(arrayBuffer.byteLength); new Uint8Array(result).set(new Uint8Array(arrayBuffer)); return result; } /** * Creates a clone of `dataView`. * * @private * @param {Object} dataView The data view to clone. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Object} Returns the cloned data view. */ function cloneDataView(dataView, isDeep) { var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); } /** * Creates a clone of `map`. * * @private * @param {Object} map The map to clone. * @param {Function} cloneFunc The function to clone values. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Object} Returns the cloned map. */ function cloneMap(map, isDeep, cloneFunc) { var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map); return arrayReduce(array, addMapEntry, new map.constructor); } /** * Creates a clone of `regexp`. * * @private * @param {Object} regexp The regexp to clone. * @returns {Object} Returns the cloned regexp. */ function cloneRegExp(regexp) { var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); result.lastIndex = regexp.lastIndex; return result; } /** * Creates a clone of `set`. * * @private * @param {Object} set The set to clone. * @param {Function} cloneFunc The function to clone values. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Object} Returns the cloned set. */ function cloneSet(set, isDeep, cloneFunc) { var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set); return arrayReduce(array, addSetEntry, new set.constructor); } /** * Creates a clone of the `symbol` object. * * @private * @param {Object} symbol The symbol object to clone. * @returns {Object} Returns the cloned symbol object. */ function cloneSymbol(symbol) { return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; } /** * Creates a clone of `typedArray`. * * @private * @param {Object} typedArray The typed array to clone. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Object} Returns the cloned typed array. */ function cloneTypedArray(typedArray, isDeep) { var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); } /** * Compares values to sort them in ascending order. * * @private * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {number} Returns the sort order indicator for `value`. */ function compareAscending(value, other) { if (value !== other) { var valIsDefined = value !== undefined, valIsNull = value === null, valIsReflexive = value === value, valIsSymbol = isSymbol(value); var othIsDefined = other !== undefined, othIsNull = other === null, othIsReflexive = other === other, othIsSymbol = isSymbol(other); if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || (valIsNull && othIsDefined && othIsReflexive) || (!valIsDefined && othIsReflexive) || !valIsReflexive) { return 1; } if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || (othIsNull && valIsDefined && valIsReflexive) || (!othIsDefined && valIsReflexive) || !othIsReflexive) { return -1; } } return 0; } /** * Used by `_.orderBy` to compare multiple properties of a value to another * and stable sort them. * * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, * specify an order of "desc" for descending or "asc" for ascending sort order * of corresponding values. * * @private * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {boolean[]|string[]} orders The order to sort by for each property. * @returns {number} Returns the sort order indicator for `object`. */ function compareMultiple(object, other, orders) { var index = -1, objCriteria = object.criteria, othCriteria = other.criteria, length = objCriteria.length, ordersLength = orders.length; while (++index < length) { var result = compareAscending(objCriteria[index], othCriteria[index]); if (result) { if (index >= ordersLength) { return result; } var order = orders[index]; return result * (order == 'desc' ? -1 : 1); } } // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications // that causes it, under certain circumstances, to provide the same value for // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 // for more details. // // This also ensures a stable sort in V8 and other engines. // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. return object.index - other.index; } /** * Creates an array that is the composition of partially applied arguments, * placeholders, and provided arguments into a single array of arguments. * * @private * @param {Array} args The provided arguments. * @param {Array} partials The arguments to prepend to those provided. * @param {Array} holders The `partials` placeholder indexes. * @params {boolean} [isCurried] Specify composing for a curried function. * @returns {Array} Returns the new array of composed arguments. */ function composeArgs(args, partials, holders, isCurried) { var argsIndex = -1, argsLength = args.length, holdersLength = holders.length, leftIndex = -1, leftLength = partials.length, rangeLength = nativeMax(argsLength - holdersLength, 0), result = Array(leftLength + rangeLength), isUncurried = !isCurried; while (++leftIndex < leftLength) { result[leftIndex] = partials[leftIndex]; } while (++argsIndex < holdersLength) { if (isUncurried || argsIndex < argsLength) { result[holders[argsIndex]] = args[argsIndex]; } } while (rangeLength--) { result[leftIndex++] = args[argsIndex++]; } return result; } /** * This function is like `composeArgs` except that the arguments composition * is tailored for `_.partialRight`. * * @private * @param {Array} args The provided arguments. * @param {Array} partials The arguments to append to those provided. * @param {Array} holders The `partials` placeholder indexes. * @params {boolean} [isCurried] Specify composing for a curried function. * @returns {Array} Returns the new array of composed arguments. */ function composeArgsRight(args, partials, holders, isCurried) { var argsIndex = -1, argsLength = args.length, holdersIndex = -1, holdersLength = holders.length, rightIndex = -1, rightLength = partials.length, rangeLength = nativeMax(argsLength - holdersLength, 0), result = Array(rangeLength + rightLength), isUncurried = !isCurried; while (++argsIndex < rangeLength) { result[argsIndex] = args[argsIndex]; } var offset = argsIndex; while (++rightIndex < rightLength) { result[offset + rightIndex] = partials[rightIndex]; } while (++holdersIndex < holdersLength) { if (isUncurried || argsIndex < argsLength) { result[offset + holders[holdersIndex]] = args[argsIndex++]; } } return result; } /** * Copies the values of `source` to `array`. * * @private * @param {Array} source The array to copy values from. * @param {Array} [array=[]] The array to copy values to. * @returns {Array} Returns `array`. */ function copyArray(source, array) { var index = -1, length = source.length; array || (array = Array(length)); while (++index < length) { array[index] = source[index]; } return array; } /** * Copies properties of `source` to `object`. * * @private * @param {Object} source The object to copy properties from. * @param {Array} props The property identifiers to copy. * @param {Object} [object={}] The object to copy properties to. * @param {Function} [customizer] The function to customize copied values. * @returns {Object} Returns `object`. */ function copyObject(source, props, object, customizer) { var isNew = !object; object || (object = {}); var index = -1, length = props.length; while (++index < length) { var key = props[index]; var newValue = customizer ? customizer(object[key], source[key], key, object, source) : undefined; if (newValue === undefined) { newValue = source[key]; } if (isNew) { baseAssignValue(object, key, newValue); } else { assignValue(object, key, newValue); } } return object; } /** * Copies own symbols of `source` to `object`. * * @private * @param {Object} source The object to copy symbols from. * @param {Object} [object={}] The object to copy symbols to. * @returns {Object} Returns `object`. */ function copySymbols(source, object) { return copyObject(source, getSymbols(source), object); } /** * Copies own and inherited symbols of `source` to `object`. * * @private * @param {Object} source The object to copy symbols from. * @param {Object} [object={}] The object to copy symbols to. * @returns {Object} Returns `object`. */ function copySymbolsIn(source, object) { return copyObject(source, getSymbolsIn(source), object); } /** * Creates a function like `_.groupBy`. * * @private * @param {Function} setter The function to set accumulator values. * @param {Function} [initializer] The accumulator object initializer. * @returns {Function} Returns the new aggregator function. */ function createAggregator(setter, initializer) { return function(collection, iteratee) { var func = isArray(collection) ? arrayAggregator : baseAggregator, accumulator = initializer ? initializer() : {}; return func(collection, setter, getIteratee(iteratee, 2), accumulator); }; } /** * Creates a function like `_.assign`. * * @private * @param {Function} assigner The function to assign values. * @returns {Function} Returns the new assigner function. */ function createAssigner(assigner) { return baseRest(function(object, sources) { var index = -1, length = sources.length, customizer = length > 1 ? sources[length - 1] : undefined, guard = length > 2 ? sources[2] : undefined; customizer = (assigner.length > 3 && typeof customizer == 'function') ? (length--, customizer) : undefined; if (guard && isIterateeCall(sources[0], sources[1], guard)) { customizer = length < 3 ? undefined : customizer; length = 1; } object = Object(object); while (++index < length) { var source = sources[index]; if (source) { assigner(object, source, index, customizer); } } return object; }); } /** * Creates a `baseEach` or `baseEachRight` function. * * @private * @param {Function} eachFunc The function to iterate over a collection. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {Function} Returns the new base function. */ function createBaseEach(eachFunc, fromRight) { return function(collection, iteratee) { if (collection == null) { return collection; } if (!isArrayLike(collection)) { return eachFunc(collection, iteratee); } var length = collection.length, index = fromRight ? length : -1, iterable = Object(collection); while ((fromRight ? index-- : ++index < length)) { if (iteratee(iterable[index], index, iterable) === false) { break; } } return collection; }; } /** * Creates a base function for methods like `_.forIn` and `_.forOwn`. * * @private * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {Function} Returns the new base function. */ function createBaseFor(fromRight) { return function(object, iteratee, keysFunc) { var index = -1, iterable = Object(object), props = keysFunc(object), length = props.length; while (length--) { var key = props[fromRight ? length : ++index]; if (iteratee(iterable[key], key, iterable) === false) { break; } } return object; }; } /** * Creates a function that wraps `func` to invoke it with the optional `this` * binding of `thisArg`. * * @private * @param {Function} func The function to wrap. * @param {number} bitmask The bitmask flags. See `createWrap` for more details. * @param {*} [thisArg] The `this` binding of `func`. * @returns {Function} Returns the new wrapped function. */ function createBind(func, bitmask, thisArg) { var isBind = bitmask & WRAP_BIND_FLAG, Ctor = createCtor(func); function wrapper() { var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; return fn.apply(isBind ? thisArg : this, arguments); } return wrapper; } /** * Creates a function like `_.lowerFirst`. * * @private * @param {string} methodName The name of the `String` case method to use. * @returns {Function} Returns the new case function. */ function createCaseFirst(methodName) { return function(string) { string = toString(string); var strSymbols = hasUnicode(string) ? stringToArray(string) : undefined; var chr = strSymbols ? strSymbols[0] : string.charAt(0); var trailing = strSymbols ? castSlice(strSymbols, 1).join('') : string.slice(1); return chr[methodName]() + trailing; }; } /** * Creates a function like `_.camelCase`. * * @private * @param {Function} callback The function to combine each word. * @returns {Function} Returns the new compounder function. */ function createCompounder(callback) { return function(string) { return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); }; } /** * Creates a function that produces an instance of `Ctor` regardless of * whether it was invoked as part of a `new` expression or by `call` or `apply`. * * @private * @param {Function} Ctor The constructor to wrap. * @returns {Function} Returns the new wrapped function. */ function createCtor(Ctor) { return function() { // Use a `switch` statement to work with class constructors. See // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist // for more details. var args = arguments; switch (args.length) { case 0: return new Ctor; case 1: return new Ctor(args[0]); case 2: return new Ctor(args[0], args[1]); case 3: return new Ctor(args[0], args[1], args[2]); case 4: return new Ctor(args[0], args[1], args[2], args[3]); case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); } var thisBinding = baseCreate(Ctor.prototype), result = Ctor.apply(thisBinding, args); // Mimic the constructor's `return` behavior. // See https://es5.github.io/#x13.2.2 for more details. return isObject(result) ? result : thisBinding; }; } /** * Creates a function that wraps `func` to enable currying. * * @private * @param {Function} func The function to wrap. * @param {number} bitmask The bitmask flags. See `createWrap` for more details. * @param {number} arity The arity of `func`. * @returns {Function} Returns the new wrapped function. */ function createCurry(func, bitmask, arity) { var Ctor = createCtor(func); function wrapper() { var length = arguments.length, args = Array(length), index = length, placeholder = getHolder(wrapper); while (index--) { args[index] = arguments[index]; } var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) ? [] : replaceHolders(args, placeholder); length -= holders.length; if (length < arity) { return createRecurry( func, bitmask, createHybrid, wrapper.placeholder, undefined, args, holders, undefined, undefined, arity - length); } var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; return apply(fn, this, args); } return wrapper; } /** * Creates a `_.find` or `_.findLast` function. * * @private * @param {Function} findIndexFunc The function to find the collection index. * @returns {Function} Returns the new find function. */ function createFind(findIndexFunc) { return function(collection, predicate, fromIndex) { var iterable = Object(collection); if (!isArrayLike(collection)) { var iteratee = getIteratee(predicate, 3); collection = keys(collection); predicate = function(key) { return iteratee(iterable[key], key, iterable); }; } var index = findIndexFunc(collection, predicate, fromIndex); return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; }; } /** * Creates a `_.flow` or `_.flowRight` function. * * @private * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {Function} Returns the new flow function. */ function createFlow(fromRight) { return flatRest(function(funcs) { var length = funcs.length, index = length, prereq = LodashWrapper.prototype.thru; if (fromRight) { funcs.reverse(); } while (index--) { var func = funcs[index]; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } if (prereq && !wrapper && getFuncName(func) == 'wrapper') { var wrapper = new LodashWrapper([], true); } } index = wrapper ? index : length; while (++index < length) { func = funcs[index]; var funcName = getFuncName(func), data = funcName == 'wrapper' ? getData(func) : undefined; if (data && isLaziable(data[0]) && data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && !data[4].length && data[9] == 1 ) { wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); } else { wrapper = (func.length == 1 && isLaziable(func)) ? wrapper[funcName]() : wrapper.thru(func); } } return function() { var args = arguments, value = args[0]; if (wrapper && args.length == 1 && isArray(value)) { return wrapper.plant(value).value(); } var index = 0, result = length ? funcs[index].apply(this, args) : value; while (++index < length) { result = funcs[index].call(this, result); } return result; }; }); } /** * Creates a function that wraps `func` to invoke it with optional `this` * binding of `thisArg`, partial application, and currying. * * @private * @param {Function|string} func The function or method name to wrap. * @param {number} bitmask The bitmask flags. See `createWrap` for more details. * @param {*} [thisArg] The `this` binding of `func`. * @param {Array} [partials] The arguments to prepend to those provided to * the new function. * @param {Array} [holders] The `partials` placeholder indexes. * @param {Array} [partialsRight] The arguments to append to those provided * to the new function. * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. * @param {Array} [argPos] The argument positions of the new function. * @param {number} [ary] The arity cap of `func`. * @param {number} [arity] The arity of `func`. * @returns {Function} Returns the new wrapped function. */ function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { var isAry = bitmask & WRAP_ARY_FLAG, isBind = bitmask & WRAP_BIND_FLAG, isBindKey = bitmask & WRAP_BIND_KEY_FLAG, isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), isFlip = bitmask & WRAP_FLIP_FLAG, Ctor = isBindKey ? undefined : createCtor(func); function wrapper() { var length = arguments.length, args = Array(length), index = length; while (index--) { args[index] = arguments[index]; } if (isCurried) { var placeholder = getHolder(wrapper), holdersCount = countHolders(args, placeholder); } if (partials) { args = composeArgs(args, partials, holders, isCurried); } if (partialsRight) { args = composeArgsRight(args, partialsRight, holdersRight, isCurried); } length -= holdersCount; if (isCurried && length < arity) { var newHolders = replaceHolders(args, placeholder); return createRecurry( func, bitmask, createHybrid, wrapper.placeholder, thisArg, args, newHolders, argPos, ary, arity - length ); } var thisBinding = isBind ? thisArg : this, fn = isBindKey ? thisBinding[func] : func; length = args.length; if (argPos) { args = reorder(args, argPos); } else if (isFlip && length > 1) { args.reverse(); } if (isAry && ary < length) { args.length = ary; } if (this && this !== root && this instanceof wrapper) { fn = Ctor || createCtor(fn); } return fn.apply(thisBinding, args); } return wrapper; } /** * Creates a function like `_.invertBy`. * * @private * @param {Function} setter The function to set accumulator values. * @param {Function} toIteratee The function to resolve iteratees. * @returns {Function} Returns the new inverter function. */ function createInverter(setter, toIteratee) { return function(object, iteratee) { return baseInverter(object, setter, toIteratee(iteratee), {}); }; } /** * Creates a function that performs a mathematical operation on two values. * * @private * @param {Function} operator The function to perform the operation. * @param {number} [defaultValue] The value used for `undefined` arguments. * @returns {Function} Returns the new mathematical operation function. */ function createMathOperation(operator, defaultValue) { return function(value, other) { var result; if (value === undefined && other === undefined) { return defaultValue; } if (value !== undefined) { result = value; } if (other !== undefined) { if (result === undefined) { return other; } if (typeof value == 'string' || typeof other == 'string') { value = baseToString(value); other = baseToString(other); } else { value = baseToNumber(value); other = baseToNumber(other); } result = operator(value, other); } return result; }; } /** * Creates a function like `_.over`. * * @private * @param {Function} arrayFunc The function to iterate over iteratees. * @returns {Function} Returns the new over function. */ function createOver(arrayFunc) { return flatRest(function(iteratees) { iteratees = arrayMap(iteratees, baseUnary(getIteratee())); return baseRest(function(args) { var thisArg = this; return arrayFunc(iteratees, function(iteratee) { return apply(iteratee, thisArg, args); }); }); }); } /** * Creates the padding for `string` based on `length`. The `chars` string * is truncated if the number of characters exceeds `length`. * * @private * @param {number} length The padding length. * @param {string} [chars=' '] The string used as padding. * @returns {string} Returns the padding for `string`. */ function createPadding(length, chars) { chars = chars === undefined ? ' ' : baseToString(chars); var charsLength = chars.length; if (charsLength < 2) { return charsLength ? baseRepeat(chars, length) : chars; } var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); return hasUnicode(chars) ? castSlice(stringToArray(result), 0, length).join('') : result.slice(0, length); } /** * Creates a function that wraps `func` to invoke it with the `this` binding * of `thisArg` and `partials` prepended to the arguments it receives. * * @private * @param {Function} func The function to wrap. * @param {number} bitmask The bitmask flags. See `createWrap` for more details. * @param {*} thisArg The `this` binding of `func`. * @param {Array} partials The arguments to prepend to those provided to * the new function. * @returns {Function} Returns the new wrapped function. */ function createPartial(func, bitmask, thisArg, partials) { var isBind = bitmask & WRAP_BIND_FLAG, Ctor = createCtor(func); function wrapper() { var argsIndex = -1, argsLength = arguments.length, leftIndex = -1, leftLength = partials.length, args = Array(leftLength + argsLength), fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; while (++leftIndex < leftLength) { args[leftIndex] = partials[leftIndex]; } while (argsLength--) { args[leftIndex++] = arguments[++argsIndex]; } return apply(fn, isBind ? thisArg : this, args); } return wrapper; } /** * Creates a `_.range` or `_.rangeRight` function. * * @private * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {Function} Returns the new range function. */ function createRange(fromRight) { return function(start, end, step) { if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { end = step = undefined; } // Ensure the sign of `-0` is preserved. start = toFinite(start); if (end === undefined) { end = start; start = 0; } else { end = toFinite(end); } step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); return baseRange(start, end, step, fromRight); }; } /** * Creates a function that performs a relational operation on two values. * * @private * @param {Function} operator The function to perform the operation. * @returns {Function} Returns the new relational operation function. */ function createRelationalOperation(operator) { return function(value, other) { if (!(typeof value == 'string' && typeof other == 'string')) { value = toNumber(value); other = toNumber(other); } return operator(value, other); }; } /** * Creates a function that wraps `func` to continue currying. * * @private * @param {Function} func The function to wrap. * @param {number} bitmask The bitmask flags. See `createWrap` for more details. * @param {Function} wrapFunc The function to create the `func` wrapper. * @param {*} placeholder The placeholder value. * @param {*} [thisArg] The `this` binding of `func`. * @param {Array} [partials] The arguments to prepend to those provided to * the new function. * @param {Array} [holders] The `partials` placeholder indexes. * @param {Array} [argPos] The argument positions of the new function. * @param {number} [ary] The arity cap of `func`. * @param {number} [arity] The arity of `func`. * @returns {Function} Returns the new wrapped function. */ function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { var isCurry = bitmask & WRAP_CURRY_FLAG, newHolders = isCurry ? holders : undefined, newHoldersRight = isCurry ? undefined : holders, newPartials = isCurry ? partials : undefined, newPartialsRight = isCurry ? undefined : partials; bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); } var newData = [ func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, newHoldersRight, argPos, ary, arity ]; var result = wrapFunc.apply(undefined, newData); if (isLaziable(func)) { setData(result, newData); } result.placeholder = placeholder; return setWrapToString(result, func, bitmask); } /** * Creates a function like `_.round`. * * @private * @param {string} methodName The name of the `Math` method to use when rounding. * @returns {Function} Returns the new round function. */ function createRound(methodName) { var func = Math[methodName]; return function(number, precision) { number = toNumber(number); precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); if (precision) { // Shift with exponential notation to avoid floating-point issues. // See [MDN](https://mdn.io/round#Examples) for more details. var pair = (toString(number) + 'e').split('e'), value = func(pair[0] + 'e' + (+pair[1] + precision)); pair = (toString(value) + 'e').split('e'); return +(pair[0] + 'e' + (+pair[1] - precision)); } return func(number); }; } /** * Creates a set object of `values`. * * @private * @param {Array} values The values to add to the set. * @returns {Object} Returns the new set. */ var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { return new Set(values); }; /** * Creates a `_.toPairs` or `_.toPairsIn` function. * * @private * @param {Function} keysFunc The function to get the keys of a given object. * @returns {Function} Returns the new pairs function. */ function createToPairs(keysFunc) { return function(object) { var tag = getTag(object); if (tag == mapTag) { return mapToArray(object); } if (tag == setTag) { return setToPairs(object); } return baseToPairs(object, keysFunc(object)); }; } /** * Creates a function that either curries or invokes `func` with optional * `this` binding and partially applied arguments. * * @private * @param {Function|string} func The function or method name to wrap. * @param {number} bitmask The bitmask flags. * 1 - `_.bind` * 2 - `_.bindKey` * 4 - `_.curry` or `_.curryRight` of a bound function * 8 - `_.curry` * 16 - `_.curryRight` * 32 - `_.partial` * 64 - `_.partialRight` * 128 - `_.rearg` * 256 - `_.ary` * 512 - `_.flip` * @param {*} [thisArg] The `this` binding of `func`. * @param {Array} [partials] The arguments to be partially applied. * @param {Array} [holders] The `partials` placeholder indexes. * @param {Array} [argPos] The argument positions of the new function. * @param {number} [ary] The arity cap of `func`. * @param {number} [arity] The arity of `func`. * @returns {Function} Returns the new wrapped function. */ function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; if (!isBindKey && typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } var length = partials ? partials.length : 0; if (!length) { bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); partials = holders = undefined; } ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); arity = arity === undefined ? arity : toInteger(arity); length -= holders ? holders.length : 0; if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { var partialsRight = partials, holdersRight = holders; partials = holders = undefined; } var data = isBindKey ? undefined : getData(func); var newData = [ func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity ]; if (data) { mergeData(newData, data); } func = newData[0]; bitmask = newData[1]; thisArg = newData[2]; partials = newData[3]; holders = newData[4]; arity = newData[9] = newData[9] === undefined ? (isBindKey ? 0 : func.length) : nativeMax(newData[9] - length, 0); if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); } if (!bitmask || bitmask == WRAP_BIND_FLAG) { var result = createBind(func, bitmask, thisArg); } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { result = createCurry(func, bitmask, arity); } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { result = createPartial(func, bitmask, thisArg, partials); } else { result = createHybrid.apply(undefined, newData); } var setter = data ? baseSetData : setData; return setWrapToString(setter(result, newData), func, bitmask); } /** * Used by `_.defaults` to customize its `_.assignIn` use to assign properties * of source objects to the destination object for all destination properties * that resolve to `undefined`. * * @private * @param {*} objValue The destination value. * @param {*} srcValue The source value. * @param {string} key The key of the property to assign. * @param {Object} object The parent object of `objValue`. * @returns {*} Returns the value to assign. */ function customDefaultsAssignIn(objValue, srcValue, key, object) { if (objValue === undefined || (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { return srcValue; } return objValue; } /** * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source * objects into destination objects that are passed thru. * * @private * @param {*} objValue The destination value. * @param {*} srcValue The source value. * @param {string} key The key of the property to merge. * @param {Object} object The parent object of `objValue`. * @param {Object} source The parent object of `srcValue`. * @param {Object} [stack] Tracks traversed source values and their merged * counterparts. * @returns {*} Returns the value to assign. */ function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { if (isObject(objValue) && isObject(srcValue)) { // Recursively merge objects and arrays (susceptible to call stack limits). stack.set(srcValue, objValue); baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); stack['delete'](srcValue); } return objValue; } /** * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain * objects. * * @private * @param {*} value The value to inspect. * @param {string} key The key of the property to inspect. * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. */ function customOmitClone(value) { return isPlainObject(value) ? undefined : value; } /** * A specialized version of `baseIsEqualDeep` for arrays with support for * partial deep comparisons. * * @private * @param {Array} array The array to compare. * @param {Array} other The other array to compare. * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. * @param {Function} customizer The function to customize comparisons. * @param {Function} equalFunc The function to determine equivalents of values. * @param {Object} stack Tracks traversed `array` and `other` objects. * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. */ function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array.length, othLength = other.length; if (arrLength != othLength && !(isPartial && othLength > arrLength)) { return false; } // Assume cyclic values are equal. var stacked = stack.get(array); if (stacked && stack.get(other)) { return stacked == other; } var index = -1, result = true, seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; stack.set(array, other); stack.set(other, array); // Ignore non-index properties. while (++index < arrLength) { var arrValue = array[index], othValue = other[index]; if (customizer) { var compared = isPartial ? customizer(othValue, arrValue, index, other, array, stack) : customizer(arrValue, othValue, index, array, other, stack); } if (compared !== undefined) { if (compared) { continue; } result = false; break; } // Recursively compare arrays (susceptible to call stack limits). if (seen) { if (!arraySome(other, function(othValue, othIndex) { if (!cacheHas(seen, othIndex) && (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { return seen.push(othIndex); } })) { result = false; break; } } else if (!( arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack) )) { result = false; break; } } stack['delete'](array); stack['delete'](other); return result; } /** * A specialized version of `baseIsEqualDeep` for comparing objects of * the same `toStringTag`. * * **Note:** This function only supports comparing values with tags of * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. * * @private * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {string} tag The `toStringTag` of the objects to compare. * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. * @param {Function} customizer The function to customize comparisons. * @param {Function} equalFunc The function to determine equivalents of values. * @param {Object} stack Tracks traversed `object` and `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { switch (tag) { case dataViewTag: if ((object.byteLength != other.byteLength) || (object.byteOffset != other.byteOffset)) { return false; } object = object.buffer; other = other.buffer; case arrayBufferTag: if ((object.byteLength != other.byteLength) || !equalFunc(new Uint8Array(object), new Uint8Array(other))) { return false; } return true; case boolTag: case dateTag: case numberTag: // Coerce booleans to `1` or `0` and dates to milliseconds. // Invalid dates are coerced to `NaN`. return eq(+object, +other); case errorTag: return object.name == other.name && object.message == other.message; case regexpTag: case stringTag: // Coerce regexes to strings and treat strings, primitives and objects, // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring // for more details. return object == (other + ''); case mapTag: var convert = mapToArray; case setTag: var isPartial = bitmask & COMPARE_PARTIAL_FLAG; convert || (convert = setToArray); if (object.size != other.size && !isPartial) { return false; } // Assume cyclic values are equal. var stacked = stack.get(object); if (stacked) { return stacked == other; } bitmask |= COMPARE_UNORDERED_FLAG; // Recursively compare objects (susceptible to call stack limits). stack.set(object, other); var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); stack['delete'](object); return result; case symbolTag: if (symbolValueOf) { return symbolValueOf.call(object) == symbolValueOf.call(other); } } return false; } /** * A specialized version of `baseIsEqualDeep` for objects with support for * partial deep comparisons. * * @private * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. * @param {Function} customizer The function to customize comparisons. * @param {Function} equalFunc The function to determine equivalents of values. * @param {Object} stack Tracks traversed `object` and `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { var isPartial = bitmask & COMPARE_PARTIAL_FLAG, objProps = getAllKeys(object), objLength = objProps.length, othProps = getAllKeys(other), othLength = othProps.length; if (objLength != othLength && !isPartial) { return false; } var index = objLength; while (index--) { var key = objProps[index]; if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { return false; } } // Assume cyclic values are equal. var stacked = stack.get(object); if (stacked && stack.get(other)) { return stacked == other; } var result = true; stack.set(object, other); stack.set(other, object); var skipCtor = isPartial; while (++index < objLength) { key = objProps[index]; var objValue = object[key], othValue = other[key]; if (customizer) { var compared = isPartial ? customizer(othValue, objValue, key, other, object, stack) : customizer(objValue, othValue, key, object, other, stack); } // Recursively compare objects (susceptible to call stack limits). if (!(compared === undefined ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) : compared )) { result = false; break; } skipCtor || (skipCtor = key == 'constructor'); } if (result && !skipCtor) { var objCtor = object.constructor, othCtor = other.constructor; // Non `Object` object instances with different constructors are not equal. if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) && !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) { result = false; } } stack['delete'](object); stack['delete'](other); return result; } /** * A specialized version of `baseRest` which flattens the rest array. * * @private * @param {Function} func The function to apply a rest parameter to. * @returns {Function} Returns the new function. */ function flatRest(func) { return setToString(overRest(func, undefined, flatten), func + ''); } /** * Creates an array of own enumerable property names and symbols of `object`. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of property names and symbols. */ function getAllKeys(object) { return baseGetAllKeys(object, keys, getSymbols); } /** * Creates an array of own and inherited enumerable property names and * symbols of `object`. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of property names and symbols. */ function getAllKeysIn(object) { return baseGetAllKeys(object, keysIn, getSymbolsIn); } /** * Gets metadata for `func`. * * @private * @param {Function} func The function to query. * @returns {*} Returns the metadata for `func`. */ var getData = !metaMap ? noop : function(func) { return metaMap.get(func); }; /** * Gets the name of `func`. * * @private * @param {Function} func The function to query. * @returns {string} Returns the function name. */ function getFuncName(func) { var result = (func.name + ''), array = realNames[result], length = hasOwnProperty.call(realNames, result) ? array.length : 0; while (length--) { var data = array[length], otherFunc = data.func; if (otherFunc == null || otherFunc == func) { return data.name; } } return result; } /** * Gets the argument placeholder value for `func`. * * @private * @param {Function} func The function to inspect. * @returns {*} Returns the placeholder value. */ function getHolder(func) { var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; return object.placeholder; } /** * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, * this function returns the custom method, otherwise it returns `baseIteratee`. * If arguments are provided, the chosen function is invoked with them and * its result is returned. * * @private * @param {*} [value] The value to convert to an iteratee. * @param {number} [arity] The arity of the created iteratee. * @returns {Function} Returns the chosen function or its result. */ function getIteratee() { var result = lodash.iteratee || iteratee; result = result === iteratee ? baseIteratee : result; return arguments.length ? result(arguments[0], arguments[1]) : result; } /** * Gets the data for `map`. * * @private * @param {Object} map The map to query. * @param {string} key The reference key. * @returns {*} Returns the map data. */ function getMapData(map, key) { var data = map.__data__; return isKeyable(key) ? data[typeof key == 'string' ? 'string' : 'hash'] : data.map; } /** * Gets the property names, values, and compare flags of `object`. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the match data of `object`. */ function getMatchData(object) { var result = keys(object), length = result.length; while (length--) { var key = result[length], value = object[key]; result[length] = [key, value, isStrictComparable(value)]; } return result; } /** * Gets the native function at `key` of `object`. * * @private * @param {Object} object The object to query. * @param {string} key The key of the method to get. * @returns {*} Returns the function if it's native, else `undefined`. */ function getNative(object, key) { var value = getValue(object, key); return baseIsNative(value) ? value : undefined; } /** * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. * * @private * @param {*} value The value to query. * @returns {string} Returns the raw `toStringTag`. */ function getRawTag(value) { var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag]; try { value[symToStringTag] = undefined; var unmasked = true; } catch (e) {} var result = nativeObjectToString.call(value); if (unmasked) { if (isOwn) { value[symToStringTag] = tag; } else { delete value[symToStringTag]; } } return result; } /** * Creates an array of the own enumerable symbols of `object`. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of symbols. */ var getSymbols = !nativeGetSymbols ? stubArray : function(object) { if (object == null) { return []; } object = Object(object); return arrayFilter(nativeGetSymbols(object), function(symbol) { return propertyIsEnumerable.call(object, symbol); }); }; /** * Creates an array of the own and inherited enumerable symbols of `object`. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of symbols. */ var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { var result = []; while (object) { arrayPush(result, getSymbols(object)); object = getPrototype(object); } return result; }; /** * Gets the `toStringTag` of `value`. * * @private * @param {*} value The value to query. * @returns {string} Returns the `toStringTag`. */ var getTag = baseGetTag; // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || (Map && getTag(new Map) != mapTag) || (Promise && getTag(Promise.resolve()) != promiseTag) || (Set && getTag(new Set) != setTag) || (WeakMap && getTag(new WeakMap) != weakMapTag)) { getTag = function(value) { var result = baseGetTag(value), Ctor = result == objectTag ? value.constructor : undefined, ctorString = Ctor ? toSource(Ctor) : ''; if (ctorString) { switch (ctorString) { case dataViewCtorString: return dataViewTag; case mapCtorString: return mapTag; case promiseCtorString: return promiseTag; case setCtorString: return setTag; case weakMapCtorString: return weakMapTag; } } return result; }; } /** * Gets the view, applying any `transforms` to the `start` and `end` positions. * * @private * @param {number} start The start of the view. * @param {number} end The end of the view. * @param {Array} transforms The transformations to apply to the view. * @returns {Object} Returns an object containing the `start` and `end` * positions of the view. */ function getView(start, end, transforms) { var index = -1, length = transforms.length; while (++index < length) { var data = transforms[index], size = data.size; switch (data.type) { case 'drop': start += size; break; case 'dropRight': end -= size; break; case 'take': end = nativeMin(end, start + size); break; case 'takeRight': start = nativeMax(start, end - size); break; } } return { 'start': start, 'end': end }; } /** * Extracts wrapper details from the `source` body comment. * * @private * @param {string} source The source to inspect. * @returns {Array} Returns the wrapper details. */ function getWrapDetails(source) { var match = source.match(reWrapDetails); return match ? match[1].split(reSplitDetails) : []; } /** * Checks if `path` exists on `object`. * * @private * @param {Object} object The object to query. * @param {Array|string} path The path to check. * @param {Function} hasFunc The function to check properties. * @returns {boolean} Returns `true` if `path` exists, else `false`. */ function hasPath(object, path, hasFunc) { path = castPath(path, object); var index = -1, length = path.length, result = false; while (++index < length) { var key = toKey(path[index]); if (!(result = object != null && hasFunc(object, key))) { break; } object = object[key]; } if (result || ++index != length) { return result; } length = object == null ? 0 : object.length; return !!length && isLength(length) && isIndex(key, length) && (isArray(object) || isArguments(object)); } /** * Initializes an array clone. * * @private * @param {Array} array The array to clone. * @returns {Array} Returns the initialized clone. */ function initCloneArray(array) { var length = array.length, result = array.constructor(length); // Add properties assigned by `RegExp#exec`. if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { result.index = array.index; result.input = array.input; } return result; } /** * Initializes an object clone. * * @private * @param {Object} object The object to clone. * @returns {Object} Returns the initialized clone. */ function initCloneObject(object) { return (typeof object.constructor == 'function' && !isPrototype(object)) ? baseCreate(getPrototype(object)) : {}; } /** * Initializes an object clone based on its `toStringTag`. * * **Note:** This function only supports cloning values with tags of * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. * * @private * @param {Object} object The object to clone. * @param {string} tag The `toStringTag` of the object to clone. * @param {Function} cloneFunc The function to clone values. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Object} Returns the initialized clone. */ function initCloneByTag(object, tag, cloneFunc, isDeep) { var Ctor = object.constructor; switch (tag) { case arrayBufferTag: return cloneArrayBuffer(object); case boolTag: case dateTag: return new Ctor(+object); case dataViewTag: return cloneDataView(object, isDeep); case float32Tag: case float64Tag: case int8Tag: case int16Tag: case int32Tag: case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: return cloneTypedArray(object, isDeep); case mapTag: return cloneMap(object, isDeep, cloneFunc); case numberTag: case stringTag: return new Ctor(object); case regexpTag: return cloneRegExp(object); case setTag: return cloneSet(object, isDeep, cloneFunc); case symbolTag: return cloneSymbol(object); } } /** * Inserts wrapper `details` in a comment at the top of the `source` body. * * @private * @param {string} source The source to modify. * @returns {Array} details The details to insert. * @returns {string} Returns the modified source. */ function insertWrapDetails(source, details) { var length = details.length; if (!length) { return source; } var lastIndex = length - 1; details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; details = details.join(length > 2 ? ', ' : ' '); return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); } /** * Checks if `value` is a flattenable `arguments` object or array. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. */ function isFlattenable(value) { return isArray(value) || isArguments(value) || !!(spreadableSymbol && value && value[spreadableSymbol]); } /** * Checks if `value` is a valid array-like index. * * @private * @param {*} value The value to check. * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. */ function isIndex(value, length) { length = length == null ? MAX_SAFE_INTEGER : length; return !!length && (typeof value == 'number' || reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length); } /** * Checks if the given arguments are from an iteratee call. * * @private * @param {*} value The potential iteratee value argument. * @param {*} index The potential iteratee index or key argument. * @param {*} object The potential iteratee object argument. * @returns {boolean} Returns `true` if the arguments are from an iteratee call, * else `false`. */ function isIterateeCall(value, index, object) { if (!isObject(object)) { return false; } var type = typeof index; if (type == 'number' ? (isArrayLike(object) && isIndex(index, object.length)) : (type == 'string' && index in object) ) { return eq(object[index], value); } return false; } /** * Checks if `value` is a property name and not a property path. * * @private * @param {*} value The value to check. * @param {Object} [object] The object to query keys on. * @returns {boolean} Returns `true` if `value` is a property name, else `false`. */ function isKey(value, object) { if (isArray(value)) { return false; } var type = typeof value; if (type == 'number' || type == 'symbol' || type == 'boolean' || value == null || isSymbol(value)) { return true; } return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || (object != null && value in Object(object)); } /** * Checks if `value` is suitable for use as unique object key. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is suitable, else `false`. */ function isKeyable(value) { var type = typeof value; return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') ? (value !== '__proto__') : (value === null); } /** * Checks if `func` has a lazy counterpart. * * @private * @param {Function} func The function to check. * @returns {boolean} Returns `true` if `func` has a lazy counterpart, * else `false`. */ function isLaziable(func) { var funcName = getFuncName(func), other = lodash[funcName]; if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { return false; } if (func === other) { return true; } var data = getData(other); return !!data && func === data[0]; } /** * Checks if `func` has its source masked. * * @private * @param {Function} func The function to check. * @returns {boolean} Returns `true` if `func` is masked, else `false`. */ function isMasked(func) { return !!maskSrcKey && (maskSrcKey in func); } /** * Checks if `func` is capable of being masked. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `func` is maskable, else `false`. */ var isMaskable = coreJsData ? isFunction : stubFalse; /** * Checks if `value` is likely a prototype object. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. */ function isPrototype(value) { var Ctor = value && value.constructor, proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; return value === proto; } /** * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` if suitable for strict * equality comparisons, else `false`. */ function isStrictComparable(value) { return value === value && !isObject(value); } /** * A specialized version of `matchesProperty` for source values suitable * for strict equality comparisons, i.e. `===`. * * @private * @param {string} key The key of the property to get. * @param {*} srcValue The value to match. * @returns {Function} Returns the new spec function. */ function matchesStrictComparable(key, srcValue) { return function(object) { if (object == null) { return false; } return object[key] === srcValue && (srcValue !== undefined || (key in Object(object))); }; } /** * A specialized version of `_.memoize` which clears the memoized function's * cache when it exceeds `MAX_MEMOIZE_SIZE`. * * @private * @param {Function} func The function to have its output memoized. * @returns {Function} Returns the new memoized function. */ function memoizeCapped(func) { var result = memoize(func, function(key) { if (cache.size === MAX_MEMOIZE_SIZE) { cache.clear(); } return key; }); var cache = result.cache; return result; } /** * Merges the function metadata of `source` into `data`. * * Merging metadata reduces the number of wrappers used to invoke a function. * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` * may be applied regardless of execution order. Methods like `_.ary` and * `_.rearg` modify function arguments, making the order in which they are * executed important, preventing the merging of metadata. However, we make * an exception for a safe combined case where curried functions have `_.ary` * and or `_.rearg` applied. * * @private * @param {Array} data The destination metadata. * @param {Array} source The source metadata. * @returns {Array} Returns `data`. */ function mergeData(data, source) { var bitmask = data[1], srcBitmask = source[1], newBitmask = bitmask | srcBitmask, isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); var isCombo = ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); // Exit early if metadata can't be merged. if (!(isCommon || isCombo)) { return data; } // Use source `thisArg` if available. if (srcBitmask & WRAP_BIND_FLAG) { data[2] = source[2]; // Set when currying a bound function. newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; } // Compose partial arguments. var value = source[3]; if (value) { var partials = data[3]; data[3] = partials ? composeArgs(partials, value, source[4]) : value; data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; } // Compose partial right arguments. value = source[5]; if (value) { partials = data[5]; data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; } // Use source `argPos` if available. value = source[7]; if (value) { data[7] = value; } // Use source `ary` if it's smaller. if (srcBitmask & WRAP_ARY_FLAG) { data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); } // Use source `arity` if one is not provided. if (data[9] == null) { data[9] = source[9]; } // Use source `func` and merge bitmasks. data[0] = source[0]; data[1] = newBitmask; return data; } /** * This function is like * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) * except that it includes inherited enumerable properties. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. */ function nativeKeysIn(object) { var result = []; if (object != null) { for (var key in Object(object)) { result.push(key); } } return result; } /** * Converts `value` to a string using `Object.prototype.toString`. * * @private * @param {*} value The value to convert. * @returns {string} Returns the converted string. */ function objectToString(value) { return nativeObjectToString.call(value); } /** * A specialized version of `baseRest` which transforms the rest array. * * @private * @param {Function} func The function to apply a rest parameter to. * @param {number} [start=func.length-1] The start position of the rest parameter. * @param {Function} transform The rest array transform. * @returns {Function} Returns the new function. */ function overRest(func, start, transform) { start = nativeMax(start === undefined ? (func.length - 1) : start, 0); return function() { var args = arguments, index = -1, length = nativeMax(args.length - start, 0), array = Array(length); while (++index < length) { array[index] = args[start + index]; } index = -1; var otherArgs = Array(start + 1); while (++index < start) { otherArgs[index] = args[index]; } otherArgs[start] = transform(array); return apply(func, this, otherArgs); }; } /** * Gets the parent value at `path` of `object`. * * @private * @param {Object} object The object to query. * @param {Array} path The path to get the parent value of. * @returns {*} Returns the parent value. */ function parent(object, path) { return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); } /** * Reorder `array` according to the specified indexes where the element at * the first index is assigned as the first element, the element at * the second index is assigned as the second element, and so on. * * @private * @param {Array} array The array to reorder. * @param {Array} indexes The arranged array indexes. * @returns {Array} Returns `array`. */ function reorder(array, indexes) { var arrLength = array.length, length = nativeMin(indexes.length, arrLength), oldArray = copyArray(array); while (length--) { var index = indexes[length]; array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; } return array; } /** * Sets metadata for `func`. * * **Note:** If this function becomes hot, i.e. is invoked a lot in a short * period of time, it will trip its breaker and transition to an identity * function to avoid garbage collection pauses in V8. See * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) * for more details. * * @private * @param {Function} func The function to associate metadata with. * @param {*} data The metadata. * @returns {Function} Returns `func`. */ var setData = shortOut(baseSetData); /** * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). * * @private * @param {Function} func The function to delay. * @param {number} wait The number of milliseconds to delay invocation. * @returns {number|Object} Returns the timer id or timeout object. */ var setTimeout = ctxSetTimeout || function(func, wait) { return root.setTimeout(func, wait); }; /** * Sets the `toString` method of `func` to return `string`. * * @private * @param {Function} func The function to modify. * @param {Function} string The `toString` result. * @returns {Function} Returns `func`. */ var setToString = shortOut(baseSetToString); /** * Sets the `toString` method of `wrapper` to mimic the source of `reference` * with wrapper details in a comment at the top of the source body. * * @private * @param {Function} wrapper The function to modify. * @param {Function} reference The reference function. * @param {number} bitmask The bitmask flags. See `createWrap` for more details. * @returns {Function} Returns `wrapper`. */ function setWrapToString(wrapper, reference, bitmask) { var source = (reference + ''); return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); } /** * Creates a function that'll short out and invoke `identity` instead * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` * milliseconds. * * @private * @param {Function} func The function to restrict. * @returns {Function} Returns the new shortable function. */ function shortOut(func) { var count = 0, lastCalled = 0; return function() { var stamp = nativeNow(), remaining = HOT_SPAN - (stamp - lastCalled); lastCalled = stamp; if (remaining > 0) { if (++count >= HOT_COUNT) { return arguments[0]; } } else { count = 0; } return func.apply(undefined, arguments); }; } /** * A specialized version of `_.shuffle` which mutates and sets the size of `array`. * * @private * @param {Array} array The array to shuffle. * @param {number} [size=array.length] The size of `array`. * @returns {Array} Returns `array`. */ function shuffleSelf(array, size) { var index = -1, length = array.length, lastIndex = length - 1; size = size === undefined ? length : size; while (++index < size) { var rand = baseRandom(index, lastIndex), value = array[rand]; array[rand] = array[index]; array[index] = value; } array.length = size; return array; } /** * Converts `string` to a property path array. * * @private * @param {string} string The string to convert. * @returns {Array} Returns the property path array. */ var stringToPath = memoizeCapped(function(string) { var result = []; if (reLeadingDot.test(string)) { result.push(''); } string.replace(rePropName, function(match, number, quote, string) { result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); }); return result; }); /** * Converts `value` to a string key if it's not a string or symbol. * * @private * @param {*} value The value to inspect. * @returns {string|symbol} Returns the key. */ function toKey(value) { if (typeof value == 'string' || isSymbol(value)) { return value; } var result = (value + ''); return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; } /** * Converts `func` to its source code. * * @private * @param {Function} func The function to convert. * @returns {string} Returns the source code. */ function toSource(func) { if (func != null) { try { return funcToString.call(func); } catch (e) {} try { return (func + ''); } catch (e) {} } return ''; } /** * Updates wrapper `details` based on `bitmask` flags. * * @private * @returns {Array} details The details to modify. * @param {number} bitmask The bitmask flags. See `createWrap` for more details. * @returns {Array} Returns `details`. */ function updateWrapDetails(details, bitmask) { arrayEach(wrapFlags, function(pair) { var value = '_.' + pair[0]; if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { details.push(value); } }); return details.sort(); } /** * Creates a clone of `wrapper`. * * @private * @param {Object} wrapper The wrapper to clone. * @returns {Object} Returns the cloned wrapper. */ function wrapperClone(wrapper) { if (wrapper instanceof LazyWrapper) { return wrapper.clone(); } var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); result.__actions__ = copyArray(wrapper.__actions__); result.__index__ = wrapper.__index__; result.__values__ = wrapper.__values__; return result; } /*------------------------------------------------------------------------*/ /** * Creates an array of elements split into groups the length of `size`. * If `array` can't be split evenly, the final chunk will be the remaining * elements. * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to process. * @param {number} [size=1] The length of each chunk * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Array} Returns the new array of chunks. * @example * * _.chunk(['a', 'b', 'c', 'd'], 2); * // => [['a', 'b'], ['c', 'd']] * * _.chunk(['a', 'b', 'c', 'd'], 3); * // => [['a', 'b', 'c'], ['d']] */ function chunk(array, size, guard) { if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { size = 1; } else { size = nativeMax(toInteger(size), 0); } var length = array == null ? 0 : array.length; if (!length || size < 1) { return []; } var index = 0, resIndex = 0, result = Array(nativeCeil(length / size)); while (index < length) { result[resIndex++] = baseSlice(array, index, (index += size)); } return result; } /** * Creates an array with all falsey values removed. The values `false`, `null`, * `0`, `""`, `undefined`, and `NaN` are falsey. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to compact. * @returns {Array} Returns the new array of filtered values. * @example * * _.compact([0, 1, false, 2, '', 3]); * // => [1, 2, 3] */ function compact(array) { var index = -1, length = array == null ? 0 : array.length, resIndex = 0, result = []; while (++index < length) { var value = array[index]; if (value) { result[resIndex++] = value; } } return result; } /** * Creates a new array concatenating `array` with any additional arrays * and/or values. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to concatenate. * @param {...*} [values] The values to concatenate. * @returns {Array} Returns the new concatenated array. * @example * * var array = [1]; * var other = _.concat(array, 2, [3], [[4]]); * * console.log(other); * // => [1, 2, 3, [4]] * * console.log(array); * // => [1] */ function concat() { var length = arguments.length; if (!length) { return []; } var args = Array(length - 1), array = arguments[0], index = length; while (index--) { args[index - 1] = arguments[index]; } return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); } /** * Creates an array of `array` values not included in the other given arrays * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons. The order and references of result values are * determined by the first array. * * **Note:** Unlike `_.pullAll`, this method returns a new array. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to inspect. * @param {...Array} [values] The values to exclude. * @returns {Array} Returns the new array of filtered values. * @see _.without, _.xor * @example * * _.difference([2, 1], [2, 3]); * // => [1] */ var difference = baseRest(function(array, values) { return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) : []; }); /** * This method is like `_.difference` except that it accepts `iteratee` which * is invoked for each element of `array` and `values` to generate the criterion * by which they're compared. The order and references of result values are * determined by the first array. The iteratee is invoked with one argument: * (value). * * **Note:** Unlike `_.pullAllBy`, this method returns a new array. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {...Array} [values] The values to exclude. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {Array} Returns the new array of filtered values. * @example * * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); * // => [1.2] * * // The `_.property` iteratee shorthand. * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); * // => [{ 'x': 2 }] */ var differenceBy = baseRest(function(array, values) { var iteratee = last(values); if (isArrayLikeObject(iteratee)) { iteratee = undefined; } return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) : []; }); /** * This method is like `_.difference` except that it accepts `comparator` * which is invoked to compare elements of `array` to `values`. The order and * references of result values are determined by the first array. The comparator * is invoked with two arguments: (arrVal, othVal). * * **Note:** Unlike `_.pullAllWith`, this method returns a new array. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {...Array} [values] The values to exclude. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of filtered values. * @example * * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; * * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); * // => [{ 'x': 2, 'y': 1 }] */ var differenceWith = baseRest(function(array, values) { var comparator = last(values); if (isArrayLikeObject(comparator)) { comparator = undefined; } return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) : []; }); /** * Creates a slice of `array` with `n` elements dropped from the beginning. * * @static * @memberOf _ * @since 0.5.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to drop. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * * _.drop([1, 2, 3]); * // => [2, 3] * * _.drop([1, 2, 3], 2); * // => [3] * * _.drop([1, 2, 3], 5); * // => [] * * _.drop([1, 2, 3], 0); * // => [1, 2, 3] */ function drop(array, n, guard) { var length = array == null ? 0 : array.length; if (!length) { return []; } n = (guard || n === undefined) ? 1 : toInteger(n); return baseSlice(array, n < 0 ? 0 : n, length); } /** * Creates a slice of `array` with `n` elements dropped from the end. * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to drop. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * * _.dropRight([1, 2, 3]); * // => [1, 2] * * _.dropRight([1, 2, 3], 2); * // => [1] * * _.dropRight([1, 2, 3], 5); * // => [] * * _.dropRight([1, 2, 3], 0); * // => [1, 2, 3] */ function dropRight(array, n, guard) { var length = array == null ? 0 : array.length; if (!length) { return []; } n = (guard || n === undefined) ? 1 : toInteger(n); n = length - n; return baseSlice(array, 0, n < 0 ? 0 : n); } /** * Creates a slice of `array` excluding elements dropped from the end. * Elements are dropped until `predicate` returns falsey. The predicate is * invoked with three arguments: (value, index, array). * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * * _.dropRightWhile(users, function(o) { return !o.active; }); * // => objects for ['barney'] * * // The `_.matches` iteratee shorthand. * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); * // => objects for ['barney', 'fred'] * * // The `_.matchesProperty` iteratee shorthand. * _.dropRightWhile(users, ['active', false]); * // => objects for ['barney'] * * // The `_.property` iteratee shorthand. * _.dropRightWhile(users, 'active'); * // => objects for ['barney', 'fred', 'pebbles'] */ function dropRightWhile(array, predicate) { return (array && array.length) ? baseWhile(array, getIteratee(predicate, 3), true, true) : []; } /** * Creates a slice of `array` excluding elements dropped from the beginning. * Elements are dropped until `predicate` returns falsey. The predicate is * invoked with three arguments: (value, index, array). * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * * _.dropWhile(users, function(o) { return !o.active; }); * // => objects for ['pebbles'] * * // The `_.matches` iteratee shorthand. * _.dropWhile(users, { 'user': 'barney', 'active': false }); * // => objects for ['fred', 'pebbles'] * * // The `_.matchesProperty` iteratee shorthand. * _.dropWhile(users, ['active', false]); * // => objects for ['pebbles'] * * // The `_.property` iteratee shorthand. * _.dropWhile(users, 'active'); * // => objects for ['barney', 'fred', 'pebbles'] */ function dropWhile(array, predicate) { return (array && array.length) ? baseWhile(array, getIteratee(predicate, 3), true) : []; } /** * Fills elements of `array` with `value` from `start` up to, but not * including, `end`. * * **Note:** This method mutates `array`. * * @static * @memberOf _ * @since 3.2.0 * @category Array * @param {Array} array The array to fill. * @param {*} value The value to fill `array` with. * @param {number} [start=0] The start position. * @param {number} [end=array.length] The end position. * @returns {Array} Returns `array`. * @example * * var array = [1, 2, 3]; * * _.fill(array, 'a'); * console.log(array); * // => ['a', 'a', 'a'] * * _.fill(Array(3), 2); * // => [2, 2, 2] * * _.fill([4, 6, 8, 10], '*', 1, 3); * // => [4, '*', '*', 10] */ function fill(array, value, start, end) { var length = array == null ? 0 : array.length; if (!length) { return []; } if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { start = 0; end = length; } return baseFill(array, value, start, end); } /** * This method is like `_.find` except that it returns the index of the first * element `predicate` returns truthy for instead of the element itself. * * @static * @memberOf _ * @since 1.1.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @param {number} [fromIndex=0] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @example * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * * _.findIndex(users, function(o) { return o.user == 'barney'; }); * // => 0 * * // The `_.matches` iteratee shorthand. * _.findIndex(users, { 'user': 'fred', 'active': false }); * // => 1 * * // The `_.matchesProperty` iteratee shorthand. * _.findIndex(users, ['active', false]); * // => 0 * * // The `_.property` iteratee shorthand. * _.findIndex(users, 'active'); * // => 2 */ function findIndex(array, predicate, fromIndex) { var length = array == null ? 0 : array.length; if (!length) { return -1; } var index = fromIndex == null ? 0 : toInteger(fromIndex); if (index < 0) { index = nativeMax(length + index, 0); } return baseFindIndex(array, getIteratee(predicate, 3), index); } /** * This method is like `_.findIndex` except that it iterates over elements * of `collection` from right to left. * * @static * @memberOf _ * @since 2.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @param {number} [fromIndex=array.length-1] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @example * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); * // => 2 * * // The `_.matches` iteratee shorthand. * _.findLastIndex(users, { 'user': 'barney', 'active': true }); * // => 0 * * // The `_.matchesProperty` iteratee shorthand. * _.findLastIndex(users, ['active', false]); * // => 2 * * // The `_.property` iteratee shorthand. * _.findLastIndex(users, 'active'); * // => 0 */ function findLastIndex(array, predicate, fromIndex) { var length = array == null ? 0 : array.length; if (!length) { return -1; } var index = length - 1; if (fromIndex !== undefined) { index = toInteger(fromIndex); index = fromIndex < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); } return baseFindIndex(array, getIteratee(predicate, 3), index, true); } /** * Flattens `array` a single level deep. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to flatten. * @returns {Array} Returns the new flattened array. * @example * * _.flatten([1, [2, [3, [4]], 5]]); * // => [1, 2, [3, [4]], 5] */ function flatten(array) { var length = array == null ? 0 : array.length; return length ? baseFlatten(array, 1) : []; } /** * Recursively flattens `array`. * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to flatten. * @returns {Array} Returns the new flattened array. * @example * * _.flattenDeep([1, [2, [3, [4]], 5]]); * // => [1, 2, 3, 4, 5] */ function flattenDeep(array) { var length = array == null ? 0 : array.length; return length ? baseFlatten(array, INFINITY) : []; } /** * Recursively flatten `array` up to `depth` times. * * @static * @memberOf _ * @since 4.4.0 * @category Array * @param {Array} array The array to flatten. * @param {number} [depth=1] The maximum recursion depth. * @returns {Array} Returns the new flattened array. * @example * * var array = [1, [2, [3, [4]], 5]]; * * _.flattenDepth(array, 1); * // => [1, 2, [3, [4]], 5] * * _.flattenDepth(array, 2); * // => [1, 2, 3, [4], 5] */ function flattenDepth(array, depth) { var length = array == null ? 0 : array.length; if (!length) { return []; } depth = depth === undefined ? 1 : toInteger(depth); return baseFlatten(array, depth); } /** * The inverse of `_.toPairs`; this method returns an object composed * from key-value `pairs`. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} pairs The key-value pairs. * @returns {Object} Returns the new object. * @example * * _.fromPairs([['a', 1], ['b', 2]]); * // => { 'a': 1, 'b': 2 } */ function fromPairs(pairs) { var index = -1, length = pairs == null ? 0 : pairs.length, result = {}; while (++index < length) { var pair = pairs[index]; result[pair[0]] = pair[1]; } return result; } /** * Gets the first element of `array`. * * @static * @memberOf _ * @since 0.1.0 * @alias first * @category Array * @param {Array} array The array to query. * @returns {*} Returns the first element of `array`. * @example * * _.head([1, 2, 3]); * // => 1 * * _.head([]); * // => undefined */ function head(array) { return (array && array.length) ? array[0] : undefined; } /** * Gets the index at which the first occurrence of `value` is found in `array` * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons. If `fromIndex` is negative, it's used as the * offset from the end of `array`. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} [fromIndex=0] The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. * @example * * _.indexOf([1, 2, 1, 2], 2); * // => 1 * * // Search from the `fromIndex`. * _.indexOf([1, 2, 1, 2], 2, 2); * // => 3 */ function indexOf(array, value, fromIndex) { var length = array == null ? 0 : array.length; if (!length) { return -1; } var index = fromIndex == null ? 0 : toInteger(fromIndex); if (index < 0) { index = nativeMax(length + index, 0); } return baseIndexOf(array, value, index); } /** * Gets all but the last element of `array`. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to query. * @returns {Array} Returns the slice of `array`. * @example * * _.initial([1, 2, 3]); * // => [1, 2] */ function initial(array) { var length = array == null ? 0 : array.length; return length ? baseSlice(array, 0, -1) : []; } /** * Creates an array of unique values that are included in all given arrays * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons. The order and references of result values are * determined by the first array. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @returns {Array} Returns the new array of intersecting values. * @example * * _.intersection([2, 1], [2, 3]); * // => [2] */ var intersection = baseRest(function(arrays) { var mapped = arrayMap(arrays, castArrayLikeObject); return (mapped.length && mapped[0] === arrays[0]) ? baseIntersection(mapped) : []; }); /** * This method is like `_.intersection` except that it accepts `iteratee` * which is invoked for each element of each `arrays` to generate the criterion * by which they're compared. The order and references of result values are * determined by the first array. The iteratee is invoked with one argument: * (value). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {Array} Returns the new array of intersecting values. * @example * * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); * // => [2.1] * * // The `_.property` iteratee shorthand. * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }] */ var intersectionBy = baseRest(function(arrays) { var iteratee = last(arrays), mapped = arrayMap(arrays, castArrayLikeObject); if (iteratee === last(mapped)) { iteratee = undefined; } else { mapped.pop(); } return (mapped.length && mapped[0] === arrays[0]) ? baseIntersection(mapped, getIteratee(iteratee, 2)) : []; }); /** * This method is like `_.intersection` except that it accepts `comparator` * which is invoked to compare elements of `arrays`. The order and references * of result values are determined by the first array. The comparator is * invoked with two arguments: (arrVal, othVal). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of intersecting values. * @example * * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; * * _.intersectionWith(objects, others, _.isEqual); * // => [{ 'x': 1, 'y': 2 }] */ var intersectionWith = baseRest(function(arrays) { var comparator = last(arrays), mapped = arrayMap(arrays, castArrayLikeObject); comparator = typeof comparator == 'function' ? comparator : undefined; if (comparator) { mapped.pop(); } return (mapped.length && mapped[0] === arrays[0]) ? baseIntersection(mapped, undefined, comparator) : []; }); /** * Converts all elements in `array` into a string separated by `separator`. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to convert. * @param {string} [separator=','] The element separator. * @returns {string} Returns the joined string. * @example * * _.join(['a', 'b', 'c'], '~'); * // => 'a~b~c' */ function join(array, separator) { return array == null ? '' : nativeJoin.call(array, separator); } /** * Gets the last element of `array`. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to query. * @returns {*} Returns the last element of `array`. * @example * * _.last([1, 2, 3]); * // => 3 */ function last(array) { var length = array == null ? 0 : array.length; return length ? array[length - 1] : undefined; } /** * This method is like `_.indexOf` except that it iterates over elements of * `array` from right to left. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} [fromIndex=array.length-1] The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. * @example * * _.lastIndexOf([1, 2, 1, 2], 2); * // => 3 * * // Search from the `fromIndex`. * _.lastIndexOf([1, 2, 1, 2], 2, 2); * // => 1 */ function lastIndexOf(array, value, fromIndex) { var length = array == null ? 0 : array.length; if (!length) { return -1; } var index = length; if (fromIndex !== undefined) { index = toInteger(fromIndex); index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); } return value === value ? strictLastIndexOf(array, value, index) : baseFindIndex(array, baseIsNaN, index, true); } /** * Gets the element at index `n` of `array`. If `n` is negative, the nth * element from the end is returned. * * @static * @memberOf _ * @since 4.11.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=0] The index of the element to return. * @returns {*} Returns the nth element of `array`. * @example * * var array = ['a', 'b', 'c', 'd']; * * _.nth(array, 1); * // => 'b' * * _.nth(array, -2); * // => 'c'; */ function nth(array, n) { return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; } /** * Removes all given values from `array` using * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons. * * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` * to remove elements from an array by predicate. * * @static * @memberOf _ * @since 2.0.0 * @category Array * @param {Array} array The array to modify. * @param {...*} [values] The values to remove. * @returns {Array} Returns `array`. * @example * * var array = ['a', 'b', 'c', 'a', 'b', 'c']; * * _.pull(array, 'a', 'c'); * console.log(array); * // => ['b', 'b'] */ var pull = baseRest(pullAll); /** * This method is like `_.pull` except that it accepts an array of values to remove. * * **Note:** Unlike `_.difference`, this method mutates `array`. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to modify. * @param {Array} values The values to remove. * @returns {Array} Returns `array`. * @example * * var array = ['a', 'b', 'c', 'a', 'b', 'c']; * * _.pullAll(array, ['a', 'c']); * console.log(array); * // => ['b', 'b'] */ function pullAll(array, values) { return (array && array.length && values && values.length) ? basePullAll(array, values) : array; } /** * This method is like `_.pullAll` except that it accepts `iteratee` which is * invoked for each element of `array` and `values` to generate the criterion * by which they're compared. The iteratee is invoked with one argument: (value). * * **Note:** Unlike `_.differenceBy`, this method mutates `array`. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to modify. * @param {Array} values The values to remove. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {Array} Returns `array`. * @example * * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; * * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); * console.log(array); * // => [{ 'x': 2 }] */ function pullAllBy(array, values, iteratee) { return (array && array.length && values && values.length) ? basePullAll(array, values, getIteratee(iteratee, 2)) : array; } /** * This method is like `_.pullAll` except that it accepts `comparator` which * is invoked to compare elements of `array` to `values`. The comparator is * invoked with two arguments: (arrVal, othVal). * * **Note:** Unlike `_.differenceWith`, this method mutates `array`. * * @static * @memberOf _ * @since 4.6.0 * @category Array * @param {Array} array The array to modify. * @param {Array} values The values to remove. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns `array`. * @example * * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; * * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); * console.log(array); * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] */ function pullAllWith(array, values, comparator) { return (array && array.length && values && values.length) ? basePullAll(array, values, undefined, comparator) : array; } /** * Removes elements from `array` corresponding to `indexes` and returns an * array of removed elements. * * **Note:** Unlike `_.at`, this method mutates `array`. * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to modify. * @param {...(number|number[])} [indexes] The indexes of elements to remove. * @returns {Array} Returns the new array of removed elements. * @example * * var array = ['a', 'b', 'c', 'd']; * var pulled = _.pullAt(array, [1, 3]); * * console.log(array); * // => ['a', 'c'] * * console.log(pulled); * // => ['b', 'd'] */ var pullAt = flatRest(function(array, indexes) { var length = array == null ? 0 : array.length, result = baseAt(array, indexes); basePullAt(array, arrayMap(indexes, function(index) { return isIndex(index, length) ? +index : index; }).sort(compareAscending)); return result; }); /** * Removes all elements from `array` that `predicate` returns truthy for * and returns an array of the removed elements. The predicate is invoked * with three arguments: (value, index, array). * * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` * to pull elements from an array by value. * * @static * @memberOf _ * @since 2.0.0 * @category Array * @param {Array} array The array to modify. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the new array of removed elements. * @example * * var array = [1, 2, 3, 4]; * var evens = _.remove(array, function(n) { * return n % 2 == 0; * }); * * console.log(array); * // => [1, 3] * * console.log(evens); * // => [2, 4] */ function remove(array, predicate) { var result = []; if (!(array && array.length)) { return result; } var index = -1, indexes = [], length = array.length; predicate = getIteratee(predicate, 3); while (++index < length) { var value = array[index]; if (predicate(value, index, array)) { result.push(value); indexes.push(index); } } basePullAt(array, indexes); return result; } /** * Reverses `array` so that the first element becomes the last, the second * element becomes the second to last, and so on. * * **Note:** This method mutates `array` and is based on * [`Array#reverse`](https://mdn.io/Array/reverse). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to modify. * @returns {Array} Returns `array`. * @example * * var array = [1, 2, 3]; * * _.reverse(array); * // => [3, 2, 1] * * console.log(array); * // => [3, 2, 1] */ function reverse(array) { return array == null ? array : nativeReverse.call(array); } /** * Creates a slice of `array` from `start` up to, but not including, `end`. * * **Note:** This method is used instead of * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are * returned. * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to slice. * @param {number} [start=0] The start position. * @param {number} [end=array.length] The end position. * @returns {Array} Returns the slice of `array`. */ function slice(array, start, end) { var length = array == null ? 0 : array.length; if (!length) { return []; } if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { start = 0; end = length; } else { start = start == null ? 0 : toInteger(start); end = end === undefined ? length : toInteger(end); } return baseSlice(array, start, end); } /** * Uses a binary search to determine the lowest index at which `value` * should be inserted into `array` in order to maintain its sort order. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. * @returns {number} Returns the index at which `value` should be inserted * into `array`. * @example * * _.sortedIndex([30, 50], 40); * // => 1 */ function sortedIndex(array, value) { return baseSortedIndex(array, value); } /** * This method is like `_.sortedIndex` except that it accepts `iteratee` * which is invoked for `value` and each element of `array` to compute their * sort ranking. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {number} Returns the index at which `value` should be inserted * into `array`. * @example * * var objects = [{ 'x': 4 }, { 'x': 5 }]; * * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); * // => 0 * * // The `_.property` iteratee shorthand. * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); * // => 0 */ function sortedIndexBy(array, value, iteratee) { return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); } /** * This method is like `_.indexOf` except that it performs a binary * search on a sorted `array`. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @returns {number} Returns the index of the matched value, else `-1`. * @example * * _.sortedIndexOf([4, 5, 5, 5, 6], 5); * // => 1 */ function sortedIndexOf(array, value) { var length = array == null ? 0 : array.length; if (length) { var index = baseSortedIndex(array, value); if (index < length && eq(array[index], value)) { return index; } } return -1; } /** * This method is like `_.sortedIndex` except that it returns the highest * index at which `value` should be inserted into `array` in order to * maintain its sort order. * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. * @returns {number} Returns the index at which `value` should be inserted * into `array`. * @example * * _.sortedLastIndex([4, 5, 5, 5, 6], 5); * // => 4 */ function sortedLastIndex(array, value) { return baseSortedIndex(array, value, true); } /** * This method is like `_.sortedLastIndex` except that it accepts `iteratee` * which is invoked for `value` and each element of `array` to compute their * sort ranking. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {number} Returns the index at which `value` should be inserted * into `array`. * @example * * var objects = [{ 'x': 4 }, { 'x': 5 }]; * * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); * // => 1 * * // The `_.property` iteratee shorthand. * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); * // => 1 */ function sortedLastIndexBy(array, value, iteratee) { return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); } /** * This method is like `_.lastIndexOf` except that it performs a binary * search on a sorted `array`. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @returns {number} Returns the index of the matched value, else `-1`. * @example * * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); * // => 3 */ function sortedLastIndexOf(array, value) { var length = array == null ? 0 : array.length; if (length) { var index = baseSortedIndex(array, value, true) - 1; if (eq(array[index], value)) { return index; } } return -1; } /** * This method is like `_.uniq` except that it's designed and optimized * for sorted arrays. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @returns {Array} Returns the new duplicate free array. * @example * * _.sortedUniq([1, 1, 2]); * // => [1, 2] */ function sortedUniq(array) { return (array && array.length) ? baseSortedUniq(array) : []; } /** * This method is like `_.uniqBy` except that it's designed and optimized * for sorted arrays. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} [iteratee] The iteratee invoked per element. * @returns {Array} Returns the new duplicate free array. * @example * * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); * // => [1.1, 2.3] */ function sortedUniqBy(array, iteratee) { return (array && array.length) ? baseSortedUniq(array, getIteratee(iteratee, 2)) : []; } /** * Gets all but the first element of `array`. * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to query. * @returns {Array} Returns the slice of `array`. * @example * * _.tail([1, 2, 3]); * // => [2, 3] */ function tail(array) { var length = array == null ? 0 : array.length; return length ? baseSlice(array, 1, length) : []; } /** * Creates a slice of `array` with `n` elements taken from the beginning. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to take. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * * _.take([1, 2, 3]); * // => [1] * * _.take([1, 2, 3], 2); * // => [1, 2] * * _.take([1, 2, 3], 5); * // => [1, 2, 3] * * _.take([1, 2, 3], 0); * // => [] */ function take(array, n, guard) { if (!(array && array.length)) { return []; } n = (guard || n === undefined) ? 1 : toInteger(n); return baseSlice(array, 0, n < 0 ? 0 : n); } /** * Creates a slice of `array` with `n` elements taken from the end. * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to take. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * * _.takeRight([1, 2, 3]); * // => [3] * * _.takeRight([1, 2, 3], 2); * // => [2, 3] * * _.takeRight([1, 2, 3], 5); * // => [1, 2, 3] * * _.takeRight([1, 2, 3], 0); * // => [] */ function takeRight(array, n, guard) { var length = array == null ? 0 : array.length; if (!length) { return []; } n = (guard || n === undefined) ? 1 : toInteger(n); n = length - n; return baseSlice(array, n < 0 ? 0 : n, length); } /** * Creates a slice of `array` with elements taken from the end. Elements are * taken until `predicate` returns falsey. The predicate is invoked with * three arguments: (value, index, array). * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * * _.takeRightWhile(users, function(o) { return !o.active; }); * // => objects for ['fred', 'pebbles'] * * // The `_.matches` iteratee shorthand. * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); * // => objects for ['pebbles'] * * // The `_.matchesProperty` iteratee shorthand. * _.takeRightWhile(users, ['active', false]); * // => objects for ['fred', 'pebbles'] * * // The `_.property` iteratee shorthand. * _.takeRightWhile(users, 'active'); * // => [] */ function takeRightWhile(array, predicate) { return (array && array.length) ? baseWhile(array, getIteratee(predicate, 3), false, true) : []; } /** * Creates a slice of `array` with elements taken from the beginning. Elements * are taken until `predicate` returns falsey. The predicate is invoked with * three arguments: (value, index, array). * * @static * @memberOf _ * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * * _.takeWhile(users, function(o) { return !o.active; }); * // => objects for ['barney', 'fred'] * * // The `_.matches` iteratee shorthand. * _.takeWhile(users, { 'user': 'barney', 'active': false }); * // => objects for ['barney'] * * // The `_.matchesProperty` iteratee shorthand. * _.takeWhile(users, ['active', false]); * // => objects for ['barney', 'fred'] * * // The `_.property` iteratee shorthand. * _.takeWhile(users, 'active'); * // => [] */ function takeWhile(array, predicate) { return (array && array.length) ? baseWhile(array, getIteratee(predicate, 3)) : []; } /** * Creates an array of unique values, in order, from all given arrays using * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @returns {Array} Returns the new array of combined values. * @example * * _.union([2], [1, 2]); * // => [2, 1] */ var union = baseRest(function(arrays) { return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); }); /** * This method is like `_.union` except that it accepts `iteratee` which is * invoked for each element of each `arrays` to generate the criterion by * which uniqueness is computed. Result values are chosen from the first * array in which the value occurs. The iteratee is invoked with one argument: * (value). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {Array} Returns the new array of combined values. * @example * * _.unionBy([2.1], [1.2, 2.3], Math.floor); * // => [2.1, 1.2] * * // The `_.property` iteratee shorthand. * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ var unionBy = baseRest(function(arrays) { var iteratee = last(arrays); if (isArrayLikeObject(iteratee)) { iteratee = undefined; } return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); }); /** * This method is like `_.union` except that it accepts `comparator` which * is invoked to compare elements of `arrays`. Result values are chosen from * the first array in which the value occurs. The comparator is invoked * with two arguments: (arrVal, othVal). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of combined values. * @example * * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; * * _.unionWith(objects, others, _.isEqual); * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] */ var unionWith = baseRest(function(arrays) { var comparator = last(arrays); comparator = typeof comparator == 'function' ? comparator : undefined; return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); }); /** * Creates a duplicate-free version of an array, using * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons, in which only the first occurrence of each element * is kept. The order of result values is determined by the order they occur * in the array. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to inspect. * @returns {Array} Returns the new duplicate free array. * @example * * _.uniq([2, 1, 2]); * // => [2, 1] */ function uniq(array) { return (array && array.length) ? baseUniq(array) : []; } /** * This method is like `_.uniq` except that it accepts `iteratee` which is * invoked for each element in `array` to generate the criterion by which * uniqueness is computed. The order of result values is determined by the * order they occur in the array. The iteratee is invoked with one argument: * (value). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {Array} Returns the new duplicate free array. * @example * * _.uniqBy([2.1, 1.2, 2.3], Math.floor); * // => [2.1, 1.2] * * // The `_.property` iteratee shorthand. * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ function uniqBy(array, iteratee) { return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; } /** * This method is like `_.uniq` except that it accepts `comparator` which * is invoked to compare elements of `array`. The order of result values is * determined by the order they occur in the array.The comparator is invoked * with two arguments: (arrVal, othVal). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new duplicate free array. * @example * * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; * * _.uniqWith(objects, _.isEqual); * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] */ function uniqWith(array, comparator) { comparator = typeof comparator == 'function' ? comparator : undefined; return (array && array.length) ? baseUniq(array, undefined, comparator) : []; } /** * This method is like `_.zip` except that it accepts an array of grouped * elements and creates an array regrouping the elements to their pre-zip * configuration. * * @static * @memberOf _ * @since 1.2.0 * @category Array * @param {Array} array The array of grouped elements to process. * @returns {Array} Returns the new array of regrouped elements. * @example * * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); * // => [['a', 1, true], ['b', 2, false]] * * _.unzip(zipped); * // => [['a', 'b'], [1, 2], [true, false]] */ function unzip(array) { if (!(array && array.length)) { return []; } var length = 0; array = arrayFilter(array, function(group) { if (isArrayLikeObject(group)) { length = nativeMax(group.length, length); return true; } }); return baseTimes(length, function(index) { return arrayMap(array, baseProperty(index)); }); } /** * This method is like `_.unzip` except that it accepts `iteratee` to specify * how regrouped values should be combined. The iteratee is invoked with the * elements of each group: (...group). * * @static * @memberOf _ * @since 3.8.0 * @category Array * @param {Array} array The array of grouped elements to process. * @param {Function} [iteratee=_.identity] The function to combine * regrouped values. * @returns {Array} Returns the new array of regrouped elements. * @example * * var zipped = _.zip([1, 2], [10, 20], [100, 200]); * // => [[1, 10, 100], [2, 20, 200]] * * _.unzipWith(zipped, _.add); * // => [3, 30, 300] */ function unzipWith(array, iteratee) { if (!(array && array.length)) { return []; } var result = unzip(array); if (iteratee == null) { return result; } return arrayMap(result, function(group) { return apply(iteratee, undefined, group); }); } /** * Creates an array excluding all given values using * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons. * * **Note:** Unlike `_.pull`, this method returns a new array. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to inspect. * @param {...*} [values] The values to exclude. * @returns {Array} Returns the new array of filtered values. * @see _.difference, _.xor * @example * * _.without([2, 1, 2, 3], 1, 2); * // => [3] */ var without = baseRest(function(array, values) { return isArrayLikeObject(array) ? baseDifference(array, values) : []; }); /** * Creates an array of unique values that is the * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) * of the given arrays. The order of result values is determined by the order * they occur in the arrays. * * @static * @memberOf _ * @since 2.4.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @returns {Array} Returns the new array of filtered values. * @see _.difference, _.without * @example * * _.xor([2, 1], [2, 3]); * // => [1, 3] */ var xor = baseRest(function(arrays) { return baseXor(arrayFilter(arrays, isArrayLikeObject)); }); /** * This method is like `_.xor` except that it accepts `iteratee` which is * invoked for each element of each `arrays` to generate the criterion by * which by which they're compared. The order of result values is determined * by the order they occur in the arrays. The iteratee is invoked with one * argument: (value). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {Array} Returns the new array of filtered values. * @example * * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); * // => [1.2, 3.4] * * // The `_.property` iteratee shorthand. * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 2 }] */ var xorBy = baseRest(function(arrays) { var iteratee = last(arrays); if (isArrayLikeObject(iteratee)) { iteratee = undefined; } return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); }); /** * This method is like `_.xor` except that it accepts `comparator` which is * invoked to compare elements of `arrays`. The order of result values is * determined by the order they occur in the arrays. The comparator is invoked * with two arguments: (arrVal, othVal). * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of filtered values. * @example * * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; * * _.xorWith(objects, others, _.isEqual); * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] */ var xorWith = baseRest(function(arrays) { var comparator = last(arrays); comparator = typeof comparator == 'function' ? comparator : undefined; return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); }); /** * Creates an array of grouped elements, the first of which contains the * first elements of the given arrays, the second of which contains the * second elements of the given arrays, and so on. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {...Array} [arrays] The arrays to process. * @returns {Array} Returns the new array of grouped elements. * @example * * _.zip(['a', 'b'], [1, 2], [true, false]); * // => [['a', 1, true], ['b', 2, false]] */ var zip = baseRest(unzip); /** * This method is like `_.fromPairs` except that it accepts two arrays, * one of property identifiers and one of corresponding values. * * @static * @memberOf _ * @since 0.4.0 * @category Array * @param {Array} [props=[]] The property identifiers. * @param {Array} [values=[]] The property values. * @returns {Object} Returns the new object. * @example * * _.zipObject(['a', 'b'], [1, 2]); * // => { 'a': 1, 'b': 2 } */ function zipObject(props, values) { return baseZipObject(props || [], values || [], assignValue); } /** * This method is like `_.zipObject` except that it supports property paths. * * @static * @memberOf _ * @since 4.1.0 * @category Array * @param {Array} [props=[]] The property identifiers. * @param {Array} [values=[]] The property values. * @returns {Object} Returns the new object. * @example * * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } */ function zipObjectDeep(props, values) { return baseZipObject(props || [], values || [], baseSet); } /** * This method is like `_.zip` except that it accepts `iteratee` to specify * how grouped values should be combined. The iteratee is invoked with the * elements of each group: (...group). * * @static * @memberOf _ * @since 3.8.0 * @category Array * @param {...Array} [arrays] The arrays to process. * @param {Function} [iteratee=_.identity] The function to combine * grouped values. * @returns {Array} Returns the new array of grouped elements. * @example * * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { * return a + b + c; * }); * // => [111, 222] */ var zipWith = baseRest(function(arrays) { var length = arrays.length, iteratee = length > 1 ? arrays[length - 1] : undefined; iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; return unzipWith(arrays, iteratee); }); /*------------------------------------------------------------------------*/ /** * Creates a `lodash` wrapper instance that wraps `value` with explicit method * chain sequences enabled. The result of such sequences must be unwrapped * with `_#value`. * * @static * @memberOf _ * @since 1.3.0 * @category Seq * @param {*} value The value to wrap. * @returns {Object} Returns the new `lodash` wrapper instance. * @example * * var users = [ * { 'user': 'barney', 'age': 36 }, * { 'user': 'fred', 'age': 40 }, * { 'user': 'pebbles', 'age': 1 } * ]; * * var youngest = _ * .chain(users) * .sortBy('age') * .map(function(o) { * return o.user + ' is ' + o.age; * }) * .head() * .value(); * // => 'pebbles is 1' */ function chain(value) { var result = lodash(value); result.__chain__ = true; return result; } /** * This method invokes `interceptor` and returns `value`. The interceptor * is invoked with one argument; (value). The purpose of this method is to * "tap into" a method chain sequence in order to modify intermediate results. * * @static * @memberOf _ * @since 0.1.0 * @category Seq * @param {*} value The value to provide to `interceptor`. * @param {Function} interceptor The function to invoke. * @returns {*} Returns `value`. * @example * * _([1, 2, 3]) * .tap(function(array) { * // Mutate input array. * array.pop(); * }) * .reverse() * .value(); * // => [2, 1] */ function tap(value, interceptor) { interceptor(value); return value; } /** * This method is like `_.tap` except that it returns the result of `interceptor`. * The purpose of this method is to "pass thru" values replacing intermediate * results in a method chain sequence. * * @static * @memberOf _ * @since 3.0.0 * @category Seq * @param {*} value The value to provide to `interceptor`. * @param {Function} interceptor The function to invoke. * @returns {*} Returns the result of `interceptor`. * @example * * _(' abc ') * .chain() * .trim() * .thru(function(value) { * return [value]; * }) * .value(); * // => ['abc'] */ function thru(value, interceptor) { return interceptor(value); } /** * This method is the wrapper version of `_.at`. * * @name at * @memberOf _ * @since 1.0.0 * @category Seq * @param {...(string|string[])} [paths] The property paths to pick. * @returns {Object} Returns the new `lodash` wrapper instance. * @example * * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; * * _(object).at(['a[0].b.c', 'a[1]']).value(); * // => [3, 4] */ var wrapperAt = flatRest(function(paths) { var length = paths.length, start = length ? paths[0] : 0, value = this.__wrapped__, interceptor = function(object) { return baseAt(object, paths); }; if (length > 1 || this.__actions__.length || !(value instanceof LazyWrapper) || !isIndex(start)) { return this.thru(interceptor); } value = value.slice(start, +start + (length ? 1 : 0)); value.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined }); return new LodashWrapper(value, this.__chain__).thru(function(array) { if (length && !array.length) { array.push(undefined); } return array; }); }); /** * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. * * @name chain * @memberOf _ * @since 0.1.0 * @category Seq * @returns {Object} Returns the new `lodash` wrapper instance. * @example * * var users = [ * { 'user': 'barney', 'age': 36 }, * { 'user': 'fred', 'age': 40 } * ]; * * // A sequence without explicit chaining. * _(users).head(); * // => { 'user': 'barney', 'age': 36 } * * // A sequence with explicit chaining. * _(users) * .chain() * .head() * .pick('user') * .value(); * // => { 'user': 'barney' } */ function wrapperChain() { return chain(this); } /** * Executes the chain sequence and returns the wrapped result. * * @name commit * @memberOf _ * @since 3.2.0 * @category Seq * @returns {Object} Returns the new `lodash` wrapper instance. * @example * * var array = [1, 2]; * var wrapped = _(array).push(3); * * console.log(array); * // => [1, 2] * * wrapped = wrapped.commit(); * console.log(array); * // => [1, 2, 3] * * wrapped.last(); * // => 3 * * console.log(array); * // => [1, 2, 3] */ function wrapperCommit() { return new LodashWrapper(this.value(), this.__chain__); } /** * Gets the next value on a wrapped object following the * [iterator protocol](https://mdn.io/iteration_protocols#iterator). * * @name next * @memberOf _ * @since 4.0.0 * @category Seq * @returns {Object} Returns the next iterator value. * @example * * var wrapped = _([1, 2]); * * wrapped.next(); * // => { 'done': false, 'value': 1 } * * wrapped.next(); * // => { 'done': false, 'value': 2 } * * wrapped.next(); * // => { 'done': true, 'value': undefined } */ function wrapperNext() { if (this.__values__ === undefined) { this.__values__ = toArray(this.value()); } var done = this.__index__ >= this.__values__.length, value = done ? undefined : this.__values__[this.__index__++]; return { 'done': done, 'value': value }; } /** * Enables the wrapper to be iterable. * * @name Symbol.iterator * @memberOf _ * @since 4.0.0 * @category Seq * @returns {Object} Returns the wrapper object. * @example * * var wrapped = _([1, 2]); * * wrapped[Symbol.iterator]() === wrapped; * // => true * * Array.from(wrapped); * // => [1, 2] */ function wrapperToIterator() { return this; } /** * Creates a clone of the chain sequence planting `value` as the wrapped value. * * @name plant * @memberOf _ * @since 3.2.0 * @category Seq * @param {*} value The value to plant. * @returns {Object} Returns the new `lodash` wrapper instance. * @example * * function square(n) { * return n * n; * } * * var wrapped = _([1, 2]).map(square); * var other = wrapped.plant([3, 4]); * * other.value(); * // => [9, 16] * * wrapped.value(); * // => [1, 4] */ function wrapperPlant(value) { var result, parent = this; while (parent instanceof baseLodash) { var clone = wrapperClone(parent); clone.__index__ = 0; clone.__values__ = undefined; if (result) { previous.__wrapped__ = clone; } else { result = clone; } var previous = clone; parent = parent.__wrapped__; } previous.__wrapped__ = value; return result; } /** * This method is the wrapper version of `_.reverse`. * * **Note:** This method mutates the wrapped array. * * @name reverse * @memberOf _ * @since 0.1.0 * @category Seq * @returns {Object} Returns the new `lodash` wrapper instance. * @example * * var array = [1, 2, 3]; * * _(array).reverse().value() * // => [3, 2, 1] * * console.log(array); * // => [3, 2, 1] */ function wrapperReverse() { var value = this.__wrapped__; if (value instanceof LazyWrapper) { var wrapped = value; if (this.__actions__.length) { wrapped = new LazyWrapper(this); } wrapped = wrapped.reverse(); wrapped.__actions__.push({ 'func': thru, 'args': [reverse], 'thisArg': undefined }); return new LodashWrapper(wrapped, this.__chain__); } return this.thru(reverse); } /** * Executes the chain sequence to resolve the unwrapped value. * * @name value * @memberOf _ * @since 0.1.0 * @alias toJSON, valueOf * @category Seq * @returns {*} Returns the resolved unwrapped value. * @example * * _([1, 2, 3]).value(); * // => [1, 2, 3] */ function wrapperValue() { return baseWrapperValue(this.__wrapped__, this.__actions__); } /*------------------------------------------------------------------------*/ /** * Creates an object composed of keys generated from the results of running * each element of `collection` thru `iteratee`. The corresponding value of * each key is the number of times the key was returned by `iteratee`. The * iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @since 0.5.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The iteratee to transform keys. * @returns {Object} Returns the composed aggregate object. * @example * * _.countBy([6.1, 4.2, 6.3], Math.floor); * // => { '4': 1, '6': 2 } * * // The `_.property` iteratee shorthand. * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */ var countBy = createAggregator(function(result, value, key) { if (hasOwnProperty.call(result, key)) { ++result[key]; } else { baseAssignValue(result, key, 1); } }); /** * Checks if `predicate` returns truthy for **all** elements of `collection`. * Iteration is stopped once `predicate` returns falsey. The predicate is * invoked with three arguments: (value, index|key, collection). * * **Note:** This method returns `true` for * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of * elements of empty collections. * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {boolean} Returns `true` if all elements pass the predicate check, * else `false`. * @example * * _.every([true, 1, null, 'yes'], Boolean); * // => false * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': false } * ]; * * // The `_.matches` iteratee shorthand. * _.every(users, { 'user': 'barney', 'active': false }); * // => false * * // The `_.matchesProperty` iteratee shorthand. * _.every(users, ['active', false]); * // => true * * // The `_.property` iteratee shorthand. * _.every(users, 'active'); * // => false */ function every(collection, predicate, guard) { var func = isArray(collection) ? arrayEvery : baseEvery; if (guard && isIterateeCall(collection, predicate, guard)) { predicate = undefined; } return func(collection, getIteratee(predicate, 3)); } /** * Iterates over elements of `collection`, returning an array of all elements * `predicate` returns truthy for. The predicate is invoked with three * arguments: (value, index|key, collection). * * **Note:** Unlike `_.remove`, this method returns a new array. * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the new filtered array. * @see _.reject * @example * * var users = [ * { 'user': 'barney', 'age': 36, 'active': true }, * { 'user': 'fred', 'age': 40, 'active': false } * ]; * * _.filter(users, function(o) { return !o.active; }); * // => objects for ['fred'] * * // The `_.matches` iteratee shorthand. * _.filter(users, { 'age': 36, 'active': true }); * // => objects for ['barney'] * * // The `_.matchesProperty` iteratee shorthand. * _.filter(users, ['active', false]); * // => objects for ['fred'] * * // The `_.property` iteratee shorthand. * _.filter(users, 'active'); * // => objects for ['barney'] */ function filter(collection, predicate) { var func = isArray(collection) ? arrayFilter : baseFilter; return func(collection, getIteratee(predicate, 3)); } /** * Iterates over elements of `collection`, returning the first element * `predicate` returns truthy for. The predicate is invoked with three * arguments: (value, index|key, collection). * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to inspect. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @param {number} [fromIndex=0] The index to search from. * @returns {*} Returns the matched element, else `undefined`. * @example * * var users = [ * { 'user': 'barney', 'age': 36, 'active': true }, * { 'user': 'fred', 'age': 40, 'active': false }, * { 'user': 'pebbles', 'age': 1, 'active': true } * ]; * * _.find(users, function(o) { return o.age < 40; }); * // => object for 'barney' * * // The `_.matches` iteratee shorthand. * _.find(users, { 'age': 1, 'active': true }); * // => object for 'pebbles' * * // The `_.matchesProperty` iteratee shorthand. * _.find(users, ['active', false]); * // => object for 'fred' * * // The `_.property` iteratee shorthand. * _.find(users, 'active'); * // => object for 'barney' */ var find = createFind(findIndex); /** * This method is like `_.find` except that it iterates over elements of * `collection` from right to left. * * @static * @memberOf _ * @since 2.0.0 * @category Collection * @param {Array|Object} collection The collection to inspect. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @param {number} [fromIndex=collection.length-1] The index to search from. * @returns {*} Returns the matched element, else `undefined`. * @example * * _.findLast([1, 2, 3, 4], function(n) { * return n % 2 == 1; * }); * // => 3 */ var findLast = createFind(findLastIndex); /** * Creates a flattened array of values by running each element in `collection` * thru `iteratee` and flattening the mapped results. The iteratee is invoked * with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @since 4.0.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Array} Returns the new flattened array. * @example * * function duplicate(n) { * return [n, n]; * } * * _.flatMap([1, 2], duplicate); * // => [1, 1, 2, 2] */ function flatMap(collection, iteratee) { return baseFlatten(map(collection, iteratee), 1); } /** * This method is like `_.flatMap` except that it recursively flattens the * mapped results. * * @static * @memberOf _ * @since 4.7.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Array} Returns the new flattened array. * @example * * function duplicate(n) { * return [[[n, n]]]; * } * * _.flatMapDeep([1, 2], duplicate); * // => [1, 1, 2, 2] */ function flatMapDeep(collection, iteratee) { return baseFlatten(map(collection, iteratee), INFINITY); } /** * This method is like `_.flatMap` except that it recursively flattens the * mapped results up to `depth` times. * * @static * @memberOf _ * @since 4.7.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {number} [depth=1] The maximum recursion depth. * @returns {Array} Returns the new flattened array. * @example * * function duplicate(n) { * return [[[n, n]]]; * } * * _.flatMapDepth([1, 2], duplicate, 2); * // => [[1, 1], [2, 2]] */ function flatMapDepth(collection, iteratee, depth) { depth = depth === undefined ? 1 : toInteger(depth); return baseFlatten(map(collection, iteratee), depth); } /** * Iterates over elements of `collection` and invokes `iteratee` for each element. * The iteratee is invoked with three arguments: (value, index|key, collection). * Iteratee functions may exit iteration early by explicitly returning `false`. * * **Note:** As with other "Collections" methods, objects with a "length" * property are iterated like arrays. To avoid this behavior use `_.forIn` * or `_.forOwn` for object iteration. * * @static * @memberOf _ * @since 0.1.0 * @alias each * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Array|Object} Returns `collection`. * @see _.forEachRight * @example * * _.forEach([1, 2], function(value) { * console.log(value); * }); * // => Logs `1` then `2`. * * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { * console.log(key); * }); * // => Logs 'a' then 'b' (iteration order is not guaranteed). */ function forEach(collection, iteratee) { var func = isArray(collection) ? arrayEach : baseEach; return func(collection, getIteratee(iteratee, 3)); } /** * This method is like `_.forEach` except that it iterates over elements of * `collection` from right to left. * * @static * @memberOf _ * @since 2.0.0 * @alias eachRight * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Array|Object} Returns `collection`. * @see _.forEach * @example * * _.forEachRight([1, 2], function(value) { * console.log(value); * }); * // => Logs `2` then `1`. */ function forEachRight(collection, iteratee) { var func = isArray(collection) ? arrayEachRight : baseEachRight; return func(collection, getIteratee(iteratee, 3)); } /** * Creates an object composed of keys generated from the results of running * each element of `collection` thru `iteratee`. The order of grouped values * is determined by the order they occur in `collection`. The corresponding * value of each key is an array of elements responsible for generating the * key. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The iteratee to transform keys. * @returns {Object} Returns the composed aggregate object. * @example * * _.groupBy([6.1, 4.2, 6.3], Math.floor); * // => { '4': [4.2], '6': [6.1, 6.3] } * * // The `_.property` iteratee shorthand. * _.groupBy(['one', 'two', 'three'], 'length'); * // => { '3': ['one', 'two'], '5': ['three'] } */ var groupBy = createAggregator(function(result, value, key) { if (hasOwnProperty.call(result, key)) { result[key].push(value); } else { baseAssignValue(result, key, [value]); } }); /** * Checks if `value` is in `collection`. If `collection` is a string, it's * checked for a substring of `value`, otherwise * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * is used for equality comparisons. If `fromIndex` is negative, it's used as * the offset from the end of `collection`. * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object|string} collection The collection to inspect. * @param {*} value The value to search for. * @param {number} [fromIndex=0] The index to search from. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. * @returns {boolean} Returns `true` if `value` is found, else `false`. * @example * * _.includes([1, 2, 3], 1); * // => true * * _.includes([1, 2, 3], 1, 2); * // => false * * _.includes({ 'a': 1, 'b': 2 }, 1); * // => true * * _.includes('abcd', 'bc'); * // => true */ function includes(collection, value, fromIndex, guard) { collection = isArrayLike(collection) ? collection : values(collection); fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; var length = collection.length; if (fromIndex < 0) { fromIndex = nativeMax(length + fromIndex, 0); } return isString(collection) ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) : (!!length && baseIndexOf(collection, value, fromIndex) > -1); } /** * Invokes the method at `path` of each element in `collection`, returning * an array of the results of each invoked method. Any additional arguments * are provided to each invoked method. If `path` is a function, it's invoked * for, and `this` bound to, each element in `collection`. * * @static * @memberOf _ * @since 4.0.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Array|Function|string} path The path of the method to invoke or * the function invoked per iteration. * @param {...*} [args] The arguments to invoke each method with. * @returns {Array} Returns the array of results. * @example * * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); * // => [[1, 5, 7], [1, 2, 3]] * * _.invokeMap([123, 456], String.prototype.split, ''); * // => [['1', '2', '3'], ['4', '5', '6']] */ var invokeMap = baseRest(function(collection, path, args) { var index = -1, isFunc = typeof path == 'function', result = isArrayLike(collection) ? Array(collection.length) : []; baseEach(collection, function(value) { result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); }); return result; }); /** * Creates an object composed of keys generated from the results of running * each element of `collection` thru `iteratee`. The corresponding value of * each key is the last element responsible for generating the key. The * iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @since 4.0.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The iteratee to transform keys. * @returns {Object} Returns the composed aggregate object. * @example * * var array = [ * { 'dir': 'left', 'code': 97 }, * { 'dir': 'right', 'code': 100 } * ]; * * _.keyBy(array, function(o) { * return String.fromCharCode(o.code); * }); * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } * * _.keyBy(array, 'dir'); * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } */ var keyBy = createAggregator(function(result, value, key) { baseAssignValue(result, key, value); }); /** * Creates an array of values by running each element in `collection` thru * `iteratee`. The iteratee is invoked with three arguments: * (value, index|key, collection). * * Many lodash methods are guarded to work as iteratees for methods like * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. * * The guarded methods are: * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, * `template`, `trim`, `trimEnd`, `trimStart`, and `words` * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Array} Returns the new mapped array. * @example * * function square(n) { * return n * n; * } * * _.map([4, 8], square); * // => [16, 64] * * _.map({ 'a': 4, 'b': 8 }, square); * // => [16, 64] (iteration order is not guaranteed) * * var users = [ * { 'user': 'barney' }, * { 'user': 'fred' } * ]; * * // The `_.property` iteratee shorthand. * _.map(users, 'user'); * // => ['barney', 'fred'] */ function map(collection, iteratee) { var func = isArray(collection) ? arrayMap : baseMap; return func(collection, getIteratee(iteratee, 3)); } /** * This method is like `_.sortBy` except that it allows specifying the sort * orders of the iteratees to sort by. If `orders` is unspecified, all values * are sorted in ascending order. Otherwise, specify an order of "desc" for * descending or "asc" for ascending sort order of corresponding values. * * @static * @memberOf _ * @since 4.0.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] * The iteratees to sort by. * @param {string[]} [orders] The sort orders of `iteratees`. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. * @returns {Array} Returns the new sorted array. * @example * * var users = [ * { 'user': 'fred', 'age': 48 }, * { 'user': 'barney', 'age': 34 }, * { 'user': 'fred', 'age': 40 }, * { 'user': 'barney', 'age': 36 } * ]; * * // Sort by `user` in ascending order and by `age` in descending order. * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] */ function orderBy(collection, iteratees, orders, guard) { if (collection == null) { return []; } if (!isArray(iteratees)) { iteratees = iteratees == null ? [] : [iteratees]; } orders = guard ? undefined : orders; if (!isArray(orders)) { orders = orders == null ? [] : [orders]; } return baseOrderBy(collection, iteratees, orders); } /** * Creates an array of elements split into two groups, the first of which * contains elements `predicate` returns truthy for, the second of which * contains elements `predicate` returns falsey for. The predicate is * invoked with one argument: (value). * * @static * @memberOf _ * @since 3.0.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the array of grouped elements. * @example * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true }, * { 'user': 'pebbles', 'age': 1, 'active': false } * ]; * * _.partition(users, function(o) { return o.active; }); * // => objects for [['fred'], ['barney', 'pebbles']] * * // The `_.matches` iteratee shorthand. * _.partition(users, { 'age': 1, 'active': false }); * // => objects for [['pebbles'], ['barney', 'fred']] * * // The `_.matchesProperty` iteratee shorthand. * _.partition(users, ['active', false]); * // => objects for [['barney', 'pebbles'], ['fred']] * * // The `_.property` iteratee shorthand. * _.partition(users, 'active'); * // => objects for [['fred'], ['barney', 'pebbles']] */ var partition = createAggregator(function(result, value, key) { result[key ? 0 : 1].push(value); }, function() { return [[], []]; }); /** * Reduces `collection` to a value which is the accumulated result of running * each element in `collection` thru `iteratee`, where each successive * invocation is supplied the return value of the previous. If `accumulator` * is not given, the first element of `collection` is used as the initial * value. The iteratee is invoked with four arguments: * (accumulator, value, index|key, collection). * * Many lodash methods are guarded to work as iteratees for methods like * `_.reduce`, `_.reduceRight`, and `_.transform`. * * The guarded methods are: * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, * and `sortBy` * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The initial value. * @returns {*} Returns the accumulated value. * @see _.reduceRight * @example * * _.reduce([1, 2], function(sum, n) { * return sum + n; * }, 0); * // => 3 * * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { * (result[value] || (result[value] = [])).push(key); * return result; * }, {}); * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) */ function reduce(collection, iteratee, accumulator) { var func = isArray(collection) ? arrayReduce : baseReduce, initAccum = arguments.length < 3; return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); } /** * This method is like `_.reduce` except that it iterates over elements of * `collection` from right to left. * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The initial value. * @returns {*} Returns the accumulated value. * @see _.reduce * @example * * var array = [[0, 1], [2, 3], [4, 5]]; * * _.reduceRight(array, function(flattened, other) { * return flattened.concat(other); * }, []); * // => [4, 5, 2, 3, 0, 1] */ function reduceRight(collection, iteratee, accumulator) { var func = isArray(collection) ? arrayReduceRight : baseReduce, initAccum = arguments.length < 3; return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); } /** * The opposite of `_.filter`; this method returns the elements of `collection` * that `predicate` does **not** return truthy for. * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the new filtered array. * @see _.filter * @example * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true } * ]; * * _.reject(users, function(o) { return !o.active; }); * // => objects for ['fred'] * * // The `_.matches` iteratee shorthand. * _.reject(users, { 'age': 40, 'active': true }); * // => objects for ['barney'] * * // The `_.matchesProperty` iteratee shorthand. * _.reject(users, ['active', false]); * // => objects for ['fred'] * * // The `_.property` iteratee shorthand. * _.reject(users, 'active'); * // => objects for ['barney'] */ function reject(collection, predicate) { var func = isArray(collection) ? arrayFilter : baseFilter; return func(collection, negate(getIteratee(predicate, 3))); } /** * Gets a random element from `collection`. * * @static * @memberOf _ * @since 2.0.0 * @category Collection * @param {Array|Object} collection The collection to sample. * @returns {*} Returns the random element. * @example * * _.sample([1, 2, 3, 4]); * // => 2 */ function sample(collection) { var func = isArray(collection) ? arraySample : baseSample; return func(collection); } /** * Gets `n` random elements at unique keys from `collection` up to the * size of `collection`. * * @static * @memberOf _ * @since 4.0.0 * @category Collection * @param {Array|Object} collection The collection to sample. * @param {number} [n=1] The number of elements to sample. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Array} Returns the random elements. * @example * * _.sampleSize([1, 2, 3], 2); * // => [3, 1] * * _.sampleSize([1, 2, 3], 4); * // => [2, 3, 1] */ function sampleSize(collection, n, guard) { if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { n = 1; } else { n = toInteger(n); } var func = isArray(collection) ? arraySampleSize : baseSampleSize; return func(collection, n); } /** * Creates an array of shuffled values, using a version of the * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to shuffle. * @returns {Array} Returns the new shuffled array. * @example * * _.shuffle([1, 2, 3, 4]); * // => [4, 1, 3, 2] */ function shuffle(collection) { var func = isArray(collection) ? arrayShuffle : baseShuffle; return func(collection); } /** * Gets the size of `collection` by returning its length for array-like * values or the number of own enumerable string keyed properties for objects. * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object|string} collection The collection to inspect. * @returns {number} Returns the collection size. * @example * * _.size([1, 2, 3]); * // => 3 * * _.size({ 'a': 1, 'b': 2 }); * // => 2 * * _.size('pebbles'); * // => 7 */ function size(collection) { if (collection == null) { return 0; } if (isArrayLike(collection)) { return isString(collection) ? stringSize(collection) : collection.length; } var tag = getTag(collection); if (tag == mapTag || tag == setTag) { return collection.size; } return baseKeys(collection).length; } /** * Checks if `predicate` returns truthy for **any** element of `collection`. * Iteration is stopped once `predicate` returns truthy. The predicate is * invoked with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {boolean} Returns `true` if any element passes the predicate check, * else `false`. * @example * * _.some([null, 0, 'yes', false], Boolean); * // => true * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false } * ]; * * // The `_.matches` iteratee shorthand. * _.some(users, { 'user': 'barney', 'active': false }); * // => false * * // The `_.matchesProperty` iteratee shorthand. * _.some(users, ['active', false]); * // => true * * // The `_.property` iteratee shorthand. * _.some(users, 'active'); * // => true */ function some(collection, predicate, guard) { var func = isArray(collection) ? arraySome : baseSome; if (guard && isIterateeCall(collection, predicate, guard)) { predicate = undefined; } return func(collection, getIteratee(predicate, 3)); } /** * Creates an array of elements, sorted in ascending order by the results of * running each element in a collection thru each iteratee. This method * performs a stable sort, that is, it preserves the original sort order of * equal elements. The iteratees are invoked with one argument: (value). * * @static * @memberOf _ * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {...(Function|Function[])} [iteratees=[_.identity]] * The iteratees to sort by. * @returns {Array} Returns the new sorted array. * @example * * var users = [ * { 'user': 'fred', 'age': 48 }, * { 'user': 'barney', 'age': 36 }, * { 'user': 'fred', 'age': 40 }, * { 'user': 'barney', 'age': 34 } * ]; * * _.sortBy(users, [function(o) { return o.user; }]); * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] * * _.sortBy(users, ['user', 'age']); * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] */ var sortBy = baseRest(function(collection, iteratees) { if (collection == null) { return []; } var length = iteratees.length; if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { iteratees = []; } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { iteratees = [iteratees[0]]; } return baseOrderBy(collection, baseFlatten(iteratees, 1), []); }); /*------------------------------------------------------------------------*/ /** * Gets the timestamp of the number of milliseconds that have elapsed since * the Unix epoch (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ * @since 2.4.0 * @category Date * @returns {number} Returns the timestamp. * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); * // => Logs the number of milliseconds it took for the deferred invocation. */ var now = ctxNow || function() { return root.Date.now(); }; /*------------------------------------------------------------------------*/ /** * The opposite of `_.before`; this method creates a function that invokes * `func` once it's called `n` or more times. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {number} n The number of calls before `func` is invoked. * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var saves = ['profile', 'settings']; * * var done = _.after(saves.length, function() { * console.log('done saving!'); * }); * * _.forEach(saves, function(type) { * asyncSave({ 'type': type, 'complete': done }); * }); * // => Logs 'done saving!' after the two async saves have completed. */ function after(n, func) { if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } n = toInteger(n); return function() { if (--n < 1) { return func.apply(this, arguments); } }; } /** * Creates a function that invokes `func`, with up to `n` arguments, * ignoring any additional arguments. * * @static * @memberOf _ * @since 3.0.0 * @category Function * @param {Function} func The function to cap arguments for. * @param {number} [n=func.length] The arity cap. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Function} Returns the new capped function. * @example * * _.map(['6', '8', '10'], _.ary(parseInt, 1)); * // => [6, 8, 10] */ function ary(func, n, guard) { n = guard ? undefined : n; n = (func && n == null) ? func.length : n; return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); } /** * Creates a function that invokes `func`, with the `this` binding and arguments * of the created function, while it's called less than `n` times. Subsequent * calls to the created function return the result of the last `func` invocation. * * @static * @memberOf _ * @since 3.0.0 * @category Function * @param {number} n The number of calls at which `func` is no longer invoked. * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * jQuery(element).on('click', _.before(5, addContactToList)); * // => Allows adding up to 4 contacts to the list. */ function before(n, func) { var result; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } n = toInteger(n); return function() { if (--n > 0) { result = func.apply(this, arguments); } if (n <= 1) { func = undefined; } return result; }; } /** * Creates a function that invokes `func` with the `this` binding of `thisArg` * and `partials` prepended to the arguments it receives. * * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, * may be used as a placeholder for partially applied arguments. * * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" * property of bound functions. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to bind. * @param {*} thisArg The `this` binding of `func`. * @param {...*} [partials] The arguments to be partially applied. * @returns {Function} Returns the new bound function. * @example * * function greet(greeting, punctuation) { * return greeting + ' ' + this.user + punctuation; * } * * var object = { 'user': 'fred' }; * * var bound = _.bind(greet, object, 'hi'); * bound('!'); * // => 'hi fred!' * * // Bound with placeholders. * var bound = _.bind(greet, object, _, '!'); * bound('hi'); * // => 'hi fred!' */ var bind = baseRest(function(func, thisArg, partials) { var bitmask = WRAP_BIND_FLAG; if (partials.length) { var holders = replaceHolders(partials, getHolder(bind)); bitmask |= WRAP_PARTIAL_FLAG; } return createWrap(func, bitmask, thisArg, partials, holders); }); /** * Creates a function that invokes the method at `object[key]` with `partials` * prepended to the arguments it receives. * * This method differs from `_.bind` by allowing bound functions to reference * methods that may be redefined or don't yet exist. See * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) * for more details. * * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for partially applied arguments. * * @static * @memberOf _ * @since 0.10.0 * @category Function * @param {Object} object The object to invoke the method on. * @param {string} key The key of the method. * @param {...*} [partials] The arguments to be partially applied. * @returns {Function} Returns the new bound function. * @example * * var object = { * 'user': 'fred', * 'greet': function(greeting, punctuation) { * return greeting + ' ' + this.user + punctuation; * } * }; * * var bound = _.bindKey(object, 'greet', 'hi'); * bound('!'); * // => 'hi fred!' * * object.greet = function(greeting, punctuation) { * return greeting + 'ya ' + this.user + punctuation; * }; * * bound('!'); * // => 'hiya fred!' * * // Bound with placeholders. * var bound = _.bindKey(object, 'greet', _, '!'); * bound('hi'); * // => 'hiya fred!' */ var bindKey = baseRest(function(object, key, partials) { var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; if (partials.length) { var holders = replaceHolders(partials, getHolder(bindKey)); bitmask |= WRAP_PARTIAL_FLAG; } return createWrap(key, bitmask, object, partials, holders); }); /** * Creates a function that accepts arguments of `func` and either invokes * `func` returning its result, if at least `arity` number of arguments have * been provided, or returns a function that accepts the remaining `func` * arguments, and so on. The arity of `func` may be specified if `func.length` * is not sufficient. * * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, * may be used as a placeholder for provided arguments. * * **Note:** This method doesn't set the "length" property of curried functions. * * @static * @memberOf _ * @since 2.0.0 * @category Function * @param {Function} func The function to curry. * @param {number} [arity=func.length] The arity of `func`. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Function} Returns the new curried function. * @example * * var abc = function(a, b, c) { * return [a, b, c]; * }; * * var curried = _.curry(abc); * * curried(1)(2)(3); * // => [1, 2, 3] * * curried(1, 2)(3); * // => [1, 2, 3] * * curried(1, 2, 3); * // => [1, 2, 3] * * // Curried with placeholders. * curried(1)(_, 3)(2); * // => [1, 2, 3] */ function curry(func, arity, guard) { arity = guard ? undefined : arity; var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); result.placeholder = curry.placeholder; return result; } /** * This method is like `_.curry` except that arguments are applied to `func` * in the manner of `_.partialRight` instead of `_.partial`. * * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for provided arguments. * * **Note:** This method doesn't set the "length" property of curried functions. * * @static * @memberOf _ * @since 3.0.0 * @category Function * @param {Function} func The function to curry. * @param {number} [arity=func.length] The arity of `func`. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Function} Returns the new curried function. * @example * * var abc = function(a, b, c) { * return [a, b, c]; * }; * * var curried = _.curryRight(abc); * * curried(3)(2)(1); * // => [1, 2, 3] * * curried(2, 3)(1); * // => [1, 2, 3] * * curried(1, 2, 3); * // => [1, 2, 3] * * // Curried with placeholders. * curried(3)(1, _)(2); * // => [1, 2, 3] */ function curryRight(func, arity, guard) { arity = guard ? undefined : arity; var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); result.placeholder = curryRight.placeholder; return result; } /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel * delayed `func` invocations and a `flush` method to immediately invoke them. * Provide `options` to indicate whether `func` should be invoked on the * leading and/or trailing edge of the `wait` timeout. The `func` is invoked * with the last arguments provided to the debounced function. Subsequent * calls to the debounced function return the result of the last `func` * invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the debounced function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=false] * Specify invoking on the leading edge of the timeout. * @param {number} [options.maxWait] * The maximum time `func` is allowed to be delayed before it's invoked. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * // Avoid costly calculations while the window size is in flux. * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); * * // Invoke `sendMail` when clicked, debouncing subsequent calls. * jQuery(element).on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * * // Ensure `batchLog` is invoked once after 1 second of debounced calls. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); * var source = new EventSource('/stream'); * jQuery(source).on('message', debounced); * * // Cancel the trailing debounced invocation. * jQuery(window).on('popstate', debounced.cancel); */ function debounce(func, wait, options) { var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = toNumber(wait) || 0; if (isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs, thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = setTimeout(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result = wait - timeSinceLastCall; return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); } function timerExpired() { var time = now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = setTimeout(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { clearTimeout(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(now()); } function debounced() { var time = now(), isInvoking = shouldInvoke(time); lastArgs = arguments; lastThis = this; lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; return debounced; } /** * Defers invoking the `func` until the current call stack has cleared. Any * additional arguments are provided to `func` when it's invoked. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to defer. * @param {...*} [args] The arguments to invoke `func` with. * @returns {number} Returns the timer id. * @example * * _.defer(function(text) { * console.log(text); * }, 'deferred'); * // => Logs 'deferred' after one millisecond. */ var defer = baseRest(function(func, args) { return baseDelay(func, 1, args); }); /** * Invokes `func` after `wait` milliseconds. Any additional arguments are * provided to `func` when it's invoked. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to delay. * @param {number} wait The number of milliseconds to delay invocation. * @param {...*} [args] The arguments to invoke `func` with. * @returns {number} Returns the timer id. * @example * * _.delay(function(text) { * console.log(text); * }, 1000, 'later'); * // => Logs 'later' after one second. */ var delay = baseRest(function(func, wait, args) { return baseDelay(func, toNumber(wait) || 0, args); }); /** * Creates a function that invokes `func` with arguments reversed. * * @static * @memberOf _ * @since 4.0.0 * @category Function * @param {Function} func The function to flip arguments for. * @returns {Function} Returns the new flipped function. * @example * * var flipped = _.flip(function() { * return _.toArray(arguments); * }); * * flipped('a', 'b', 'c', 'd'); * // => ['d', 'c', 'b', 'a'] */ function flip(func) { return createWrap(func, WRAP_FLIP_FLAG); } /** * Creates a function that memoizes the result of `func`. If `resolver` is * provided, it determines the cache key for storing the result based on the * arguments provided to the memoized function. By default, the first argument * provided to the memoized function is used as the map cache key. The `func` * is invoked with the `this` binding of the memoized function. * * **Note:** The cache is exposed as the `cache` property on the memoized * function. Its creation may be customized by replacing the `_.memoize.Cache` * constructor with one whose instances implement the * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) * method interface of `clear`, `delete`, `get`, `has`, and `set`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to have its output memoized. * @param {Function} [resolver] The function to resolve the cache key. * @returns {Function} Returns the new memoized function. * @example * * var object = { 'a': 1, 'b': 2 }; * var other = { 'c': 3, 'd': 4 }; * * var values = _.memoize(_.values); * values(object); * // => [1, 2] * * values(other); * // => [3, 4] * * object.a = 2; * values(object); * // => [1, 2] * * // Modify the result cache. * values.cache.set(object, ['a', 'b']); * values(object); * // => ['a', 'b'] * * // Replace `_.memoize.Cache`. * _.memoize.Cache = WeakMap; */ function memoize(func, resolver) { if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { throw new TypeError(FUNC_ERROR_TEXT); } var memoized = function() { var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache; if (cache.has(key)) { return cache.get(key); } var result = func.apply(this, args); memoized.cache = cache.set(key, result) || cache; return result; }; memoized.cache = new (memoize.Cache || MapCache); return memoized; } // Expose `MapCache`. memoize.Cache = MapCache; /** * Creates a function that negates the result of the predicate `func`. The * `func` predicate is invoked with the `this` binding and arguments of the * created function. * * @static * @memberOf _ * @since 3.0.0 * @category Function * @param {Function} predicate The predicate to negate. * @returns {Function} Returns the new negated function. * @example * * function isEven(n) { * return n % 2 == 0; * } * * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); * // => [1, 3, 5] */ function negate(predicate) { if (typeof predicate != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } return function() { var args = arguments; switch (args.length) { case 0: return !predicate.call(this); case 1: return !predicate.call(this, args[0]); case 2: return !predicate.call(this, args[0], args[1]); case 3: return !predicate.call(this, args[0], args[1], args[2]); } return !predicate.apply(this, args); }; } /** * Creates a function that is restricted to invoking `func` once. Repeat calls * to the function return the value of the first invocation. The `func` is * invoked with the `this` binding and arguments of the created function. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var initialize = _.once(createApplication); * initialize(); * initialize(); * // => `createApplication` is invoked once */ function once(func) { return before(2, func); } /** * Creates a function that invokes `func` with its arguments transformed. * * @static * @since 4.0.0 * @memberOf _ * @category Function * @param {Function} func The function to wrap. * @param {...(Function|Function[])} [transforms=[_.identity]] * The argument transforms. * @returns {Function} Returns the new function. * @example * * function doubled(n) { * return n * 2; * } * * function square(n) { * return n * n; * } * * var func = _.overArgs(function(x, y) { * return [x, y]; * }, [square, doubled]); * * func(9, 3); * // => [81, 6] * * func(10, 5); * // => [100, 10] */ var overArgs = castRest(function(func, transforms) { transforms = (transforms.length == 1 && isArray(transforms[0])) ? arrayMap(transforms[0], baseUnary(getIteratee())) : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); var funcsLength = transforms.length; return baseRest(function(args) { var index = -1, length = nativeMin(args.length, funcsLength); while (++index < length) { args[index] = transforms[index].call(this, args[index]); } return apply(func, this, args); }); }); /** * Creates a function that invokes `func` with `partials` prepended to the * arguments it receives. This method is like `_.bind` except it does **not** * alter the `this` binding. * * The `_.partial.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for partially applied arguments. * * **Note:** This method doesn't set the "length" property of partially * applied functions. * * @static * @memberOf _ * @since 0.2.0 * @category Function * @param {Function} func The function to partially apply arguments to. * @param {...*} [partials] The arguments to be partially applied. * @returns {Function} Returns the new partially applied function. * @example * * function greet(greeting, name) { * return greeting + ' ' + name; * } * * var sayHelloTo = _.partial(greet, 'hello'); * sayHelloTo('fred'); * // => 'hello fred' * * // Partially applied with placeholders. * var greetFred = _.partial(greet, _, 'fred'); * greetFred('hi'); * // => 'hi fred' */ var partial = baseRest(function(func, partials) { var holders = replaceHolders(partials, getHolder(partial)); return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); }); /** * This method is like `_.partial` except that partially applied arguments * are appended to the arguments it receives. * * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for partially applied arguments. * * **Note:** This method doesn't set the "length" property of partially * applied functions. * * @static * @memberOf _ * @since 1.0.0 * @category Function * @param {Function} func The function to partially apply arguments to. * @param {...*} [partials] The arguments to be partially applied. * @returns {Function} Returns the new partially applied function. * @example * * function greet(greeting, name) { * return greeting + ' ' + name; * } * * var greetFred = _.partialRight(greet, 'fred'); * greetFred('hi'); * // => 'hi fred' * * // Partially applied with placeholders. * var sayHelloTo = _.partialRight(greet, 'hello', _); * sayHelloTo('fred'); * // => 'hello fred' */ var partialRight = baseRest(function(func, partials) { var holders = replaceHolders(partials, getHolder(partialRight)); return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); }); /** * Creates a function that invokes `func` with arguments arranged according * to the specified `indexes` where the argument value at the first index is * provided as the first argument, the argument value at the second index is * provided as the second argument, and so on. * * @static * @memberOf _ * @since 3.0.0 * @category Function * @param {Function} func The function to rearrange arguments for. * @param {...(number|number[])} indexes The arranged argument indexes. * @returns {Function} Returns the new function. * @example * * var rearged = _.rearg(function(a, b, c) { * return [a, b, c]; * }, [2, 0, 1]); * * rearged('b', 'c', 'a') * // => ['a', 'b', 'c'] */ var rearg = flatRest(function(func, indexes) { return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); }); /** * Creates a function that invokes `func` with the `this` binding of the * created function and arguments from `start` and beyond provided as * an array. * * **Note:** This method is based on the * [rest parameter](https://mdn.io/rest_parameters). * * @static * @memberOf _ * @since 4.0.0 * @category Function * @param {Function} func The function to apply a rest parameter to. * @param {number} [start=func.length-1] The start position of the rest parameter. * @returns {Function} Returns the new function. * @example * * var say = _.rest(function(what, names) { * return what + ' ' + _.initial(names).join(', ') + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); * }); * * say('hello', 'fred', 'barney', 'pebbles'); * // => 'hello fred, barney, & pebbles' */ function rest(func, start) { if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } start = start === undefined ? start : toInteger(start); return baseRest(func, start); } /** * Creates a function that invokes `func` with the `this` binding of the * create function and an array of arguments much like * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). * * **Note:** This method is based on the * [spread operator](https://mdn.io/spread_operator). * * @static * @memberOf _ * @since 3.2.0 * @category Function * @param {Function} func The function to spread arguments over. * @param {number} [start=0] The start position of the spread. * @returns {Function} Returns the new function. * @example * * var say = _.spread(function(who, what) { * return who + ' says ' + what; * }); * * say(['fred', 'hello']); * // => 'fred says hello' * * var numbers = Promise.all([ * Promise.resolve(40), * Promise.resolve(36) * ]); * * numbers.then(_.spread(function(x, y) { * return x + y; * })); * // => a Promise of 76 */ function spread(func, start) { if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } start = start == null ? 0 : nativeMax(toInteger(start), 0); return baseRest(function(args) { var array = args[start], otherArgs = castSlice(args, 0, start); if (array) { arrayPush(otherArgs, array); } return apply(func, this, otherArgs); }); } /** * Creates a throttled function that only invokes `func` at most once per * every `wait` milliseconds. The throttled function comes with a `cancel` * method to cancel delayed `func` invocations and a `flush` method to * immediately invoke them. Provide `options` to indicate whether `func` * should be invoked on the leading and/or trailing edge of the `wait` * timeout. The `func` is invoked with the last arguments provided to the * throttled function. Subsequent calls to the throttled function return the * result of the last `func` invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the throttled function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.throttle` and `_.debounce`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to throttle. * @param {number} [wait=0] The number of milliseconds to throttle invocations to. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=true] * Specify invoking on the leading edge of the timeout. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new throttled function. * @example * * // Avoid excessively updating the position while scrolling. * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); * * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); * jQuery(element).on('click', throttled); * * // Cancel the trailing throttled invocation. * jQuery(window).on('popstate', throttled.cancel); */ function throttle(func, wait, options) { var leading = true, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } if (isObject(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } return debounce(func, wait, { 'leading': leading, 'maxWait': wait, 'trailing': trailing }); } /** * Creates a function that accepts up to one argument, ignoring any * additional arguments. * * @static * @memberOf _ * @since 4.0.0 * @category Function * @param {Function} func The function to cap arguments for. * @returns {Function} Returns the new capped function. * @example * * _.map(['6', '8', '10'], _.unary(parseInt)); * // => [6, 8, 10] */ function unary(func) { return ary(func, 1); } /** * Creates a function that provides `value` to `wrapper` as its first * argument. Any additional arguments provided to the function are appended * to those provided to the `wrapper`. The wrapper is invoked with the `this` * binding of the created function. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {*} value The value to wrap. * @param {Function} [wrapper=identity] The wrapper function. * @returns {Function} Returns the new function. * @example * * var p = _.wrap(_.escape, function(func, text) { * return '

' + func(text) + '

'; * }); * * p('fred, barney, & pebbles'); * // => '

fred, barney, & pebbles

' */ function wrap(value, wrapper) { return partial(castFunction(wrapper), value); } /*------------------------------------------------------------------------*/ /** * Casts `value` as an array if it's not one. * * @static * @memberOf _ * @since 4.4.0 * @category Lang * @param {*} value The value to inspect. * @returns {Array} Returns the cast array. * @example * * _.castArray(1); * // => [1] * * _.castArray({ 'a': 1 }); * // => [{ 'a': 1 }] * * _.castArray('abc'); * // => ['abc'] * * _.castArray(null); * // => [null] * * _.castArray(undefined); * // => [undefined] * * _.castArray(); * // => [] * * var array = [1, 2, 3]; * console.log(_.castArray(array) === array); * // => true */ function castArray() { if (!arguments.length) { return []; } var value = arguments[0]; return isArray(value) ? value : [value]; } /** * Creates a shallow clone of `value`. * * **Note:** This method is loosely based on the * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) * and supports cloning arrays, array buffers, booleans, date objects, maps, * numbers, `Object` objects, regexes, sets, strings, symbols, and typed * arrays. The own enumerable properties of `arguments` objects are cloned * as plain objects. An empty object is returned for uncloneable values such * as error objects, functions, DOM nodes, and WeakMaps. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to clone. * @returns {*} Returns the cloned value. * @see _.cloneDeep * @example * * var objects = [{ 'a': 1 }, { 'b': 2 }]; * * var shallow = _.clone(objects); * console.log(shallow[0] === objects[0]); * // => true */ function clone(value) { return baseClone(value, CLONE_SYMBOLS_FLAG); } /** * This method is like `_.clone` except that it accepts `customizer` which * is invoked to produce the cloned value. If `customizer` returns `undefined`, * cloning is handled by the method instead. The `customizer` is invoked with * up to four arguments; (value [, index|key, object, stack]). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to clone. * @param {Function} [customizer] The function to customize cloning. * @returns {*} Returns the cloned value. * @see _.cloneDeepWith * @example * * function customizer(value) { * if (_.isElement(value)) { * return value.cloneNode(false); * } * } * * var el = _.cloneWith(document.body, customizer); * * console.log(el === document.body); * // => false * console.log(el.nodeName); * // => 'BODY' * console.log(el.childNodes.length); * // => 0 */ function cloneWith(value, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); } /** * This method is like `_.clone` except that it recursively clones `value`. * * @static * @memberOf _ * @since 1.0.0 * @category Lang * @param {*} value The value to recursively clone. * @returns {*} Returns the deep cloned value. * @see _.clone * @example * * var objects = [{ 'a': 1 }, { 'b': 2 }]; * * var deep = _.cloneDeep(objects); * console.log(deep[0] === objects[0]); * // => false */ function cloneDeep(value) { return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); } /** * This method is like `_.cloneWith` except that it recursively clones `value`. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to recursively clone. * @param {Function} [customizer] The function to customize cloning. * @returns {*} Returns the deep cloned value. * @see _.cloneWith * @example * * function customizer(value) { * if (_.isElement(value)) { * return value.cloneNode(true); * } * } * * var el = _.cloneDeepWith(document.body, customizer); * * console.log(el === document.body); * // => false * console.log(el.nodeName); * // => 'BODY' * console.log(el.childNodes.length); * // => 20 */ function cloneDeepWith(value, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); } /** * Checks if `object` conforms to `source` by invoking the predicate * properties of `source` with the corresponding property values of `object`. * * **Note:** This method is equivalent to `_.conforms` when `source` is * partially applied. * * @static * @memberOf _ * @since 4.14.0 * @category Lang * @param {Object} object The object to inspect. * @param {Object} source The object of property predicates to conform to. * @returns {boolean} Returns `true` if `object` conforms, else `false`. * @example * * var object = { 'a': 1, 'b': 2 }; * * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); * // => true * * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); * // => false */ function conformsTo(object, source) { return source == null || baseConformsTo(object, source, keys(source)); } /** * Performs a * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * comparison between two values to determine if they are equivalent. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * * var object = { 'a': 1 }; * var other = { 'a': 1 }; * * _.eq(object, object); * // => true * * _.eq(object, other); * // => false * * _.eq('a', 'a'); * // => true * * _.eq('a', Object('a')); * // => false * * _.eq(NaN, NaN); * // => true */ function eq(value, other) { return value === other || (value !== value && other !== other); } /** * Checks if `value` is greater than `other`. * * @static * @memberOf _ * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if `value` is greater than `other`, * else `false`. * @see _.lt * @example * * _.gt(3, 1); * // => true * * _.gt(3, 3); * // => false * * _.gt(1, 3); * // => false */ var gt = createRelationalOperation(baseGt); /** * Checks if `value` is greater than or equal to `other`. * * @static * @memberOf _ * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if `value` is greater than or equal to * `other`, else `false`. * @see _.lte * @example * * _.gte(3, 1); * // => true * * _.gte(3, 3); * // => true * * _.gte(1, 3); * // => false */ var gte = createRelationalOperation(function(value, other) { return value >= other; }); /** * Checks if `value` is likely an `arguments` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an `arguments` object, * else `false`. * @example * * _.isArguments(function() { return arguments; }()); * // => true * * _.isArguments([1, 2, 3]); * // => false */ var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); }; /** * Checks if `value` is classified as an `Array` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array, else `false`. * @example * * _.isArray([1, 2, 3]); * // => true * * _.isArray(document.body.children); * // => false * * _.isArray('abc'); * // => false * * _.isArray(_.noop); * // => false */ var isArray = Array.isArray; /** * Checks if `value` is classified as an `ArrayBuffer` object. * * @static * @memberOf _ * @since 4.3.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. * @example * * _.isArrayBuffer(new ArrayBuffer(2)); * // => true * * _.isArrayBuffer(new Array(2)); * // => false */ var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; /** * Checks if `value` is array-like. A value is considered array-like if it's * not a function and has a `value.length` that's an integer greater than or * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is array-like, else `false`. * @example * * _.isArrayLike([1, 2, 3]); * // => true * * _.isArrayLike(document.body.children); * // => true * * _.isArrayLike('abc'); * // => true * * _.isArrayLike(_.noop); * // => false */ function isArrayLike(value) { return value != null && isLength(value.length) && !isFunction(value); } /** * This method is like `_.isArrayLike` except that it also checks if `value` * is an object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array-like object, * else `false`. * @example * * _.isArrayLikeObject([1, 2, 3]); * // => true * * _.isArrayLikeObject(document.body.children); * // => true * * _.isArrayLikeObject('abc'); * // => false * * _.isArrayLikeObject(_.noop); * // => false */ function isArrayLikeObject(value) { return isObjectLike(value) && isArrayLike(value); } /** * Checks if `value` is classified as a boolean primitive or object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. * @example * * _.isBoolean(false); * // => true * * _.isBoolean(null); * // => false */ function isBoolean(value) { return value === true || value === false || (isObjectLike(value) && baseGetTag(value) == boolTag); } /** * Checks if `value` is a buffer. * * @static * @memberOf _ * @since 4.3.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. * @example * * _.isBuffer(new Buffer(2)); * // => true * * _.isBuffer(new Uint8Array(2)); * // => false */ var isBuffer = nativeIsBuffer || stubFalse; /** * Checks if `value` is classified as a `Date` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a date object, else `false`. * @example * * _.isDate(new Date); * // => true * * _.isDate('Mon April 23 2012'); * // => false */ var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; /** * Checks if `value` is likely a DOM element. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. * @example * * _.isElement(document.body); * // => true * * _.isElement(''); * // => false */ function isElement(value) { return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); } /** * Checks if `value` is an empty object, collection, map, or set. * * Objects are considered empty if they have no own enumerable string keyed * properties. * * Array-like values such as `arguments` objects, arrays, buffers, strings, or * jQuery-like collections are considered empty if they have a `length` of `0`. * Similarly, maps and sets are considered empty if they have a `size` of `0`. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is empty, else `false`. * @example * * _.isEmpty(null); * // => true * * _.isEmpty(true); * // => true * * _.isEmpty(1); * // => true * * _.isEmpty([1, 2, 3]); * // => false * * _.isEmpty({ 'a': 1 }); * // => false */ function isEmpty(value) { if (value == null) { return true; } if (isArrayLike(value) && (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || isBuffer(value) || isTypedArray(value) || isArguments(value))) { return !value.length; } var tag = getTag(value); if (tag == mapTag || tag == setTag) { return !value.size; } if (isPrototype(value)) { return !baseKeys(value).length; } for (var key in value) { if (hasOwnProperty.call(value, key)) { return false; } } return true; } /** * Performs a deep comparison between two values to determine if they are * equivalent. * * **Note:** This method supports comparing arrays, array buffers, booleans, * date objects, error objects, maps, numbers, `Object` objects, regexes, * sets, strings, symbols, and typed arrays. `Object` objects are compared * by their own, not inherited, enumerable properties. Functions and DOM * nodes are compared by strict equality, i.e. `===`. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * * var object = { 'a': 1 }; * var other = { 'a': 1 }; * * _.isEqual(object, other); * // => true * * object === other; * // => false */ function isEqual(value, other) { return baseIsEqual(value, other); } /** * This method is like `_.isEqual` except that it accepts `customizer` which * is invoked to compare values. If `customizer` returns `undefined`, comparisons * are handled by the method instead. The `customizer` is invoked with up to * six arguments: (objValue, othValue [, index|key, object, other, stack]). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * * function isGreeting(value) { * return /^h(?:i|ello)$/.test(value); * } * * function customizer(objValue, othValue) { * if (isGreeting(objValue) && isGreeting(othValue)) { * return true; * } * } * * var array = ['hello', 'goodbye']; * var other = ['hi', 'goodbye']; * * _.isEqualWith(array, other, customizer); * // => true */ function isEqualWith(value, other, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; var result = customizer ? customizer(value, other) : undefined; return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; } /** * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, * `SyntaxError`, `TypeError`, or `URIError` object. * * @static * @memberOf _ * @since 3.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an error object, else `false`. * @example * * _.isError(new Error); * // => true * * _.isError(Error); * // => false */ function isError(value) { if (!isObjectLike(value)) { return false; } var tag = baseGetTag(value); return tag == errorTag || tag == domExcTag || (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); } /** * Checks if `value` is a finite primitive number. * * **Note:** This method is based on * [`Number.isFinite`](https://mdn.io/Number/isFinite). * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. * @example * * _.isFinite(3); * // => true * * _.isFinite(Number.MIN_VALUE); * // => true * * _.isFinite(Infinity); * // => false * * _.isFinite('3'); * // => false */ function isFinite(value) { return typeof value == 'number' && nativeIsFinite(value); } /** * Checks if `value` is classified as a `Function` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true * * _.isFunction(/abc/); * // => false */ function isFunction(value) { if (!isObject(value)) { return false; } // The use of `Object#toString` avoids issues with the `typeof` operator // in Safari 9 which returns 'object' for typed arrays and other constructors. var tag = baseGetTag(value); return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; } /** * Checks if `value` is an integer. * * **Note:** This method is based on * [`Number.isInteger`](https://mdn.io/Number/isInteger). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an integer, else `false`. * @example * * _.isInteger(3); * // => true * * _.isInteger(Number.MIN_VALUE); * // => false * * _.isInteger(Infinity); * // => false * * _.isInteger('3'); * // => false */ function isInteger(value) { return typeof value == 'number' && value == toInteger(value); } /** * Checks if `value` is a valid array-like length. * * **Note:** This method is loosely based on * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. * @example * * _.isLength(3); * // => true * * _.isLength(Number.MIN_VALUE); * // => false * * _.isLength(Infinity); * // => false * * _.isLength('3'); * // => false */ function isLength(value) { return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return value != null && (type == 'object' || type == 'function'); } /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return value != null && typeof value == 'object'; } /** * Checks if `value` is classified as a `Map` object. * * @static * @memberOf _ * @since 4.3.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a map, else `false`. * @example * * _.isMap(new Map); * // => true * * _.isMap(new WeakMap); * // => false */ var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; /** * Performs a partial deep comparison between `object` and `source` to * determine if `object` contains equivalent property values. * * **Note:** This method is equivalent to `_.matches` when `source` is * partially applied. * * Partial comparisons will match empty array and empty object `source` * values against any array or object value, respectively. See `_.isEqual` * for a list of supported value comparisons. * * @static * @memberOf _ * @since 3.0.0 * @category Lang * @param {Object} object The object to inspect. * @param {Object} source The object of property values to match. * @returns {boolean} Returns `true` if `object` is a match, else `false`. * @example * * var object = { 'a': 1, 'b': 2 }; * * _.isMatch(object, { 'b': 2 }); * // => true * * _.isMatch(object, { 'b': 1 }); * // => false */ function isMatch(object, source) { return object === source || baseIsMatch(object, source, getMatchData(source)); } /** * This method is like `_.isMatch` except that it accepts `customizer` which * is invoked to compare values. If `customizer` returns `undefined`, comparisons * are handled by the method instead. The `customizer` is invoked with five * arguments: (objValue, srcValue, index|key, object, source). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {Object} object The object to inspect. * @param {Object} source The object of property values to match. * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if `object` is a match, else `false`. * @example * * function isGreeting(value) { * return /^h(?:i|ello)$/.test(value); * } * * function customizer(objValue, srcValue) { * if (isGreeting(objValue) && isGreeting(srcValue)) { * return true; * } * } * * var object = { 'greeting': 'hello' }; * var source = { 'greeting': 'hi' }; * * _.isMatchWith(object, source, customizer); * // => true */ function isMatchWith(object, source, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; return baseIsMatch(object, source, getMatchData(source), customizer); } /** * Checks if `value` is `NaN`. * * **Note:** This method is based on * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for * `undefined` and other non-number values. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. * @example * * _.isNaN(NaN); * // => true * * _.isNaN(new Number(NaN)); * // => true * * isNaN(undefined); * // => true * * _.isNaN(undefined); * // => false */ function isNaN(value) { // An `NaN` primitive is the only value that is not equal to itself. // Perform the `toStringTag` check first to avoid errors with some // ActiveX objects in IE. return isNumber(value) && value != +value; } /** * Checks if `value` is a pristine native function. * * **Note:** This method can't reliably detect native functions in the presence * of the core-js package because core-js circumvents this kind of detection. * Despite multiple requests, the core-js maintainer has made it clear: any * attempt to fix the detection will be obstructed. As a result, we're left * with little choice but to throw an error. Unfortunately, this also affects * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), * which rely on core-js. * * @static * @memberOf _ * @since 3.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a native function, * else `false`. * @example * * _.isNative(Array.prototype.push); * // => true * * _.isNative(_); * // => false */ function isNative(value) { if (isMaskable(value)) { throw new Error(CORE_ERROR_TEXT); } return baseIsNative(value); } /** * Checks if `value` is `null`. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is `null`, else `false`. * @example * * _.isNull(null); * // => true * * _.isNull(void 0); * // => false */ function isNull(value) { return value === null; } /** * Checks if `value` is `null` or `undefined`. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is nullish, else `false`. * @example * * _.isNil(null); * // => true * * _.isNil(void 0); * // => true * * _.isNil(NaN); * // => false */ function isNil(value) { return value == null; } /** * Checks if `value` is classified as a `Number` primitive or object. * * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are * classified as numbers, use the `_.isFinite` method. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a number, else `false`. * @example * * _.isNumber(3); * // => true * * _.isNumber(Number.MIN_VALUE); * // => true * * _.isNumber(Infinity); * // => true * * _.isNumber('3'); * // => false */ function isNumber(value) { return typeof value == 'number' || (isObjectLike(value) && baseGetTag(value) == numberTag); } /** * Checks if `value` is a plain object, that is, an object created by the * `Object` constructor or one with a `[[Prototype]]` of `null`. * * @static * @memberOf _ * @since 0.8.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. * @example * * function Foo() { * this.a = 1; * } * * _.isPlainObject(new Foo); * // => false * * _.isPlainObject([1, 2, 3]); * // => false * * _.isPlainObject({ 'x': 0, 'y': 0 }); * // => true * * _.isPlainObject(Object.create(null)); * // => true */ function isPlainObject(value) { if (!isObjectLike(value) || baseGetTag(value) != objectTag) { return false; } var proto = getPrototype(value); if (proto === null) { return true; } var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; return typeof Ctor == 'function' && Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString; } /** * Checks if `value` is classified as a `RegExp` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. * @example * * _.isRegExp(/abc/); * // => true * * _.isRegExp('/abc/'); * // => false */ var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; /** * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 * double precision number which isn't the result of a rounded unsafe integer. * * **Note:** This method is based on * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. * @example * * _.isSafeInteger(3); * // => true * * _.isSafeInteger(Number.MIN_VALUE); * // => false * * _.isSafeInteger(Infinity); * // => false * * _.isSafeInteger('3'); * // => false */ function isSafeInteger(value) { return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; } /** * Checks if `value` is classified as a `Set` object. * * @static * @memberOf _ * @since 4.3.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a set, else `false`. * @example * * _.isSet(new Set); * // => true * * _.isSet(new WeakSet); * // => false */ var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; /** * Checks if `value` is classified as a `String` primitive or object. * * @static * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a string, else `false`. * @example * * _.isString('abc'); * // => true * * _.isString(1); * // => false */ function isString(value) { return typeof value == 'string' || (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); } /** * Checks if `value` is classified as a `Symbol` primitive or object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. * @example * * _.isSymbol(Symbol.iterator); * // => true * * _.isSymbol('abc'); * // => false */ function isSymbol(value) { return typeof value == 'symbol' || (isObjectLike(value) && baseGetTag(value) == symbolTag); } /** * Checks if `value` is classified as a typed array. * * @static * @memberOf _ * @since 3.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. * @example * * _.isTypedArray(new Uint8Array); * // => true * * _.isTypedArray([]); * // => false */ var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; /** * Checks if `value` is `undefined`. * * @static * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. * @example * * _.isUndefined(void 0); * // => true * * _.isUndefined(null); * // => false */ function isUndefined(value) { return value === undefined; } /** * Checks if `value` is classified as a `WeakMap` object. * * @static * @memberOf _ * @since 4.3.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. * @example * * _.isWeakMap(new WeakMap); * // => true * * _.isWeakMap(new Map); * // => false */ function isWeakMap(value) { return isObjectLike(value) && getTag(value) == weakMapTag; } /** * Checks if `value` is classified as a `WeakSet` object. * * @static * @memberOf _ * @since 4.3.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. * @example * * _.isWeakSet(new WeakSet); * // => true * * _.isWeakSet(new Set); * // => false */ function isWeakSet(value) { return isObjectLike(value) && baseGetTag(value) == weakSetTag; } /** * Checks if `value` is less than `other`. * * @static * @memberOf _ * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if `value` is less than `other`, * else `false`. * @see _.gt * @example * * _.lt(1, 3); * // => true * * _.lt(3, 3); * // => false * * _.lt(3, 1); * // => false */ var lt = createRelationalOperation(baseLt); /** * Checks if `value` is less than or equal to `other`. * * @static * @memberOf _ * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if `value` is less than or equal to * `other`, else `false`. * @see _.gte * @example * * _.lte(1, 3); * // => true * * _.lte(3, 3); * // => true * * _.lte(3, 1); * // => false */ var lte = createRelationalOperation(function(value, other) { return value <= other; }); /** * Converts `value` to an array. * * @static * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to convert. * @returns {Array} Returns the converted array. * @example * * _.toArray({ 'a': 1, 'b': 2 }); * // => [1, 2] * * _.toArray('abc'); * // => ['a', 'b', 'c'] * * _.toArray(1); * // => [] * * _.toArray(null); * // => [] */ function toArray(value) { if (!value) { return []; } if (isArrayLike(value)) { return isString(value) ? stringToArray(value) : copyArray(value); } if (symIterator && value[symIterator]) { return iteratorToArray(value[symIterator]()); } var tag = getTag(value), func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); return func(value); } /** * Converts `value` to a finite number. * * @static * @memberOf _ * @since 4.12.0 * @category Lang * @param {*} value The value to convert. * @returns {number} Returns the converted number. * @example * * _.toFinite(3.2); * // => 3.2 * * _.toFinite(Number.MIN_VALUE); * // => 5e-324 * * _.toFinite(Infinity); * // => 1.7976931348623157e+308 * * _.toFinite('3.2'); * // => 3.2 */ function toFinite(value) { if (!value) { return value === 0 ? value : 0; } value = toNumber(value); if (value === INFINITY || value === -INFINITY) { var sign = (value < 0 ? -1 : 1); return sign * MAX_INTEGER; } return value === value ? value : 0; } /** * Converts `value` to an integer. * * **Note:** This method is loosely based on * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to convert. * @returns {number} Returns the converted integer. * @example * * _.toInteger(3.2); * // => 3 * * _.toInteger(Number.MIN_VALUE); * // => 0 * * _.toInteger(Infinity); * // => 1.7976931348623157e+308 * * _.toInteger('3.2'); * // => 3 */ function toInteger(value) { var result = toFinite(value), remainder = result % 1; return result === result ? (remainder ? result - remainder : result) : 0; } /** * Converts `value` to an integer suitable for use as the length of an * array-like object. * * **Note:** This method is based on * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to convert. * @returns {number} Returns the converted integer. * @example * * _.toLength(3.2); * // => 3 * * _.toLength(Number.MIN_VALUE); * // => 0 * * _.toLength(Infinity); * // => 4294967295 * * _.toLength('3.2'); * // => 3 */ function toLength(value) { return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; } /** * Converts `value` to a number. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {number} Returns the number. * @example * * _.toNumber(3.2); * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 * * _.toNumber(Infinity); * // => Infinity * * _.toNumber('3.2'); * // => 3.2 */ function toNumber(value) { if (typeof value == 'number') { return value; } if (isSymbol(value)) { return NAN; } if (isObject(value)) { var other = typeof value.valueOf == 'function' ? value.valueOf() : value; value = isObject(other) ? (other + '') : other; } if (typeof value != 'string') { return value === 0 ? value : +value; } value = value.replace(reTrim, ''); var isBinary = reIsBinary.test(value); return (isBinary || reIsOctal.test(value)) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : (reIsBadHex.test(value) ? NAN : +value); } /** * Converts `value` to a plain object flattening inherited enumerable string * keyed properties of `value` to own properties of the plain object. * * @static * @memberOf _ * @since 3.0.0 * @category Lang * @param {*} value The value to convert. * @returns {Object} Returns the converted plain object. * @example * * function Foo() { * this.b = 2; * } * * Foo.prototype.c = 3; * * _.assign({ 'a': 1 }, new Foo); * // => { 'a': 1, 'b': 2 } * * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); * // => { 'a': 1, 'b': 2, 'c': 3 } */ function toPlainObject(value) { return copyObject(value, keysIn(value)); } /** * Converts `value` to a safe integer. A safe integer can be compared and * represented correctly. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to convert. * @returns {number} Returns the converted integer. * @example * * _.toSafeInteger(3.2); * // => 3 * * _.toSafeInteger(Number.MIN_VALUE); * // => 0 * * _.toSafeInteger(Infinity); * // => 9007199254740991 * * _.toSafeInteger('3.2'); * // => 3 */ function toSafeInteger(value) { return value ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) : (value === 0 ? value : 0); } /** * Converts `value` to a string. An empty string is returned for `null` * and `undefined` values. The sign of `-0` is preserved. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to convert. * @returns {string} Returns the converted string. * @example * * _.toString(null); * // => '' * * _.toString(-0); * // => '-0' * * _.toString([1, 2, 3]); * // => '1,2,3' */ function toString(value) { return value == null ? '' : baseToString(value); } /*------------------------------------------------------------------------*/ /** * Assigns own enumerable string keyed properties of source objects to the * destination object. Source objects are applied from left to right. * Subsequent sources overwrite property assignments of previous sources. * * **Note:** This method mutates `object` and is loosely based on * [`Object.assign`](https://mdn.io/Object/assign). * * @static * @memberOf _ * @since 0.10.0 * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. * @see _.assignIn * @example * * function Foo() { * this.a = 1; * } * * function Bar() { * this.c = 3; * } * * Foo.prototype.b = 2; * Bar.prototype.d = 4; * * _.assign({ 'a': 0 }, new Foo, new Bar); * // => { 'a': 1, 'c': 3 } */ var assign = createAssigner(function(object, source) { if (isPrototype(source) || isArrayLike(source)) { copyObject(source, keys(source), object); return; } for (var key in source) { if (hasOwnProperty.call(source, key)) { assignValue(object, key, source[key]); } } }); /** * This method is like `_.assign` except that it iterates over own and * inherited source properties. * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.0.0 * @alias extend * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. * @see _.assign * @example * * function Foo() { * this.a = 1; * } * * function Bar() { * this.c = 3; * } * * Foo.prototype.b = 2; * Bar.prototype.d = 4; * * _.assignIn({ 'a': 0 }, new Foo, new Bar); * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } */ var assignIn = createAssigner(function(object, source) { copyObject(source, keysIn(source), object); }); /** * This method is like `_.assignIn` except that it accepts `customizer` * which is invoked to produce the assigned values. If `customizer` returns * `undefined`, assignment is handled by the method instead. The `customizer` * is invoked with five arguments: (objValue, srcValue, key, object, source). * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.0.0 * @alias extendWith * @category Object * @param {Object} object The destination object. * @param {...Object} sources The source objects. * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @see _.assignWith * @example * * function customizer(objValue, srcValue) { * return _.isUndefined(objValue) ? srcValue : objValue; * } * * var defaults = _.partialRight(_.assignInWith, customizer); * * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); * // => { 'a': 1, 'b': 2 } */ var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { copyObject(source, keysIn(source), object, customizer); }); /** * This method is like `_.assign` except that it accepts `customizer` * which is invoked to produce the assigned values. If `customizer` returns * `undefined`, assignment is handled by the method instead. The `customizer` * is invoked with five arguments: (objValue, srcValue, key, object, source). * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The destination object. * @param {...Object} sources The source objects. * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @see _.assignInWith * @example * * function customizer(objValue, srcValue) { * return _.isUndefined(objValue) ? srcValue : objValue; * } * * var defaults = _.partialRight(_.assignWith, customizer); * * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); * // => { 'a': 1, 'b': 2 } */ var assignWith = createAssigner(function(object, source, srcIndex, customizer) { copyObject(source, keys(source), object, customizer); }); /** * Creates an array of values corresponding to `paths` of `object`. * * @static * @memberOf _ * @since 1.0.0 * @category Object * @param {Object} object The object to iterate over. * @param {...(string|string[])} [paths] The property paths to pick. * @returns {Array} Returns the picked values. * @example * * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; * * _.at(object, ['a[0].b.c', 'a[1]']); * // => [3, 4] */ var at = flatRest(baseAt); /** * Creates an object that inherits from the `prototype` object. If a * `properties` object is given, its own enumerable string keyed properties * are assigned to the created object. * * @static * @memberOf _ * @since 2.3.0 * @category Object * @param {Object} prototype The object to inherit from. * @param {Object} [properties] The properties to assign to the object. * @returns {Object} Returns the new object. * @example * * function Shape() { * this.x = 0; * this.y = 0; * } * * function Circle() { * Shape.call(this); * } * * Circle.prototype = _.create(Shape.prototype, { * 'constructor': Circle * }); * * var circle = new Circle; * circle instanceof Circle; * // => true * * circle instanceof Shape; * // => true */ function create(prototype, properties) { var result = baseCreate(prototype); return properties == null ? result : baseAssign(result, properties); } /** * Assigns own and inherited enumerable string keyed properties of source * objects to the destination object for all destination properties that * resolve to `undefined`. Source objects are applied from left to right. * Once a property is set, additional values of the same property are ignored. * * **Note:** This method mutates `object`. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. * @see _.defaultsDeep * @example * * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); * // => { 'a': 1, 'b': 2 } */ var defaults = baseRest(function(args) { args.push(undefined, customDefaultsAssignIn); return apply(assignInWith, undefined, args); }); /** * This method is like `_.defaults` except that it recursively assigns * default properties. * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 3.10.0 * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. * @see _.defaults * @example * * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); * // => { 'a': { 'b': 2, 'c': 3 } } */ var defaultsDeep = baseRest(function(args) { args.push(undefined, customDefaultsMerge); return apply(mergeWith, undefined, args); }); /** * This method is like `_.find` except that it returns the key of the first * element `predicate` returns truthy for instead of the element itself. * * @static * @memberOf _ * @since 1.1.0 * @category Object * @param {Object} object The object to inspect. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {string|undefined} Returns the key of the matched element, * else `undefined`. * @example * * var users = { * 'barney': { 'age': 36, 'active': true }, * 'fred': { 'age': 40, 'active': false }, * 'pebbles': { 'age': 1, 'active': true } * }; * * _.findKey(users, function(o) { return o.age < 40; }); * // => 'barney' (iteration order is not guaranteed) * * // The `_.matches` iteratee shorthand. * _.findKey(users, { 'age': 1, 'active': true }); * // => 'pebbles' * * // The `_.matchesProperty` iteratee shorthand. * _.findKey(users, ['active', false]); * // => 'fred' * * // The `_.property` iteratee shorthand. * _.findKey(users, 'active'); * // => 'barney' */ function findKey(object, predicate) { return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); } /** * This method is like `_.findKey` except that it iterates over elements of * a collection in the opposite order. * * @static * @memberOf _ * @since 2.0.0 * @category Object * @param {Object} object The object to inspect. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @returns {string|undefined} Returns the key of the matched element, * else `undefined`. * @example * * var users = { * 'barney': { 'age': 36, 'active': true }, * 'fred': { 'age': 40, 'active': false }, * 'pebbles': { 'age': 1, 'active': true } * }; * * _.findLastKey(users, function(o) { return o.age < 40; }); * // => returns 'pebbles' assuming `_.findKey` returns 'barney' * * // The `_.matches` iteratee shorthand. * _.findLastKey(users, { 'age': 36, 'active': true }); * // => 'barney' * * // The `_.matchesProperty` iteratee shorthand. * _.findLastKey(users, ['active', false]); * // => 'fred' * * // The `_.property` iteratee shorthand. * _.findLastKey(users, 'active'); * // => 'pebbles' */ function findLastKey(object, predicate) { return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); } /** * Iterates over own and inherited enumerable string keyed properties of an * object and invokes `iteratee` for each property. The iteratee is invoked * with three arguments: (value, key, object). Iteratee functions may exit * iteration early by explicitly returning `false`. * * @static * @memberOf _ * @since 0.3.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns `object`. * @see _.forInRight * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.forIn(new Foo, function(value, key) { * console.log(key); * }); * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). */ function forIn(object, iteratee) { return object == null ? object : baseFor(object, getIteratee(iteratee, 3), keysIn); } /** * This method is like `_.forIn` except that it iterates over properties of * `object` in the opposite order. * * @static * @memberOf _ * @since 2.0.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns `object`. * @see _.forIn * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.forInRight(new Foo, function(value, key) { * console.log(key); * }); * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. */ function forInRight(object, iteratee) { return object == null ? object : baseForRight(object, getIteratee(iteratee, 3), keysIn); } /** * Iterates over own enumerable string keyed properties of an object and * invokes `iteratee` for each property. The iteratee is invoked with three * arguments: (value, key, object). Iteratee functions may exit iteration * early by explicitly returning `false`. * * @static * @memberOf _ * @since 0.3.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns `object`. * @see _.forOwnRight * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.forOwn(new Foo, function(value, key) { * console.log(key); * }); * // => Logs 'a' then 'b' (iteration order is not guaranteed). */ function forOwn(object, iteratee) { return object && baseForOwn(object, getIteratee(iteratee, 3)); } /** * This method is like `_.forOwn` except that it iterates over properties of * `object` in the opposite order. * * @static * @memberOf _ * @since 2.0.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns `object`. * @see _.forOwn * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.forOwnRight(new Foo, function(value, key) { * console.log(key); * }); * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. */ function forOwnRight(object, iteratee) { return object && baseForOwnRight(object, getIteratee(iteratee, 3)); } /** * Creates an array of function property names from own enumerable properties * of `object`. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to inspect. * @returns {Array} Returns the function names. * @see _.functionsIn * @example * * function Foo() { * this.a = _.constant('a'); * this.b = _.constant('b'); * } * * Foo.prototype.c = _.constant('c'); * * _.functions(new Foo); * // => ['a', 'b'] */ function functions(object) { return object == null ? [] : baseFunctions(object, keys(object)); } /** * Creates an array of function property names from own and inherited * enumerable properties of `object`. * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The object to inspect. * @returns {Array} Returns the function names. * @see _.functions * @example * * function Foo() { * this.a = _.constant('a'); * this.b = _.constant('b'); * } * * Foo.prototype.c = _.constant('c'); * * _.functionsIn(new Foo); * // => ['a', 'b', 'c'] */ function functionsIn(object) { return object == null ? [] : baseFunctions(object, keysIn(object)); } /** * Gets the value at `path` of `object`. If the resolved value is * `undefined`, the `defaultValue` is returned in its place. * * @static * @memberOf _ * @since 3.7.0 * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path of the property to get. * @param {*} [defaultValue] The value returned for `undefined` resolved values. * @returns {*} Returns the resolved value. * @example * * var object = { 'a': [{ 'b': { 'c': 3 } }] }; * * _.get(object, 'a[0].b.c'); * // => 3 * * _.get(object, ['a', '0', 'b', 'c']); * // => 3 * * _.get(object, 'a.b.c', 'default'); * // => 'default' */ function get(object, path, defaultValue) { var result = object == null ? undefined : baseGet(object, path); return result === undefined ? defaultValue : result; } /** * Checks if `path` is a direct property of `object`. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path to check. * @returns {boolean} Returns `true` if `path` exists, else `false`. * @example * * var object = { 'a': { 'b': 2 } }; * var other = _.create({ 'a': _.create({ 'b': 2 }) }); * * _.has(object, 'a'); * // => true * * _.has(object, 'a.b'); * // => true * * _.has(object, ['a', 'b']); * // => true * * _.has(other, 'a'); * // => false */ function has(object, path) { return object != null && hasPath(object, path, baseHas); } /** * Checks if `path` is a direct or inherited property of `object`. * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path to check. * @returns {boolean} Returns `true` if `path` exists, else `false`. * @example * * var object = _.create({ 'a': _.create({ 'b': 2 }) }); * * _.hasIn(object, 'a'); * // => true * * _.hasIn(object, 'a.b'); * // => true * * _.hasIn(object, ['a', 'b']); * // => true * * _.hasIn(object, 'b'); * // => false */ function hasIn(object, path) { return object != null && hasPath(object, path, baseHasIn); } /** * Creates an object composed of the inverted keys and values of `object`. * If `object` contains duplicate values, subsequent values overwrite * property assignments of previous values. * * @static * @memberOf _ * @since 0.7.0 * @category Object * @param {Object} object The object to invert. * @returns {Object} Returns the new inverted object. * @example * * var object = { 'a': 1, 'b': 2, 'c': 1 }; * * _.invert(object); * // => { '1': 'c', '2': 'b' } */ var invert = createInverter(function(result, value, key) { result[value] = key; }, constant(identity)); /** * This method is like `_.invert` except that the inverted object is generated * from the results of running each element of `object` thru `iteratee`. The * corresponding inverted value of each inverted key is an array of keys * responsible for generating the inverted value. The iteratee is invoked * with one argument: (value). * * @static * @memberOf _ * @since 4.1.0 * @category Object * @param {Object} object The object to invert. * @param {Function} [iteratee=_.identity] The iteratee invoked per element. * @returns {Object} Returns the new inverted object. * @example * * var object = { 'a': 1, 'b': 2, 'c': 1 }; * * _.invertBy(object); * // => { '1': ['a', 'c'], '2': ['b'] } * * _.invertBy(object, function(value) { * return 'group' + value; * }); * // => { 'group1': ['a', 'c'], 'group2': ['b'] } */ var invertBy = createInverter(function(result, value, key) { if (hasOwnProperty.call(result, value)) { result[value].push(key); } else { result[value] = [key]; } }, getIteratee); /** * Invokes the method at `path` of `object`. * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path of the method to invoke. * @param {...*} [args] The arguments to invoke the method with. * @returns {*} Returns the result of the invoked method. * @example * * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; * * _.invoke(object, 'a[0].b.c.slice', 1, 3); * // => [2, 3] */ var invoke = baseRest(baseInvoke); /** * Creates an array of the own enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. See the * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) * for more details. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.keys(new Foo); * // => ['a', 'b'] (iteration order is not guaranteed) * * _.keys('hi'); * // => ['0', '1'] */ function keys(object) { return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); } /** * Creates an array of the own and inherited enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. * * @static * @memberOf _ * @since 3.0.0 * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.keysIn(new Foo); * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); } /** * The opposite of `_.mapValues`; this method creates an object with the * same values as `object` and keys generated by running each own enumerable * string keyed property of `object` thru `iteratee`. The iteratee is invoked * with three arguments: (value, key, object). * * @static * @memberOf _ * @since 3.8.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns the new mapped object. * @see _.mapValues * @example * * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { * return key + value; * }); * // => { 'a1': 1, 'b2': 2 } */ function mapKeys(object, iteratee) { var result = {}; iteratee = getIteratee(iteratee, 3); baseForOwn(object, function(value, key, object) { baseAssignValue(result, iteratee(value, key, object), value); }); return result; } /** * Creates an object with the same keys as `object` and values generated * by running each own enumerable string keyed property of `object` thru * `iteratee`. The iteratee is invoked with three arguments: * (value, key, object). * * @static * @memberOf _ * @since 2.4.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns the new mapped object. * @see _.mapKeys * @example * * var users = { * 'fred': { 'user': 'fred', 'age': 40 }, * 'pebbles': { 'user': 'pebbles', 'age': 1 } * }; * * _.mapValues(users, function(o) { return o.age; }); * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) * * // The `_.property` iteratee shorthand. * _.mapValues(users, 'age'); * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) */ function mapValues(object, iteratee) { var result = {}; iteratee = getIteratee(iteratee, 3); baseForOwn(object, function(value, key, object) { baseAssignValue(result, key, iteratee(value, key, object)); }); return result; } /** * This method is like `_.assign` except that it recursively merges own and * inherited enumerable string keyed properties of source objects into the * destination object. Source properties that resolve to `undefined` are * skipped if a destination value exists. Array and plain object properties * are merged recursively. Other objects and value types are overridden by * assignment. Source objects are applied from left to right. Subsequent * sources overwrite property assignments of previous sources. * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 0.5.0 * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. * @example * * var object = { * 'a': [{ 'b': 2 }, { 'd': 4 }] * }; * * var other = { * 'a': [{ 'c': 3 }, { 'e': 5 }] * }; * * _.merge(object, other); * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } */ var merge = createAssigner(function(object, source, srcIndex) { baseMerge(object, source, srcIndex); }); /** * This method is like `_.merge` except that it accepts `customizer` which * is invoked to produce the merged values of the destination and source * properties. If `customizer` returns `undefined`, merging is handled by the * method instead. The `customizer` is invoked with six arguments: * (objValue, srcValue, key, object, source, stack). * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The destination object. * @param {...Object} sources The source objects. * @param {Function} customizer The function to customize assigned values. * @returns {Object} Returns `object`. * @example * * function customizer(objValue, srcValue) { * if (_.isArray(objValue)) { * return objValue.concat(srcValue); * } * } * * var object = { 'a': [1], 'b': [2] }; * var other = { 'a': [3], 'b': [4] }; * * _.mergeWith(object, other, customizer); * // => { 'a': [1, 3], 'b': [2, 4] } */ var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { baseMerge(object, source, srcIndex, customizer); }); /** * The opposite of `_.pick`; this method creates an object composed of the * own and inherited enumerable property paths of `object` that are not omitted. * * **Note:** This method is considerably slower than `_.pick`. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The source object. * @param {...(string|string[])} [paths] The property paths to omit. * @returns {Object} Returns the new object. * @example * * var object = { 'a': 1, 'b': '2', 'c': 3 }; * * _.omit(object, ['a', 'c']); * // => { 'b': '2' } */ var omit = flatRest(function(object, paths) { var result = {}; if (object == null) { return result; } var isDeep = false; paths = arrayMap(paths, function(path) { path = castPath(path, object); isDeep || (isDeep = path.length > 1); return path; }); copyObject(object, getAllKeysIn(object), result); if (isDeep) { result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); } var length = paths.length; while (length--) { baseUnset(result, paths[length]); } return result; }); /** * The opposite of `_.pickBy`; this method creates an object composed of * the own and inherited enumerable string keyed properties of `object` that * `predicate` doesn't return truthy for. The predicate is invoked with two * arguments: (value, key). * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The source object. * @param {Function} [predicate=_.identity] The function invoked per property. * @returns {Object} Returns the new object. * @example * * var object = { 'a': 1, 'b': '2', 'c': 3 }; * * _.omitBy(object, _.isNumber); * // => { 'b': '2' } */ function omitBy(object, predicate) { return pickBy(object, negate(getIteratee(predicate))); } /** * Creates an object composed of the picked `object` properties. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The source object. * @param {...(string|string[])} [paths] The property paths to pick. * @returns {Object} Returns the new object. * @example * * var object = { 'a': 1, 'b': '2', 'c': 3 }; * * _.pick(object, ['a', 'c']); * // => { 'a': 1, 'c': 3 } */ var pick = flatRest(function(object, paths) { return object == null ? {} : basePick(object, paths); }); /** * Creates an object composed of the `object` properties `predicate` returns * truthy for. The predicate is invoked with two arguments: (value, key). * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The source object. * @param {Function} [predicate=_.identity] The function invoked per property. * @returns {Object} Returns the new object. * @example * * var object = { 'a': 1, 'b': '2', 'c': 3 }; * * _.pickBy(object, _.isNumber); * // => { 'a': 1, 'c': 3 } */ function pickBy(object, predicate) { if (object == null) { return {}; } var props = arrayMap(getAllKeysIn(object), function(prop) { return [prop]; }); predicate = getIteratee(predicate); return basePickBy(object, props, function(value, path) { return predicate(value, path[0]); }); } /** * This method is like `_.get` except that if the resolved value is a * function it's invoked with the `this` binding of its parent object and * its result is returned. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path of the property to resolve. * @param {*} [defaultValue] The value returned for `undefined` resolved values. * @returns {*} Returns the resolved value. * @example * * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; * * _.result(object, 'a[0].b.c1'); * // => 3 * * _.result(object, 'a[0].b.c2'); * // => 4 * * _.result(object, 'a[0].b.c3', 'default'); * // => 'default' * * _.result(object, 'a[0].b.c3', _.constant('default')); * // => 'default' */ function result(object, path, defaultValue) { path = castPath(path, object); var index = -1, length = path.length; // Ensure the loop is entered when path is empty. if (!length) { length = 1; object = undefined; } while (++index < length) { var value = object == null ? undefined : object[toKey(path[index])]; if (value === undefined) { index = length; value = defaultValue; } object = isFunction(value) ? value.call(object) : value; } return object; } /** * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, * it's created. Arrays are created for missing index properties while objects * are created for all other missing properties. Use `_.setWith` to customize * `path` creation. * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 3.7.0 * @category Object * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to set. * @param {*} value The value to set. * @returns {Object} Returns `object`. * @example * * var object = { 'a': [{ 'b': { 'c': 3 } }] }; * * _.set(object, 'a[0].b.c', 4); * console.log(object.a[0].b.c); * // => 4 * * _.set(object, ['x', '0', 'y', 'z'], 5); * console.log(object.x[0].y.z); * // => 5 */ function set(object, path, value) { return object == null ? object : baseSet(object, path, value); } /** * This method is like `_.set` except that it accepts `customizer` which is * invoked to produce the objects of `path`. If `customizer` returns `undefined` * path creation is handled by the method instead. The `customizer` is invoked * with three arguments: (nsValue, key, nsObject). * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to set. * @param {*} value The value to set. * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @example * * var object = {}; * * _.setWith(object, '[0][1]', 'a', Object); * // => { '0': { '1': 'a' } } */ function setWith(object, path, value, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; return object == null ? object : baseSet(object, path, value, customizer); } /** * Creates an array of own enumerable string keyed-value pairs for `object` * which can be consumed by `_.fromPairs`. If `object` is a map or set, its * entries are returned. * * @static * @memberOf _ * @since 4.0.0 * @alias entries * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the key-value pairs. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.toPairs(new Foo); * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) */ var toPairs = createToPairs(keys); /** * Creates an array of own and inherited enumerable string keyed-value pairs * for `object` which can be consumed by `_.fromPairs`. If `object` is a map * or set, its entries are returned. * * @static * @memberOf _ * @since 4.0.0 * @alias entriesIn * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the key-value pairs. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.toPairsIn(new Foo); * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) */ var toPairsIn = createToPairs(keysIn); /** * An alternative to `_.reduce`; this method transforms `object` to a new * `accumulator` object which is the result of running each of its own * enumerable string keyed properties thru `iteratee`, with each invocation * potentially mutating the `accumulator` object. If `accumulator` is not * provided, a new object with the same `[[Prototype]]` will be used. The * iteratee is invoked with four arguments: (accumulator, value, key, object). * Iteratee functions may exit iteration early by explicitly returning `false`. * * @static * @memberOf _ * @since 1.3.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The custom accumulator value. * @returns {*} Returns the accumulated value. * @example * * _.transform([2, 3, 4], function(result, n) { * result.push(n *= n); * return n % 2 == 0; * }, []); * // => [4, 9] * * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { * (result[value] || (result[value] = [])).push(key); * }, {}); * // => { '1': ['a', 'c'], '2': ['b'] } */ function transform(object, iteratee, accumulator) { var isArr = isArray(object), isArrLike = isArr || isBuffer(object) || isTypedArray(object); iteratee = getIteratee(iteratee, 4); if (accumulator == null) { var Ctor = object && object.constructor; if (isArrLike) { accumulator = isArr ? new Ctor : []; } else if (isObject(object)) { accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; } else { accumulator = {}; } } (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { return iteratee(accumulator, value, index, object); }); return accumulator; } /** * Removes the property at `path` of `object`. * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.0.0 * @category Object * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to unset. * @returns {boolean} Returns `true` if the property is deleted, else `false`. * @example * * var object = { 'a': [{ 'b': { 'c': 7 } }] }; * _.unset(object, 'a[0].b.c'); * // => true * * console.log(object); * // => { 'a': [{ 'b': {} }] }; * * _.unset(object, ['a', '0', 'b', 'c']); * // => true * * console.log(object); * // => { 'a': [{ 'b': {} }] }; */ function unset(object, path) { return object == null ? true : baseUnset(object, path); } /** * This method is like `_.set` except that accepts `updater` to produce the * value to set. Use `_.updateWith` to customize `path` creation. The `updater` * is invoked with one argument: (value). * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.6.0 * @category Object * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to set. * @param {Function} updater The function to produce the updated value. * @returns {Object} Returns `object`. * @example * * var object = { 'a': [{ 'b': { 'c': 3 } }] }; * * _.update(object, 'a[0].b.c', function(n) { return n * n; }); * console.log(object.a[0].b.c); * // => 9 * * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); * console.log(object.x[0].y.z); * // => 0 */ function update(object, path, updater) { return object == null ? object : baseUpdate(object, path, castFunction(updater)); } /** * This method is like `_.update` except that it accepts `customizer` which is * invoked to produce the objects of `path`. If `customizer` returns `undefined` * path creation is handled by the method instead. The `customizer` is invoked * with three arguments: (nsValue, key, nsObject). * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.6.0 * @category Object * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to set. * @param {Function} updater The function to produce the updated value. * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @example * * var object = {}; * * _.updateWith(object, '[0][1]', _.constant('a'), Object); * // => { '0': { '1': 'a' } } */ function updateWith(object, path, updater, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); } /** * Creates an array of the own enumerable string keyed property values of `object`. * * **Note:** Non-object values are coerced to objects. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property values. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.values(new Foo); * // => [1, 2] (iteration order is not guaranteed) * * _.values('hi'); * // => ['h', 'i'] */ function values(object) { return object == null ? [] : baseValues(object, keys(object)); } /** * Creates an array of the own and inherited enumerable string keyed property * values of `object`. * * **Note:** Non-object values are coerced to objects. * * @static * @memberOf _ * @since 3.0.0 * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property values. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.valuesIn(new Foo); * // => [1, 2, 3] (iteration order is not guaranteed) */ function valuesIn(object) { return object == null ? [] : baseValues(object, keysIn(object)); } /*------------------------------------------------------------------------*/ /** * Clamps `number` within the inclusive `lower` and `upper` bounds. * * @static * @memberOf _ * @since 4.0.0 * @category Number * @param {number} number The number to clamp. * @param {number} [lower] The lower bound. * @param {number} upper The upper bound. * @returns {number} Returns the clamped number. * @example * * _.clamp(-10, -5, 5); * // => -5 * * _.clamp(10, -5, 5); * // => 5 */ function clamp(number, lower, upper) { if (upper === undefined) { upper = lower; lower = undefined; } if (upper !== undefined) { upper = toNumber(upper); upper = upper === upper ? upper : 0; } if (lower !== undefined) { lower = toNumber(lower); lower = lower === lower ? lower : 0; } return baseClamp(toNumber(number), lower, upper); } /** * Checks if `n` is between `start` and up to, but not including, `end`. If * `end` is not specified, it's set to `start` with `start` then set to `0`. * If `start` is greater than `end` the params are swapped to support * negative ranges. * * @static * @memberOf _ * @since 3.3.0 * @category Number * @param {number} number The number to check. * @param {number} [start=0] The start of the range. * @param {number} end The end of the range. * @returns {boolean} Returns `true` if `number` is in the range, else `false`. * @see _.range, _.rangeRight * @example * * _.inRange(3, 2, 4); * // => true * * _.inRange(4, 8); * // => true * * _.inRange(4, 2); * // => false * * _.inRange(2, 2); * // => false * * _.inRange(1.2, 2); * // => true * * _.inRange(5.2, 4); * // => false * * _.inRange(-3, -2, -6); * // => true */ function inRange(number, start, end) { start = toFinite(start); if (end === undefined) { end = start; start = 0; } else { end = toFinite(end); } number = toNumber(number); return baseInRange(number, start, end); } /** * Produces a random number between the inclusive `lower` and `upper` bounds. * If only one argument is provided a number between `0` and the given number * is returned. If `floating` is `true`, or either `lower` or `upper` are * floats, a floating-point number is returned instead of an integer. * * **Note:** JavaScript follows the IEEE-754 standard for resolving * floating-point values which can produce unexpected results. * * @static * @memberOf _ * @since 0.7.0 * @category Number * @param {number} [lower=0] The lower bound. * @param {number} [upper=1] The upper bound. * @param {boolean} [floating] Specify returning a floating-point number. * @returns {number} Returns the random number. * @example * * _.random(0, 5); * // => an integer between 0 and 5 * * _.random(5); * // => also an integer between 0 and 5 * * _.random(5, true); * // => a floating-point number between 0 and 5 * * _.random(1.2, 5.2); * // => a floating-point number between 1.2 and 5.2 */ function random(lower, upper, floating) { if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { upper = floating = undefined; } if (floating === undefined) { if (typeof upper == 'boolean') { floating = upper; upper = undefined; } else if (typeof lower == 'boolean') { floating = lower; lower = undefined; } } if (lower === undefined && upper === undefined) { lower = 0; upper = 1; } else { lower = toFinite(lower); if (upper === undefined) { upper = lower; lower = 0; } else { upper = toFinite(upper); } } if (lower > upper) { var temp = lower; lower = upper; upper = temp; } if (floating || lower % 1 || upper % 1) { var rand = nativeRandom(); return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); } return baseRandom(lower, upper); } /*------------------------------------------------------------------------*/ /** * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the camel cased string. * @example * * _.camelCase('Foo Bar'); * // => 'fooBar' * * _.camelCase('--foo-bar--'); * // => 'fooBar' * * _.camelCase('__FOO_BAR__'); * // => 'fooBar' */ var camelCase = createCompounder(function(result, word, index) { word = word.toLowerCase(); return result + (index ? capitalize(word) : word); }); /** * Converts the first character of `string` to upper case and the remaining * to lower case. * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to capitalize. * @returns {string} Returns the capitalized string. * @example * * _.capitalize('FRED'); * // => 'Fred' */ function capitalize(string) { return upperFirst(toString(string).toLowerCase()); } /** * Deburrs `string` by converting * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) * letters to basic Latin letters and removing * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to deburr. * @returns {string} Returns the deburred string. * @example * * _.deburr('déjà vu'); * // => 'deja vu' */ function deburr(string) { string = toString(string); return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); } /** * Checks if `string` ends with the given target string. * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to inspect. * @param {string} [target] The string to search for. * @param {number} [position=string.length] The position to search up to. * @returns {boolean} Returns `true` if `string` ends with `target`, * else `false`. * @example * * _.endsWith('abc', 'c'); * // => true * * _.endsWith('abc', 'b'); * // => false * * _.endsWith('abc', 'b', 2); * // => true */ function endsWith(string, target, position) { string = toString(string); target = baseToString(target); var length = string.length; position = position === undefined ? length : baseClamp(toInteger(position), 0, length); var end = position; position -= target.length; return position >= 0 && string.slice(position, end) == target; } /** * Converts the characters "&", "<", ">", '"', and "'" in `string` to their * corresponding HTML entities. * * **Note:** No other characters are escaped. To escape additional * characters use a third-party library like [_he_](https://mths.be/he). * * Though the ">" character is escaped for symmetry, characters like * ">" and "/" don't need escaping in HTML and have no special meaning * unless they're part of a tag or unquoted attribute value. See * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) * (under "semi-related fun fact") for more details. * * When working with HTML you should always * [quote attribute values](http://wonko.com/post/html-escaping) to reduce * XSS vectors. * * @static * @since 0.1.0 * @memberOf _ * @category String * @param {string} [string=''] The string to escape. * @returns {string} Returns the escaped string. * @example * * _.escape('fred, barney, & pebbles'); * // => 'fred, barney, & pebbles' */ function escape(string) { string = toString(string); return (string && reHasUnescapedHtml.test(string)) ? string.replace(reUnescapedHtml, escapeHtmlChar) : string; } /** * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to escape. * @returns {string} Returns the escaped string. * @example * * _.escapeRegExp('[lodash](https://lodash.com/)'); * // => '\[lodash\]\(https://lodash\.com/\)' */ function escapeRegExp(string) { string = toString(string); return (string && reHasRegExpChar.test(string)) ? string.replace(reRegExpChar, '\\$&') : string; } /** * Converts `string` to * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the kebab cased string. * @example * * _.kebabCase('Foo Bar'); * // => 'foo-bar' * * _.kebabCase('fooBar'); * // => 'foo-bar' * * _.kebabCase('__FOO_BAR__'); * // => 'foo-bar' */ var kebabCase = createCompounder(function(result, word, index) { return result + (index ? '-' : '') + word.toLowerCase(); }); /** * Converts `string`, as space separated words, to lower case. * * @static * @memberOf _ * @since 4.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the lower cased string. * @example * * _.lowerCase('--Foo-Bar--'); * // => 'foo bar' * * _.lowerCase('fooBar'); * // => 'foo bar' * * _.lowerCase('__FOO_BAR__'); * // => 'foo bar' */ var lowerCase = createCompounder(function(result, word, index) { return result + (index ? ' ' : '') + word.toLowerCase(); }); /** * Converts the first character of `string` to lower case. * * @static * @memberOf _ * @since 4.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the converted string. * @example * * _.lowerFirst('Fred'); * // => 'fred' * * _.lowerFirst('FRED'); * // => 'fRED' */ var lowerFirst = createCaseFirst('toLowerCase'); /** * Pads `string` on the left and right sides if it's shorter than `length`. * Padding characters are truncated if they can't be evenly divided by `length`. * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to pad. * @param {number} [length=0] The padding length. * @param {string} [chars=' '] The string used as padding. * @returns {string} Returns the padded string. * @example * * _.pad('abc', 8); * // => ' abc ' * * _.pad('abc', 8, '_-'); * // => '_-abc_-_' * * _.pad('abc', 3); * // => 'abc' */ function pad(string, length, chars) { string = toString(string); length = toInteger(length); var strLength = length ? stringSize(string) : 0; if (!length || strLength >= length) { return string; } var mid = (length - strLength) / 2; return ( createPadding(nativeFloor(mid), chars) + string + createPadding(nativeCeil(mid), chars) ); } /** * Pads `string` on the right side if it's shorter than `length`. Padding * characters are truncated if they exceed `length`. * * @static * @memberOf _ * @since 4.0.0 * @category String * @param {string} [string=''] The string to pad. * @param {number} [length=0] The padding length. * @param {string} [chars=' '] The string used as padding. * @returns {string} Returns the padded string. * @example * * _.padEnd('abc', 6); * // => 'abc ' * * _.padEnd('abc', 6, '_-'); * // => 'abc_-_' * * _.padEnd('abc', 3); * // => 'abc' */ function padEnd(string, length, chars) { string = toString(string); length = toInteger(length); var strLength = length ? stringSize(string) : 0; return (length && strLength < length) ? (string + createPadding(length - strLength, chars)) : string; } /** * Pads `string` on the left side if it's shorter than `length`. Padding * characters are truncated if they exceed `length`. * * @static * @memberOf _ * @since 4.0.0 * @category String * @param {string} [string=''] The string to pad. * @param {number} [length=0] The padding length. * @param {string} [chars=' '] The string used as padding. * @returns {string} Returns the padded string. * @example * * _.padStart('abc', 6); * // => ' abc' * * _.padStart('abc', 6, '_-'); * // => '_-_abc' * * _.padStart('abc', 3); * // => 'abc' */ function padStart(string, length, chars) { string = toString(string); length = toInteger(length); var strLength = length ? stringSize(string) : 0; return (length && strLength < length) ? (createPadding(length - strLength, chars) + string) : string; } /** * Converts `string` to an integer of the specified radix. If `radix` is * `undefined` or `0`, a `radix` of `10` is used unless `value` is a * hexadecimal, in which case a `radix` of `16` is used. * * **Note:** This method aligns with the * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. * * @static * @memberOf _ * @since 1.1.0 * @category String * @param {string} string The string to convert. * @param {number} [radix=10] The radix to interpret `value` by. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {number} Returns the converted integer. * @example * * _.parseInt('08'); * // => 8 * * _.map(['6', '08', '10'], _.parseInt); * // => [6, 8, 10] */ function parseInt(string, radix, guard) { if (guard || radix == null) { radix = 0; } else if (radix) { radix = +radix; } return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); } /** * Repeats the given string `n` times. * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to repeat. * @param {number} [n=1] The number of times to repeat the string. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {string} Returns the repeated string. * @example * * _.repeat('*', 3); * // => '***' * * _.repeat('abc', 2); * // => 'abcabc' * * _.repeat('abc', 0); * // => '' */ function repeat(string, n, guard) { if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { n = 1; } else { n = toInteger(n); } return baseRepeat(toString(string), n); } /** * Replaces matches for `pattern` in `string` with `replacement`. * * **Note:** This method is based on * [`String#replace`](https://mdn.io/String/replace). * * @static * @memberOf _ * @since 4.0.0 * @category String * @param {string} [string=''] The string to modify. * @param {RegExp|string} pattern The pattern to replace. * @param {Function|string} replacement The match replacement. * @returns {string} Returns the modified string. * @example * * _.replace('Hi Fred', 'Fred', 'Barney'); * // => 'Hi Barney' */ function replace() { var args = arguments, string = toString(args[0]); return args.length < 3 ? string : string.replace(args[1], args[2]); } /** * Converts `string` to * [snake case](https://en.wikipedia.org/wiki/Snake_case). * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the snake cased string. * @example * * _.snakeCase('Foo Bar'); * // => 'foo_bar' * * _.snakeCase('fooBar'); * // => 'foo_bar' * * _.snakeCase('--FOO-BAR--'); * // => 'foo_bar' */ var snakeCase = createCompounder(function(result, word, index) { return result + (index ? '_' : '') + word.toLowerCase(); }); /** * Splits `string` by `separator`. * * **Note:** This method is based on * [`String#split`](https://mdn.io/String/split). * * @static * @memberOf _ * @since 4.0.0 * @category String * @param {string} [string=''] The string to split. * @param {RegExp|string} separator The separator pattern to split by. * @param {number} [limit] The length to truncate results to. * @returns {Array} Returns the string segments. * @example * * _.split('a-b-c', '-', 2); * // => ['a', 'b'] */ function split(string, separator, limit) { if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { separator = limit = undefined; } limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; if (!limit) { return []; } string = toString(string); if (string && ( typeof separator == 'string' || (separator != null && !isRegExp(separator)) )) { separator = baseToString(separator); if (!separator && hasUnicode(string)) { return castSlice(stringToArray(string), 0, limit); } } return string.split(separator, limit); } /** * Converts `string` to * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). * * @static * @memberOf _ * @since 3.1.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the start cased string. * @example * * _.startCase('--foo-bar--'); * // => 'Foo Bar' * * _.startCase('fooBar'); * // => 'Foo Bar' * * _.startCase('__FOO_BAR__'); * // => 'FOO BAR' */ var startCase = createCompounder(function(result, word, index) { return result + (index ? ' ' : '') + upperFirst(word); }); /** * Checks if `string` starts with the given target string. * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to inspect. * @param {string} [target] The string to search for. * @param {number} [position=0] The position to search from. * @returns {boolean} Returns `true` if `string` starts with `target`, * else `false`. * @example * * _.startsWith('abc', 'a'); * // => true * * _.startsWith('abc', 'b'); * // => false * * _.startsWith('abc', 'b', 1); * // => true */ function startsWith(string, target, position) { string = toString(string); position = position == null ? 0 : baseClamp(toInteger(position), 0, string.length); target = baseToString(target); return string.slice(position, position + target.length) == target; } /** * Creates a compiled template function that can interpolate data properties * in "interpolate" delimiters, HTML-escape interpolated data properties in * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data * properties may be accessed as free variables in the template. If a setting * object is given, it takes precedence over `_.templateSettings` values. * * **Note:** In the development build `_.template` utilizes * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) * for easier debugging. * * For more information on precompiling templates see * [lodash's custom builds documentation](https://lodash.com/custom-builds). * * For more information on Chrome extension sandboxes see * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). * * @static * @since 0.1.0 * @memberOf _ * @category String * @param {string} [string=''] The template string. * @param {Object} [options={}] The options object. * @param {RegExp} [options.escape=_.templateSettings.escape] * The HTML "escape" delimiter. * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] * The "evaluate" delimiter. * @param {Object} [options.imports=_.templateSettings.imports] * An object to import into the template as free variables. * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] * The "interpolate" delimiter. * @param {string} [options.sourceURL='lodash.templateSources[n]'] * The sourceURL of the compiled template. * @param {string} [options.variable='obj'] * The data object variable name. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. * @returns {Function} Returns the compiled template function. * @example * * // Use the "interpolate" delimiter to create a compiled template. * var compiled = _.template('hello <%= user %>!'); * compiled({ 'user': 'fred' }); * // => 'hello fred!' * * // Use the HTML "escape" delimiter to escape data property values. * var compiled = _.template('<%- value %>'); * compiled({ 'value': ' glances-2.11.1/glances/password.py000066400000000000000000000116601315472316100170470ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage password.""" import getpass import hashlib import os import sys import uuid from io import open from glances.compat import b, input from glances.config import user_config_dir from glances.globals import safe_makedirs from glances.logger import logger class GlancesPassword(object): """This class contains all the methods relating to password.""" def __init__(self, username='glances'): self.username = username self.password_dir = user_config_dir() self.password_filename = self.username + '.pwd' self.password_file = os.path.join(self.password_dir, self.password_filename) def sha256_hash(self, plain_password): """Return the SHA-256 of the given password.""" return hashlib.sha256(b(plain_password)).hexdigest() def get_hash(self, salt, plain_password): """Return the hashed password, salt + SHA-256.""" return hashlib.sha256(salt.encode() + plain_password.encode()).hexdigest() def hash_password(self, plain_password): """Hash password with a salt based on UUID (universally unique identifier).""" salt = uuid.uuid4().hex encrypted_password = self.get_hash(salt, plain_password) return salt + '$' + encrypted_password def check_password(self, hashed_password, plain_password): """Encode the plain_password with the salt of the hashed_password. Return the comparison with the encrypted_password. """ salt, encrypted_password = hashed_password.split('$') re_encrypted_password = self.get_hash(salt, plain_password) return encrypted_password == re_encrypted_password def get_password(self, description='', confirm=False, clear=False): """Get the password from a Glances client or server. For Glances server, get the password (confirm=True, clear=False): 1) from the password file (if it exists) 2) from the CLI Optionally: save the password to a file (hashed with salt + SHA-256) For Glances client, get the password (confirm=False, clear=True): 1) from the CLI 2) the password is hashed with SHA-256 (only SHA string transit through the network) """ if os.path.exists(self.password_file) and not clear: # If the password file exist then use it logger.info("Read password from file {}".format(self.password_file)) password = self.load_password() else: # password_sha256 is the plain SHA-256 password # password_hashed is the salt + SHA-256 password password_sha256 = self.sha256_hash(getpass.getpass(description)) password_hashed = self.hash_password(password_sha256) if confirm: # password_confirm is the clear password (only used to compare) password_confirm = self.sha256_hash(getpass.getpass('Password (confirm): ')) if not self.check_password(password_hashed, password_confirm): logger.critical("Sorry, passwords do not match. Exit.") sys.exit(1) # Return the plain SHA-256 or the salted password if clear: password = password_sha256 else: password = password_hashed # Save the hashed password to the password file if not clear: save_input = input('Do you want to save the password? [Yes/No]: ') if len(save_input) > 0 and save_input[0].upper() == 'Y': self.save_password(password_hashed) return password def save_password(self, hashed_password): """Save the hashed password to the Glances folder.""" # Create the glances directory safe_makedirs(self.password_dir) # Create/overwrite the password file with open(self.password_file, 'wb') as file_pwd: file_pwd.write(b(hashed_password)) def load_password(self): """Load the hashed password from the Glances folder.""" # Read the password file, if it exists with open(self.password_file, 'r') as file_pwd: hashed_password = file_pwd.read() return hashed_password glances-2.11.1/glances/password_list.py000066400000000000000000000053701315472316100201030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances passwords list.""" from glances.logger import logger from glances.password import GlancesPassword class GlancesPasswordList(GlancesPassword): """Manage the Glances passwords list for the client|browser/server.""" _section = "passwords" def __init__(self, config=None, args=None): super(GlancesPasswordList, self).__init__() # password_dict is a dict (JSON compliant) # {'host': 'password', ... } # Load the configuration file self._password_dict = self.load(config) def load(self, config): """Load the password from the configuration file.""" password_dict = {} if config is None: logger.warning("No configuration file available. Cannot load password list.") elif not config.has_section(self._section): logger.warning("No [%s] section in the configuration file. Cannot load password list." % self._section) else: logger.info("Start reading the [%s] section in the configuration file" % self._section) password_dict = dict(config.items(self._section)) # Password list loaded logger.info("%s password(s) loaded from the configuration file" % len(password_dict)) logger.debug("Password dictionary: %s" % password_dict) return password_dict def get_password(self, host=None): """ If host=None, return the current server list (dict). Else, return the host's password (or the default one if defined or None) """ if host is None: return self._password_dict else: try: return self._password_dict[host] except (KeyError, TypeError): try: return self._password_dict['default'] except (KeyError, TypeError): return None def set_password(self, host, password): """Set a password for a specific host.""" self._password_dict[host] = password glances-2.11.1/glances/plugins/000077500000000000000000000000001315472316100163105ustar00rootroot00000000000000glances-2.11.1/glances/plugins/__init__.py000066400000000000000000000000001315472316100204070ustar00rootroot00000000000000glances-2.11.1/glances/plugins/glances_alert.py000066400000000000000000000146211315472316100214710ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Alert plugin.""" from datetime import datetime from glances.logs import glances_logs from glances.thresholds import glances_thresholds from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin # Static decision tree for the global alert message # - msg: Message to be displayed (result of the decision tree) # - threasholds: a list of stats to take into account # - thresholds_min: minimal value of the threasholds sum tree = [{'msg': 'No warning or critical alert detected', 'thresholds': [], 'thresholds_min': 0}, {'msg': 'High CPU user mode', 'thresholds': ['cpu_user'], 'thresholds_min': 2}, {'msg': 'High CPU kernel usage', 'thresholds': ['cpu_system'], 'thresholds_min': 2}, {'msg': 'High CPU I/O waiting', 'thresholds': ['cpu_iowait'], 'thresholds_min': 2}, {'msg': 'Large CPU stolen time. System running the hypervisor is too busy.', 'thresholds': ['cpu_steal'], 'thresholds_min': 2}, {'msg': 'High CPU niced value', 'thresholds': ['cpu_niced'], 'thresholds_min': 2}, {'msg': 'System overloaded in the last 5 minutes', 'thresholds': ['load'], 'thresholds_min': 2}, {'msg': 'High swap (paging) usage', 'thresholds': ['memswap'], 'thresholds_min': 2}, {'msg': 'High memory consumption', 'thresholds': ['mem'], 'thresholds_min': 2}, ] def global_message(): """Parse the decision tree and return the message corresponding to the current threasholds values""" # Compute the weight for each item in the tree current_thresholds = glances_thresholds.get() for i in tree: i['weight'] = sum([current_thresholds[t].value() for t in i['thresholds'] if t in current_thresholds]) themax = max(tree, key=lambda d: d['weight']) if themax['weight'] >= themax['thresholds_min']: # Check if the weight is > to the minimal threashold value return themax['msg'] else: return tree[0]['msg'] class Plugin(GlancesPlugin): """Glances alert plugin. Only for display. """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Set the message position self.align = 'bottom' # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = [] def update(self): """Nothing to do here. Just return the global glances_log.""" # Set the stats to the glances_logs self.stats = glances_logs.get() # Define the global message thanks to the current thresholds # and the decision tree # !!! Call directly in the msg_curse function # global_message() def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if display plugin enable... if not self.stats and self.is_disable(): return ret # Build the string message # Header ret.append(self.curse_add_line(global_message(), "TITLE")) if self.stats: # Header # msg = 'Warning or critical alerts' # ret.append(self.curse_add_line(msg, "TITLE")) # logs_len = glances_logs.len() # if logs_len > 1: # msg = ' (last {} entries)'.format(logs_len) # else: # msg = ' (one entry)' # ret.append(self.curse_add_line(msg, "TITLE")) # Loop over alerts for alert in self.stats: # New line ret.append(self.curse_new_line()) # Start msg = str(datetime.fromtimestamp(alert[0])) ret.append(self.curse_add_line(msg)) # Duration if alert[1] > 0: # If finished display duration msg = ' ({})'.format(datetime.fromtimestamp(alert[1]) - datetime.fromtimestamp(alert[0])) else: msg = ' (ongoing)' ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line(" - ")) # Infos if alert[1] > 0: # If finished do not display status msg = '{} on {}'.format(alert[2], alert[3]) ret.append(self.curse_add_line(msg)) else: msg = str(alert[3]) ret.append(self.curse_add_line(msg, decoration=alert[2])) # Min / Mean / Max if self.approx_equal(alert[6], alert[4], tolerance=0.1): msg = ' ({:.1f})'.format(alert[5]) else: msg = ' (Min:{:.1f} Mean:{:.1f} Max:{:.1f})'.format( alert[6], alert[5], alert[4]) ret.append(self.curse_add_line(msg)) # Top processes top_process = ', '.join([p['name'] for p in alert[9]]) if top_process != '': msg = ': {}'.format(top_process) ret.append(self.curse_add_line(msg)) return ret def approx_equal(self, a, b, tolerance=0.0): """Compare a with b using the tolerance (if numerical).""" if str(int(a)).isdigit() and str(int(b)).isdigit(): return abs(a - b) <= max(abs(a), abs(b)) * tolerance else: return a == b glances-2.11.1/glances/plugins/glances_amps.py000066400000000000000000000110211315472316100213110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Monitor plugin.""" from glances.compat import iteritems from glances.amps_list import AmpsList as glancesAmpsList from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Glances AMPs plugin.""" def __init__(self, args=None, config=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) self.args = args self.config = config # We want to display the stat in the curse interface self.display_curse = True # Init the list of AMP (classe define in the glances/amps_list.py script) self.glances_amps = glancesAmpsList(self.args, self.config) # Init stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the AMP list.""" # Reset stats self.reset() if self.input_method == 'local': for k, v in iteritems(self.glances_amps.update()): # self.stats.append({k: v.result()}) self.stats.append({'key': k, 'name': v.NAME, 'result': v.result(), 'refresh': v.refresh(), 'timer': v.time_until_refresh(), 'count': v.count(), 'countmin': v.count_min(), 'countmax': v.count_max()}) else: # Not available in SNMP mode pass return self.stats def get_alert(self, nbprocess=0, countmin=None, countmax=None, header="", log=False): """Return the alert status relative to the process number.""" if nbprocess is None: return 'OK' if countmin is None: countmin = nbprocess if countmax is None: countmax = nbprocess if nbprocess > 0: if int(countmin) <= int(nbprocess) <= int(countmax): return 'OK' else: return 'WARNING' else: if int(countmin) == 0: return 'OK' else: return 'CRITICAL' def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message # Only process if stats exist and display plugin enable... ret = [] if not self.stats or args.disable_process or self.is_disable(): return ret # Build the string message for m in self.stats: # Only display AMP if a result exist if m['result'] is None: continue # Display AMP first_column = '{}'.format(m['name']) first_column_style = self.get_alert(m['count'], m['countmin'], m['countmax']) second_column = '{}'.format(m['count']) for l in m['result'].split('\n'): # Display first column with the process name... msg = '{:<16} '.format(first_column) ret.append(self.curse_add_line(msg, first_column_style)) # ... and second column with the number of matching processes... msg = '{:<4} '.format(second_column) ret.append(self.curse_add_line(msg)) # ... only on the first line first_column = second_column = '' # Display AMP result in the third column ret.append(self.curse_add_line(l, splittable=True)) ret.append(self.curse_new_line()) # Delete the last empty line try: ret.pop() except IndexError: pass return ret glances-2.11.1/glances/plugins/glances_batpercent.py000066400000000000000000000101561315472316100225100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Battery plugin.""" import psutil from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin # Batinfo library (optional; Linux-only) batinfo_tag = True try: import batinfo except ImportError: logger.debug("batpercent plugin - Batinfo library not found. Trying fallback to PsUtil.") batinfo_tag = False # PsUtil library 5.2.0 or higher (optional; Linux-only) psutil_tag = True try: psutil.sensors_battery() except AttributeError: logger.debug("batpercent plugin - PsUtil 5.2.0 or higher is needed to grab battery stats.") psutil_tag = False class Plugin(GlancesPlugin): """Glances battery capacity plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # Init the sensor class self.glancesgrabbat = GlancesGrabBat() # We do not want to display the stat in a dedicated area # The HDD temp is displayed within the sensors plugin self.display_curse = False # Init stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update battery capacity stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats self.glancesgrabbat.update() self.stats = self.glancesgrabbat.get() elif self.input_method == 'snmp': # Update stats using SNMP # Not avalaible pass return self.stats class GlancesGrabBat(object): """Get batteries stats using the batinfo library.""" def __init__(self): """Init batteries stats.""" self.bat_list = [] if batinfo_tag: self.bat = batinfo.batteries() elif psutil_tag: self.bat = psutil else: self.bat = None def update(self): """Update the stats.""" if batinfo_tag: # Use the batinfo lib to grab the stats # Compatible with multiple batteries self.bat.update() self.bat_list = [{ 'label': 'Battery', 'value': self.battery_percent, 'unit': '%'}] elif psutil_tag and hasattr(self.bat.sensors_battery(), 'percent'): # Use the PSUtil 5.2.0 or higher lib to grab the stats # Give directly the battery percent self.bat_list = [{ 'label': 'Battery', 'value': int(self.bat.sensors_battery().percent), 'unit': '%'}] else: # No stats... self.bat_list = [] def get(self): """Get the stats.""" return self.bat_list @property def battery_percent(self): """Get batteries capacity percent.""" if not batinfo_tag or not self.bat.stat: return [] # Init the bsum (sum of percent) # and Loop over batteries (yes a computer could have more than 1 battery) bsum = 0 for b in self.bat.stat: try: bsum += int(b.capacity) except ValueError: return [] # Return the global percent return int(bsum / len(self.bat.stat)) glances-2.11.1/glances/plugins/glances_cloud.py000066400000000000000000000131731315472316100214710ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Cloud plugin. Supported Cloud API: - AWS EC2 (class ThreadAwsEc2Grabber, see bellow) """ try: import requests except ImportError: cloud_tag = False else: cloud_tag = True import threading from glances.compat import iteritems, to_ascii from glances.plugins.glances_plugin import GlancesPlugin from glances.logger import logger class Plugin(GlancesPlugin): """Glances' cloud plugin. The goal of this plugin is to retreive additional information concerning the datacenter where the host is connected. See https://github.com/nicolargo/glances/issues/1029 stats is a dict """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() # Init thread to grab AWS EC2 stats asynchroniously self.aws_ec2 = ThreadAwsEc2Grabber() # Run the thread self.aws_ec2. start() def reset(self): """Reset/init the stats.""" self.stats = {} def exit(self): """Overwrite the exit method to close threads""" self.aws_ec2.stop() # Call the father class super(Plugin, self).exit() @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the cloud stats. Return the stats (dict) """ # Reset stats self.reset() # Requests lib is needed to get stats from the Cloud API if not cloud_tag: return self.stats # Update the stats if self.input_method == 'local': self.stats = self.aws_ec2.stats # self.stats = {'ami-id': 'ami-id', # 'instance-id': 'instance-id', # 'instance-type': 'instance-type', # 'region': 'placement/availability-zone'} return self.stats def msg_curse(self, args=None): """Return the string to display in the curse interface.""" # Init the return message ret = [] if not self.stats or self.stats == {} or self.is_disable(): return ret # Generate the output if 'ami-id' in self.stats and 'region' in self.stats: msg = 'AWS EC2' ret.append(self.curse_add_line(msg, "TITLE")) msg = ' {} instance {} ({})'.format(to_ascii(self.stats['instance-type']), to_ascii(self.stats['instance-id']), to_ascii(self.stats['region'])) ret.append(self.curse_add_line(msg)) # Return the message with decoration logger.info(ret) return ret class ThreadAwsEc2Grabber(threading.Thread): """ Specific thread to grab AWS EC2 stats. stats is a dict """ # AWS EC2 # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html AWS_EC2_API_URL = 'http://169.254.169.254/latest/meta-data' AWS_EC2_API_METADATA = {'ami-id': 'ami-id', 'instance-id': 'instance-id', 'instance-type': 'instance-type', 'region': 'placement/availability-zone'} def __init__(self): """Init the class""" logger.debug("cloud plugin - Create thread for AWS EC2") super(ThreadAwsEc2Grabber, self).__init__() # Event needed to stop properly the thread self._stopper = threading.Event() # The class return the stats as a dict self._stats = {} def run(self): """Function called to grab stats. Infinite loop, should be stopped by calling the stop() method""" if not cloud_tag: logger.debug("cloud plugin - Requests lib is not installed") self.stop() return False for k, v in iteritems(self.AWS_EC2_API_METADATA): r_url = '{}/{}'.format(self.AWS_EC2_API_URL, v) try: # Local request, a timeout of 3 seconds is OK r = requests.get(r_url, timeout=3) except Exception as e: logger.debug('cloud plugin - Cannot connect to the AWS EC2 API {}: {}'.format(r_url, e)) break else: if r.ok: self._stats[k] = r.content return True @property def stats(self): """Stats getter""" return self._stats @stats.setter def stats(self, value): """Stats setter""" self._stats = value def stop(self, timeout=None): """Stop the thread""" logger.debug("cloud plugin - Close thread for AWS EC2") self._stopper.set() def stopped(self): """Return True is the thread is stopped""" return self._stopper.isSet() glances-2.11.1/glances/plugins/glances_core.py000066400000000000000000000046201315472316100213100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """CPU core plugin.""" from glances.plugins.glances_plugin import GlancesPlugin import psutil class Plugin(GlancesPlugin): """Glances CPU core plugin. Get stats about CPU core number. stats is integer (number of core) """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We dot not want to display the stat in the curse interface # The core number is displayed by the load plugin self.display_curse = False # Init the stat self.reset() def reset(self): """Reset/init the stat using the input method.""" self.stats = {} def update(self): """Update core stats. Stats is a dict (with both physical and log cpu number) instead of a integer. """ # Reset the stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # The PSUtil 2.0 include psutil.cpu_count() and psutil.cpu_count(logical=False) # Return a dict with: # - phys: physical cores only (hyper thread CPUs are excluded) # - log: logical CPUs in the system # Return None if undefine try: self.stats["phys"] = psutil.cpu_count(logical=False) self.stats["log"] = psutil.cpu_count() except NameError: self.reset() elif self.input_method == 'snmp': # Update stats using SNMP # http://stackoverflow.com/questions/5662467/how-to-find-out-the-number-of-cpus-using-snmp pass return self.stats glances-2.11.1/glances/plugins/glances_cpu.py000066400000000000000000000355331315472316100211560ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """CPU plugin.""" from glances.timer import getTimeSinceLastUpdate from glances.compat import iterkeys from glances.cpu_percent import cpu_percent from glances.globals import LINUX from glances.plugins.glances_core import Plugin as CorePlugin from glances.plugins.glances_plugin import GlancesPlugin import psutil # SNMP OID # percentage of user CPU time: .1.3.6.1.4.1.2021.11.9.0 # percentages of system CPU time: .1.3.6.1.4.1.2021.11.10.0 # percentages of idle CPU time: .1.3.6.1.4.1.2021.11.11.0 snmp_oid = {'default': {'user': '1.3.6.1.4.1.2021.11.9.0', 'system': '1.3.6.1.4.1.2021.11.10.0', 'idle': '1.3.6.1.4.1.2021.11.11.0'}, 'windows': {'percent': '1.3.6.1.2.1.25.3.3.1.2'}, 'esxi': {'percent': '1.3.6.1.2.1.25.3.3.1.2'}, 'netapp': {'system': '1.3.6.1.4.1.789.1.2.1.3.0', 'idle': '1.3.6.1.4.1.789.1.2.1.5.0', 'nb_log_core': '1.3.6.1.4.1.789.1.2.1.6.0'}} # Define the history items list # - 'name' define the stat identifier # - 'color' define the graph color in #RGB format # - 'y_unit' define the Y label # All items in this list will be historised if the --enable-history tag is set items_history_list = [{'name': 'user', 'description': 'User CPU usage', 'color': '#00FF00', 'y_unit': '%'}, {'name': 'system', 'description': 'System CPU usage', 'color': '#FF0000', 'y_unit': '%'}] class Plugin(GlancesPlugin): """Glances CPU plugin. 'stats' is a dictionary that contains the system-wide CPU utilization as a percentage. """ def __init__(self, args=None): """Init the CPU plugin.""" super(Plugin, self).__init__(args=args, items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True # Init stats self.reset() # Call CorePlugin in order to display the core number try: self.nb_log_core = CorePlugin(args=self.args).update()["log"] except Exception: self.nb_log_core = 1 def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update CPU stats using the input method.""" # Reset stats self.reset() # Grab stats into self.stats if self.input_method == 'local': self.update_local() elif self.input_method == 'snmp': self.update_snmp() return self.stats def update_local(self): """Update CPU stats using PSUtil.""" # Grab CPU stats using psutil's cpu_percent and cpu_times_percent # Get all possible values for CPU stats: user, system, idle, # nice (UNIX), iowait (Linux), irq (Linux, FreeBSD), steal (Linux 2.6.11+) # The following stats are returned by the API but not displayed in the UI: # softirq (Linux), guest (Linux 2.6.24+), guest_nice (Linux 3.2.0+) self.stats['total'] = cpu_percent.get() cpu_times_percent = psutil.cpu_times_percent(interval=0.0) for stat in ['user', 'system', 'idle', 'nice', 'iowait', 'irq', 'softirq', 'steal', 'guest', 'guest_nice']: if hasattr(cpu_times_percent, stat): self.stats[stat] = getattr(cpu_times_percent, stat) # Additionnal CPU stats (number of events / not as a %) # ctx_switches: number of context switches (voluntary + involuntary) per second # interrupts: number of interrupts per second # soft_interrupts: number of software interrupts per second. Always set to 0 on Windows and SunOS. # syscalls: number of system calls since boot. Always set to 0 on Linux. try: cpu_stats = psutil.cpu_stats() except AttributeError: # cpu_stats only available with PSUtil 4.1 or + pass else: # By storing time data we enable Rx/s and Tx/s calculations in the # XML/RPC API, which would otherwise be overly difficult work # for users of the API time_since_update = getTimeSinceLastUpdate('cpu') # Previous CPU stats are stored in the cpu_stats_old variable if not hasattr(self, 'cpu_stats_old'): # First call, we init the cpu_stats_old var self.cpu_stats_old = cpu_stats else: for stat in cpu_stats._fields: if getattr(cpu_stats, stat) is not None: self.stats[stat] = getattr(cpu_stats, stat) - getattr(self.cpu_stats_old, stat) self.stats['time_since_update'] = time_since_update # Core number is needed to compute the CTX switch limit self.stats['cpucore'] = self.nb_log_core # Save stats to compute next step self.cpu_stats_old = cpu_stats def update_snmp(self): """Update CPU stats using SNMP.""" # Update stats using SNMP if self.short_system_name in ('windows', 'esxi'): # Windows or VMWare ESXi # You can find the CPU utilization of windows system by querying the oid # Give also the number of core (number of element in the table) try: cpu_stats = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name], bulk=True) except KeyError: self.reset() # Iter through CPU and compute the idle CPU stats self.stats['nb_log_core'] = 0 self.stats['idle'] = 0 for c in cpu_stats: if c.startswith('percent'): self.stats['idle'] += float(cpu_stats['percent.3']) self.stats['nb_log_core'] += 1 if self.stats['nb_log_core'] > 0: self.stats['idle'] = self.stats[ 'idle'] / self.stats['nb_log_core'] self.stats['idle'] = 100 - self.stats['idle'] self.stats['total'] = 100 - self.stats['idle'] else: # Default behavor try: self.stats = self.get_stats_snmp( snmp_oid=snmp_oid[self.short_system_name]) except KeyError: self.stats = self.get_stats_snmp( snmp_oid=snmp_oid['default']) if self.stats['idle'] == '': self.reset() return self.stats # Convert SNMP stats to float for key in iterkeys(self.stats): self.stats[key] = float(self.stats[key]) self.stats['total'] = 100 - self.stats['idle'] def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert and log for key in ['user', 'system', 'iowait']: if key in self.stats: self.views[key]['decoration'] = self.get_alert_log(self.stats[key], header=key) # Alert only for key in ['steal', 'total']: if key in self.stats: self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key) # Alert only but depend on Core number for key in ['ctx_switches']: if key in self.stats: self.views[key]['decoration'] = self.get_alert(self.stats[key], maximum=100 * self.stats['cpucore'], header=key) # Optional for key in ['nice', 'irq', 'iowait', 'steal', 'ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls']: if key in self.stats: self.views[key]['optional'] = True def msg_curse(self, args=None): """Return the list to display in the UI.""" # Init the return message ret = [] # Only process if stats exist and plugin not disable if not self.stats or self.is_disable(): return ret # Build the string message # If user stat is not here, display only idle / total CPU usage (for # exemple on Windows OS) idle_tag = 'user' not in self.stats # Header msg = '{}'.format('CPU') ret.append(self.curse_add_line(msg, "TITLE")) trend_user = self.get_trend('user') trend_system = self.get_trend('system') if trend_user is None or trend_user is None: trend_cpu = None else: trend_cpu = trend_user + trend_system msg = ' {:4}'.format(self.trend_msg(trend_cpu)) ret.append(self.curse_add_line(msg)) # Total CPU usage msg = '{:5.1f}%'.format(self.stats['total']) if idle_tag: ret.append(self.curse_add_line( msg, self.get_views(key='total', option='decoration'))) else: ret.append(self.curse_add_line(msg)) # Nice CPU if 'nice' in self.stats: msg = ' {:8}'.format('nice:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='nice', option='optional'))) msg = '{:5.1f}%'.format(self.stats['nice']) ret.append(self.curse_add_line(msg, optional=self.get_views(key='nice', option='optional'))) # ctx_switches if 'ctx_switches' in self.stats: msg = ' {:8}'.format('ctx_sw:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='ctx_switches', option='optional'))) msg = '{:>5}'.format(self.auto_unit(int(self.stats['ctx_switches'] // self.stats['time_since_update']), min_symbol='K')) ret.append(self.curse_add_line( msg, self.get_views(key='ctx_switches', option='decoration'), optional=self.get_views(key='ctx_switches', option='optional'))) # New line ret.append(self.curse_new_line()) # User CPU if 'user' in self.stats: msg = '{:8}'.format('user:') ret.append(self.curse_add_line(msg)) msg = '{:5.1f}%'.format(self.stats['user']) ret.append(self.curse_add_line( msg, self.get_views(key='user', option='decoration'))) elif 'idle' in self.stats: msg = '{:8}'.format('idle:') ret.append(self.curse_add_line(msg)) msg = '{:5.1f}%'.format(self.stats['idle']) ret.append(self.curse_add_line(msg)) # IRQ CPU if 'irq' in self.stats: msg = ' {:8}'.format('irq:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='irq', option='optional'))) msg = '{:5.1f}%'.format(self.stats['irq']) ret.append(self.curse_add_line(msg, optional=self.get_views(key='irq', option='optional'))) # interrupts if 'interrupts' in self.stats: msg = ' {:8}'.format('inter:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='interrupts', option='optional'))) msg = '{:>5}'.format(int(self.stats['interrupts'] // self.stats['time_since_update'])) ret.append(self.curse_add_line(msg, optional=self.get_views(key='interrupts', option='optional'))) # New line ret.append(self.curse_new_line()) # System CPU if 'system' in self.stats and not idle_tag: msg = '{:8}'.format('system:') ret.append(self.curse_add_line(msg)) msg = '{:5.1f}%'.format(self.stats['system']) ret.append(self.curse_add_line( msg, self.get_views(key='system', option='decoration'))) else: msg = '{:8}'.format('core:') ret.append(self.curse_add_line(msg)) msg = '{:>6}'.format(self.stats['nb_log_core']) ret.append(self.curse_add_line(msg)) # IOWait CPU if 'iowait' in self.stats: msg = ' {:8}'.format('iowait:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='iowait', option='optional'))) msg = '{:5.1f}%'.format(self.stats['iowait']) ret.append(self.curse_add_line( msg, self.get_views(key='iowait', option='decoration'), optional=self.get_views(key='iowait', option='optional'))) # soft_interrupts if 'soft_interrupts' in self.stats: msg = ' {:8}'.format('sw_int:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='soft_interrupts', option='optional'))) msg = '{:>5}'.format(int(self.stats['soft_interrupts'] // self.stats['time_since_update'])) ret.append(self.curse_add_line(msg, optional=self.get_views(key='soft_interrupts', option='optional'))) # New line ret.append(self.curse_new_line()) # Idle CPU if 'idle' in self.stats and not idle_tag: msg = '{:8}'.format('idle:') ret.append(self.curse_add_line(msg)) msg = '{:5.1f}%'.format(self.stats['idle']) ret.append(self.curse_add_line(msg)) # Steal CPU usage if 'steal' in self.stats: msg = ' {:8}'.format('steal:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='steal', option='optional'))) msg = '{:5.1f}%'.format(self.stats['steal']) ret.append(self.curse_add_line( msg, self.get_views(key='steal', option='decoration'), optional=self.get_views(key='steal', option='optional'))) # syscalls # syscalls: number of system calls since boot. Always set to 0 on Linux. (do not display) if 'syscalls' in self.stats and not LINUX: msg = ' {:8}'.format('syscal:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='syscalls', option='optional'))) msg = '{:>5}'.format(int(self.stats['syscalls'] // self.stats['time_since_update'])) ret.append(self.curse_add_line(msg, optional=self.get_views(key='syscalls', option='optional'))) # Return the message with decoration return ret glances-2.11.1/glances/plugins/glances_diskio.py000066400000000000000000000231461315472316100216460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Disk I/O plugin.""" import operator from glances.timer import getTimeSinceLastUpdate from glances.plugins.glances_plugin import GlancesPlugin import psutil # Define the history items list # All items in this list will be historised if the --enable-history tag is set # 'color' define the graph color in #RGB format items_history_list = [{'name': 'read_bytes', 'description': 'Bytes read per second', 'color': '#00FF00', 'y_unit': 'B/s'}, {'name': 'write_bytes', 'description': 'Bytes write per second', 'color': '#FF0000', 'y_unit': 'B/s'}] class Plugin(GlancesPlugin): """Glances disks I/O plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def get_key(self): """Return the key of the list.""" return 'disk_name' def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update disk I/O stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Grab the stat using the PsUtil disk_io_counters method # read_count: number of reads # write_count: number of writes # read_bytes: number of bytes read # write_bytes: number of bytes written # read_time: time spent reading from disk (in milliseconds) # write_time: time spent writing to disk (in milliseconds) try: diskiocounters = psutil.disk_io_counters(perdisk=True) except Exception: return self.stats # Previous disk IO stats are stored in the diskio_old variable if not hasattr(self, 'diskio_old'): # First call, we init the diskio_old var try: self.diskio_old = diskiocounters except (IOError, UnboundLocalError): pass else: # By storing time data we enable Rx/s and Tx/s calculations in the # XML/RPC API, which would otherwise be overly difficult work # for users of the API time_since_update = getTimeSinceLastUpdate('disk') diskio_new = diskiocounters for disk in diskio_new: # By default, RamFS is not displayed (issue #714) if self.args is not None and not self.args.diskio_show_ramfs and disk.startswith('ram'): continue # Do not take hide disk into account if self.is_hide(disk): continue # Compute count and bit rate try: read_count = (diskio_new[disk].read_count - self.diskio_old[disk].read_count) write_count = (diskio_new[disk].write_count - self.diskio_old[disk].write_count) read_bytes = (diskio_new[disk].read_bytes - self.diskio_old[disk].read_bytes) write_bytes = (diskio_new[disk].write_bytes - self.diskio_old[disk].write_bytes) diskstat = { 'time_since_update': time_since_update, 'disk_name': disk, 'read_count': read_count, 'write_count': write_count, 'read_bytes': read_bytes, 'write_bytes': write_bytes} # Add alias if exist (define in the configuration file) if self.has_alias(disk) is not None: diskstat['alias'] = self.has_alias(disk) except KeyError: continue else: diskstat['key'] = self.get_key() self.stats.append(diskstat) # Save stats to compute next bitrate self.diskio_old = diskio_new elif self.input_method == 'snmp': # Update stats using SNMP # No standard way for the moment... pass return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert for i in self.stats: disk_real_name = i['disk_name'] self.views[i[self.get_key()]]['read_bytes']['decoration'] = self.get_alert(int(i['read_bytes'] // i['time_since_update']), header=disk_real_name + '_rx') self.views[i[self.get_key()]]['write_bytes']['decoration'] = self.get_alert(int(i['write_bytes'] // i['time_since_update']), header=disk_real_name + '_tx') def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or self.is_disable(): return ret # Build the string message # Header msg = '{:9}'.format('DISK I/O') ret.append(self.curse_add_line(msg, "TITLE")) if args.diskio_iops: msg = '{:>7}'.format('IOR/s') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('IOW/s') ret.append(self.curse_add_line(msg)) else: msg = '{:>7}'.format('R/s') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('W/s') ret.append(self.curse_add_line(msg)) # Disk list (sorted by name) for i in sorted(self.stats, key=operator.itemgetter(self.get_key())): # Is there an alias for the disk name ? disk_real_name = i['disk_name'] disk_name = self.has_alias(i['disk_name']) if disk_name is None: disk_name = disk_real_name # New line ret.append(self.curse_new_line()) if len(disk_name) > 9: # Cut disk name if it is too long disk_name = '_' + disk_name[-8:] msg = '{:9}'.format(disk_name) ret.append(self.curse_add_line(msg)) if args.diskio_iops: # count txps = self.auto_unit( int(i['read_count'] // i['time_since_update'])) rxps = self.auto_unit( int(i['write_count'] // i['time_since_update'])) msg = '{:>7}'.format(txps) ret.append(self.curse_add_line(msg, self.get_views(item=i[self.get_key()], key='read_count', option='decoration'))) msg = '{:>7}'.format(rxps) ret.append(self.curse_add_line(msg, self.get_views(item=i[self.get_key()], key='write_count', option='decoration'))) else: # Bitrate txps = self.auto_unit( int(i['read_bytes'] // i['time_since_update'])) rxps = self.auto_unit( int(i['write_bytes'] // i['time_since_update'])) msg = '{:>7}'.format(txps) ret.append(self.curse_add_line(msg, self.get_views(item=i[self.get_key()], key='read_bytes', option='decoration'))) msg = '{:>7}'.format(rxps) ret.append(self.curse_add_line(msg, self.get_views(item=i[self.get_key()], key='write_bytes', option='decoration'))) return ret glances-2.11.1/glances/plugins/glances_docker.py000066400000000000000000000672001315472316100216320ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Docker plugin.""" import os import re import threading import time from glances.compat import iterkeys, itervalues from glances.logger import logger from glances.timer import getTimeSinceLastUpdate from glances.plugins.glances_plugin import GlancesPlugin from glances.globals import WINDOWS # Docker-py library (optional and Linux-only) # https://github.com/docker/docker-py try: import docker import requests except ImportError as e: logger.debug("Docker library not found (%s). Glances cannot grab Docker info." % e) docker_tag = False else: docker_tag = True class Plugin(GlancesPlugin): """Glances Docker plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # The plgin can be disable using: args.disable_docker self.args = args # We want to display the stat in the curse interface self.display_curse = True # Init the Docker API self.docker_client = False # Dict of thread (to grab stats asynchroniously, one thread is created by container) # key: Container Id # value: instance of ThreadDockerGrabber self.thread_list = {} # Init the stats self.reset() def exit(self): """Overwrite the exit method to close threads""" for t in itervalues(self.thread_list): t.stop() # Call the father class super(Plugin, self).exit() def get_key(self): """Return the key of the list.""" return 'name' def get_export(self): """Overwrite the default export method. - Only exports containers - The key is the first container name """ ret = [] try: ret = self.stats['containers'] except KeyError as e: logger.debug("docker plugin - Docker export error {}".format(e)) return ret def __connect_old(self, version): """Connect to the Docker server with the 'old school' method""" # Glances is compatible with both API 2.0 and <2.0 # (thanks to the @bacondropped patch) if hasattr(docker, 'APIClient'): # Correct issue #1000 for API 2.0 init_docker = docker.APIClient elif hasattr(docker, 'Client'): # < API 2.0 init_docker = docker.Client else: # Can not found init method (new API version ?) logger.error("docker plugin - Can not found any way to init the Docker API") return None # Init connection to the Docker API try: if WINDOWS: url = 'npipe:////./pipe/docker_engine' else: url = 'unix://var/run/docker.sock' if version is None: ret = init_docker(base_url=url) else: ret = init_docker(base_url=url, version=version) except NameError: # docker lib not found return None return ret def connect(self, version=None): """Connect to the Docker server.""" if hasattr(docker, 'from_env') and version is not None: # Connect to Docker using the default socket or # the configuration in your environment ret = docker.from_env() else: ret = self.__connect_old(version=version) # Check the server connection with the version() method try: ret.version() except requests.exceptions.ConnectionError as e: # Connexion error (Docker not detected) # Let this message in debug mode logger.debug("docker plugin - Can't connect to the Docker server (%s)" % e) return None except docker.errors.APIError as e: if version is None: # API error (Version mismatch ?) logger.debug("docker plugin - Docker API error (%s)" % e) # Try the connection with the server version version = re.search('(?:server API version|server)\:\ (.*)\)\".*\)', str(e)) if version: logger.debug("docker plugin - Try connection with Docker API version %s" % version.group(1)) ret = self.connect(version=version.group(1)) else: logger.debug("docker plugin - Can not retreive Docker server version") ret = None else: # API error logger.error("docker plugin - Docker API error (%s)" % e) ret = None except Exception as e: # Others exceptions... # Connexion error (Docker not detected) logger.error("docker plugin - Can't connect to the Docker server (%s)" % e) ret = None # Log an info if Docker plugin is disabled if ret is None: logger.debug("docker plugin - Docker plugin is disable because an error has been detected") return ret def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update Docker stats using the input method.""" global docker_tag # Reset stats self.reset() # Get the current Docker API client if not self.docker_client: # First time, try to connect to the server try: self.docker_client = self.connect() except Exception: docker_tag = False else: if self.docker_client is None: docker_tag = False # The Docker-py lib is mandatory if not docker_tag: return self.stats if self.input_method == 'local': # Update stats # Docker version # Exemple: { # "KernelVersion": "3.16.4-tinycore64", # "Arch": "amd64", # "ApiVersion": "1.15", # "Version": "1.3.0", # "GitCommit": "c78088f", # "Os": "linux", # "GoVersion": "go1.3.3" # } try: self.stats['version'] = self.docker_client.version() except Exception as e: # Correct issue#649 logger.error("{} plugin - Cannot get Docker version ({})".format(self.plugin_name, e)) return self.stats # Container globals information # Example: [{u'Status': u'Up 36 seconds', # u'Created': 1420378904, # u'Image': u'nginx:1', # u'Ports': [{u'Type': u'tcp', u'PrivatePort': 443}, # {u'IP': u'0.0.0.0', u'Type': u'tcp', u'PublicPort': 8080, u'PrivatePort': 80}], # u'Command': u"nginx -g 'daemon off;'", # u'Names': [u'/webstack_nginx_1'], # u'Id': u'b0da859e84eb4019cf1d965b15e9323006e510352c402d2f442ea632d61faaa5'}] # Update current containers list try: self.stats['containers'] = self.docker_client.containers() or [] except Exception as e: logger.error("{} plugin - Cannot get containers list ({})".format(self.plugin_name, e)) return self.stats # Start new thread for new container for container in self.stats['containers']: if container['Id'] not in self.thread_list: # Thread did not exist in the internal dict # Create it and add it to the internal dict logger.debug("{} plugin - Create thread for container {}".format(self.plugin_name, container['Id'][:12])) t = ThreadDockerGrabber(self.docker_client, container['Id']) self.thread_list[container['Id']] = t t.start() # Stop threads for non-existing containers nonexisting_containers = set(iterkeys(self.thread_list)) - set([c['Id'] for c in self.stats['containers']]) for container_id in nonexisting_containers: # Stop the thread logger.debug("{} plugin - Stop thread for old container {}".format(self.plugin_name, container_id[:12])) self.thread_list[container_id].stop() # Delete the item from the dict del self.thread_list[container_id] # Get stats for all containers for container in self.stats['containers']: # The key is the container name and not the Id container['key'] = self.get_key() # Export name (first name in the list, without the /) container['name'] = container['Names'][0][1:] container['cpu'] = self.get_docker_cpu(container['Id'], self.thread_list[container['Id']].stats) container['memory'] = self.get_docker_memory(container['Id'], self.thread_list[container['Id']].stats) container['network'] = self.get_docker_network(container['Id'], self.thread_list[container['Id']].stats) container['io'] = self.get_docker_io(container['Id'], self.thread_list[container['Id']].stats) elif self.input_method == 'snmp': # Update stats using SNMP # Not available pass return self.stats def get_docker_cpu(self, container_id, all_stats): """Return the container CPU usage. Input: id is the full container id all_stats is the output of the stats method of the Docker API Output: a dict {'total': 1.49} """ cpu_new = {} ret = {'total': 0.0} # Read the stats # For each container, you will find a pseudo-file cpuacct.stat, # containing the CPU usage accumulated by the processes of the container. # Those times are expressed in ticks of 1/USER_HZ of a second. # On x86 systems, USER_HZ is 100. try: cpu_new['total'] = all_stats['cpu_stats']['cpu_usage']['total_usage'] cpu_new['system'] = all_stats['cpu_stats']['system_cpu_usage'] cpu_new['nb_core'] = len(all_stats['cpu_stats']['cpu_usage']['percpu_usage'] or []) except KeyError as e: # all_stats do not have CPU information logger.debug("docker plugin - Cannot grab CPU usage for container {} ({})".format(container_id, e)) logger.debug(all_stats) else: # Previous CPU stats stored in the cpu_old variable if not hasattr(self, 'cpu_old'): # First call, we init the cpu_old variable self.cpu_old = {} try: self.cpu_old[container_id] = cpu_new except (IOError, UnboundLocalError): pass if container_id not in self.cpu_old: try: self.cpu_old[container_id] = cpu_new except (IOError, UnboundLocalError): pass else: # cpu_delta = float(cpu_new['total'] - self.cpu_old[container_id]['total']) system_delta = float(cpu_new['system'] - self.cpu_old[container_id]['system']) if cpu_delta > 0.0 and system_delta > 0.0: ret['total'] = (cpu_delta / system_delta) * float(cpu_new['nb_core']) * 100 # Save stats to compute next stats self.cpu_old[container_id] = cpu_new # Return the stats return ret def get_docker_memory(self, container_id, all_stats): """Return the container MEMORY. Input: id is the full container id all_stats is the output of the stats method of the Docker API Output: a dict {'rss': 1015808, 'cache': 356352, 'usage': ..., 'max_usage': ...} """ ret = {} # Read the stats try: # Do not exist anymore with Docker 1.11 (issue #848) # ret['rss'] = all_stats['memory_stats']['stats']['rss'] # ret['cache'] = all_stats['memory_stats']['stats']['cache'] ret['usage'] = all_stats['memory_stats']['usage'] ret['limit'] = all_stats['memory_stats']['limit'] ret['max_usage'] = all_stats['memory_stats']['max_usage'] except (KeyError, TypeError) as e: # all_stats do not have MEM information logger.debug("docker plugin - Cannot grab MEM usage for container {} ({})".format(container_id, e)) logger.debug(all_stats) # Return the stats return ret def get_docker_network(self, container_id, all_stats): """Return the container network usage using the Docker API (v1.0 or higher). Input: id is the full container id Output: a dict {'time_since_update': 3000, 'rx': 10, 'tx': 65}. with: time_since_update: number of seconds elapsed between the latest grab rx: Number of byte received tx: Number of byte transmited """ # Init the returned dict network_new = {} # Read the rx/tx stats (in bytes) try: netcounters = all_stats["networks"] except KeyError as e: # all_stats do not have NETWORK information logger.debug("docker plugin - Cannot grab NET usage for container {} ({})".format(container_id, e)) logger.debug(all_stats) # No fallback available... return network_new # Previous network interface stats are stored in the network_old variable if not hasattr(self, 'inetcounters_old'): # First call, we init the network_old var self.netcounters_old = {} try: self.netcounters_old[container_id] = netcounters except (IOError, UnboundLocalError): pass if container_id not in self.netcounters_old: try: self.netcounters_old[container_id] = netcounters except (IOError, UnboundLocalError): pass else: # By storing time data we enable Rx/s and Tx/s calculations in the # XML/RPC API, which would otherwise be overly difficult work # for users of the API try: network_new['time_since_update'] = getTimeSinceLastUpdate('docker_net_{}'.format(container_id)) network_new['rx'] = netcounters["eth0"]["rx_bytes"] - self.netcounters_old[container_id]["eth0"]["rx_bytes"] network_new['tx'] = netcounters["eth0"]["tx_bytes"] - self.netcounters_old[container_id]["eth0"]["tx_bytes"] network_new['cumulative_rx'] = netcounters["eth0"]["rx_bytes"] network_new['cumulative_tx'] = netcounters["eth0"]["tx_bytes"] except KeyError as e: # all_stats do not have INTERFACE information logger.debug("docker plugin - Cannot grab network interface usage for container {} ({})".format(container_id, e)) logger.debug(all_stats) # Save stats to compute next bitrate self.netcounters_old[container_id] = netcounters # Return the stats return network_new def get_docker_io(self, container_id, all_stats): """Return the container IO usage using the Docker API (v1.0 or higher). Input: id is the full container id Output: a dict {'time_since_update': 3000, 'ior': 10, 'iow': 65}. with: time_since_update: number of seconds elapsed between the latest grab ior: Number of byte readed iow: Number of byte written """ # Init the returned dict io_new = {} # Read the ior/iow stats (in bytes) try: iocounters = all_stats["blkio_stats"] except KeyError as e: # all_stats do not have io information logger.debug("docker plugin - Cannot grab block IO usage for container {} ({})".format(container_id, e)) logger.debug(all_stats) # No fallback available... return io_new # Previous io interface stats are stored in the io_old variable if not hasattr(self, 'iocounters_old'): # First call, we init the io_old var self.iocounters_old = {} try: self.iocounters_old[container_id] = iocounters except (IOError, UnboundLocalError): pass if container_id not in self.iocounters_old: try: self.iocounters_old[container_id] = iocounters except (IOError, UnboundLocalError): pass else: # By storing time data we enable IoR/s and IoW/s calculations in the # XML/RPC API, which would otherwise be overly difficult work # for users of the API try: # Read IOR and IOW value in the structure list of dict ior = [i for i in iocounters['io_service_bytes_recursive'] if i['op'] == 'Read'][0]['value'] iow = [i for i in iocounters['io_service_bytes_recursive'] if i['op'] == 'Write'][0]['value'] ior_old = [i for i in self.iocounters_old[container_id]['io_service_bytes_recursive'] if i['op'] == 'Read'][0]['value'] iow_old = [i for i in self.iocounters_old[container_id]['io_service_bytes_recursive'] if i['op'] == 'Write'][0]['value'] except (IndexError, KeyError) as e: # all_stats do not have io information logger.debug("docker plugin - Cannot grab block IO usage for container {} ({})".format(container_id, e)) else: io_new['time_since_update'] = getTimeSinceLastUpdate('docker_io_{}'.format(container_id)) io_new['ior'] = ior - ior_old io_new['iow'] = iow - iow_old io_new['cumulative_ior'] = ior io_new['cumulative_iow'] = iow # Save stats to compute next bitrate self.iocounters_old[container_id] = iocounters # Return the stats return io_new def get_user_ticks(self): """Return the user ticks by reading the environment variable.""" return os.sysconf(os.sysconf_names['SC_CLK_TCK']) def get_stats_action(self): """Return stats for the action Docker will return self.stats['containers']""" return self.stats['containers'] def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() if 'containers' not in self.stats: return False # Add specifics informations # Alert for i in self.stats['containers']: # Init the views for the current container (key = container name) self.views[i[self.get_key()]] = {'cpu': {}, 'mem': {}} # CPU alert if 'cpu' in i and 'total' in i['cpu']: # Looking for specific CPU container threasold in the conf file alert = self.get_alert(i['cpu']['total'], header=i['name'] + '_cpu', action_key=i['name']) if alert == 'DEFAULT': # Not found ? Get back to default CPU threasold value alert = self.get_alert(i['cpu']['total'], header='cpu') self.views[i[self.get_key()]]['cpu']['decoration'] = alert # MEM alert if 'memory' in i and 'usage' in i['memory']: # Looking for specific MEM container threasold in the conf file alert = self.get_alert(i['memory']['usage'], maximum=i['memory']['limit'], header=i['name'] + '_mem', action_key=i['name']) if alert == 'DEFAULT': # Not found ? Get back to default MEM threasold value alert = self.get_alert(i['memory']['usage'], maximum=i['memory']['limit'], header='mem') self.views[i[self.get_key()]]['mem']['decoration'] = alert return True def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist (and non null) and display plugin enable... if not self.stats or len(self.stats['containers']) == 0 or self.is_disable(): return ret # Build the string message # Title msg = '{}'.format('CONTAINERS') ret.append(self.curse_add_line(msg, "TITLE")) msg = ' {}'.format(len(self.stats['containers'])) ret.append(self.curse_add_line(msg)) msg = ' (served by Docker {})'.format(self.stats['version']["Version"]) ret.append(self.curse_add_line(msg)) ret.append(self.curse_new_line()) # Header ret.append(self.curse_new_line()) # msg = '{:>14}'.format('Id') # ret.append(self.curse_add_line(msg)) # Get the maximum containers name (cutted to 20 char max) name_max_width = min(20, len(max(self.stats['containers'], key=lambda x: len(x['name']))['name'])) msg = ' {:{width}}'.format('Name', width=name_max_width) ret.append(self.curse_add_line(msg)) msg = '{:>26}'.format('Status') ret.append(self.curse_add_line(msg)) msg = '{:>6}'.format('CPU%') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('MEM') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('/MAX') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('IOR/s') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('IOW/s') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('Rx/s') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('Tx/s') ret.append(self.curse_add_line(msg)) msg = ' {:8}'.format('Command') ret.append(self.curse_add_line(msg)) # Data for container in self.stats['containers']: ret.append(self.curse_new_line()) # Id # msg = '{:>14}'.format(container['Id'][0:12]) # ret.append(self.curse_add_line(msg)) # Name name = container['name'] if len(name) > name_max_width: name = '_' + name[-name_max_width + 1:] else: name = name[:name_max_width] msg = ' {:{width}}'.format(name, width=name_max_width) ret.append(self.curse_add_line(msg)) # Status status = self.container_alert(container['Status']) msg = container['Status'].replace("minute", "min") msg = '{:>26}'.format(msg[0:25]) ret.append(self.curse_add_line(msg, status)) # CPU try: msg = '{:>6.1f}'.format(container['cpu']['total']) except KeyError: msg = '{:>6}'.format('?') ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='cpu', option='decoration'))) # MEM try: msg = '{:>7}'.format(self.auto_unit(container['memory']['usage'])) except KeyError: msg = '{:>7}'.format('?') ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='mem', option='decoration'))) try: msg = '{:>7}'.format(self.auto_unit(container['memory']['limit'])) except KeyError: msg = '{:>7}'.format('?') ret.append(self.curse_add_line(msg)) # IO R/W for r in ['ior', 'iow']: try: value = self.auto_unit(int(container['io'][r] // container['io']['time_since_update'] * 8)) + "b" msg = '{:>7}'.format(value) except KeyError: msg = '{:>7}'.format('?') ret.append(self.curse_add_line(msg)) # NET RX/TX if args.byte: # Bytes per second (for dummy) to_bit = 1 unit = '' else: # Bits per second (for real network administrator | Default) to_bit = 8 unit = 'b' for r in ['rx', 'tx']: try: value = self.auto_unit(int(container['network'][r] // container['network']['time_since_update'] * to_bit)) + unit msg = '{:>7}'.format(value) except KeyError: msg = '{:>7}'.format('?') ret.append(self.curse_add_line(msg)) # Command msg = ' {}'.format(container['Command']) ret.append(self.curse_add_line(msg, splittable=True)) return ret def container_alert(self, status): """Analyse the container status.""" if "Paused" in status: return 'CAREFUL' else: return 'OK' class ThreadDockerGrabber(threading.Thread): """ Specific thread to grab docker stats. stats is a dict """ def __init__(self, docker_client, container_id): """Init the class: docker_client: instance of Docker-py client container_id: Id of the container""" logger.debug("docker plugin - Create thread for container {}".format(container_id[:12])) super(ThreadDockerGrabber, self).__init__() # Event needed to stop properly the thread self._stopper = threading.Event() # The docker-py return stats as a stream self._container_id = container_id self._stats_stream = docker_client.stats(container_id, decode=True) # The class return the stats as a dict self._stats = {} def run(self): """Function called to grab stats. Infinite loop, should be stopped by calling the stop() method""" for i in self._stats_stream: self._stats = i time.sleep(0.1) if self.stopped(): break @property def stats(self): """Stats getter""" return self._stats @stats.setter def stats(self, value): """Stats setter""" self._stats = value def stop(self, timeout=None): """Stop the thread""" logger.debug("docker plugin - Close thread for container {}".format(self._container_id[:12])) self._stopper.set() def stopped(self): """Return True is the thread is stopped""" return self._stopper.isSet() glances-2.11.1/glances/plugins/glances_folders.py000066400000000000000000000075471315472316100220310ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Folder plugin.""" import numbers from glances.folder_list import FolderList as glancesFolderList from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Glances folder plugin.""" def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init stats self.glances_folders = None self.reset() def get_key(self): """Return the key of the list.""" return 'path' def reset(self): """Reset/init the stats.""" self.stats = [] def load_limits(self, config): """Load the foldered list from the config file, if it exists.""" self.glances_folders = glancesFolderList(config) @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the foldered list.""" # Reset the list self.reset() if self.input_method == 'local': # Folder list only available in a full Glances environment # Check if the glances_folder instance is init if self.glances_folders is None: return self.stats # Update the foldered list (result of command) self.glances_folders.update() # Put it on the stats var self.stats = self.glances_folders.get() else: pass return self.stats def get_alert(self, stat): """Manage limits of the folder list""" if not isinstance(stat['size'], numbers.Number): return 'DEFAULT' else: ret = 'OK' if stat['critical'] is not None and stat['size'] > int(stat['critical']) * 1000000: ret = 'CRITICAL' elif stat['warning'] is not None and stat['size'] > int(stat['warning']) * 1000000: ret = 'WARNING' elif stat['careful'] is not None and stat['size'] > int(stat['careful']) * 1000000: ret = 'CAREFUL' return ret def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or self.is_disable(): return ret # Build the string message # Header msg = '{}'.format('FOLDERS') ret.append(self.curse_add_line(msg, "TITLE")) # Data for i in self.stats: ret.append(self.curse_new_line()) if len(i['path']) > 15: # Cut path if it is too long path = '_' + i['path'][-15 + 1:] else: path = i['path'] msg = '{:<16} '.format(path) ret.append(self.curse_add_line(msg)) try: msg = '{:>6}'.format(self.auto_unit(i['size'])) except (TypeError, ValueError): msg = '{:>6}'.format(i['size']) ret.append(self.curse_add_line(msg, self.get_alert(i))) return ret glances-2.11.1/glances/plugins/glances_fs.py000066400000000000000000000241541315472316100207740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """File system plugin.""" import operator from glances.compat import u from glances.plugins.glances_plugin import GlancesPlugin import psutil # SNMP OID # The snmpd.conf needs to be edited. # Add the following to enable it on all disk # ... # includeAllDisks 10% # ... # The OIDs are as follows (for the first disk) # Path where the disk is mounted: .1.3.6.1.4.1.2021.9.1.2.1 # Path of the device for the partition: .1.3.6.1.4.1.2021.9.1.3.1 # Total size of the disk/partion (kBytes): .1.3.6.1.4.1.2021.9.1.6.1 # Available space on the disk: .1.3.6.1.4.1.2021.9.1.7.1 # Used space on the disk: .1.3.6.1.4.1.2021.9.1.8.1 # Percentage of space used on disk: .1.3.6.1.4.1.2021.9.1.9.1 # Percentage of inodes used on disk: .1.3.6.1.4.1.2021.9.1.10.1 snmp_oid = {'default': {'mnt_point': '1.3.6.1.4.1.2021.9.1.2', 'device_name': '1.3.6.1.4.1.2021.9.1.3', 'size': '1.3.6.1.4.1.2021.9.1.6', 'used': '1.3.6.1.4.1.2021.9.1.8', 'percent': '1.3.6.1.4.1.2021.9.1.9'}, 'windows': {'mnt_point': '1.3.6.1.2.1.25.2.3.1.3', 'alloc_unit': '1.3.6.1.2.1.25.2.3.1.4', 'size': '1.3.6.1.2.1.25.2.3.1.5', 'used': '1.3.6.1.2.1.25.2.3.1.6'}, 'netapp': {'mnt_point': '1.3.6.1.4.1.789.1.5.4.1.2', 'device_name': '1.3.6.1.4.1.789.1.5.4.1.10', 'size': '1.3.6.1.4.1.789.1.5.4.1.3', 'used': '1.3.6.1.4.1.789.1.5.4.1.4', 'percent': '1.3.6.1.4.1.789.1.5.4.1.6'}} snmp_oid['esxi'] = snmp_oid['windows'] # Define the history items list # All items in this list will be historised if the --enable-history tag is set # 'color' define the graph color in #RGB format items_history_list = [{'name': 'percent', 'description': 'File system usage in percent', 'color': '#00FF00'}] class Plugin(GlancesPlugin): """Glances file system plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def get_key(self): """Return the key of the list.""" return 'mnt_point' def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the FS stats using the input method.""" # Reset the list self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Grab the stats using the PsUtil disk_partitions # If 'all'=False return physical devices only (e.g. hard disks, cd-rom drives, USB keys) # and ignore all others (e.g. memory partitions such as /dev/shm) try: fs_stat = psutil.disk_partitions(all=False) except UnicodeDecodeError: return self.stats # Optionnal hack to allow logicals mounts points (issue #448) # Ex: Had to put 'allow=zfs' in the [fs] section of the conf file # to allow zfs monitoring for fstype in self.get_conf_value('allow'): try: fs_stat += [f for f in psutil.disk_partitions(all=True) if f.fstype.find(fstype) >= 0] except UnicodeDecodeError: return self.stats # Loop over fs for fs in fs_stat: # Do not take hidden file system into account if self.is_hide(fs.mountpoint): continue # Grab the disk usage try: fs_usage = psutil.disk_usage(fs.mountpoint) except OSError: # Correct issue #346 # Disk is ejected during the command continue fs_current = { 'device_name': fs.device, 'fs_type': fs.fstype, # Manage non breaking space (see issue #1065) 'mnt_point': u(fs.mountpoint).replace(u'\u00A0', ' '), 'size': fs_usage.total, 'used': fs_usage.used, 'free': fs_usage.free, 'percent': fs_usage.percent, 'key': self.get_key()} self.stats.append(fs_current) elif self.input_method == 'snmp': # Update stats using SNMP # SNMP bulk command to get all file system in one shot try: fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name], bulk=True) except KeyError: fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid['default'], bulk=True) # Loop over fs if self.short_system_name in ('windows', 'esxi'): # Windows or ESXi tips for fs in fs_stat: # Memory stats are grabbed in the same OID table (ignore it) if fs == 'Virtual Memory' or fs == 'Physical Memory' or fs == 'Real Memory': continue size = int(fs_stat[fs]['size']) * int(fs_stat[fs]['alloc_unit']) used = int(fs_stat[fs]['used']) * int(fs_stat[fs]['alloc_unit']) percent = float(used * 100 / size) fs_current = { 'device_name': '', 'mnt_point': fs.partition(' ')[0], 'size': size, 'used': used, 'percent': percent, 'key': self.get_key()} self.stats.append(fs_current) else: # Default behavior for fs in fs_stat: fs_current = { 'device_name': fs_stat[fs]['device_name'], 'mnt_point': fs, 'size': int(fs_stat[fs]['size']) * 1024, 'used': int(fs_stat[fs]['used']) * 1024, 'percent': float(fs_stat[fs]['percent']), 'key': self.get_key()} self.stats.append(fs_current) return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert for i in self.stats: self.views[i[self.get_key()]]['used']['decoration'] = self.get_alert( i['used'], maximum=i['size'], header=i['mnt_point']) def msg_curse(self, args=None, max_width=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or self.is_disable(): return ret # Max size for the fsname name if max_width is not None and max_width >= 23: # Interface size name = max_width - space for interfaces bitrate fsname_max_width = max_width - 14 else: fsname_max_width = 9 # Build the string message # Header msg = '{:{width}}'.format('FILE SYS', width=fsname_max_width) ret.append(self.curse_add_line(msg, "TITLE")) if args.fs_free_space: msg = '{:>7}'.format('Free') else: msg = '{:>7}'.format('Used') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('Total') ret.append(self.curse_add_line(msg)) # Filesystem list (sorted by name) for i in sorted(self.stats, key=operator.itemgetter(self.get_key())): # New line ret.append(self.curse_new_line()) if i['device_name'] == '' or i['device_name'] == 'none': mnt_point = i['mnt_point'][-fsname_max_width + 1:] elif len(i['mnt_point']) + len(i['device_name'].split('/')[-1]) <= fsname_max_width - 3: # If possible concatenate mode info... Glances touch inside :) mnt_point = i['mnt_point'] + ' (' + i['device_name'].split('/')[-1] + ')' elif len(i['mnt_point']) > fsname_max_width: # Cut mount point name if it is too long mnt_point = '_' + i['mnt_point'][-fsname_max_width + 1:] else: mnt_point = i['mnt_point'] msg = '{:{width}}'.format(mnt_point, width=fsname_max_width) ret.append(self.curse_add_line(msg)) if args.fs_free_space: msg = '{:>7}'.format(self.auto_unit(i['free'])) else: msg = '{:>7}'.format(self.auto_unit(i['used'])) ret.append(self.curse_add_line(msg, self.get_views(item=i[self.get_key()], key='used', option='decoration'))) msg = '{:>7}'.format(self.auto_unit(i['size'])) ret.append(self.curse_add_line(msg)) return ret glances-2.11.1/glances/plugins/glances_gpu.py000066400000000000000000000230561315472316100211570ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Kirby Banman # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """GPU plugin (limited to NVIDIA chipsets)""" from glances.compat import nativestr from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin try: import pynvml except Exception as e: logger.error("Could not import pynvml. NVIDIA stats will not be collected.") logger.debug("pynvml error: {}".format(e)) gpu_nvidia_tag = False else: gpu_nvidia_tag = True class Plugin(GlancesPlugin): """Glances GPU plugin (limited to NVIDIA chipsets). stats is a list of dictionaries with one entry per GPU """ def __init__(self, args=None): """Init the plugin""" super(Plugin, self).__init__(args=args) # Init the NVidia API self.init_nvidia() # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = [] def init_nvidia(self): """Init the NVIDIA API""" if not gpu_nvidia_tag: self.nvml_ready = False try: pynvml.nvmlInit() self.device_handles = get_device_handles() self.nvml_ready = True except Exception: logger.debug("pynvml could not be initialized.") self.nvml_ready = False return self.nvml_ready def get_key(self): """Return the key of the list.""" return 'gpu_id' @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the GPU stats""" self.reset() # !!! JUST FOR TEST # self.stats = [{"key": "gpu_id", "mem": None, "proc": 60, "gpu_id": 0, "name": "GeForce GTX 560 Ti"}] # self.stats = [{"key": "gpu_id", "mem": 10, "proc": 60, "gpu_id": 0, "name": "GeForce GTX 560 Ti"}] # self.stats = [{"key": "gpu_id", "mem": 48.64645, "proc": 60.73, "gpu_id": 0, "name": "GeForce GTX 560 Ti"}, # {"key": "gpu_id", "mem": 70.743, "proc": 80.28, "gpu_id": 1, "name": "GeForce GTX 560 Ti"}, # {"key": "gpu_id", "mem": 0, "proc": 0, "gpu_id": 2, "name": "GeForce GTX 560 Ti"}] # self.stats = [{"key": "gpu_id", "mem": 48.64645, "proc": 60.73, "gpu_id": 0, "name": "GeForce GTX 560 Ti"}, # {"key": "gpu_id", "mem": None, "proc": 80.28, "gpu_id": 1, "name": "GeForce GTX 560 Ti"}, # {"key": "gpu_id", "mem": 0, "proc": 0, "gpu_id": 2, "name": "ANOTHER GPU"}] # !!! TO BE COMMENTED if not self.nvml_ready: return self.stats if self.input_method == 'local': self.stats = self.get_device_stats() elif self.input_method == 'snmp': # not available pass return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert for i in self.stats: # Init the views for the current GPU self.views[i[self.get_key()]] = {'proc': {}, 'mem': {}} # Processor alert if 'proc' in i: alert = self.get_alert(i['proc'], header='proc') self.views[i[self.get_key()]]['proc']['decoration'] = alert # Memory alert if 'mem' in i: alert = self.get_alert(i['mem'], header='mem') self.views[i[self.get_key()]]['mem']['decoration'] = alert return True def msg_curse(self, args=None, max_width=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist, not empty (issue #871) and plugin not disabled if not self.stats or (self.stats == []) or self.is_disable(): return ret # Check if all GPU have the same name same_name = all(s['name'] == self.stats[0]['name'] for s in self.stats) # gpu_stats contain the first GPU in the list gpu_stats = self.stats[0] # Header header = '' if len(self.stats) > 1: header += '{} '.format(len(self.stats)) if same_name: header += '{} {}'.format('GPU', gpu_stats['name']) else: header += '{}'.format('GPU') msg = header[:17] ret.append(self.curse_add_line(msg, "TITLE")) # Build the string message if len(self.stats) == 1 or args.meangpu: # GPU stat summary or mono GPU # New line ret.append(self.curse_new_line()) # GPU PROC try: mean_proc = sum(s['proc'] for s in self.stats if s is not None) / len(self.stats) except TypeError: mean_proc_msg = '{:>4}'.format('N/A') else: mean_proc_msg = '{:>3.0f}%'.format(mean_proc) if len(self.stats) > 1: msg = '{:13}'.format('proc mean:') else: msg = '{:13}'.format('proc:') ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line( mean_proc_msg, self.get_views(item=gpu_stats[self.get_key()], key='proc', option='decoration'))) # New line ret.append(self.curse_new_line()) # GPU MEM try: mean_mem = sum(s['mem'] for s in self.stats if s is not None) / len(self.stats) except TypeError: mean_mem_msg = '{:>4}'.format('N/A') else: mean_mem_msg = '{:>3.0f}%'.format(mean_mem) if len(self.stats) > 1: msg = '{:13}'.format('mem mean:') else: msg = '{:13}'.format('mem:') ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line( mean_mem_msg, self.get_views(item=gpu_stats[self.get_key()], key='mem', option='decoration'))) else: # Multi GPU for gpu_stats in self.stats: # New line ret.append(self.curse_new_line()) # GPU ID + PROC + MEM id_msg = '{}'.format(gpu_stats['gpu_id']) try: proc_msg = '{:>3.0f}%'.format(gpu_stats['proc']) except ValueError: proc_msg = '{:>4}'.format('N/A') try: mem_msg = '{:>3.0f}%'.format(gpu_stats['mem']) except ValueError: mem_msg = '{:>4}'.format('N/A') msg = '{}: {} mem: {}'.format(id_msg, proc_msg, mem_msg) ret.append(self.curse_add_line(msg)) return ret def get_device_stats(self): """Get GPU stats""" stats = [] for index, device_handle in enumerate(self.device_handles): device_stats = {} # Dictionnary key is the GPU_ID device_stats['key'] = self.get_key() # GPU id (for multiple GPU, start at 0) device_stats['gpu_id'] = index # GPU name device_stats['name'] = get_device_name(device_handle) # Memory consumption in % (not available on all GPU) device_stats['mem'] = get_mem(device_handle) # Processor consumption in % device_stats['proc'] = get_proc(device_handle) stats.append(device_stats) return stats def exit(self): """Overwrite the exit method to close the GPU API""" if self.nvml_ready: try: pynvml.nvmlShutdown() except Exception as e: logger.debug("pynvml failed to shutdown correctly ({})".format(e)) # Call the father exit method super(Plugin, self).exit() def get_device_handles(): """ Returns a list of NVML device handles, one per device. Can throw NVMLError. """ return [pynvml.nvmlDeviceGetHandleByIndex(i) for i in range(pynvml.nvmlDeviceGetCount())] def get_device_name(device_handle): """Get GPU device name""" try: return nativestr(pynvml.nvmlDeviceGetName(device_handle)) except pynvml.NVMlError: return "NVIDIA" def get_mem(device_handle): """Get GPU device memory consumption in percent""" try: memory_info = pynvml.nvmlDeviceGetMemoryInfo(device_handle) return memory_info.used * 100.0 / memory_info.total except pynvml.NVMLError: return None def get_proc(device_handle): """Get GPU device CPU consumption in percent""" try: return pynvml.nvmlDeviceGetUtilizationRates(device_handle).gpu except pynvml.NVMLError: return None glances-2.11.1/glances/plugins/glances_hddtemp.py000066400000000000000000000117251315472316100220110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """HDD temperature plugin.""" import os import socket from glances.compat import nativestr, range from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Glances HDD temperature sensors plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # Init the sensor class self.glancesgrabhddtemp = GlancesGrabHDDTemp(args=args) # We do not want to display the stat in a dedicated area # The HDD temp is displayed within the sensors plugin self.display_curse = False # Init stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update HDD stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib self.stats = self.glancesgrabhddtemp.get() else: # Update stats using SNMP # Not available for the moment pass return self.stats class GlancesGrabHDDTemp(object): """Get hddtemp stats using a socket connection.""" def __init__(self, host='127.0.0.1', port=7634, args=None): """Init hddtemp stats.""" self.args = args self.host = host self.port = port self.cache = "" self.reset() def reset(self): """Reset/init the stats.""" self.hddtemp_list = [] def __update__(self): """Update the stats.""" # Reset the list self.reset() # Fetch the data # data = ("|/dev/sda|WDC WD2500JS-75MHB0|44|C|" # "|/dev/sdb|WDC WD2500JS-75MHB0|35|C|" # "|/dev/sdc|WDC WD3200AAKS-75B3A0|45|C|" # "|/dev/sdd|WDC WD3200AAKS-75B3A0|45|C|" # "|/dev/sde|WDC WD3200AAKS-75B3A0|43|C|" # "|/dev/sdf|???|ERR|*|" # "|/dev/sdg|HGST HTS541010A9E680|SLP|*|" # "|/dev/sdh|HGST HTS541010A9E680|UNK|*|") data = self.fetch() # Exit if no data if data == "": return # Safety check to avoid malformed data # Considering the size of "|/dev/sda||0||" as the minimum if len(data) < 14: data = self.cache if len(self.cache) > 0 else self.fetch() self.cache = data try: fields = data.split(b'|') except TypeError: fields = "" devices = (len(fields) - 1) // 5 for item in range(devices): offset = item * 5 hddtemp_current = {} device = os.path.basename(nativestr(fields[offset + 1])) temperature = fields[offset + 3] unit = nativestr(fields[offset + 4]) hddtemp_current['label'] = device try: hddtemp_current['value'] = float(temperature) except ValueError: # Temperature could be 'ERR', 'SLP' or 'UNK' (see issue #824) # Improper bytes/unicode in glances_hddtemp.py (see issue #887) hddtemp_current['value'] = nativestr(temperature) hddtemp_current['unit'] = unit self.hddtemp_list.append(hddtemp_current) def fetch(self): """Fetch the data from hddtemp daemon.""" # Taking care of sudden deaths/stops of hddtemp daemon try: sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sck.connect((self.host, self.port)) data = sck.recv(4096) except socket.error as e: logger.debug("Cannot connect to an HDDtemp server ({}:{} => {})".format(self.host, self.port, e)) logger.debug("Disable the HDDtemp module. Use the --disable-hddtemp to hide the previous message.") if self.args is not None: self.args.disable_hddtemp = True data = "" finally: sck.close() return data def get(self): """Get HDDs list.""" self.__update__() return self.hddtemp_list glances-2.11.1/glances/plugins/glances_help.py000066400000000000000000000236051315472316100213140ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ Help plugin. Just a stupid plugin to display the help screen. """ from glances import __version__, psutil_version from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Glances help plugin.""" def __init__(self, args=None, config=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # Set the config instance self.config = config # We want to display the stat in the curse interface self.display_curse = True # init data dictionary self.view_data = {} self.generate_view_data() def reset(self): """No stats. It is just a plugin to display the help.""" pass def update(self): """No stats. It is just a plugin to display the help.""" pass def generate_view_data(self): self.view_data['version'] = '{} {}'.format('Glances', __version__) self.view_data['psutil_version'] = ' with PSutil {}'.format(psutil_version) try: self.view_data['configuration_file'] = 'Configuration file: {}'.format(self.config.loaded_config_file) except AttributeError: pass msg_col = ' {0:1} {1:35}' msg_col2 = ' {0:1} {1:35}' self.view_data['sort_auto'] = msg_col.format('a', 'Sort processes automatically') self.view_data['sort_network'] = msg_col2.format('b', 'Bytes or bits for network I/O') self.view_data['sort_cpu'] = msg_col.format('c', 'Sort processes by CPU%') self.view_data['show_hide_alert'] = msg_col2.format('l', 'Show/hide alert logs') self.view_data['sort_mem'] = msg_col.format('m', 'Sort processes by MEM%') self.view_data['sort_user'] = msg_col.format('u', 'Sort processes by USER') self.view_data['delete_warning_alerts'] = msg_col2.format('w', 'Delete warning alerts') self.view_data['sort_proc'] = msg_col.format('p', 'Sort processes by name') self.view_data['delete_warning_critical_alerts'] = msg_col2.format('x', 'Delete warning and critical alerts') self.view_data['sort_io'] = msg_col.format('i', 'Sort processes by I/O rate') self.view_data['percpu'] = msg_col2.format('1', 'Global CPU or per-CPU stats') self.view_data['sort_cpu_times'] = msg_col.format('t', 'Sort processes by TIME') self.view_data['show_hide_help'] = msg_col2.format('h', 'Show/hide this help screen') self.view_data['show_hide_diskio'] = msg_col.format('d', 'Show/hide disk I/O stats') self.view_data['show_hide_irq'] = msg_col2.format('Q', 'Show/hide IRQ stats') self.view_data['view_network_io_combination'] = msg_col2.format('T', 'View network I/O as combination') self.view_data['show_hide_filesystem'] = msg_col.format('f', 'Show/hide filesystem stats') self.view_data['view_cumulative_network'] = msg_col2.format('U', 'View cumulative network I/O') self.view_data['show_hide_network'] = msg_col.format('n', 'Show/hide network stats') self.view_data['show_hide_filesytem_freespace'] = msg_col2.format('F', 'Show filesystem free space') self.view_data['show_hide_sensors'] = msg_col.format('s', 'Show/hide sensors stats') self.view_data['generate_graphs'] = msg_col2.format('g', 'Generate graphs for current history') self.view_data['show_hide_left_sidebar'] = msg_col.format('2', 'Show/hide left sidebar') self.view_data['reset_history'] = msg_col2.format('r', 'Reset history') self.view_data['enable_disable_process_stats'] = msg_col.format('z', 'Enable/disable processes stats') self.view_data['quit'] = msg_col2.format('q', 'Quit (Esc and Ctrl-C also work)') self.view_data['enable_disable_top_extends_stats'] = msg_col.format('e', 'Enable/disable top extended stats') self.view_data['enable_disable_short_processname'] = msg_col.format('/', 'Enable/disable short processes name') self.view_data['enable_disable_irix'] = msg_col.format('0', 'Enable/disable Irix process CPU') self.view_data['enable_disable_docker'] = msg_col2.format('D', 'Enable/disable Docker stats') self.view_data['enable_disable_quick_look'] = msg_col.format('3', 'Enable/disable quick look plugin') self.view_data['show_hide_ip'] = msg_col2.format('I', 'Show/hide IP module') self.view_data['diskio_iops'] = msg_col2.format('B', 'Count/rate for Disk I/O') self.view_data['show_hide_top_menu'] = msg_col2.format('5', 'Show/hide top menu (QL, CPU, MEM, SWAP and LOAD)') self.view_data['enable_disable_gpu'] = msg_col.format('G', 'Enable/disable gpu plugin') self.view_data['enable_disable_mean_gpu'] = msg_col2.format('6', 'Enable/disable mean gpu') self.view_data['edit_pattern_filter'] = 'ENTER: Edit the process filter pattern' def get_view_data(self, args=None): return self.view_data def msg_curse(self, args=None): """Return the list to display in the curse interface.""" # Init the return message ret = [] # Build the string message # Header ret.append(self.curse_add_line(self.view_data['version'], 'TITLE')) ret.append(self.curse_add_line(self.view_data['psutil_version'])) ret.append(self.curse_new_line()) # Configuration file path if 'configuration_file' in self.view_data: ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['configuration_file'])) ret.append(self.curse_new_line()) # Keys ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['sort_auto'])) ret.append(self.curse_add_line(self.view_data['sort_network'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['sort_cpu'])) ret.append(self.curse_add_line(self.view_data['show_hide_alert'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['sort_mem'])) ret.append(self.curse_add_line(self.view_data['delete_warning_alerts'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['sort_user'])) ret.append(self.curse_add_line(self.view_data['delete_warning_critical_alerts'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['sort_proc'])) ret.append(self.curse_add_line(self.view_data['percpu'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['sort_io'])) ret.append(self.curse_add_line(self.view_data['show_hide_ip'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['sort_cpu_times'])) ret.append(self.curse_add_line(self.view_data['enable_disable_docker'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['show_hide_diskio'])) ret.append(self.curse_add_line(self.view_data['view_network_io_combination'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['show_hide_filesystem'])) ret.append(self.curse_add_line(self.view_data['view_cumulative_network'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['show_hide_network'])) ret.append(self.curse_add_line(self.view_data['show_hide_filesytem_freespace'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['show_hide_sensors'])) ret.append(self.curse_add_line(self.view_data['generate_graphs'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['show_hide_left_sidebar'])) ret.append(self.curse_add_line(self.view_data['reset_history'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['enable_disable_process_stats'])) ret.append(self.curse_add_line(self.view_data['show_hide_help'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['enable_disable_quick_look'])) ret.append(self.curse_add_line(self.view_data['diskio_iops'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['enable_disable_top_extends_stats'])) ret.append(self.curse_add_line(self.view_data['show_hide_top_menu'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['enable_disable_short_processname'])) ret.append(self.curse_add_line(self.view_data['show_hide_irq'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['enable_disable_gpu'])) ret.append(self.curse_add_line(self.view_data['enable_disable_mean_gpu'])) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['enable_disable_irix'])) ret.append(self.curse_add_line(self.view_data['quit'])) ret.append(self.curse_new_line()) ret.append(self.curse_new_line()) ret.append(self.curse_add_line(self.view_data['edit_pattern_filter'])) # Return the message with decoration return ret glances-2.11.1/glances/plugins/glances_ip.py000066400000000000000000000147311315472316100207740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """IP plugin.""" import threading from json import loads from glances.compat import iterkeys, urlopen, queue from glances.globals import BSD from glances.logger import logger from glances.timer import Timer from glances.plugins.glances_plugin import GlancesPlugin # XXX *BSDs: Segmentation fault (core dumped) # -- https://bitbucket.org/al45tair/netifaces/issues/15 # Also used in the ports_list script if not BSD: try: import netifaces netifaces_tag = True except ImportError: netifaces_tag = False else: netifaces_tag = False # List of online services to retreive public IP address # List of tuple (url, json, key) # - url: URL of the Web site # - json: service return a JSON (True) or string (False) # - key: key of the IP addresse in the JSON structure urls = [('http://ip.42.pl/raw', False, None), ('http://httpbin.org/ip', True, 'origin'), ('http://jsonip.com', True, 'ip'), ('https://api.ipify.org/?format=json', True, 'ip')] class Plugin(GlancesPlugin): """Glances IP Plugin. stats is a dict """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Get the public IP address once self.public_address = PublicIpAddress().get() # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update IP stats using the input method. Stats is dict """ # Reset stats self.reset() if self.input_method == 'local' and netifaces_tag: # Update stats using the netifaces lib try: default_gw = netifaces.gateways()['default'][netifaces.AF_INET] except (KeyError, AttributeError) as e: logger.debug("Cannot grab the default gateway ({})".format(e)) else: try: self.stats['address'] = netifaces.ifaddresses(default_gw[1])[netifaces.AF_INET][0]['addr'] self.stats['mask'] = netifaces.ifaddresses(default_gw[1])[netifaces.AF_INET][0]['netmask'] self.stats['mask_cidr'] = self.ip_to_cidr(self.stats['mask']) self.stats['gateway'] = netifaces.gateways()['default'][netifaces.AF_INET][0] # !!! SHOULD be done once, not on each refresh self.stats['public_address'] = self.public_address except (KeyError, AttributeError) as e: logger.debug("Cannot grab IP information: {}".format(e)) elif self.input_method == 'snmp': # Not implemented yet pass return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Optional for key in iterkeys(self.stats): self.views[key]['optional'] = True def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or self.is_disable(): return ret # Build the string message msg = ' - ' ret.append(self.curse_add_line(msg)) msg = 'IP ' ret.append(self.curse_add_line(msg, 'TITLE')) msg = '{}'.format(self.stats['address']) ret.append(self.curse_add_line(msg)) if 'mask_cidr' in self.stats: # VPN with no internet access (issue #842) msg = '/{}'.format(self.stats['mask_cidr']) ret.append(self.curse_add_line(msg)) try: msg_pub = '{}'.format(self.stats['public_address']) except UnicodeEncodeError: pass else: if self.stats['public_address'] is not None: msg = ' Pub ' ret.append(self.curse_add_line(msg, 'TITLE')) ret.append(self.curse_add_line(msg_pub)) return ret @staticmethod def ip_to_cidr(ip): """Convert IP address to CIDR. Example: '255.255.255.0' will return 24 """ return sum([int(x) << 8 for x in ip.split('.')]) // 8128 class PublicIpAddress(object): """Get public IP address from online services""" def __init__(self, timeout=2): self.timeout = timeout def get(self): """Get the first public IP address returned by one of the online services""" q = queue.Queue() for u, j, k in urls: t = threading.Thread(target=self._get_ip_public, args=(q, u, j, k)) t.daemon = True t.start() timer = Timer(self.timeout) ip = None while not timer.finished() and ip is None: if q.qsize() > 0: ip = q.get() return ip def _get_ip_public(self, queue_target, url, json=False, key=None): """Request the url service and put the result in the queue_target""" try: response = urlopen(url, timeout=self.timeout).read().decode('utf-8') except Exception as e: logger.debug("IP plugin - Cannot open URL {} ({})".format(url, e)) queue_target.put(None) else: # Request depend on service try: if not json: queue_target.put(response) else: queue_target.put(loads(response)[key]) except ValueError: queue_target.put(None) glances-2.11.1/glances/plugins/glances_irq.py000066400000000000000000000152411315472316100211540ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Angelo Poerio # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """IRQ plugin.""" import os import operator from glances.globals import LINUX from glances.timer import getTimeSinceLastUpdate from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Glances IRQ plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.irq = GlancesIRQ() self.reset() def get_key(self): """Return the key of the list.""" return self.irq.get_key() def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the IRQ stats""" # Reset the list self.reset() # IRQ plugin only available on GNU/Linux if not LINUX: return self.stats if self.input_method == 'local': # Grab the stats self.stats = self.irq.get() elif self.input_method == 'snmp': # not available pass # Get the TOP 5 self.stats = sorted(self.stats, key=operator.itemgetter( 'irq_rate'), reverse=True)[:5] # top 5 IRQ by rate/s return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() def msg_curse(self, args=None, max_width=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only available on GNU/Linux # Only process if stats exist and display plugin enable... if not LINUX or not self.stats or not self.args.enable_irq: return ret if max_width is not None and max_width >= 23: irq_max_width = max_width - 14 else: irq_max_width = 9 # Build the string message # Header msg = '{:{width}}'.format('IRQ', width=irq_max_width) ret.append(self.curse_add_line(msg, "TITLE")) msg = '{:>14}'.format('Rate/s') ret.append(self.curse_add_line(msg)) for i in self.stats: ret.append(self.curse_new_line()) msg = '{:<15}'.format(i['irq_line'][:15]) ret.append(self.curse_add_line(msg)) msg = '{:>8}'.format(str(i['irq_rate'])) ret.append(self.curse_add_line(msg)) return ret class GlancesIRQ(object): """ This class manages the IRQ file """ IRQ_FILE = '/proc/interrupts' def __init__(self): """ Init the class The stat are stored in a internal list of dict """ self.lasts = {} self.reset() def reset(self): """Reset the stats""" self.stats = [] self.cpu_number = 0 def get(self): """Return the current IRQ stats""" return self.__update() def get_key(self): """Return the key of the dict.""" return 'irq_line' def __header(self, line): """The header contain the number of CPU CPU0 CPU1 CPU2 CPU3 0: 21 0 0 0 IO-APIC 2-edge timer """ self.cpu_number = len(line.split()) return self.cpu_number def __humanname(self, line): """Get a line and Return the IRQ name, alias or number (choose the best for human) IRQ line samples: 1: 44487 341 44 72 IO-APIC 1-edge i8042 LOC: 33549868 22394684 32474570 21855077 Local timer interrupts """ splitted_line = line.split() irq_line = splitted_line[0].replace(':', '') if irq_line.isdigit(): # If the first column is a digit, use the alias (last column) irq_line += '_{}'.format(splitted_line[-1]) return irq_line def __sum(self, line): """Get a line and Return the IRQ sum number IRQ line samples: 1: 44487 341 44 72 IO-APIC 1-edge i8042 LOC: 33549868 22394684 32474570 21855077 Local timer interrupts FIQ: usb_fiq """ splitted_line = line.split() try: ret = sum(map(int, splitted_line[1:(self.cpu_number + 1)])) except ValueError: # Correct issue #1007 on some conf (Raspberry Pi with Raspbian) ret = 0 return ret def __update(self): """ Load the IRQ file and update the internal dict """ self.reset() if not os.path.exists(self.IRQ_FILE): # Correct issue #947: IRQ file do not exist on OpenVZ container return self.stats try: with open(self.IRQ_FILE) as irq_proc: time_since_update = getTimeSinceLastUpdate('irq') # Read the header self.__header(irq_proc.readline()) # Read the rest of the lines (one line per IRQ) for line in irq_proc.readlines(): irq_line = self.__humanname(line) current_irqs = self.__sum(line) irq_rate = int( current_irqs - self.lasts.get(irq_line) if self.lasts.get(irq_line) else 0 // time_since_update) irq_current = { 'irq_line': irq_line, 'irq_rate': irq_rate, 'key': self.get_key(), 'time_since_update': time_since_update } self.stats.append(irq_current) self.lasts[irq_line] = current_irqs except (OSError, IOError): pass return self.stats glances-2.11.1/glances/plugins/glances_load.py000066400000000000000000000134441315472316100213030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Load plugin.""" import os from glances.compat import iteritems from glances.plugins.glances_core import Plugin as CorePlugin from glances.plugins.glances_plugin import GlancesPlugin # SNMP OID # 1 minute Load: .1.3.6.1.4.1.2021.10.1.3.1 # 5 minute Load: .1.3.6.1.4.1.2021.10.1.3.2 # 15 minute Load: .1.3.6.1.4.1.2021.10.1.3.3 snmp_oid = {'min1': '1.3.6.1.4.1.2021.10.1.3.1', 'min5': '1.3.6.1.4.1.2021.10.1.3.2', 'min15': '1.3.6.1.4.1.2021.10.1.3.3'} # Define the history items list # All items in this list will be historised if the --enable-history tag is set # 'color' define the graph color in #RGB format items_history_list = [{'name': 'min1', 'description': '1 minute load', 'color': '#0000FF'}, {'name': 'min5', 'description': '5 minutes load', 'color': '#0000AA'}, {'name': 'min15', 'description': '15 minutes load', 'color': '#000044'}] class Plugin(GlancesPlugin): """Glances load plugin. stats is a dict """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True # Init stats self.reset() # Call CorePlugin in order to display the core number try: self.nb_log_core = CorePlugin(args=self.args).update()["log"] except Exception: self.nb_log_core = 1 def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update load stats.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Get the load using the os standard lib try: load = os.getloadavg() except (OSError, AttributeError): self.stats = {} else: self.stats = {'min1': load[0], 'min5': load[1], 'min15': load[2], 'cpucore': self.nb_log_core} elif self.input_method == 'snmp': # Update stats using SNMP self.stats = self.get_stats_snmp(snmp_oid=snmp_oid) if self.stats['min1'] == '': self.reset() return self.stats # Python 3 return a dict like: # {'min1': "b'0.08'", 'min5': "b'0.12'", 'min15': "b'0.15'"} for k, v in iteritems(self.stats): self.stats[k] = float(v) self.stats['cpucore'] = self.nb_log_core return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations try: # Alert and log self.views['min15']['decoration'] = self.get_alert_log(self.stats['min15'], maximum=100 * self.stats['cpucore']) # Alert only self.views['min5']['decoration'] = self.get_alert(self.stats['min5'], maximum=100 * self.stats['cpucore']) except KeyError: # try/except mandatory for Windows compatibility (no load stats) pass def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist, not empty (issue #871) and plugin not disabled if not self.stats or (self.stats == {}) or self.is_disable(): return ret # Build the string message # Header msg = '{:8}'.format('LOAD') ret.append(self.curse_add_line(msg, "TITLE")) # Core number if 'cpucore' in self.stats and self.stats['cpucore'] > 0: msg = '{}-core'.format(int(self.stats['cpucore'])) ret.append(self.curse_add_line(msg)) # New line ret.append(self.curse_new_line()) # 1min load msg = '{:8}'.format('1 min:') ret.append(self.curse_add_line(msg)) msg = '{:>6.2f}'.format(self.stats['min1']) ret.append(self.curse_add_line(msg)) # New line ret.append(self.curse_new_line()) # 5min load msg = '{:8}'.format('5 min:') ret.append(self.curse_add_line(msg)) msg = '{:>6.2f}'.format(self.stats['min5']) ret.append(self.curse_add_line( msg, self.get_views(key='min5', option='decoration'))) # New line ret.append(self.curse_new_line()) # 15min load msg = '{:8}'.format('15 min:') ret.append(self.curse_add_line(msg)) msg = '{:>6.2f}'.format(self.stats['min15']) ret.append(self.curse_add_line( msg, self.get_views(key='min15', option='decoration'))) return ret glances-2.11.1/glances/plugins/glances_mem.py000066400000000000000000000260311315472316100211360ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Virtual memory plugin.""" from glances.compat import iterkeys from glances.plugins.glances_plugin import GlancesPlugin import psutil # SNMP OID # Total RAM in machine: .1.3.6.1.4.1.2021.4.5.0 # Total RAM used: .1.3.6.1.4.1.2021.4.6.0 # Total RAM Free: .1.3.6.1.4.1.2021.4.11.0 # Total RAM Shared: .1.3.6.1.4.1.2021.4.13.0 # Total RAM Buffered: .1.3.6.1.4.1.2021.4.14.0 # Total Cached Memory: .1.3.6.1.4.1.2021.4.15.0 # Note: For Windows, stats are in the FS table snmp_oid = {'default': {'total': '1.3.6.1.4.1.2021.4.5.0', 'free': '1.3.6.1.4.1.2021.4.11.0', 'shared': '1.3.6.1.4.1.2021.4.13.0', 'buffers': '1.3.6.1.4.1.2021.4.14.0', 'cached': '1.3.6.1.4.1.2021.4.15.0'}, 'windows': {'mnt_point': '1.3.6.1.2.1.25.2.3.1.3', 'alloc_unit': '1.3.6.1.2.1.25.2.3.1.4', 'size': '1.3.6.1.2.1.25.2.3.1.5', 'used': '1.3.6.1.2.1.25.2.3.1.6'}, 'esxi': {'mnt_point': '1.3.6.1.2.1.25.2.3.1.3', 'alloc_unit': '1.3.6.1.2.1.25.2.3.1.4', 'size': '1.3.6.1.2.1.25.2.3.1.5', 'used': '1.3.6.1.2.1.25.2.3.1.6'}} # Define the history items list # All items in this list will be historised if the --enable-history tag is set # 'color' define the graph color in #RGB format items_history_list = [{'name': 'percent', 'description': 'RAM memory usage', 'color': '#00FF00', 'y_unit': '%'}] class Plugin(GlancesPlugin): """Glances' memory plugin. stats is a dict """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update RAM memory stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Grab MEM using the PSUtil virtual_memory method vm_stats = psutil.virtual_memory() # Get all the memory stats (copy/paste of the PsUtil documentation) # total: total physical memory available. # available: the actual amount of available memory that can be given instantly to processes that request more memory in bytes; this is calculated by summing different memory values depending on the platform (e.g. free + buffers + cached on Linux) and it is supposed to be used to monitor actual memory usage in a cross platform fashion. # percent: the percentage usage calculated as (total - available) / total * 100. # used: memory used, calculated differently depending on the platform and designed for informational purposes only. # free: memory not being used at all (zeroed) that is readily available; note that this doesn’t reflect the actual memory available (use ‘available’ instead). # Platform-specific fields: # active: (UNIX): memory currently in use or very recently used, and so it is in RAM. # inactive: (UNIX): memory that is marked as not used. # buffers: (Linux, BSD): cache for things like file system metadata. # cached: (Linux, BSD): cache for various things. # wired: (BSD, macOS): memory that is marked to always stay in RAM. It is never moved to disk. # shared: (BSD): memory that may be simultaneously accessed by multiple processes. self.reset() for mem in ['total', 'available', 'percent', 'used', 'free', 'active', 'inactive', 'buffers', 'cached', 'wired', 'shared']: if hasattr(vm_stats, mem): self.stats[mem] = getattr(vm_stats, mem) # Use the 'free'/htop calculation # free=available+buffer+cached self.stats['free'] = self.stats['available'] if hasattr(self.stats, 'buffers'): self.stats['free'] += self.stats['buffers'] if hasattr(self.stats, 'cached'): self.stats['free'] += self.stats['cached'] # used=total-free self.stats['used'] = self.stats['total'] - self.stats['free'] elif self.input_method == 'snmp': # Update stats using SNMP if self.short_system_name in ('windows', 'esxi'): # Mem stats for Windows|Vmware Esxi are stored in the FS table try: fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name], bulk=True) except KeyError: self.reset() else: for fs in fs_stat: # The Physical Memory (Windows) or Real Memory (VMware) # gives statistics on RAM usage and availability. if fs in ('Physical Memory', 'Real Memory'): self.stats['total'] = int(fs_stat[fs]['size']) * int(fs_stat[fs]['alloc_unit']) self.stats['used'] = int(fs_stat[fs]['used']) * int(fs_stat[fs]['alloc_unit']) self.stats['percent'] = float(self.stats['used'] * 100 / self.stats['total']) self.stats['free'] = self.stats['total'] - self.stats['used'] break else: # Default behavor for others OS self.stats = self.get_stats_snmp(snmp_oid=snmp_oid['default']) if self.stats['total'] == '': self.reset() return self.stats for key in iterkeys(self.stats): if self.stats[key] != '': self.stats[key] = float(self.stats[key]) * 1024 # Use the 'free'/htop calculation self.stats['free'] = self.stats['free'] - self.stats['total'] + (self.stats['buffers'] + self.stats['cached']) # used=total-free self.stats['used'] = self.stats['total'] - self.stats['free'] # percent: the percentage usage calculated as (total - available) / total * 100. self.stats['percent'] = float((self.stats['total'] - self.stats['free']) / self.stats['total'] * 100) return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert and log self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total']) # Optional for key in ['active', 'inactive', 'buffers', 'cached']: if key in self.stats: self.views[key]['optional'] = True def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and plugin not disabled if not self.stats or self.is_disable(): return ret # Build the string message # Header msg = '{}'.format('MEM') ret.append(self.curse_add_line(msg, "TITLE")) msg = ' {:2}'.format(self.trend_msg(self.get_trend('percent'))) ret.append(self.curse_add_line(msg)) # Percent memory usage msg = '{:>7.1%}'.format(self.stats['percent'] / 100) ret.append(self.curse_add_line(msg)) # Active memory usage if 'active' in self.stats: msg = ' {:9}'.format('active:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='active', option='optional'))) msg = '{:>7}'.format(self.auto_unit(self.stats['active'])) ret.append(self.curse_add_line(msg, optional=self.get_views(key='active', option='optional'))) # New line ret.append(self.curse_new_line()) # Total memory usage msg = '{:6}'.format('total:') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format(self.auto_unit(self.stats['total'])) ret.append(self.curse_add_line(msg)) # Inactive memory usage if 'inactive' in self.stats: msg = ' {:9}'.format('inactive:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='inactive', option='optional'))) msg = '{:>7}'.format(self.auto_unit(self.stats['inactive'])) ret.append(self.curse_add_line(msg, optional=self.get_views(key='inactive', option='optional'))) # New line ret.append(self.curse_new_line()) # Used memory usage msg = '{:6}'.format('used:') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format(self.auto_unit(self.stats['used'])) ret.append(self.curse_add_line( msg, self.get_views(key='used', option='decoration'))) # Buffers memory usage if 'buffers' in self.stats: msg = ' {:9}'.format('buffers:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='buffers', option='optional'))) msg = '{:>7}'.format(self.auto_unit(self.stats['buffers'])) ret.append(self.curse_add_line(msg, optional=self.get_views(key='buffers', option='optional'))) # New line ret.append(self.curse_new_line()) # Free memory usage msg = '{:6}'.format('free:') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format(self.auto_unit(self.stats['free'])) ret.append(self.curse_add_line(msg)) # Cached memory usage if 'cached' in self.stats: msg = ' {:9}'.format('cached:') ret.append(self.curse_add_line(msg, optional=self.get_views(key='cached', option='optional'))) msg = '{:>7}'.format(self.auto_unit(self.stats['cached'])) ret.append(self.curse_add_line(msg, optional=self.get_views(key='cached', option='optional'))) return ret glances-2.11.1/glances/plugins/glances_memswap.py000066400000000000000000000163171315472316100220370ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Swap memory plugin.""" from glances.compat import iterkeys from glances.plugins.glances_plugin import GlancesPlugin import psutil # SNMP OID # Total Swap Size: .1.3.6.1.4.1.2021.4.3.0 # Available Swap Space: .1.3.6.1.4.1.2021.4.4.0 snmp_oid = {'default': {'total': '1.3.6.1.4.1.2021.4.3.0', 'free': '1.3.6.1.4.1.2021.4.4.0'}, 'windows': {'mnt_point': '1.3.6.1.2.1.25.2.3.1.3', 'alloc_unit': '1.3.6.1.2.1.25.2.3.1.4', 'size': '1.3.6.1.2.1.25.2.3.1.5', 'used': '1.3.6.1.2.1.25.2.3.1.6'}} # Define the history items list # All items in this list will be historised if the --enable-history tag is set # 'color' define the graph color in #RGB format items_history_list = [{'name': 'percent', 'description': 'Swap memory usage', 'color': '#00FF00', 'y_unit': '%'}] class Plugin(GlancesPlugin): """Glances swap memory plugin. stats is a dict """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update swap memory stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Grab SWAP using the PSUtil swap_memory method sm_stats = psutil.swap_memory() # Get all the swap stats (copy/paste of the PsUtil documentation) # total: total swap memory in bytes # used: used swap memory in bytes # free: free swap memory in bytes # percent: the percentage usage # sin: the number of bytes the system has swapped in from disk (cumulative) # sout: the number of bytes the system has swapped out from disk # (cumulative) for swap in ['total', 'used', 'free', 'percent', 'sin', 'sout']: if hasattr(sm_stats, swap): self.stats[swap] = getattr(sm_stats, swap) elif self.input_method == 'snmp': # Update stats using SNMP if self.short_system_name == 'windows': # Mem stats for Windows OS are stored in the FS table try: fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name], bulk=True) except KeyError: self.reset() else: for fs in fs_stat: # The virtual memory concept is used by the operating # system to extend (virtually) the physical memory and # thus to run more programs by swapping unused memory # zone (page) to a disk file. if fs == 'Virtual Memory': self.stats['total'] = int( fs_stat[fs]['size']) * int(fs_stat[fs]['alloc_unit']) self.stats['used'] = int( fs_stat[fs]['used']) * int(fs_stat[fs]['alloc_unit']) self.stats['percent'] = float( self.stats['used'] * 100 / self.stats['total']) self.stats['free'] = self.stats[ 'total'] - self.stats['used'] break else: self.stats = self.get_stats_snmp(snmp_oid=snmp_oid['default']) if self.stats['total'] == '': self.reset() return self.stats for key in iterkeys(self.stats): if self.stats[key] != '': self.stats[key] = float(self.stats[key]) * 1024 # used=total-free self.stats['used'] = self.stats['total'] - self.stats['free'] # percent: the percentage usage calculated as (total - # available) / total * 100. self.stats['percent'] = float( (self.stats['total'] - self.stats['free']) / self.stats['total'] * 100) return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert and log self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total']) def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and plugin not disabled if not self.stats or self.is_disable(): return ret # Build the string message # Header msg = '{}'.format('SWAP') ret.append(self.curse_add_line(msg, "TITLE")) msg = ' {:3}'.format(self.trend_msg(self.get_trend('percent'))) ret.append(self.curse_add_line(msg)) # Percent memory usage msg = '{:>6.1%}'.format(self.stats['percent'] / 100) ret.append(self.curse_add_line(msg)) # New line ret.append(self.curse_new_line()) # Total memory usage msg = '{:8}'.format('total:') ret.append(self.curse_add_line(msg)) msg = '{:>6}'.format(self.auto_unit(self.stats['total'])) ret.append(self.curse_add_line(msg)) # New line ret.append(self.curse_new_line()) # Used memory usage msg = '{:8}'.format('used:') ret.append(self.curse_add_line(msg)) msg = '{:>6}'.format(self.auto_unit(self.stats['used'])) ret.append(self.curse_add_line( msg, self.get_views(key='used', option='decoration'))) # New line ret.append(self.curse_new_line()) # Free memory usage msg = '{:8}'.format('free:') ret.append(self.curse_add_line(msg)) msg = '{:>6}'.format(self.auto_unit(self.stats['free'])) ret.append(self.curse_add_line(msg)) return ret glances-2.11.1/glances/plugins/glances_network.py000066400000000000000000000345521315472316100220600ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Network plugin.""" import base64 import operator from glances.timer import getTimeSinceLastUpdate from glances.plugins.glances_plugin import GlancesPlugin import psutil # SNMP OID # http://www.net-snmp.org/docs/mibs/interfaces.html # Dict key = interface_name snmp_oid = {'default': {'interface_name': '1.3.6.1.2.1.2.2.1.2', 'cumulative_rx': '1.3.6.1.2.1.2.2.1.10', 'cumulative_tx': '1.3.6.1.2.1.2.2.1.16'}} # Define the history items list # All items in this list will be historised if the --enable-history tag is set # 'color' define the graph color in #RGB format items_history_list = [{'name': 'rx', 'description': 'Download rate per second', 'color': '#00FF00', 'y_unit': 'bit/s'}, {'name': 'tx', 'description': 'Upload rate per second', 'color': '#FF0000', 'y_unit': 'bit/s'}] class Plugin(GlancesPlugin): """Glances network plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args, items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def get_key(self): """Return the key of the list.""" return 'interface_name' def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update network stats using the input method. Stats is a list of dict (one dict per interface) """ # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Grab network interface stat using the PsUtil net_io_counter method try: netiocounters = psutil.net_io_counters(pernic=True) except UnicodeDecodeError: return self.stats # New in PsUtil 3.0 # - import the interface's status (issue #765) # - import the interface's speed (issue #718) netstatus = {} try: netstatus = psutil.net_if_stats() except (AttributeError, OSError): pass # Previous network interface stats are stored in the network_old variable if not hasattr(self, 'network_old'): # First call, we init the network_old var try: self.network_old = netiocounters except (IOError, UnboundLocalError): pass else: # By storing time data we enable Rx/s and Tx/s calculations in the # XML/RPC API, which would otherwise be overly difficult work # for users of the API time_since_update = getTimeSinceLastUpdate('net') # Loop over interfaces network_new = netiocounters for net in network_new: # Do not take hidden interface into account if self.is_hide(net): continue try: cumulative_rx = network_new[net].bytes_recv cumulative_tx = network_new[net].bytes_sent cumulative_cx = cumulative_rx + cumulative_tx rx = cumulative_rx - self.network_old[net].bytes_recv tx = cumulative_tx - self.network_old[net].bytes_sent cx = rx + tx netstat = { 'interface_name': net, 'time_since_update': time_since_update, 'cumulative_rx': cumulative_rx, 'rx': rx, 'cumulative_tx': cumulative_tx, 'tx': tx, 'cumulative_cx': cumulative_cx, 'cx': cx} except KeyError: continue else: # Optional stats (only compliant with PsUtil 3.0+) # Interface status try: netstat['is_up'] = netstatus[net].isup except (KeyError, AttributeError): pass # Interface speed in Mbps, convert it to bps # Can be always 0 on some OS try: netstat['speed'] = netstatus[net].speed * 1048576 except (KeyError, AttributeError): pass # Finaly, set the key netstat['key'] = self.get_key() self.stats.append(netstat) # Save stats to compute next bitrate self.network_old = network_new elif self.input_method == 'snmp': # Update stats using SNMP # SNMP bulk command to get all network interface in one shot try: netiocounters = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name], bulk=True) except KeyError: netiocounters = self.get_stats_snmp(snmp_oid=snmp_oid['default'], bulk=True) # Previous network interface stats are stored in the network_old variable if not hasattr(self, 'network_old'): # First call, we init the network_old var try: self.network_old = netiocounters except (IOError, UnboundLocalError): pass else: # See description in the 'local' block time_since_update = getTimeSinceLastUpdate('net') # Loop over interfaces network_new = netiocounters for net in network_new: # Do not take hidden interface into account if self.is_hide(net): continue try: # Windows: a tips is needed to convert HEX to TXT # http://blogs.technet.com/b/networking/archive/2009/12/18/how-to-query-the-list-of-network-interfaces-using-snmp-via-the-ifdescr-counter.aspx if self.short_system_name == 'windows': try: interface_name = str(base64.b16decode(net[2:-2].upper())) except TypeError: interface_name = net else: interface_name = net cumulative_rx = float(network_new[net]['cumulative_rx']) cumulative_tx = float(network_new[net]['cumulative_tx']) cumulative_cx = cumulative_rx + cumulative_tx rx = cumulative_rx - float(self.network_old[net]['cumulative_rx']) tx = cumulative_tx - float(self.network_old[net]['cumulative_tx']) cx = rx + tx netstat = { 'interface_name': interface_name, 'time_since_update': time_since_update, 'cumulative_rx': cumulative_rx, 'rx': rx, 'cumulative_tx': cumulative_tx, 'tx': tx, 'cumulative_cx': cumulative_cx, 'cx': cx} except KeyError: continue else: netstat['key'] = self.get_key() self.stats.append(netstat) # Save stats to compute next bitrate self.network_old = network_new return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert for i in self.stats: ifrealname = i['interface_name'].split(':')[0] # Convert rate in bps ( to be able to compare to interface speed) bps_rx = int(i['rx'] // i['time_since_update'] * 8) bps_tx = int(i['tx'] // i['time_since_update'] * 8) # Decorate the bitrate with the configuration file thresolds alert_rx = self.get_alert(bps_rx, header=ifrealname + '_rx') alert_tx = self.get_alert(bps_tx, header=ifrealname + '_tx') # If nothing is define in the configuration file... # ... then use the interface speed (not available on all systems) if alert_rx == 'DEFAULT' and 'speed' in i and i['speed'] != 0: alert_rx = self.get_alert(current=bps_rx, maximum=i['speed'], header='rx') if alert_tx == 'DEFAULT' and 'speed' in i and i['speed'] != 0: alert_tx = self.get_alert(current=bps_tx, maximum=i['speed'], header='tx') # then decorates self.views[i[self.get_key()]]['rx']['decoration'] = alert_rx self.views[i[self.get_key()]]['tx']['decoration'] = alert_tx def msg_curse(self, args=None, max_width=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or self.is_disable(): return ret # Max size for the interface name if max_width is not None and max_width >= 23: # Interface size name = max_width - space for interfaces bitrate ifname_max_width = max_width - 14 else: ifname_max_width = 9 # Build the string message # Header msg = '{:{width}}'.format('NETWORK', width=ifname_max_width) ret.append(self.curse_add_line(msg, "TITLE")) if args.network_cumul: # Cumulative stats if args.network_sum: # Sum stats msg = '{:>14}'.format('Rx+Tx') ret.append(self.curse_add_line(msg)) else: # Rx/Tx stats msg = '{:>7}'.format('Rx') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('Tx') ret.append(self.curse_add_line(msg)) else: # Bitrate stats if args.network_sum: # Sum stats msg = '{:>14}'.format('Rx+Tx/s') ret.append(self.curse_add_line(msg)) else: msg = '{:>7}'.format('Rx/s') ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format('Tx/s') ret.append(self.curse_add_line(msg)) # Interface list (sorted by name) for i in sorted(self.stats, key=operator.itemgetter(self.get_key())): # Do not display interface in down state (issue #765) if ('is_up' in i) and (i['is_up'] is False): continue # Format stats # Is there an alias for the interface name ? ifrealname = i['interface_name'].split(':')[0] ifname = self.has_alias(i['interface_name']) if ifname is None: ifname = ifrealname if len(ifname) > ifname_max_width: # Cut interface name if it is too long ifname = '_' + ifname[-ifname_max_width + 1:] if args.byte: # Bytes per second (for dummy) to_bit = 1 unit = '' else: # Bits per second (for real network administrator | Default) to_bit = 8 unit = 'b' if args.network_cumul: rx = self.auto_unit(int(i['cumulative_rx'] * to_bit)) + unit tx = self.auto_unit(int(i['cumulative_tx'] * to_bit)) + unit sx = self.auto_unit(int(i['cumulative_rx'] * to_bit) + int(i['cumulative_tx'] * to_bit)) + unit else: rx = self.auto_unit(int(i['rx'] // i['time_since_update'] * to_bit)) + unit tx = self.auto_unit(int(i['tx'] // i['time_since_update'] * to_bit)) + unit sx = self.auto_unit(int(i['rx'] // i['time_since_update'] * to_bit) + int(i['tx'] // i['time_since_update'] * to_bit)) + unit # New line ret.append(self.curse_new_line()) msg = '{:{width}}'.format(ifname, width=ifname_max_width) ret.append(self.curse_add_line(msg)) if args.network_sum: msg = '{:>14}'.format(sx) ret.append(self.curse_add_line(msg)) else: msg = '{:>7}'.format(rx) ret.append(self.curse_add_line( msg, self.get_views(item=i[self.get_key()], key='rx', option='decoration'))) msg = '{:>7}'.format(tx) ret.append(self.curse_add_line( msg, self.get_views(item=i[self.get_key()], key='tx', option='decoration'))) return ret glances-2.11.1/glances/plugins/glances_now.py000066400000000000000000000035511315472316100211650ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . from datetime import datetime from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Plugin to get the current date/time. stats is (string) """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Set the message position self.align = 'bottom' def reset(self): """Reset/init the stats.""" self.stats = '' def update(self): """Update current date/time.""" # Had to convert it to string because datetime is not JSON serializable self.stats = datetime.now().strftime('%Y-%m-%d %H:%M:%S') return self.stats def msg_curse(self, args=None): """Return the string to display in the curse interface.""" # Init the return message ret = [] # Build the string message # 23 is the padding for the process list msg = '{:23}'.format(self.stats) ret.append(self.curse_add_line(msg)) return ret glances-2.11.1/glances/plugins/glances_percpu.py000066400000000000000000000070071315472316100216600ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Per-CPU plugin.""" from glances.cpu_percent import cpu_percent from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Glances per-CPU plugin. 'stats' is a list of dictionaries that contain the utilization percentages for each CPU. """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init stats self.reset() def get_key(self): """Return the key of the list.""" return 'cpu_number' def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update per-CPU stats using the input method.""" # Reset stats self.reset() # Grab per-CPU stats using psutil's cpu_percent(percpu=True) and # cpu_times_percent(percpu=True) methods if self.input_method == 'local': self.stats = cpu_percent.get(percpu=True) else: # Update stats using SNMP pass return self.stats def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # No per CPU stat ? Exit... if not self.stats: msg = 'PER CPU not available' ret.append(self.curse_add_line(msg, "TITLE")) return ret # Build the string message # Header msg = '{:8}'.format('PER CPU') ret.append(self.curse_add_line(msg, "TITLE")) # Total per-CPU usage for cpu in self.stats: try: msg = '{:6.1f}%'.format(cpu['total']) except TypeError: # TypeError: string indices must be integers (issue #1027) msg = '{:>6}%'.format('?') ret.append(self.curse_add_line(msg)) # Stats per-CPU for stat in ['user', 'system', 'idle', 'iowait', 'steal']: if stat not in self.stats[0]: continue ret.append(self.curse_new_line()) msg = '{:8}'.format(stat + ':') ret.append(self.curse_add_line(msg)) for cpu in self.stats: try: msg = '{:6.1f}%'.format(cpu[stat]) except TypeError: # TypeError: string indices must be integers (issue #1027) msg = '{:>6}%'.format('?') ret.append(self.curse_add_line(msg, self.get_alert(cpu[stat], header=stat))) # Return the message with decoration return ret glances-2.11.1/glances/plugins/glances_plugin.py000066400000000000000000001010101315472316100216450ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ I am your father... ...for all Glances plugins. """ import re import json from operator import itemgetter from glances.compat import iterkeys, itervalues, listkeys, map, mean from glances.actions import GlancesActions from glances.history import GlancesHistory from glances.logger import logger from glances.logs import glances_logs from glances.thresholds import glances_thresholds class GlancesPlugin(object): """Main class for Glances plugin.""" def __init__(self, args=None, items_history_list=None): """Init the plugin of plugins class. All Glances' plugins should inherit from this class. Most of the methods are already implemented in the father classes. Your plugin should return a dict or a list of dicts (stored in the self.stats). As an example, you can have a look on the mem plugin (for dict) or network (for list of dicts). A plugin should implement: - the __init__ constructor: define the self.display_curse - the reset method: to set your self.stats variable to {} or [] - the update method: where your self.stats variable is set and optionnaly: - the get_key method: set the key of the dict (only for list of dict) - the update_view method: only if you need to trick your output - the msg_curse: define the curse (UI) message (if display_curse is True) :args: args parameters :items_history_list: list of items to store in the history """ # Plugin name (= module name without glances_) self.plugin_name = self.__class__.__module__[len('glances_'):] # logger.debug("Init plugin %s" % self.plugin_name) # Init the args self.args = args # Init the default alignement (for curses) self._align = 'left' # Init the input method self._input_method = 'local' self._short_system_name = None # Init the history list self.items_history_list = items_history_list self.stats_history = self.init_stats_history() # Init the limits dictionnary self._limits = dict() # Init the actions self.actions = GlancesActions(args=args) # Init the views self.views = dict() # Init the stats (dict of list or dict) self.stats = None self.reset() def __repr__(self): """Return the raw stats.""" return self.stats def __str__(self): """Return the human-readable stats.""" return str(self.stats) def reset(self): """Reset the stats. This method should be overwrited by childs' classes""" self.stats = None def exit(self): """Method to be called when Glances exit""" logger.debug("Stop the {} plugin".format(self.plugin_name)) def get_key(self): """Return the key of the list.""" return None def is_enable(self): """Return true if plugin is enabled""" try: d = getattr(self.args, 'disable_' + self.plugin_name) except AttributeError: return True else: return d is False def is_disable(self): """Return true if plugin is disabled""" return not self.is_enable() def _json_dumps(self, d): """Return the object 'd' in a JSON format Manage the issue #815 for Windows OS""" try: return json.dumps(d) except UnicodeDecodeError: return json.dumps(d, ensure_ascii=False) def _history_enable(self): return self.args is not None and not self.args.disable_history and self.get_items_history_list() is not None def init_stats_history(self): """Init the stats history (dict of GlancesAttribute).""" if self._history_enable(): init_list = [a['name'] for a in self.get_items_history_list()] logger.debug("Stats history activated for plugin {} (items: {})".format(self.plugin_name, init_list)) return GlancesHistory() def reset_stats_history(self): """Reset the stats history (dict of GlancesAttribute).""" if self._history_enable(): reset_list = [a['name'] for a in self.get_items_history_list()] logger.debug("Reset history for plugin {} (items: {})".format(self.plugin_name, reset_list)) self.stats_history.reset() def update_stats_history(self): """Update stats history.""" # If the plugin data is a dict, the dict's key should be used if self.get_key() is None: item_name = '' else: item_name = self.get_key() # Build the history if self.stats and self._history_enable(): for i in self.get_items_history_list(): if isinstance(self.stats, list): # Stats is a list of data # Iter throught it (for exemple, iter throught network # interface) for l in self.stats: self.stats_history.add( l[item_name] + '_' + i['name'], l[i['name']], description=i['description'], history_max_size=self._limits['history_size']) else: # Stats is not a list # Add the item to the history directly self.stats_history.add(i['name'], self.stats[i['name']], description=i['description'], history_max_size=self._limits['history_size']) def get_items_history_list(self): """Return the items history list.""" return self.items_history_list def get_raw_history(self, item=None, nb=0): """Return - the stats history (dict of list) if item is None - the stats history for the given item (list) instead - None if item did not exist in the history Limit to lasts nb items (all if nb=0)""" s = self.stats_history.get(nb=nb) if item is None: return s else: if item in s: return s[item] else: return None def get_json_history(self, item=None, nb=0): """Return: - the stats history (dict of list) if item is None - the stats history for the given item (list) instead - None if item did not exist in the history Limit to lasts nb items (all if nb=0)""" s = self.stats_history.get_json(nb=nb) if item is None: return s else: if item in s: return s[item] else: return None def get_export_history(self, item=None): """Return the stats history object to export. See get_raw_history for a full description""" return self.get_raw_history(item=item) def get_stats_history(self, item=None, nb=0): """Return the stats history as a JSON object (dict or None). Limit to lasts nb items (all if nb=0)""" s = self.get_json_history(nb=nb) if item is None: return self._json_dumps(s) if isinstance(s, dict): try: return self._json_dumps({item: s[item]}) except KeyError as e: logger.error("Cannot get item history {} ({})".format(item, e)) return None elif isinstance(s, list): try: # Source: # http://stackoverflow.com/questions/4573875/python-get-index-of-dictionary-item-in-list return self._json_dumps({item: map(itemgetter(item), s)}) except (KeyError, ValueError) as e: logger.error("Cannot get item history {} ({})".format(item, e)) return None else: return None def get_trend(self, item, nb=6): """Get the trend regarding to the last nb values The trend is the diff between the mean of the last nb values and the current one. """ raw_history = self.get_raw_history(item=item, nb=nb) if raw_history is None or len(raw_history) < nb: return None last_nb = [v[1] for v in raw_history] return last_nb[-1] - mean(last_nb[:-1]) @property def input_method(self): """Get the input method.""" return self._input_method @input_method.setter def input_method(self, input_method): """Set the input method. * local: system local grab (psutil or direct access) * snmp: Client server mode via SNMP * glances: Client server mode via Glances API """ self._input_method = input_method @property def short_system_name(self): """Get the short detected OS name (SNMP).""" return self._short_system_name @short_system_name.setter def short_system_name(self, short_name): """Set the short detected OS name (SNMP).""" self._short_system_name = short_name def set_stats(self, input_stats): """Set the stats to input_stats.""" self.stats = input_stats def get_stats_snmp(self, bulk=False, snmp_oid=None): """Update stats using SNMP. If bulk=True, use a bulk request instead of a get request. """ snmp_oid = snmp_oid or {} from glances.snmp import GlancesSNMPClient # Init the SNMP request clientsnmp = GlancesSNMPClient(host=self.args.client, port=self.args.snmp_port, version=self.args.snmp_version, community=self.args.snmp_community) # Process the SNMP request ret = {} if bulk: # Bulk request snmpresult = clientsnmp.getbulk_by_oid(0, 10, itervalues(*snmp_oid)) if len(snmp_oid) == 1: # Bulk command for only one OID # Note: key is the item indexed but the OID result for item in snmpresult: if iterkeys(item)[0].startswith(itervalues(snmp_oid)[0]): ret[iterkeys(snmp_oid)[0] + iterkeys(item) [0].split(itervalues(snmp_oid)[0])[1]] = itervalues(item)[0] else: # Build the internal dict with the SNMP result # Note: key is the first item in the snmp_oid index = 1 for item in snmpresult: item_stats = {} item_key = None for key in iterkeys(snmp_oid): oid = snmp_oid[key] + '.' + str(index) if oid in item: if item_key is None: item_key = item[oid] else: item_stats[key] = item[oid] if item_stats: ret[item_key] = item_stats index += 1 else: # Simple get request snmpresult = clientsnmp.get_by_oid(itervalues(*snmp_oid)) # Build the internal dict with the SNMP result for key in iterkeys(snmp_oid): ret[key] = snmpresult[snmp_oid[key]] return ret def get_raw(self): """Return the stats object.""" return self.stats def get_export(self): """Return the stats object to export.""" return self.get_raw() def get_stats(self): """Return the stats object in JSON format.""" return self._json_dumps(self.stats) def get_stats_item(self, item): """Return the stats object for a specific item in JSON format. Stats should be a list of dict (processlist, network...) """ if isinstance(self.stats, dict): try: return self._json_dumps({item: self.stats[item]}) except KeyError as e: logger.error("Cannot get item {} ({})".format(item, e)) return None elif isinstance(self.stats, list): try: # Source: # http://stackoverflow.com/questions/4573875/python-get-index-of-dictionary-item-in-list return self._json_dumps({item: map(itemgetter(item), self.stats)}) except (KeyError, ValueError) as e: logger.error("Cannot get item {} ({})".format(item, e)) return None else: return None def get_stats_value(self, item, value): """Return the stats object for a specific item=value in JSON format. Stats should be a list of dict (processlist, network...) """ if not isinstance(self.stats, list): return None else: if value.isdigit(): value = int(value) try: return self._json_dumps({value: [i for i in self.stats if i[item] == value]}) except (KeyError, ValueError) as e: logger.error( "Cannot get item({})=value({}) ({})".format(item, value, e)) return None def update_views(self): """Default builder fo the stats views. The V of MVC A dict of dict with the needed information to display the stats. Example for the stat xxx: 'xxx': {'decoration': 'DEFAULT', 'optional': False, 'additional': False, 'splittable': False} """ ret = {} if (isinstance(self.get_raw(), list) and self.get_raw() is not None and self.get_key() is not None): # Stats are stored in a list of dict (ex: NETWORK, FS...) for i in self.get_raw(): ret[i[self.get_key()]] = {} for key in listkeys(i): value = {'decoration': 'DEFAULT', 'optional': False, 'additional': False, 'splittable': False} ret[i[self.get_key()]][key] = value elif isinstance(self.get_raw(), dict) and self.get_raw() is not None: # Stats are stored in a dict (ex: CPU, LOAD...) for key in listkeys(self.get_raw()): value = {'decoration': 'DEFAULT', 'optional': False, 'additional': False, 'splittable': False} ret[key] = value self.views = ret return self.views def set_views(self, input_views): """Set the views to input_views.""" self.views = input_views def get_views(self, item=None, key=None, option=None): """Return the views object. If key is None, return all the view for the current plugin else if option is None return the view for the specific key (all option) else return the view fo the specific key/option Specify item if the stats are stored in a dict of dict (ex: NETWORK, FS...) """ if item is None: item_views = self.views else: item_views = self.views[item] if key is None: return item_views else: if option is None: return item_views[key] else: if option in item_views[key]: return item_views[key][option] else: return 'DEFAULT' def get_json_views(self, item=None, key=None, option=None): """Return views in JSON""" return self._json_dumps(self.get_views(item, key, option)) def load_limits(self, config): """Load limits from the configuration file, if it exists.""" # By default set the history length to 3 points per second during one day self._limits['history_size'] = 28800 if not hasattr(config, 'has_section'): return False # Read the global section if config.has_section('global'): self._limits['history_size'] = config.get_float_value('global', 'history_size', default=28800) logger.debug("Load configuration key: {} = {}".format('history_size', self._limits['history_size'])) # Read the plugin specific section if config.has_section(self.plugin_name): for level, _ in config.items(self.plugin_name): # Read limits limit = '_'.join([self.plugin_name, level]) try: self._limits[limit] = config.get_float_value(self.plugin_name, level) except ValueError: self._limits[limit] = config.get_value(self.plugin_name, level).split(",") logger.debug("Load limit: {} = {}".format(limit, self._limits[limit])) return True @property def limits(self): """Return the limits object.""" return self._limits @limits.setter def limits(self, input_limits): """Set the limits to input_limits.""" self._limits = input_limits def get_stats_action(self): """Return stats for the action By default return all the stats. Can be overwrite by plugins implementation. For example, Docker will return self.stats['containers']""" return self.stats def get_alert(self, current=0, minimum=0, maximum=100, highlight_zero=True, is_max=False, header="", action_key=None, log=False): """Return the alert status relative to a current value. Use this function for minor stats. If current < CAREFUL of max then alert = OK If current > CAREFUL of max then alert = CAREFUL If current > WARNING of max then alert = WARNING If current > CRITICAL of max then alert = CRITICAL If highlight=True than 0.0 is highlighted If defined 'header' is added between the plugin name and the status. Only useful for stats with several alert status. If defined, 'action_key' define the key for the actions. By default, the action_key is equal to the header. If log=True than add log if necessary elif log=False than do not log elif log=None than apply the config given in the conf file """ # Manage 0 (0.0) value if highlight_zero is not True if not highlight_zero and current == 0: return 'DEFAULT' # Compute the % try: value = (current * 100) / maximum except ZeroDivisionError: return 'DEFAULT' except TypeError: return 'DEFAULT' # Build the stat_name = plugin_name + header if header == "": stat_name = self.plugin_name else: stat_name = self.plugin_name + '_' + header # Manage limits # If is_max is set then display the value in MAX ret = 'MAX' if is_max else 'OK' try: if value >= self.get_limit('critical', stat_name=stat_name): ret = 'CRITICAL' elif value >= self.get_limit('warning', stat_name=stat_name): ret = 'WARNING' elif value >= self.get_limit('careful', stat_name=stat_name): ret = 'CAREFUL' elif current < minimum: ret = 'CAREFUL' except KeyError: return 'DEFAULT' # Manage log log_str = "" if self.get_limit_log(stat_name=stat_name, default_action=log): # Add _LOG to the return string # So stats will be highlited with a specific color log_str = "_LOG" # Add the log to the list glances_logs.add(ret, stat_name.upper(), value) # Manage threshold self.manage_threshold(stat_name, ret) # Manage action self.manage_action(stat_name, ret.lower(), header, action_key) # Default is 'OK' return ret + log_str def manage_threshold(self, stat_name, trigger): """Manage the threshold for the current stat""" glances_thresholds.add(stat_name, trigger) # logger.info(glances_thresholds.get()) def manage_action(self, stat_name, trigger, header, action_key): """Manage the action for the current stat""" # Here is a command line for the current trigger ? try: command, repeat = self.get_limit_action(trigger, stat_name=stat_name) except KeyError: # Reset the trigger self.actions.set(stat_name, trigger) else: # Define the action key for the stats dict # If not define, then it sets to header if action_key is None: action_key = header # A command line is available for the current alert # 1) Build the {{mustache}} dictionnary if isinstance(self.get_stats_action(), list): # If the stats are stored in a list of dict (fs plugin for exemple) # Return the dict for the current header mustache_dict = {} for item in self.get_stats_action(): if item[self.get_key()] == action_key: mustache_dict = item break else: # Use the stats dict mustache_dict = self.get_stats_action() # 2) Run the action self.actions.run( stat_name, trigger, command, repeat, mustache_dict=mustache_dict) def get_alert_log(self, current=0, minimum=0, maximum=100, header="", action_key=None): """Get the alert log.""" return self.get_alert(current=current, minimum=minimum, maximum=maximum, header=header, action_key=action_key, log=True) def get_limit(self, criticity, stat_name=""): """Return the limit value for the alert.""" # Get the limit for stat + header # Exemple: network_wlan0_rx_careful try: limit = self._limits[stat_name + '_' + criticity] except KeyError: # Try fallback to plugin default limit # Exemple: network_careful limit = self._limits[self.plugin_name + '_' + criticity] # logger.debug("{} {} value is {}".format(stat_name, criticity, limit)) # Return the limit return limit def get_limit_action(self, criticity, stat_name=""): """Return the tuple (action, repeat) for the alert. - action is a command line - repeat is a bool""" # Get the action for stat + header # Exemple: network_wlan0_rx_careful_action # Action key available ? ret = [(stat_name + '_' + criticity + '_action', False), (stat_name + '_' + criticity + '_action_repeat', True), (self.plugin_name + '_' + criticity + '_action', False), (self.plugin_name + '_' + criticity + '_action_repeat', True)] for r in ret: if r[0] in self._limits: return self._limits[r[0]], r[1] # No key found, the raise an error raise KeyError def get_limit_log(self, stat_name, default_action=False): """Return the log tag for the alert.""" # Get the log tag for stat + header # Exemple: network_wlan0_rx_log try: log_tag = self._limits[stat_name + '_log'] except KeyError: # Try fallback to plugin default log # Exemple: network_log try: log_tag = self._limits[self.plugin_name + '_log'] except KeyError: # By defaukt, log are disabled return default_action # Return the action list return log_tag[0].lower() == 'true' def get_conf_value(self, value, header="", plugin_name=None): """Return the configuration (header_) value for the current plugin. ...or the one given by the plugin_name var. """ if plugin_name is None: # If not default use the current plugin name plugin_name = self.plugin_name if header != "": # Add the header plugin_name = plugin_name + '_' + header try: return self._limits[plugin_name + '_' + value] except KeyError: return [] def is_hide(self, value, header=""): """ Return True if the value is in the hide configuration list. The hide configuration list is defined in the glances.conf file. It is a comma separed list of regexp. Example for diskio: hide=sda2,sda5,loop.* """ # TODO: possible optimisation: create a re.compile list return not all(j is None for j in [re.match(i, value.lower()) for i in self.get_conf_value('hide', header=header)]) def has_alias(self, header): """Return the alias name for the relative header or None if nonexist.""" try: # Force to lower case (issue #1126) return self._limits[self.plugin_name + '_' + header.lower() + '_' + 'alias'][0] except (KeyError, IndexError): # logger.debug("No alias found for {}".format(header)) return None def msg_curse(self, args=None, max_width=None): """Return default string to display in the curse interface.""" return [self.curse_add_line(str(self.stats))] def get_stats_display(self, args=None, max_width=None): """Return a dict with all the information needed to display the stat. key | description ---------------------------- display | Display the stat (True or False) msgdict | Message to display (list of dict [{ 'msg': msg, 'decoration': decoration } ... ]) align | Message position """ display_curse = False if hasattr(self, 'display_curse'): display_curse = self.display_curse if hasattr(self, 'align'): align_curse = self._align if max_width is not None: ret = {'display': display_curse, 'msgdict': self.msg_curse(args, max_width=max_width), 'align': align_curse} else: ret = {'display': display_curse, 'msgdict': self.msg_curse(args), 'align': align_curse} return ret def curse_add_line(self, msg, decoration="DEFAULT", optional=False, additional=False, splittable=False): """Return a dict with. Where: msg: string decoration: DEFAULT: no decoration UNDERLINE: underline BOLD: bold TITLE: for stat title PROCESS: for process name STATUS: for process status NICE: for process niceness CPU_TIME: for process cpu time OK: Value is OK and non logged OK_LOG: Value is OK and logged CAREFUL: Value is CAREFUL and non logged CAREFUL_LOG: Value is CAREFUL and logged WARNING: Value is WARINING and non logged WARNING_LOG: Value is WARINING and logged CRITICAL: Value is CRITICAL and non logged CRITICAL_LOG: Value is CRITICAL and logged optional: True if the stat is optional (display only if space is available) additional: True if the stat is additional (display only if space is available after optional) spittable: Line can be splitted to fit on the screen (default is not) """ return {'msg': msg, 'decoration': decoration, 'optional': optional, 'additional': additional, 'splittable': splittable} def curse_new_line(self): """Go to a new line.""" return self.curse_add_line('\n') @property def align(self): """Get the curse align.""" return self._align @align.setter def align(self, value): """Set the curse align. value: left, right, bottom. """ self._align = value def auto_unit(self, number, low_precision=False, min_symbol='K' ): """Make a nice human-readable string out of number. Number of decimal places increases as quantity approaches 1. examples: CASE: 613421788 RESULT: 585M low_precision: 585M CASE: 5307033647 RESULT: 4.94G low_precision: 4.9G CASE: 44968414685 RESULT: 41.9G low_precision: 41.9G CASE: 838471403472 RESULT: 781G low_precision: 781G CASE: 9683209690677 RESULT: 8.81T low_precision: 8.8T CASE: 1073741824 RESULT: 1024M low_precision: 1024M CASE: 1181116006 RESULT: 1.10G low_precision: 1.1G :low_precision: returns less decimal places potentially (default is False) sacrificing precision for more readability. :min_symbol: Do not approache if number < min_symbol (default is K) """ symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') if min_symbol in symbols: symbols = symbols[symbols.index(min_symbol):] prefix = { 'Y': 1208925819614629174706176, 'Z': 1180591620717411303424, 'E': 1152921504606846976, 'P': 1125899906842624, 'T': 1099511627776, 'G': 1073741824, 'M': 1048576, 'K': 1024 } for symbol in reversed(symbols): value = float(number) / prefix[symbol] if value > 1: decimal_precision = 0 if value < 10: decimal_precision = 2 elif value < 100: decimal_precision = 1 if low_precision: if symbol in 'MK': decimal_precision = 0 else: decimal_precision = min(1, decimal_precision) elif symbol in 'K': decimal_precision = 0 return '{:.{decimal}f}{symbol}'.format( value, decimal=decimal_precision, symbol=symbol) return '{!s}'.format(number) def trend_msg(self, trend, significant=1): """Return the trend message Do not take into account if trend < significant""" ret = '-' if trend is None: ret = ' ' elif trend > significant: ret = '/' elif trend < -significant: ret = '\\' return ret def _check_decorator(fct): """Check if the plugin is enabled.""" def wrapper(self, *args, **kw): if self.is_enable(): ret = fct(self, *args, **kw) else: ret = self.stats return ret return wrapper def _log_result_decorator(fct): """Log (DEBUG) the result of the function fct.""" def wrapper(*args, **kw): ret = fct(*args, **kw) logger.debug("%s %s %s return %s" % ( args[0].__class__.__name__, args[0].__class__.__module__[len('glances_'):], fct.__name__, ret)) return ret return wrapper # Mandatory to call the decorator in childs' classes _check_decorator = staticmethod(_check_decorator) _log_result_decorator = staticmethod(_log_result_decorator) glances-2.11.1/glances/plugins/glances_ports.py000066400000000000000000000255661315472316100215430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Ports scanner plugin.""" import os import subprocess import threading import socket import time import numbers try: import requests requests_tag = True except ImportError: requests_tag = False from glances.globals import WINDOWS, MACOS, BSD from glances.ports_list import GlancesPortsList from glances.web_list import GlancesWebList from glances.timer import Timer, Counter from glances.compat import bool_type from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Glances ports scanner plugin.""" def __init__(self, args=None, config=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) self.args = args self.config = config # We want to display the stat in the curse interface self.display_curse = True # Init stats self.stats = GlancesPortsList(config=config, args=args).get_ports_list() + GlancesWebList(config=config, args=args).get_web_list() # Init global Timer self.timer_ports = Timer(0) # Global Thread running all the scans self._thread = None def exit(self): """Overwrite the exit method to close threads""" if self._thread is not None: self._thread.stop() # Call the father class super(Plugin, self).exit() def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._log_result_decorator def update(self): """Update the ports list.""" if self.input_method == 'local': # Only refresh: # * if there is not other scanning thread # * every refresh seconds (define in the configuration file) if self._thread is None: thread_is_running = False else: thread_is_running = self._thread.isAlive() if self.timer_ports.finished() and not thread_is_running: # Run ports scanner self._thread = ThreadScanner(self.stats) self._thread.start() # Restart timer if len(self.stats) > 0: self.timer_ports = Timer(self.stats[0]['refresh']) else: self.timer_ports = Timer(0) else: # Not available in SNMP mode pass return self.stats def get_ports_alert(self, port, header="", log=False): """Return the alert status relative to the port scan return value.""" if port['status'] is None: return 'CAREFUL' elif port['status'] == 0: return 'CRITICAL' elif (isinstance(port['status'], (float, int)) and port['rtt_warning'] is not None and port['status'] > port['rtt_warning']): return 'WARNING' return 'OK' def get_web_alert(self, web, header="", log=False): """Return the alert status relative to the web/url scan return value.""" if web['status'] is None: return 'CAREFUL' elif web['status'] not in [200, 301, 302]: return 'CRITICAL' elif web['rtt_warning'] is not None and web['elapsed'] > web['rtt_warning']: return 'WARNING' return 'OK' def msg_curse(self, args=None, max_width=None): """Return the dict to display in the curse interface.""" # Init the return message # Only process if stats exist and display plugin enable... ret = [] if not self.stats or args.disable_ports: return ret # Build the string message for p in self.stats: if 'host' in p: if p['host'] is None: status = 'None' elif p['status'] is None: status = 'Scanning' elif isinstance(p['status'], bool_type) and p['status'] is True: status = 'Open' elif p['status'] == 0: status = 'Timeout' else: # Convert second to ms status = '{0:.0f}ms'.format(p['status'] * 1000.0) msg = '{:14.14} '.format(p['description']) ret.append(self.curse_add_line(msg)) msg = '{:>8}'.format(status) ret.append(self.curse_add_line(msg, self.get_ports_alert(p))) ret.append(self.curse_new_line()) elif 'url' in p: msg = '{:14.14} '.format(p['description']) ret.append(self.curse_add_line(msg)) if isinstance(p['status'], numbers.Number): status = 'Code {}'.format(p['status']) elif p['status'] is None: status = 'Scanning' else: status = p['status'] msg = '{:>8}'.format(status) ret.append(self.curse_add_line(msg, self.get_web_alert(p))) ret.append(self.curse_new_line()) # Delete the last empty line try: ret.pop() except IndexError: pass return ret class ThreadScanner(threading.Thread): """ Specific thread for the port/web scanner. stats is a list of dict """ def __init__(self, stats): """Init the class""" logger.debug("ports plugin - Create thread for scan list {}".format(stats)) super(ThreadScanner, self).__init__() # Event needed to stop properly the thread self._stopper = threading.Event() # The class return the stats as a list of dict self._stats = stats # Is part of Ports plugin self.plugin_name = "ports" def run(self): """Function called to grab stats. Infinite loop, should be stopped by calling the stop() method""" for p in self._stats: # End of the thread has been asked if self.stopped(): break # Scan a port (ICMP or TCP) if 'port' in p: self._port_scan(p) # Had to wait between two scans # If not, result are not ok time.sleep(1) # Scan an URL elif 'url' in p and requests_tag: self._web_scan(p) @property def stats(self): """Stats getter""" return self._stats @stats.setter def stats(self, value): """Stats setter""" self._stats = value def stop(self, timeout=None): """Stop the thread""" logger.debug("ports plugin - Close thread for scan list {}".format(self._stats)) self._stopper.set() def stopped(self): """Return True is the thread is stopped""" return self._stopper.isSet() def _web_scan(self, web): """Scan the Web/URL (dict) and update the status key""" try: req = requests.head(web['url'], allow_redirects=True, timeout=web['timeout']) except Exception as e: logger.debug(e) web['status'] = 'Error' web['elapsed'] = 0 else: web['status'] = req.status_code web['elapsed'] = req.elapsed.total_seconds() return web def _port_scan(self, port): """Scan the port structure (dict) and update the status key""" if int(port['port']) == 0: return self._port_scan_icmp(port) else: return self._port_scan_tcp(port) def _resolv_name(self, hostname): """Convert hostname to IP address""" ip = hostname try: ip = socket.gethostbyname(hostname) except Exception as e: logger.debug("{}: Cannot convert {} to IP address ({})".format(self.plugin_name, hostname, e)) return ip def _port_scan_icmp(self, port): """Scan the (ICMP) port structure (dict) and update the status key""" ret = None # Create the ping command # Use the system ping command because it already have the steacky bit set # Python can not create ICMP packet with non root right if WINDOWS: timeout_opt = '-w' count_opt = '-n' elif MACOS or BSD: timeout_opt = '-t' count_opt = '-c' else: # Linux and co... timeout_opt = '-W' count_opt = '-c' # Build the command line # Note: Only string are allowed cmd = ['ping', count_opt, '1', timeout_opt, str(self._resolv_name(port['timeout'])), self._resolv_name(port['host'])] fnull = open(os.devnull, 'w') try: counter = Counter() ret = subprocess.check_call(cmd, stdout=fnull, stderr=fnull, close_fds=True) if ret == 0: port['status'] = counter.get() else: port['status'] = False except subprocess.CalledProcessError as e: # Correct issue #1084: No Offline status for timeouted ports port['status'] = False except Exception as e: logger.debug("{}: Error while pinging host {} ({})".format(self.plugin_name, port['host'], e)) return ret def _port_scan_tcp(self, port): """Scan the (TCP) port structure (dict) and update the status key""" ret = None # Create and configure the scanning socket try: socket.setdefaulttimeout(port['timeout']) _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except Exception as e: logger.debug("{}: Error while creating scanning socket".format(self.plugin_name)) # Scan port ip = self._resolv_name(port['host']) counter = Counter() try: ret = _socket.connect_ex((ip, int(port['port']))) except Exception as e: logger.debug("{}: Error while scanning port {} ({})".format(self.plugin_name, port, e)) else: if ret == 0: port['status'] = counter.get() else: port['status'] = False finally: _socket.close() return ret glances-2.11.1/glances/plugins/glances_processcount.py000066400000000000000000000111411315472316100231030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Process count plugin.""" from glances.processes import glances_processes from glances.plugins.glances_plugin import GlancesPlugin # Note: history items list is not compliant with process count # if a filter is applyed, the graph will show the filtered processes count class Plugin(GlancesPlugin): """Glances process count plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Note: 'glances_processes' is already init in the glances_processes.py script def reset(self): """Reset/init the stats.""" self.stats = {} def update(self): """Update processes stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Here, update is call for processcount AND processlist glances_processes.update() # Return the processes count self.stats = glances_processes.getcount() elif self.input_method == 'snmp': # Update stats using SNMP # !!! TODO pass return self.stats def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if args.disable_process: msg = "PROCESSES DISABLED (press 'z' to display)" ret.append(self.curse_add_line(msg)) return ret if not self.stats: return ret # Display the filter (if it exists) if glances_processes.process_filter is not None: msg = 'Processes filter:' ret.append(self.curse_add_line(msg, "TITLE")) msg = ' {} '.format(glances_processes.process_filter) if glances_processes.process_filter_key is not None: msg += 'on column {} '.format(glances_processes.process_filter_key) ret.append(self.curse_add_line(msg, "FILTER")) msg = '(\'ENTER\' to edit, \'E\' to reset)' ret.append(self.curse_add_line(msg)) ret.append(self.curse_new_line()) # Build the string message # Header msg = 'TASKS' ret.append(self.curse_add_line(msg, "TITLE")) # Compute processes other = self.stats['total'] msg = '{:>4}'.format(self.stats['total']) ret.append(self.curse_add_line(msg)) if 'thread' in self.stats: msg = ' ({} thr),'.format(self.stats['thread']) ret.append(self.curse_add_line(msg)) if 'running' in self.stats: other -= self.stats['running'] msg = ' {} run,'.format(self.stats['running']) ret.append(self.curse_add_line(msg)) if 'sleeping' in self.stats: other -= self.stats['sleeping'] msg = ' {} slp,'.format(self.stats['sleeping']) ret.append(self.curse_add_line(msg)) msg = ' {} oth '.format(other) ret.append(self.curse_add_line(msg)) # Display sort information if glances_processes.auto_sort: msg = 'sorted automatically' ret.append(self.curse_add_line(msg)) msg = ' by {}'.format(glances_processes.sort_key) ret.append(self.curse_add_line(msg)) else: msg = 'sorted by {}'.format(glances_processes.sort_key) ret.append(self.curse_add_line(msg)) ret[-1]["msg"] += ", %s view" % ("tree" if glances_processes.is_tree_enabled() else "flat") # if args.disable_irix: # ret[-1]["msg"] += " - IRIX off" # Return the message with decoration return ret glances-2.11.1/glances/plugins/glances_processlist.py000066400000000000000000000671361315472316100227450ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Process list plugin.""" import os from datetime import timedelta from glances.compat import iteritems from glances.globals import LINUX, WINDOWS from glances.logger import logger from glances.processes import glances_processes, sort_stats from glances.plugins.glances_core import Plugin as CorePlugin from glances.plugins.glances_plugin import GlancesPlugin def convert_timedelta(delta): """Convert timedelta to human-readable time.""" days, total_seconds = delta.days, delta.seconds hours = days * 24 + total_seconds // 3600 minutes = (total_seconds % 3600) // 60 seconds = str(total_seconds % 60).zfill(2) microseconds = str(delta.microseconds)[:2].zfill(2) return hours, minutes, seconds, microseconds def split_cmdline(cmdline): """Return path, cmd and arguments for a process cmdline.""" path, cmd = os.path.split(cmdline[0]) arguments = ' '.join(cmdline[1:]).replace('\n', ' ') # XXX: workaround for psutil issue #742 if LINUX and any(x in cmdline[0] for x in ('chrome', 'chromium')): try: exe, arguments = cmdline[0].split(' ', 1) path, cmd = os.path.split(exe) except ValueError: arguments = None return path, cmd, arguments class Plugin(GlancesPlugin): """Glances' processes plugin. stats is a list """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Trying to display proc time self.tag_proc_time = True # Call CorePlugin to get the core number (needed when not in IRIX mode / Solaris mode) try: self.nb_log_core = CorePlugin(args=self.args).update()["log"] except Exception: self.nb_log_core = 0 # Get the max values (dict) self.max_values = glances_processes.max_values() # Get the maximum PID number # Use to optimize space (see https://github.com/nicolargo/glances/issues/959) self.pid_max = glances_processes.pid_max # Note: 'glances_processes' is already init in the processes.py script def get_key(self): """Return the key of the list.""" return 'pid' def reset(self): """Reset/init the stats.""" self.stats = [] def update(self): """Update processes stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib # Note: Update is done in the processcount plugin # Just return the processes list if glances_processes.is_tree_enabled(): self.stats = glances_processes.gettree() else: self.stats = glances_processes.getlist() # Get the max values (dict) self.max_values = glances_processes.max_values() elif self.input_method == 'snmp': # No SNMP grab for processes pass return self.stats def get_process_tree_curses_data(self, node, args, first_level=True, max_node_count=None): """Get curses data to display for a process tree.""" ret = [] node_count = 0 if not node.is_root and ((max_node_count is None) or (max_node_count > 0)): node_data = self.get_process_curses_data(node.stats, False, args) node_count += 1 ret.extend(node_data) for child in node.iter_children(): # stop if we have enough nodes to display if max_node_count is not None and node_count >= max_node_count: break if max_node_count is None: children_max_node_count = None else: children_max_node_count = max_node_count - node_count child_data = self.get_process_tree_curses_data(child, args, first_level=node.is_root, max_node_count=children_max_node_count) if max_node_count is None: node_count += len(child) else: node_count += min(children_max_node_count, len(child)) if not node.is_root: child_data = self.add_tree_decoration(child_data, child is node.children[-1], first_level) ret.extend(child_data) return ret def add_tree_decoration(self, child_data, is_last_child, first_level): """Add tree curses decoration and indentation to a subtree.""" # find process command indices in messages pos = [] for i, m in enumerate(child_data): if m.get("_tree_decoration", False): del m["_tree_decoration"] pos.append(i) # add new curses items for tree decoration new_child_data = [] new_pos = [] for i, m in enumerate(child_data): if i in pos: new_pos.append(len(new_child_data)) new_child_data.append(self.curse_add_line("")) new_child_data[-1]["_tree_decoration"] = True new_child_data.append(m) child_data = new_child_data pos = new_pos if pos: # draw node prefix if is_last_child: prefix = "└─" else: prefix = "├─" child_data[pos[0]]["msg"] = prefix # add indentation for i in pos: spacing = 2 if first_level: spacing = 1 elif is_last_child and (i is not pos[0]): # compensate indentation for missing '│' char spacing = 3 child_data[i]["msg"] = "%s%s" % (" " * spacing, child_data[i]["msg"]) if not is_last_child: # add '│' tree decoration for i in pos[1:]: old_str = child_data[i]["msg"] if first_level: child_data[i]["msg"] = " │" + old_str[2:] else: child_data[i]["msg"] = old_str[:2] + "│" + old_str[3:] return child_data def get_process_curses_data(self, p, first, args): """Get curses data to display for a process. - p is the process to display - first is a tag=True if the process is the first on the list """ ret = [self.curse_new_line()] # CPU if 'cpu_percent' in p and p['cpu_percent'] is not None and p['cpu_percent'] != '': if args.disable_irix and self.nb_log_core != 0: msg = '{:>6.1f}'.format(p['cpu_percent'] / float(self.nb_log_core)) else: msg = '{:>6.1f}'.format(p['cpu_percent']) alert = self.get_alert(p['cpu_percent'], highlight_zero=False, is_max=(p['cpu_percent'] == self.max_values['cpu_percent']), header="cpu") ret.append(self.curse_add_line(msg, alert)) else: msg = '{:>6}'.format('?') ret.append(self.curse_add_line(msg)) # MEM if 'memory_percent' in p and p['memory_percent'] is not None and p['memory_percent'] != '': msg = '{:>6.1f}'.format(p['memory_percent']) alert = self.get_alert(p['memory_percent'], highlight_zero=False, is_max=(p['memory_percent'] == self.max_values['memory_percent']), header="mem") ret.append(self.curse_add_line(msg, alert)) else: msg = '{:>6}'.format('?') ret.append(self.curse_add_line(msg)) # VMS/RSS if 'memory_info' in p and p['memory_info'] is not None and p['memory_info'] != '': # VMS msg = '{:>6}'.format(self.auto_unit(p['memory_info'][1], low_precision=False)) ret.append(self.curse_add_line(msg, optional=True)) # RSS msg = '{:>6}'.format(self.auto_unit(p['memory_info'][0], low_precision=False)) ret.append(self.curse_add_line(msg, optional=True)) else: msg = '{:>6}'.format('?') ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line(msg)) # PID msg = '{:>{width}}'.format(p['pid'], width=self.__max_pid_size() + 1) ret.append(self.curse_add_line(msg)) # USER if 'username' in p: # docker internal users are displayed as ints only, therefore str() # Correct issue #886 on Windows OS msg = ' {:9}'.format(str(p['username'])[:9]) ret.append(self.curse_add_line(msg)) else: msg = ' {:9}'.format('?') ret.append(self.curse_add_line(msg)) # NICE if 'nice' in p: nice = p['nice'] if nice is None: nice = '?' msg = '{:>5}'.format(nice) if isinstance(nice, int) and ((WINDOWS and nice != 32) or (not WINDOWS and nice != 0)): ret.append(self.curse_add_line(msg, decoration='NICE')) else: ret.append(self.curse_add_line(msg)) else: msg = '{:>5}'.format('?') ret.append(self.curse_add_line(msg)) # STATUS if 'status' in p: status = p['status'] msg = '{:>2}'.format(status) if status == 'R': ret.append(self.curse_add_line(msg, decoration='STATUS')) else: ret.append(self.curse_add_line(msg)) else: msg = '{:>2}'.format('?') ret.append(self.curse_add_line(msg)) # TIME+ if self.tag_proc_time: try: delta = timedelta(seconds=sum(p['cpu_times'])) except (OverflowError, TypeError) as e: # Catch OverflowError on some Amazon EC2 server # See https://github.com/nicolargo/glances/issues/87 # Also catch TypeError on macOS # See: https://github.com/nicolargo/glances/issues/622 logger.debug("Cannot get TIME+ ({})".format(e)) self.tag_proc_time = False else: hours, minutes, seconds, microseconds = convert_timedelta(delta) if hours: msg = '{:>4}h'.format(hours) ret.append(self.curse_add_line(msg, decoration='CPU_TIME', optional=True)) msg = '{}:{}'.format(str(minutes).zfill(2), seconds) else: msg = '{:>4}:{}.{}'.format(minutes, seconds, microseconds) else: msg = '{:>10}'.format('?') ret.append(self.curse_add_line(msg, optional=True)) # IO read/write if 'io_counters' in p: # IO read io_rs = int((p['io_counters'][0] - p['io_counters'][2]) / p['time_since_update']) if io_rs == 0: msg = '{:>6}'.format("0") else: msg = '{:>6}'.format(self.auto_unit(io_rs, low_precision=True)) ret.append(self.curse_add_line(msg, optional=True, additional=True)) # IO write io_ws = int((p['io_counters'][1] - p['io_counters'][3]) / p['time_since_update']) if io_ws == 0: msg = '{:>6}'.format("0") else: msg = '{:>6}'.format(self.auto_unit(io_ws, low_precision=True)) ret.append(self.curse_add_line(msg, optional=True, additional=True)) else: msg = '{:>6}'.format("?") ret.append(self.curse_add_line(msg, optional=True, additional=True)) ret.append(self.curse_add_line(msg, optional=True, additional=True)) # Command line # If no command line for the process is available, fallback to # the bare process name instead cmdline = p['cmdline'] try: # XXX: remove `cmdline != ['']` when we'll drop support for psutil<4.0.0 if cmdline and cmdline != ['']: path, cmd, arguments = split_cmdline(cmdline) if os.path.isdir(path) and not args.process_short_name: msg = ' {}'.format(path) + os.sep ret.append(self.curse_add_line(msg, splittable=True)) if glances_processes.is_tree_enabled(): # mark position to add tree decoration ret[-1]["_tree_decoration"] = True ret.append(self.curse_add_line(cmd, decoration='PROCESS', splittable=True)) else: msg = ' {}'.format(cmd) ret.append(self.curse_add_line(msg, decoration='PROCESS', splittable=True)) if glances_processes.is_tree_enabled(): # mark position to add tree decoration ret[-1]["_tree_decoration"] = True if arguments: msg = ' {}'.format(arguments) ret.append(self.curse_add_line(msg, splittable=True)) else: msg = ' {}'.format(p['name']) ret.append(self.curse_add_line(msg, splittable=True)) except UnicodeEncodeError: ret.append(self.curse_add_line('', splittable=True)) # Add extended stats but only for the top processes # !!! CPU consumption ??? # TODO: extended stats into the web interface if first and 'extended_stats' in p: # Left padding xpad = ' ' * 13 # First line is CPU affinity if 'cpu_affinity' in p and p['cpu_affinity'] is not None: ret.append(self.curse_new_line()) msg = xpad + 'CPU affinity: ' + str(len(p['cpu_affinity'])) + ' cores' ret.append(self.curse_add_line(msg, splittable=True)) # Second line is memory info if 'memory_info' in p and p['memory_info'] is not None: ret.append(self.curse_new_line()) msg = xpad + 'Memory info: ' for k, v in iteritems(p['memory_info']._asdict()): # Ignore rss and vms (already displayed) if k not in ['rss', 'vms'] and v is not None: msg += k + ' ' + self.auto_unit(v, low_precision=False) + ' ' if 'memory_swap' in p and p['memory_swap'] is not None: msg += 'swap ' + self.auto_unit(p['memory_swap'], low_precision=False) ret.append(self.curse_add_line(msg, splittable=True)) # Third line is for open files/network sessions msg = '' if 'num_threads' in p and p['num_threads'] is not None: msg += 'threads ' + str(p['num_threads']) + ' ' if 'num_fds' in p and p['num_fds'] is not None: msg += 'files ' + str(p['num_fds']) + ' ' if 'num_handles' in p and p['num_handles'] is not None: msg += 'handles ' + str(p['num_handles']) + ' ' if 'tcp' in p and p['tcp'] is not None: msg += 'TCP ' + str(p['tcp']) + ' ' if 'udp' in p and p['udp'] is not None: msg += 'UDP ' + str(p['udp']) + ' ' if msg != '': ret.append(self.curse_new_line()) msg = xpad + 'Open: ' + msg ret.append(self.curse_add_line(msg, splittable=True)) # Fouth line is IO nice level (only Linux and Windows OS) if 'ionice' in p and p['ionice'] is not None: ret.append(self.curse_new_line()) msg = xpad + 'IO nice: ' k = 'Class is ' v = p['ionice'].ioclass # Linux: The scheduling class. 0 for none, 1 for real time, 2 for best-effort, 3 for idle. # Windows: On Windows only ioclass is used and it can be set to 2 (normal), 1 (low) or 0 (very low). if WINDOWS: if v == 0: msg += k + 'Very Low' elif v == 1: msg += k + 'Low' elif v == 2: msg += 'No specific I/O priority' else: msg += k + str(v) else: if v == 0: msg += 'No specific I/O priority' elif v == 1: msg += k + 'Real Time' elif v == 2: msg += k + 'Best Effort' elif v == 3: msg += k + 'IDLE' else: msg += k + str(v) # value is a number which goes from 0 to 7. # The higher the value, the lower the I/O priority of the process. if hasattr(p['ionice'], 'value') and p['ionice'].value != 0: msg += ' (value %s/7)' % str(p['ionice'].value) ret.append(self.curse_add_line(msg, splittable=True)) return ret def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or args.disable_process: return ret # Compute the sort key process_sort_key = glances_processes.sort_key # Header self.__msg_curse_header(ret, process_sort_key, args) # Process list if glances_processes.is_tree_enabled(): ret.extend(self.get_process_tree_curses_data( self.__sort_stats(process_sort_key), args, first_level=True, max_node_count=glances_processes.max_processes)) else: # Loop over processes (sorted by the sort key previously compute) first = True for p in self.__sort_stats(process_sort_key): ret.extend(self.get_process_curses_data(p, first, args)) # End of extended stats first = False if glances_processes.process_filter is not None: if args.reset_minmax_tag: args.reset_minmax_tag = not args.reset_minmax_tag self.__mmm_reset() self.__msg_curse_sum(ret, args=args) self.__msg_curse_sum(ret, mmm='min', args=args) self.__msg_curse_sum(ret, mmm='max', args=args) # Return the message with decoration return ret def __msg_curse_header(self, ret, process_sort_key, args=None): """ Build the header and add it to the ret dict """ sort_style = 'SORT' if args.disable_irix and 0 < self.nb_log_core < 10: msg = '{:>6}'.format('CPU%/' + str(self.nb_log_core)) elif args.disable_irix and self.nb_log_core != 0: msg = '{:>6}'.format('CPU%/C') else: msg = '{:>6}'.format('CPU%') ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'cpu_percent' else 'DEFAULT')) msg = '{:>6}'.format('MEM%') ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'memory_percent' else 'DEFAULT')) msg = '{:>6}'.format('VIRT') ret.append(self.curse_add_line(msg, optional=True)) msg = '{:>6}'.format('RES') ret.append(self.curse_add_line(msg, optional=True)) msg = '{:>{width}}'.format('PID', width=self.__max_pid_size() + 1) ret.append(self.curse_add_line(msg)) msg = ' {:10}'.format('USER') ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'username' else 'DEFAULT')) msg = '{:>4}'.format('NI') ret.append(self.curse_add_line(msg)) msg = '{:>2}'.format('S') ret.append(self.curse_add_line(msg)) msg = '{:>10}'.format('TIME+') ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'cpu_times' else 'DEFAULT', optional=True)) msg = '{:>6}'.format('R/s') ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True)) msg = '{:>6}'.format('W/s') ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True)) msg = ' {:8}'.format('Command') ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'name' else 'DEFAULT')) def __msg_curse_sum(self, ret, sep_char='_', mmm=None, args=None): """ Build the sum message (only when filter is on) and add it to the ret dict * ret: list of string where the message is added * sep_char: define the line separation char * mmm: display min, max, mean or current (if mmm=None) * args: Glances args """ ret.append(self.curse_new_line()) if mmm is None: ret.append(self.curse_add_line(sep_char * 69)) ret.append(self.curse_new_line()) # CPU percent sum msg = '{:>6.1f}'.format(self.__sum_stats('cpu_percent', mmm=mmm)) ret.append(self.curse_add_line(msg, decoration=self.__mmm_deco(mmm))) # MEM percent sum msg = '{:>6.1f}'.format(self.__sum_stats('memory_percent', mmm=mmm)) ret.append(self.curse_add_line(msg, decoration=self.__mmm_deco(mmm))) # VIRT and RES memory sum if 'memory_info' in self.stats[0] and self.stats[0]['memory_info'] is not None and self.stats[0]['memory_info'] != '': # VMS msg = '{:>6}'.format(self.auto_unit(self.__sum_stats('memory_info', indice=1, mmm=mmm), low_precision=False)) ret.append(self.curse_add_line(msg, decoration=self.__mmm_deco(mmm), optional=True)) # RSS msg = '{:>6}'.format(self.auto_unit(self.__sum_stats('memory_info', indice=0, mmm=mmm), low_precision=False)) ret.append(self.curse_add_line(msg, decoration=self.__mmm_deco(mmm), optional=True)) else: msg = '{:>6}'.format('') ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line(msg)) # PID msg = '{:>6}'.format('') ret.append(self.curse_add_line(msg)) # USER msg = ' {:9}'.format('') ret.append(self.curse_add_line(msg)) # NICE msg = '{:>5}'.format('') ret.append(self.curse_add_line(msg)) # STATUS msg = '{:>2}'.format('') ret.append(self.curse_add_line(msg)) # TIME+ msg = '{:>10}'.format('') ret.append(self.curse_add_line(msg, optional=True)) # IO read/write if 'io_counters' in self.stats[0] and mmm is None: # IO read io_rs = int((self.__sum_stats('io_counters', 0) - self.__sum_stats('io_counters', indice=2, mmm=mmm)) / self.stats[0]['time_since_update']) if io_rs == 0: msg = '{:>6}'.format('0') else: msg = '{:>6}'.format(self.auto_unit(io_rs, low_precision=True)) ret.append(self.curse_add_line(msg, decoration=self.__mmm_deco(mmm), optional=True, additional=True)) # IO write io_ws = int((self.__sum_stats('io_counters', 1) - self.__sum_stats('io_counters', indice=3, mmm=mmm)) / self.stats[0]['time_since_update']) if io_ws == 0: msg = '{:>6}'.format('0') else: msg = '{:>6}'.format(self.auto_unit(io_ws, low_precision=True)) ret.append(self.curse_add_line(msg, decoration=self.__mmm_deco(mmm), optional=True, additional=True)) else: msg = '{:>6}'.format('') ret.append(self.curse_add_line(msg, optional=True, additional=True)) ret.append(self.curse_add_line(msg, optional=True, additional=True)) if mmm is None: msg = ' < {}'.format('current') ret.append(self.curse_add_line(msg, optional=True)) else: msg = ' < {}'.format(mmm) ret.append(self.curse_add_line(msg, optional=True)) msg = ' (\'M\' to reset)' ret.append(self.curse_add_line(msg, optional=True)) def __mmm_deco(self, mmm): """ Return the decoration string for the current mmm status """ if mmm is not None: return 'DEFAULT' else: return 'FILTER' def __mmm_reset(self): """ Reset the MMM stats """ self.mmm_min = {} self.mmm_max = {} def __sum_stats(self, key, indice=None, mmm=None): """ Return the sum of the stats value for the given key * indice: If indice is set, get the p[key][indice] * mmm: display min, max, mean or current (if mmm=None) """ # Compute stats summary ret = 0 for p in self.stats: if indice is None: ret += p[key] else: ret += p[key][indice] # Manage Min/Max/Mean mmm_key = self.__mmm_key(key, indice) if mmm == 'min': try: if self.mmm_min[mmm_key] > ret: self.mmm_min[mmm_key] = ret except AttributeError: self.mmm_min = {} return 0 except KeyError: self.mmm_min[mmm_key] = ret ret = self.mmm_min[mmm_key] elif mmm == 'max': try: if self.mmm_max[mmm_key] < ret: self.mmm_max[mmm_key] = ret except AttributeError: self.mmm_max = {} return 0 except KeyError: self.mmm_max[mmm_key] = ret ret = self.mmm_max[mmm_key] return ret def __mmm_key(self, key, indice): ret = key if indice is not None: ret += str(indice) return ret def __sort_stats(self, sortedby=None): """Return the stats (dict) sorted by (sortedby)""" return sort_stats(self.stats, sortedby, tree=glances_processes.is_tree_enabled(), reverse=glances_processes.sort_reverse) def __max_pid_size(self): """Return the maximum PID size in number of char""" if self.pid_max is not None: return len(str(self.pid_max)) else: # By default return 5 (corresponding to 99999 PID number) return 5 glances-2.11.1/glances/plugins/glances_psutilversion.py000066400000000000000000000032261315472316100233070ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . from glances import psutil_version_info from glances.plugins.glances_plugin import GlancesPlugin class Plugin(GlancesPlugin): """Get the psutil version for client/server purposes. stats is a tuple """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) self.reset() def reset(self): """Reset/init the stats.""" self.stats = None @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the stats.""" # Reset stats self.reset() # Return PsUtil version as a tuple if self.input_method == 'local': # PsUtil version only available in local try: self.stats = psutil_version_info except NameError: pass else: pass return self.stats glances-2.11.1/glances/plugins/glances_quicklook.py000066400000000000000000000126761315472316100223730ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Quicklook plugin.""" from glances.cpu_percent import cpu_percent from glances.outputs.glances_bars import Bar from glances.plugins.glances_plugin import GlancesPlugin import psutil cpuinfo_tag = False try: from cpuinfo import cpuinfo except ImportError: # Correct issue #754 # Waiting for a correction on the upstream Cpuinfo lib pass else: cpuinfo_tag = True class Plugin(GlancesPlugin): """Glances quicklook plugin. 'stats' is a dictionary. """ def __init__(self, args=None): """Init the quicklook plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update quicklook stats using the input method.""" # Reset stats self.reset() # Grab quicklook stats: CPU, MEM and SWAP if self.input_method == 'local': # Get the latest CPU percent value self.stats['cpu'] = cpu_percent.get() self.stats['percpu'] = cpu_percent.get(percpu=True) # Use the PsUtil lib for the memory (virtual and swap) self.stats['mem'] = psutil.virtual_memory().percent self.stats['swap'] = psutil.swap_memory().percent elif self.input_method == 'snmp': # Not available pass # Optionnaly, get the CPU name/frequency # thanks to the cpuinfo lib: https://github.com/workhorsy/py-cpuinfo if cpuinfo_tag: cpu_info = cpuinfo.get_cpu_info() # Check cpu_info (issue #881) if cpu_info is not None: self.stats['cpu_name'] = cpu_info['brand'] self.stats['cpu_hz_current'] = cpu_info['hz_actual_raw'][0] self.stats['cpu_hz'] = cpu_info['hz_advertised_raw'][0] return self.stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert only for key in ['cpu', 'mem', 'swap']: if key in self.stats: self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key) def msg_curse(self, args=None, max_width=10): """Return the list to display in the UI.""" # Init the return message ret = [] # Only process if stats exist... if not self.stats or self.is_disable(): return ret # Define the bar bar = Bar(max_width) # Build the string message if 'cpu_name' in self.stats and 'cpu_hz_current' in self.stats and 'cpu_hz' in self.stats: msg_name = '{} - '.format(self.stats['cpu_name']) msg_freq = '{:.2f}/{:.2f}GHz'.format(self._hz_to_ghz(self.stats['cpu_hz_current']), self._hz_to_ghz(self.stats['cpu_hz'])) if len(msg_name + msg_freq) - 6 <= max_width: ret.append(self.curse_add_line(msg_name)) ret.append(self.curse_add_line(msg_freq)) ret.append(self.curse_new_line()) for key in ['cpu', 'mem', 'swap']: if key == 'cpu' and args.percpu: for cpu in self.stats['percpu']: bar.percent = cpu['total'] if cpu[cpu['key']] < 10: msg = '{:3}{} '.format(key.upper(), cpu['cpu_number']) else: msg = '{:4} '.format(cpu['cpu_number']) ret.extend(self._msg_create_line(msg, bar, key)) ret.append(self.curse_new_line()) else: bar.percent = self.stats[key] msg = '{:4} '.format(key.upper()) ret.extend(self._msg_create_line(msg, bar, key)) ret.append(self.curse_new_line()) # Remove the last new line ret.pop() # Return the message with decoration return ret def _msg_create_line(self, msg, bar, key): """Create a new line to the Quickview""" ret = [] ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line(bar.pre_char, decoration='BOLD')) ret.append(self.curse_add_line(str(bar), self.get_views(key=key, option='decoration'))) ret.append(self.curse_add_line(bar.post_char, decoration='BOLD')) ret.append(self.curse_add_line(' ')) return ret def _hz_to_ghz(self, hz): """Convert Hz to Ghz""" return hz / 1000000000.0 glances-2.11.1/glances/plugins/glances_raid.py000066400000000000000000000131231315472316100212750ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """RAID plugin.""" from glances.compat import iterkeys from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin # pymdstat only available on GNU/Linux OS try: from pymdstat import MdStat except ImportError: logger.debug("pymdstat library not found. Glances cannot grab RAID info.") class Plugin(GlancesPlugin): """Glances RAID plugin. stats is a dict (see pymdstat documentation) """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update RAID stats using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the PyMDstat lib (https://github.com/nicolargo/pymdstat) try: mds = MdStat() self.stats = mds.get_stats()['arrays'] except Exception as e: logger.debug("Can not grab RAID stats (%s)" % e) return self.stats elif self.input_method == 'snmp': # Update stats using SNMP # No standard way for the moment... pass return self.stats def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist... if not self.stats: return ret # Build the string message # Header msg = '{:11}'.format('RAID disks') ret.append(self.curse_add_line(msg, "TITLE")) msg = '{:>6}'.format('Used') ret.append(self.curse_add_line(msg)) msg = '{:>6}'.format('Avail') ret.append(self.curse_add_line(msg)) # Data arrays = sorted(iterkeys(self.stats)) for array in arrays: # New line ret.append(self.curse_new_line()) # Display the current status status = self.raid_alert(self.stats[array]['status'], self.stats[array]['used'], self.stats[array]['available']) # Data: RAID type name | disk used | disk available array_type = self.stats[array]['type'].upper() if self.stats[array]['type'] is not None else 'UNKNOWN' msg = '{:<5}{:>6}'.format(array_type, array) ret.append(self.curse_add_line(msg)) if self.stats[array]['status'] == 'active': msg = '{:>6}'.format(self.stats[array]['used']) ret.append(self.curse_add_line(msg, status)) msg = '{:>6}'.format(self.stats[array]['available']) ret.append(self.curse_add_line(msg, status)) elif self.stats[array]['status'] == 'inactive': ret.append(self.curse_new_line()) msg = '└─ Status {}'.format(self.stats[array]['status']) ret.append(self.curse_add_line(msg, status)) components = sorted(iterkeys(self.stats[array]['components'])) for i, component in enumerate(components): if i == len(components) - 1: tree_char = '└─' else: tree_char = '├─' ret.append(self.curse_new_line()) msg = ' {} disk {}: '.format(tree_char, self.stats[array]['components'][component]) ret.append(self.curse_add_line(msg)) msg = '{}'.format(component) ret.append(self.curse_add_line(msg)) if self.stats[array]['used'] < self.stats[array]['available']: # Display current array configuration ret.append(self.curse_new_line()) msg = '└─ Degraded mode' ret.append(self.curse_add_line(msg, status)) if len(self.stats[array]['config']) < 17: ret.append(self.curse_new_line()) msg = ' └─ {}'.format(self.stats[array]['config'].replace('_', 'A')) ret.append(self.curse_add_line(msg)) return ret def raid_alert(self, status, used, available): """RAID alert messages. [available/used] means that ideally the array may have _available_ devices however, _used_ devices are in use. Obviously when used >= available then things are good. """ if status == 'inactive': return 'CRITICAL' if used is None or available is None: return 'DEFAULT' elif used < available: return 'WARNING' return 'OK' glances-2.11.1/glances/plugins/glances_sensors.py000066400000000000000000000256501315472316100220620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Sensors plugin.""" import psutil from glances.logger import logger from glances.compat import iteritems from glances.plugins.glances_batpercent import Plugin as BatPercentPlugin from glances.plugins.glances_hddtemp import Plugin as HddTempPlugin from glances.plugins.glances_plugin import GlancesPlugin SENSOR_TEMP_UNIT = 'C' SENSOR_FAN_UNIT = 'rpm' def to_fahrenheit(celsius): """Convert Celsius to Fahrenheit.""" return celsius * 1.8 + 32 class Plugin(GlancesPlugin): """Glances sensors plugin. The stats list includes both sensors and hard disks stats, if any. The sensors are already grouped by chip type and then sorted by name. The hard disks are already sorted by name. """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # Init the sensor class self.glancesgrabsensors = GlancesGrabSensors() # Instance for the HDDTemp Plugin in order to display the hard disks # temperatures self.hddtemp_plugin = HddTempPlugin(args=args) # Instance for the BatPercent in order to display the batteries # capacities self.batpercent_plugin = BatPercentPlugin(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def get_key(self): """Return the key of the list.""" return 'label' def reset(self): """Reset/init the stats.""" self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update sensors stats using the input method.""" # Reset the stats self.reset() if self.input_method == 'local': # Update stats using the dedicated lib self.stats = [] # Get the temperature try: temperature = self.__set_type(self.glancesgrabsensors.get('temperature_core'), 'temperature_core') except Exception as e: logger.error("Cannot grab sensors temperatures (%s)" % e) else: # Append temperature self.stats.extend(temperature) # Get the FAN speed try: fan_speed = self.__set_type(self.glancesgrabsensors.get('fan_speed'), 'fan_speed') except Exception as e: logger.error("Cannot grab FAN speed (%s)" % e) else: # Append FAN speed self.stats.extend(fan_speed) # Update HDDtemp stats try: hddtemp = self.__set_type(self.hddtemp_plugin.update(), 'temperature_hdd') except Exception as e: logger.error("Cannot grab HDD temperature (%s)" % e) else: # Append HDD temperature self.stats.extend(hddtemp) # Update batteries stats try: batpercent = self.__set_type(self.batpercent_plugin.update(), 'battery') except Exception as e: logger.error("Cannot grab battery percent (%s)" % e) else: # Append Batteries % self.stats.extend(batpercent) elif self.input_method == 'snmp': # Update stats using SNMP # No standard: # http://www.net-snmp.org/wiki/index.php/Net-SNMP_and_lm-sensors_on_Ubuntu_10.04 pass return self.stats def __set_type(self, stats, sensor_type): """Set the plugin type. 4 types of stats is possible in the sensors plugin: - Core temperature: 'temperature_core' - Fan speed: 'fan_speed' - HDD temperature: 'temperature_hdd' - Battery capacity: 'battery' """ for i in stats: # Set the sensors type i.update({'type': sensor_type}) # also add the key name i.update({'key': self.get_key()}) return stats def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert for i in self.stats: if not i['value']: continue if i['type'] == 'battery': self.views[i[self.get_key()]]['value']['decoration'] = self.get_alert(100 - i['value'], header=i['type']) else: self.views[i[self.get_key()]]['value']['decoration'] = self.get_alert(i['value'], header=i['type']) def msg_curse(self, args=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or args.disable_sensors: return ret # Build the string message # Header msg = '{:18}'.format('SENSORS') ret.append(self.curse_add_line(msg, "TITLE")) for i in self.stats: # Do not display anything if no battery are detected if i['type'] == 'battery' and i['value'] == []: continue # New line ret.append(self.curse_new_line()) # Alias for the lable name ? label = self.has_alias(i['label'].lower()) if label is None: label = i['label'] if i['type'] != 'fan_speed': msg = '{:15}'.format(label[:15]) else: msg = '{:13}'.format(label[:13]) ret.append(self.curse_add_line(msg)) if i['value'] in (b'ERR', b'SLP', b'UNK', b'NOS'): msg = '{:>8}'.format(i['value']) ret.append(self.curse_add_line( msg, self.get_views(item=i[self.get_key()], key='value', option='decoration'))) else: if (args.fahrenheit and i['type'] != 'battery' and i['type'] != 'fan_speed'): value = to_fahrenheit(i['value']) unit = 'F' else: value = i['value'] unit = i['unit'] try: msg = '{:>7.0f}{}'.format(value, unit) ret.append(self.curse_add_line( msg, self.get_views(item=i[self.get_key()], key='value', option='decoration'))) except (TypeError, ValueError): pass return ret class GlancesGrabSensors(object): """Get sensors stats.""" def __init__(self): """Init sensors stats.""" # Temperatures self.init_temp = False self.stemps = {} try: # psutil>=5.1.0 is required self.stemps = psutil.sensors_temperatures() except AttributeError: logger.warning("PsUtil 5.1.0 or higher is needed to grab temperatures sensors") except OSError as e: # FreeBSD: If oid 'hw.acpi.battery' not present, Glances wont start #1055 logger.error("Can not grab temperatures sensors ({})".format(e)) else: self.init_temp = True # Fans self.init_fan = False self.sfans = {} try: # psutil>=5.2.0 is required self.sfans = psutil.sensors_fans() except AttributeError: logger.warning("PsUtil 5.2.0 or higher is needed to grab fans sensors") except OSError as e: logger.error("Can not grab fans sensors ({})".format(e)) else: self.init_fan = True # !!! Disable Fan: High CPU consumption is PSUtil 5.2.0 # Delete the following line when corrected self.init_fan = False # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.sensors_list = [] def __update__(self): """Update the stats.""" # Reset the list self.reset() if not self.init_temp: return self.sensors_list # Temperatures sensors self.sensors_list.extend(self.build_sensors_list(SENSOR_TEMP_UNIT)) # Fans sensors self.sensors_list.extend(self.build_sensors_list(SENSOR_FAN_UNIT)) return self.sensors_list def build_sensors_list(self, type): """Build the sensors list depending of the type. type: SENSOR_TEMP_UNIT or SENSOR_FAN_UNIT output: a list""" ret = [] if type == SENSOR_TEMP_UNIT and self.init_temp: input_list = self.stemps self.stemps = psutil.sensors_temperatures() elif type == SENSOR_FAN_UNIT and self.init_fan: input_list = self.sfans self.sfans = psutil.sensors_fans() else: return ret for chipname, chip in iteritems(input_list): i = 1 for feature in chip: sensors_current = {} # Sensor name if feature.label == '': sensors_current['label'] = chipname + ' ' + str(i) else: sensors_current['label'] = feature.label # Fan speed and unit sensors_current['value'] = int(feature.current) sensors_current['unit'] = type # Add sensor to the list ret.append(sensors_current) i += 1 return ret def get(self, sensor_type='temperature_core'): """Get sensors list.""" self.__update__() if sensor_type == 'temperature_core': ret = [s for s in self.sensors_list if s['unit'] == SENSOR_TEMP_UNIT] elif sensor_type == 'fan_speed': ret = [s for s in self.sensors_list if s['unit'] == SENSOR_FAN_UNIT] else: # Unknown type logger.debug("Unknown sensor type %s" % sensor_type) ret = [] return ret glances-2.11.1/glances/plugins/glances_system.py000066400000000000000000000177111315472316100217110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """System plugin.""" import os import platform import re from io import open from glances.compat import iteritems from glances.plugins.glances_plugin import GlancesPlugin # SNMP OID snmp_oid = {'default': {'hostname': '1.3.6.1.2.1.1.5.0', 'system_name': '1.3.6.1.2.1.1.1.0'}, 'netapp': {'hostname': '1.3.6.1.2.1.1.5.0', 'system_name': '1.3.6.1.2.1.1.1.0', 'platform': '1.3.6.1.4.1.789.1.1.5.0'}} # SNMP to human read # Dict (key: OS short name) of dict (reg exp OID to human) # Windows: # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx snmp_to_human = {'windows': {'Windows Version 10.0': 'Windows 10 or Server 2016', 'Windows Version 6.3': 'Windows 8.1 or Server 2012R2', 'Windows Version 6.2': 'Windows 8 or Server 2012', 'Windows Version 6.1': 'Windows 7 or Server 2008R2', 'Windows Version 6.0': 'Windows Vista or Server 2008', 'Windows Version 5.2': 'Windows XP 64bits or 2003 server', 'Windows Version 5.1': 'Windows XP', 'Windows Version 5.0': 'Windows 2000'}} def _linux_os_release(): """Try to determine the name of a Linux distribution. This function checks for the /etc/os-release file. It takes the name from the 'NAME' field and the version from 'VERSION_ID'. An empty string is returned if the above values cannot be determined. """ pretty_name = '' ashtray = {} keys = ['NAME', 'VERSION_ID'] try: with open(os.path.join('/etc', 'os-release')) as f: for line in f: for key in keys: if line.startswith(key): ashtray[key] = re.sub(r'^"|"$', '', line.strip().split('=')[1]) except (OSError, IOError): return pretty_name if ashtray: if 'NAME' in ashtray: pretty_name = ashtray['NAME'] if 'VERSION_ID' in ashtray: pretty_name += ' {}'.format(ashtray['VERSION_ID']) return pretty_name class Plugin(GlancesPlugin): """Glances' host/system plugin. stats is a dict """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def reset(self): """Reset/init the stats.""" self.stats = {} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update the host/system info using the input method. Return the stats (dict) """ # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib self.stats['os_name'] = platform.system() self.stats['hostname'] = platform.node() self.stats['platform'] = platform.architecture()[0] if self.stats['os_name'] == "Linux": try: linux_distro = platform.linux_distribution() except AttributeError: self.stats['linux_distro'] = _linux_os_release() else: if linux_distro[0] == '': self.stats['linux_distro'] = _linux_os_release() else: self.stats['linux_distro'] = ' '.join(linux_distro[:2]) self.stats['os_version'] = platform.release() elif (self.stats['os_name'].endswith('BSD') or self.stats['os_name'] == 'SunOS'): self.stats['os_version'] = platform.release() elif self.stats['os_name'] == "Darwin": self.stats['os_version'] = platform.mac_ver()[0] elif self.stats['os_name'] == "Windows": os_version = platform.win32_ver() self.stats['os_version'] = ' '.join(os_version[::2]) # if the python version is 32 bit perhaps the windows operating # system is 64bit if self.stats['platform'] == '32bit' and 'PROCESSOR_ARCHITEW6432' in os.environ: self.stats['platform'] = '64bit' else: self.stats['os_version'] = "" # Add human readable name if self.stats['os_name'] == "Linux": self.stats['hr_name'] = self.stats['linux_distro'] else: self.stats['hr_name'] = '{} {}'.format( self.stats['os_name'], self.stats['os_version']) self.stats['hr_name'] += ' {}'.format(self.stats['platform']) elif self.input_method == 'snmp': # Update stats using SNMP try: self.stats = self.get_stats_snmp( snmp_oid=snmp_oid[self.short_system_name]) except KeyError: self.stats = self.get_stats_snmp(snmp_oid=snmp_oid['default']) # Default behavor: display all the information self.stats['os_name'] = self.stats['system_name'] # Windows OS tips if self.short_system_name == 'windows': for r, v in iteritems(snmp_to_human['windows']): if re.search(r, self.stats['system_name']): self.stats['os_name'] = v break # Add human readable name self.stats['hr_name'] = self.stats['os_name'] return self.stats def msg_curse(self, args=None): """Return the string to display in the curse interface.""" # Init the return message ret = [] # Build the string message if args.client: # Client mode if args.cs_status.lower() == "connected": msg = 'Connected to ' ret.append(self.curse_add_line(msg, 'OK')) elif args.cs_status.lower() == "snmp": msg = 'SNMP from ' ret.append(self.curse_add_line(msg, 'OK')) elif args.cs_status.lower() == "disconnected": msg = 'Disconnected from ' ret.append(self.curse_add_line(msg, 'CRITICAL')) # Hostname is mandatory msg = self.stats['hostname'] ret.append(self.curse_add_line(msg, "TITLE")) # System info if self.stats['os_name'] == "Linux" and self.stats['linux_distro']: msg = ' ({} {} / {} {})'.format(self.stats['linux_distro'], self.stats['platform'], self.stats['os_name'], self.stats['os_version']) else: try: msg = ' ({} {} {})'.format(self.stats['os_name'], self.stats['os_version'], self.stats['platform']) except Exception: msg = ' ({})'.format(self.stats['os_name']) ret.append(self.curse_add_line(msg, optional=True)) # Return the message with decoration return ret glances-2.11.1/glances/plugins/glances_uptime.py000066400000000000000000000055341315472316100216700ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Uptime plugin.""" from datetime import datetime, timedelta from glances.plugins.glances_plugin import GlancesPlugin import psutil # SNMP OID snmp_oid = {'_uptime': '1.3.6.1.2.1.1.3.0'} class Plugin(GlancesPlugin): """Glances uptime plugin. stats is date (string) """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Set the message position self.align = 'right' # Init the stats self.uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time()) self.reset() def reset(self): """Reset/init the stats.""" self.stats = {} def get_export(self): """Overwrite the default export method. Export uptime in seconds. """ # Convert the delta time to seconds (with cast) # Correct issue #1092 (thanks to @IanTAtWork) return {'seconds': int(self.uptime.total_seconds())} @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update uptime stat using the input method.""" # Reset stats self.reset() if self.input_method == 'local': # Update stats using the standard system lib self.uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time()) # Convert uptime to string (because datetime is not JSONifi) self.stats = str(self.uptime).split('.')[0] elif self.input_method == 'snmp': # Update stats using SNMP uptime = self.get_stats_snmp(snmp_oid=snmp_oid)['_uptime'] try: # In hundredths of seconds self.stats = str(timedelta(seconds=int(uptime) / 100)) except Exception: pass # Return the result return self.stats def msg_curse(self, args=None): """Return the string to display in the curse interface.""" return [self.curse_add_line('Uptime: {}'.format(self.stats))] glances-2.11.1/glances/plugins/glances_wifi.py000066400000000000000000000157701315472316100213260ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Wifi plugin.""" import operator from glances.logger import logger from glances.plugins.glances_plugin import GlancesPlugin import psutil # Use the Wifi Python lib (https://pypi.python.org/pypi/wifi) # Linux-only try: from wifi.scan import Cell from wifi.exceptions import InterfaceError except ImportError: logger.debug("Wifi library not found. Glances cannot grab Wifi info.") wifi_tag = False else: wifi_tag = True class Plugin(GlancesPlugin): """Glances Wifi plugin. Get stats of the current Wifi hotspots. """ def __init__(self, args=None): """Init the plugin.""" super(Plugin, self).__init__(args=args) # We want to display the stat in the curse interface self.display_curse = True # Init the stats self.reset() def get_key(self): """Return the key of the list. :returns: string -- SSID is the dict key """ return 'ssid' def reset(self): """Reset/init the stats to an empty list. :returns: None """ self.stats = [] @GlancesPlugin._check_decorator @GlancesPlugin._log_result_decorator def update(self): """Update Wifi stats using the input method. Stats is a list of dict (one dict per hotspot) :returns: list -- Stats is a list of dict (hotspot) """ # Reset stats self.reset() # Exist if we can not grab the stats if not wifi_tag: return self.stats if self.input_method == 'local': # Update stats using the standard system lib # Grab network interface stat using the PsUtil net_io_counter method try: netiocounters = psutil.net_io_counters(pernic=True) except UnicodeDecodeError: return self.stats for net in netiocounters: # Do not take hidden interface into account if self.is_hide(net): continue # Grab the stats using the Wifi Python lib try: wifi_cells = Cell.all(net) except InterfaceError: # Not a Wifi interface pass except Exception as e: # Other error logger.debug("WIFI plugin: Can not grab cellule stats ({})".format(e)) pass else: for wifi_cell in wifi_cells: hotspot = { 'key': self.get_key(), 'ssid': wifi_cell.ssid, 'signal': wifi_cell.signal, 'quality': wifi_cell.quality, 'encrypted': wifi_cell.encrypted, 'encryption_type': wifi_cell.encryption_type if wifi_cell.encrypted else None } # Add the hotspot to the list self.stats.append(hotspot) elif self.input_method == 'snmp': # Update stats using SNMP # Not implemented yet pass return self.stats def get_alert(self, value): """Overwrite the default get_alert method. Alert is on signal quality where lower is better... :returns: string -- Signal alert """ ret = 'OK' try: if value <= self.get_limit('critical', stat_name=self.plugin_name): ret = 'CRITICAL' elif value <= self.get_limit('warning', stat_name=self.plugin_name): ret = 'WARNING' elif value <= self.get_limit('careful', stat_name=self.plugin_name): ret = 'CAREFUL' except KeyError: ret = 'DEFAULT' return ret def update_views(self): """Update stats views.""" # Call the father's method super(Plugin, self).update_views() # Add specifics informations # Alert on signal thresholds for i in self.stats: self.views[i[self.get_key()]]['signal']['decoration'] = self.get_alert(i['signal']) self.views[i[self.get_key()]]['quality']['decoration'] = self.views[i[self.get_key()]]['signal']['decoration'] def msg_curse(self, args=None, max_width=None): """Return the dict to display in the curse interface.""" # Init the return message ret = [] # Only process if stats exist and display plugin enable... if not self.stats or args.disable_wifi or not wifi_tag: return ret # Max size for the interface name if max_width is not None and max_width >= 23: # Interface size name = max_width - space for encyption + quality ifname_max_width = max_width - 5 else: ifname_max_width = 16 # Build the string message # Header msg = '{:{width}}'.format('WIFI', width=ifname_max_width) ret.append(self.curse_add_line(msg, "TITLE")) msg = '{:>7}'.format('dBm') ret.append(self.curse_add_line(msg)) # Hotspot list (sorted by name) for i in sorted(self.stats, key=operator.itemgetter(self.get_key())): # Do not display hotspot with no name (/ssid) if i['ssid'] == '': continue ret.append(self.curse_new_line()) # New hotspot hotspotname = i['ssid'] # Add the encryption type (if it is available) if i['encrypted']: hotspotname += ' {}'.format(i['encryption_type']) # Cut hotspotname if it is too long if len(hotspotname) > ifname_max_width: hotspotname = '_' + hotspotname[-ifname_max_width + 1:] # Add the new hotspot to the message msg = '{:{width}}'.format(hotspotname, width=ifname_max_width) ret.append(self.curse_add_line(msg)) msg = '{:>7}'.format(i['signal'], width=ifname_max_width) ret.append(self.curse_add_line(msg, self.get_views(item=i[self.get_key()], key='signal', option='decoration'))) return ret glances-2.11.1/glances/ports_list.py000066400000000000000000000132111315472316100174010ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances ports list (Ports plugin).""" from glances.compat import range from glances.logger import logger from glances.globals import BSD # XXX *BSDs: Segmentation fault (core dumped) # -- https://bitbucket.org/al45tair/netifaces/issues/15 # Also used in the glances_ip plugin if not BSD: try: import netifaces netifaces_tag = True except ImportError: netifaces_tag = False else: netifaces_tag = False class GlancesPortsList(object): """Manage the ports list for the ports plugin.""" _section = "ports" _default_refresh = 60 _default_timeout = 3 def __init__(self, config=None, args=None): # ports_list is a list of dict (JSON compliant) # [ {'host': 'www.google.fr', 'port': 443, 'refresh': 30, 'description': Internet, 'status': True} ... ] # Load the configuration file self._ports_list = self.load(config) def load(self, config): """Load the ports list from the configuration file.""" ports_list = [] if config is None: logger.debug("No configuration file available. Cannot load ports list.") elif not config.has_section(self._section): logger.debug("No [%s] section in the configuration file. Cannot load ports list." % self._section) else: logger.debug("Start reading the [%s] section in the configuration file" % self._section) refresh = int(config.get_value(self._section, 'refresh', default=self._default_refresh)) timeout = int(config.get_value(self._section, 'timeout', default=self._default_timeout)) # Add default gateway on top of the ports_list lits default_gateway = config.get_value(self._section, 'port_default_gateway', default='False') if default_gateway.lower().startswith('true') and netifaces_tag: new_port = {} try: new_port['host'] = netifaces.gateways()['default'][netifaces.AF_INET][0] except KeyError: new_port['host'] = None # ICMP new_port['port'] = 0 new_port['description'] = 'DefaultGateway' new_port['refresh'] = refresh new_port['timeout'] = timeout new_port['status'] = None new_port['rtt_warning'] = None logger.debug("Add default gateway %s to the static list" % (new_port['host'])) ports_list.append(new_port) # Read the scan list for i in range(1, 256): new_port = {} postfix = 'port_%s_' % str(i) # Read mandatories configuration key: host new_port['host'] = config.get_value(self._section, '%s%s' % (postfix, 'host')) if new_port['host'] is None: continue # Read optionals configuration keys # Port is set to 0 by default. 0 mean ICMP check instead of TCP check new_port['port'] = config.get_value(self._section, '%s%s' % (postfix, 'port'), 0) new_port['description'] = config.get_value(self._section, '%sdescription' % postfix, default="%s:%s" % (new_port['host'], new_port['port'])) # Default status new_port['status'] = None # Refresh rate in second new_port['refresh'] = refresh # Timeout in second new_port['timeout'] = int(config.get_value(self._section, '%stimeout' % postfix, default=timeout)) # RTT warning new_port['rtt_warning'] = config.get_value(self._section, '%srtt_warning' % postfix, default=None) if new_port['rtt_warning'] is not None: # Convert to second new_port['rtt_warning'] = int(new_port['rtt_warning']) / 1000.0 # Add the server to the list logger.debug("Add port %s:%s to the static list" % (new_port['host'], new_port['port'])) ports_list.append(new_port) # Ports list loaded logger.debug("Ports list loaded: %s" % ports_list) return ports_list def get_ports_list(self): """Return the current server list (dict of dict).""" return self._ports_list def set_server(self, pos, key, value): """Set the key to the value for the pos (position in the list).""" self._ports_list[pos][key] = value glances-2.11.1/glances/processes.py000066400000000000000000000533721315472316100172210ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . import operator import os from glances.compat import iteritems, itervalues, listitems from glances.globals import BSD, LINUX, MACOS, WINDOWS from glances.timer import Timer, getTimeSinceLastUpdate from glances.processes_tree import ProcessTreeNode from glances.filter import GlancesFilter from glances.logger import logger import psutil def is_kernel_thread(proc): """Return True if proc is a kernel thread, False instead.""" try: return os.getpgid(proc.pid) == 0 # Python >= 3.3 raises ProcessLookupError, which inherits OSError except OSError: # return False is process is dead return False class GlancesProcesses(object): """Get processed stats using the psutil library.""" def __init__(self, cache_timeout=60): """Init the class to collect stats about processes.""" # Add internals caches because PSUtil do not cache all the stats # See: https://code.google.com/p/psutil/issues/detail?id=462 self.username_cache = {} self.cmdline_cache = {} # The internals caches will be cleaned each 'cache_timeout' seconds self.cache_timeout = cache_timeout self.cache_timer = Timer(self.cache_timeout) # Init the io dict # key = pid # value = [ read_bytes_old, write_bytes_old ] self.io_old = {} # Wether or not to enable process tree self._enable_tree = False self.process_tree = None # Init stats self.auto_sort = True self._sort_key = 'cpu_percent' self.allprocesslist = [] self.processlist = [] self.reset_processcount() # Tag to enable/disable the processes stats (to reduce the Glances CPU consumption) # Default is to enable the processes stats self.disable_tag = False # Extended stats for top process is enable by default self.disable_extended_tag = False # Maximum number of processes showed in the UI (None if no limit) self._max_processes = None # Process filter is a regular expression self._filter = GlancesFilter() # Whether or not to hide kernel threads self.no_kernel_threads = False # Store maximums values in a dict # Used in the UI to highlight the maximum value self._max_values_list = ('cpu_percent', 'memory_percent') # { 'cpu_percent': 0.0, 'memory_percent': 0.0 } self._max_values = {} self.reset_max_values() def reset_processcount(self): self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0, 'pid_max': None} def enable(self): """Enable process stats.""" self.disable_tag = False self.update() def disable(self): """Disable process stats.""" self.disable_tag = True def enable_extended(self): """Enable extended process stats.""" self.disable_extended_tag = False self.update() def disable_extended(self): """Disable extended process stats.""" self.disable_extended_tag = True @property def pid_max(self): """ Get the maximum PID value. On Linux, the value is read from the `/proc/sys/kernel/pid_max` file. From `man 5 proc`: The default value for this file, 32768, results in the same range of PIDs as on earlier kernels. On 32-bit platfroms, 32768 is the maximum value for pid_max. On 64-bit systems, pid_max can be set to any value up to 2^22 (PID_MAX_LIMIT, approximately 4 million). If the file is unreadable or not available for whatever reason, returns None. Some other OSes: - On FreeBSD and macOS the maximum is 99999. - On OpenBSD >= 6.0 the maximum is 99999 (was 32766). - On NetBSD the maximum is 30000. :returns: int or None """ if LINUX: # XXX: waiting for https://github.com/giampaolo/psutil/issues/720 try: with open('/proc/sys/kernel/pid_max', 'rb') as f: return int(f.read()) except (OSError, IOError): return None @property def max_processes(self): """Get the maximum number of processes showed in the UI.""" return self._max_processes @max_processes.setter def max_processes(self, value): """Set the maximum number of processes showed in the UI.""" self._max_processes = value @property def process_filter_input(self): """Get the process filter (given by the user).""" return self._filter.filter_input @property def process_filter(self): """Get the process filter (current apply filter).""" return self._filter.filter @process_filter.setter def process_filter(self, value): """Set the process filter.""" self._filter.filter = value @property def process_filter_key(self): """Get the process filter key.""" return self._filter.filter_key @property def process_filter_re(self): """Get the process regular expression compiled.""" return self._filter.filter_re def disable_kernel_threads(self): """Ignore kernel threads in process list.""" self.no_kernel_threads = True def enable_tree(self): """Enable process tree.""" self._enable_tree = True def is_tree_enabled(self): """Return True if process tree is enabled, False instead.""" return self._enable_tree @property def sort_reverse(self): """Return True to sort processes in reverse 'key' order, False instead.""" if self.sort_key == 'name' or self.sort_key == 'username': return False return True def max_values(self): """Return the max values dict.""" return self._max_values def get_max_values(self, key): """Get the maximum values of the given stat (key).""" return self._max_values[key] def set_max_values(self, key, value): """Set the maximum value for a specific stat (key).""" self._max_values[key] = value def reset_max_values(self): """Reset the maximum values dict.""" self._max_values = {} for k in self._max_values_list: self._max_values[k] = 0.0 def __get_mandatory_stats(self, proc, procstat): """ Get mandatory_stats: for all processes. Needed for the sorting/filter step. Stats grabbed inside this method: * 'name', 'cpu_times', 'status', 'ppid' * 'username', 'cpu_percent', 'memory_percent' """ procstat['mandatory_stats'] = True # Name, cpu_times, status and ppid stats are in the same /proc file # Optimisation fir issue #958 try: procstat.update(proc.as_dict( attrs=['name', 'cpu_times', 'status', 'ppid'], ad_value='')) except (psutil.NoSuchProcess, psutil.AccessDenied): # Try/catch for issue #432 (process no longer exist) # Try/catch for issue #1120 (only see on Macos) return None else: procstat['status'] = str(procstat['status'])[:1].upper() try: procstat.update(proc.as_dict( attrs=['username', 'cpu_percent', 'memory_percent'], ad_value='')) except (psutil.NoSuchProcess, psutil.AccessDenied): # Try/catch for issue #432 (process no longer exist) return None if procstat['cpu_percent'] == '' or procstat['memory_percent'] == '': # Do not display process if we cannot get the basic # cpu_percent or memory_percent stats return None # Compute the maximum value for cpu_percent and memory_percent for k in self._max_values_list: if procstat[k] > self.get_max_values(k): self.set_max_values(k, procstat[k]) # Process command line (cached with internal cache) if procstat['pid'] not in self.cmdline_cache: # Patch for issue #391 try: self.cmdline_cache[procstat['pid']] = proc.cmdline() except (AttributeError, EnvironmentError, UnicodeDecodeError, psutil.AccessDenied, psutil.NoSuchProcess): self.cmdline_cache[procstat['pid']] = "" procstat['cmdline'] = self.cmdline_cache[procstat['pid']] # Process IO # procstat['io_counters'] is a list: # [read_bytes, write_bytes, read_bytes_old, write_bytes_old, io_tag] # If io_tag = 0 > Access denied (display "?") # If io_tag = 1 > No access denied (display the IO rate) # Availability: all platforms except macOS and Illumos/Solaris try: # Get the process IO counters proc_io = proc.io_counters() io_new = [proc_io.read_bytes, proc_io.write_bytes] except (psutil.AccessDenied, psutil.NoSuchProcess, NotImplementedError): # Access denied to process IO (no root account) # NoSuchProcess (process die between first and second grab) # Put 0 in all values (for sort) and io_tag = 0 (for display) procstat['io_counters'] = [0, 0] + [0, 0] io_tag = 0 except AttributeError: return procstat else: # For IO rate computation # Append saved IO r/w bytes try: procstat['io_counters'] = io_new + self.io_old[procstat['pid']] except KeyError: procstat['io_counters'] = io_new + [0, 0] # then save the IO r/w bytes self.io_old[procstat['pid']] = io_new io_tag = 1 # Append the IO tag (for display) procstat['io_counters'] += [io_tag] return procstat def __get_standard_stats(self, proc, procstat): """ Get standard_stats: only for displayed processes. Stats grabbed inside this method: * nice and memory_info """ procstat['standard_stats'] = True # Process nice and memory_info (issue #926) try: procstat.update( proc.as_dict(attrs=['nice', 'memory_info'])) except psutil.NoSuchProcess: pass return procstat def __get_extended_stats(self, proc, procstat): """ Get extended stats, only for top processes (see issue #403). - cpu_affinity (Linux, Windows, FreeBSD) - ionice (Linux and Windows > Vista) - memory_full_info (Linux) - num_ctx_switches (not available on Illumos/Solaris) - num_fds (Unix-like) - num_handles (Windows) - num_threads (not available on *BSD) - memory_maps (only swap, Linux) https://www.cyberciti.biz/faq/linux-which-process-is-using-swap/ - connections (TCP and UDP) """ procstat['extended_stats'] = True for stat in ['cpu_affinity', 'ionice', 'memory_full_info', 'num_ctx_switches', 'num_fds', 'num_handles', 'num_threads']: try: procstat.update(proc.as_dict(attrs=[stat])) except psutil.NoSuchProcess: pass # XXX: psutil>=4.3.1 raises ValueError while <4.3.1 raises AttributeError except (ValueError, AttributeError): procstat[stat] = None if LINUX: try: procstat['memory_swap'] = sum([v.swap for v in proc.memory_maps()]) except psutil.NoSuchProcess: pass except (psutil.AccessDenied, TypeError, NotImplementedError): # NotImplementedError: /proc/${PID}/smaps file doesn't exist # on kernel < 2.6.14 or CONFIG_MMU kernel configuration option # is not enabled (see psutil #533/glances #413). # XXX: Remove TypeError once we'll drop psutil < 3.0.0. procstat['memory_swap'] = None try: procstat['tcp'] = len(proc.connections(kind="tcp")) procstat['udp'] = len(proc.connections(kind="udp")) except psutil.AccessDenied: procstat['tcp'] = None procstat['udp'] = None return procstat def __get_process_stats(self, proc, mandatory_stats=True, standard_stats=True, extended_stats=False): """Get stats of a running processes.""" # Process ID (always) procstat = proc.as_dict(attrs=['pid']) if mandatory_stats: procstat = self.__get_mandatory_stats(proc, procstat) if procstat is not None and standard_stats: procstat = self.__get_standard_stats(proc, procstat) if procstat is not None and extended_stats and not self.disable_extended_tag: procstat = self.__get_extended_stats(proc, procstat) return procstat def update(self): """Update the processes stats.""" # Reset the stats self.processlist = [] self.reset_processcount() # Do not process if disable tag is set if self.disable_tag: return # Get the time since last update time_since_update = getTimeSinceLastUpdate('process_disk') # Reset the max dict self.reset_max_values() # Update the maximum process ID (pid) number self.processcount['pid_max'] = self.pid_max # Build an internal dict with only mandatories stats (sort keys) processdict = {} excluded_processes = set() for proc in psutil.process_iter(): # Ignore kernel threads if needed if self.no_kernel_threads and not WINDOWS and is_kernel_thread(proc): continue # If self.max_processes is None: Only retrieve mandatory stats # Else: retrieve mandatory and standard stats s = self.__get_process_stats(proc, mandatory_stats=True, standard_stats=self.max_processes is None) # Check if s is note None (issue #879) # ignore the 'idle' process on Windows and *BSD # ignore the 'kernel_task' process on macOS # waiting for upstream patch from psutil if (s is None or BSD and s['name'] == 'idle' or WINDOWS and s['name'] == 'System Idle Process' or MACOS and s['name'] == 'kernel_task'): continue # Continue to the next process if it has to be filtered if self._filter.is_filtered(s): excluded_processes.add(proc) continue # Ok add the process to the list processdict[proc] = s # Update processcount (global statistics) try: self.processcount[str(proc.status())] += 1 except KeyError: # Key did not exist, create it try: self.processcount[str(proc.status())] = 1 except psutil.NoSuchProcess: pass except psutil.NoSuchProcess: pass else: self.processcount['total'] += 1 # Update thread number (global statistics) try: self.processcount['thread'] += proc.num_threads() except Exception: pass if self._enable_tree: self.process_tree = ProcessTreeNode.build_tree(processdict, self.sort_key, self.sort_reverse, self.no_kernel_threads, excluded_processes) for i, node in enumerate(self.process_tree): # Only retreive stats for visible processes (max_processes) if self.max_processes is not None and i >= self.max_processes: break # add standard stats new_stats = self.__get_process_stats(node.process, mandatory_stats=False, standard_stats=True, extended_stats=False) if new_stats is not None: node.stats.update(new_stats) # Add a specific time_since_update stats for bitrate node.stats['time_since_update'] = time_since_update else: # Process optimization # Only retreive stats for visible processes (max_processes) if self.max_processes is not None: # Sort the internal dict and cut the top N (Return a list of tuple) # tuple=key (proc), dict (returned by __get_process_stats) try: processiter = sorted(iteritems(processdict), key=lambda x: x[1][self.sort_key], reverse=self.sort_reverse) except (KeyError, TypeError) as e: logger.error("Cannot sort process list by {}: {}".format(self.sort_key, e)) logger.error('{}'.format(listitems(processdict)[0])) # Fallback to all process (issue #423) processloop = iteritems(processdict) first = False else: processloop = processiter[0:self.max_processes] first = True else: # Get all processes stats processloop = iteritems(processdict) first = False for i in processloop: # Already existing mandatory stats procstat = i[1] if self.max_processes is not None: # Update with standard stats # and extended stats but only for TOP (first) process s = self.__get_process_stats(i[0], mandatory_stats=False, standard_stats=True, extended_stats=first) if s is None: continue procstat.update(s) # Add a specific time_since_update stats for bitrate procstat['time_since_update'] = time_since_update # Update process list self.processlist.append(procstat) # Next... first = False # Build the all processes list used by the AMPs self.allprocesslist = [p for p in itervalues(processdict)] # Clean internals caches if timeout is reached if self.cache_timer.finished(): self.username_cache = {} self.cmdline_cache = {} # Restart the timer self.cache_timer.reset() def getcount(self): """Get the number of processes.""" return self.processcount def getalllist(self): """Get the allprocesslist.""" return self.allprocesslist def getlist(self, sortedby=None): """Get the processlist.""" return self.processlist def gettree(self): """Get the process tree.""" return self.process_tree @property def sort_key(self): """Get the current sort key.""" return self._sort_key @sort_key.setter def sort_key(self, key): """Set the current sort key.""" self._sort_key = key # TODO: move this global function (also used in glances_processlist # and logs) inside the GlancesProcesses class def sort_stats(stats, sortedby=None, tree=False, reverse=True): """Return the stats (dict) sorted by (sortedby) Reverse the sort if reverse is True.""" if sortedby is None: # No need to sort... return stats if sortedby == 'io_counters' and not tree: # Specific case for io_counters # Sum of io_r + io_w try: # Sort process by IO rate (sum IO read + IO write) stats.sort(key=lambda process: process[sortedby][0] - process[sortedby][2] + process[sortedby][1] - process[sortedby][3], reverse=reverse) except Exception: stats.sort(key=operator.itemgetter('cpu_percent'), reverse=reverse) else: # Others sorts if tree: stats.set_sorting(sortedby, reverse) else: try: stats.sort(key=operator.itemgetter(sortedby), reverse=reverse) except (KeyError, TypeError): stats.sort(key=operator.itemgetter('name'), reverse=False) return stats glances_processes = GlancesProcesses() glances-2.11.1/glances/processes_tree.py000066400000000000000000000214241315472316100202310ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . import collections from glances.compat import iteritems import psutil class ProcessTreeNode(object): """Represent a process tree. We avoid recursive algorithm to manipulate the tree because function calls are expensive with CPython. """ def __init__(self, process=None, stats=None, sort_key=None, sort_reverse=True, root=False): self.process = process self.stats = stats self.children = [] self.children_sorted = False self.sort_key = sort_key self.sort_reverse = sort_reverse self.is_root = root def __str__(self): """Return the tree as a string for debugging.""" lines = [] nodes_to_print = collections.deque([collections.deque([("#", self)])]) while nodes_to_print: indent_str, current_node = nodes_to_print[-1].pop() if not nodes_to_print[-1]: nodes_to_print.pop() if current_node.is_root: lines.append(indent_str) else: lines.append("%s[%s]" % (indent_str, current_node.process.name())) indent_str = " " * (len(lines[-1]) - 1) children_nodes_to_print = collections.deque() for child in current_node.children: if child is current_node.children[-1]: tree_char = "└─" else: tree_char = "├─" children_nodes_to_print.appendleft( (indent_str + tree_char, child)) if children_nodes_to_print: nodes_to_print.append(children_nodes_to_print) return "\n".join(lines) def set_sorting(self, key, reverse): """Set sorting key or func for use with __iter__. This affects the whole tree from this node. """ if self.sort_key != key or self.sort_reverse != reverse: nodes_to_flag_unsorted = collections.deque([self]) while nodes_to_flag_unsorted: current_node = nodes_to_flag_unsorted.pop() current_node.children_sorted = False current_node.sort_key = key current_node.reverse_sorting = reverse nodes_to_flag_unsorted.extend(current_node.children) def get_weight(self): """Return 'weight' of a process and all its children for sorting.""" if self.sort_key == 'name' or self.sort_key == 'username': return self.stats[self.sort_key] # sum ressource usage for self and children total = 0 nodes_to_sum = collections.deque([self]) while nodes_to_sum: current_node = nodes_to_sum.pop() if isinstance(self.sort_key, collections.Callable): total += self.sort_key(current_node.stats) elif self.sort_key == "io_counters": stats = current_node.stats[self.sort_key] total += stats[0] - stats[2] + stats[1] - stats[3] elif self.sort_key == "cpu_times": total += sum(current_node.stats[self.sort_key]) else: total += current_node.stats[self.sort_key] nodes_to_sum.extend(current_node.children) return total def __len__(self): """Return the number of nodes in the tree.""" total = 0 nodes_to_sum = collections.deque([self]) while nodes_to_sum: current_node = nodes_to_sum.pop() if not current_node.is_root: total += 1 nodes_to_sum.extend(current_node.children) return total def __iter__(self): """Iterator returning ProcessTreeNode in sorted order, recursively.""" if not self.is_root: yield self if not self.children_sorted: # optimization to avoid sorting twice (once when limiting the maximum processes to grab stats for, # and once before displaying) self.children.sort( key=self.__class__.get_weight, reverse=self.sort_reverse) self.children_sorted = True for child in self.children: for n in iter(child): yield n def iter_children(self, exclude_incomplete_stats=True): """Iterator returning ProcessTreeNode in sorted order. Return only children of this node, non recursive. If exclude_incomplete_stats is True, exclude processes not having full statistics. It can happen after a resort (change of sort key) because process stats are not grabbed immediately, but only at next full update. """ if not self.children_sorted: # optimization to avoid sorting twice (once when limiting the maximum processes to grab stats for, # and once before displaying) self.children.sort( key=self.__class__.get_weight, reverse=self.sort_reverse) self.children_sorted = True for child in self.children: if not exclude_incomplete_stats or "time_since_update" in child.stats: yield child def find_process(self, process): """Search in tree for the ProcessTreeNode owning process. Return it or None if not found. """ nodes_to_search = collections.deque([self]) while nodes_to_search: current_node = nodes_to_search.pop() if not current_node.is_root and current_node.process.pid == process.pid: return current_node nodes_to_search.extend(current_node.children) @staticmethod def build_tree(process_dict, sort_key, sort_reverse, hide_kernel_threads, excluded_processes): """Build a process tree using using parent/child relationships. Return the tree root node. """ tree_root = ProcessTreeNode(root=True) nodes_to_add_last = collections.deque() # first pass: add nodes whose parent are in the tree for process, stats in iteritems(process_dict): new_node = ProcessTreeNode(process, stats, sort_key, sort_reverse) try: parent_process = process.parent() except psutil.NoSuchProcess: # parent is dead, consider no parent parent_process = None if (parent_process is None) or (parent_process in excluded_processes): # no parent, or excluded parent, add this node at the top level tree_root.children.append(new_node) else: parent_node = tree_root.find_process(parent_process) if parent_node is not None: # parent is already in the tree, add a new child parent_node.children.append(new_node) else: # parent is not in tree, add this node later nodes_to_add_last.append(new_node) # next pass(es): add nodes to their parents if it could not be done in # previous pass while nodes_to_add_last: # pop from left and append to right to avoid infinite loop node_to_add = nodes_to_add_last.popleft() try: parent_process = node_to_add.process.parent() except psutil.NoSuchProcess: # parent is dead, consider no parent, add this node at the top # level tree_root.children.append(node_to_add) else: if (parent_process is None) or (parent_process in excluded_processes): # no parent, or excluded parent, add this node at the top level tree_root.children.append(node_to_add) else: parent_node = tree_root.find_process(parent_process) if parent_node is not None: # parent is already in the tree, add a new child parent_node.children.append(node_to_add) else: # parent is not in tree, add this node later nodes_to_add_last.append(node_to_add) return tree_root glances-2.11.1/glances/server.py000066400000000000000000000207361315472316100165170ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances server.""" import json import socket import sys from base64 import b64decode from glances import __version__ from glances.compat import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer, Server from glances.autodiscover import GlancesAutoDiscoverClient from glances.logger import logger from glances.stats_server import GlancesStatsServer from glances.timer import Timer class GlancesXMLRPCHandler(SimpleXMLRPCRequestHandler, object): """Main XML-RPC handler.""" rpc_paths = ('/RPC2', ) def end_headers(self): # Hack to add a specific header # Thk to: https://gist.github.com/rca/4063325 self.send_my_headers() super(GlancesXMLRPCHandler, self).end_headers() def send_my_headers(self): # Specific header is here (solved the issue #227) self.send_header("Access-Control-Allow-Origin", "*") def authenticate(self, headers): # auth = headers.get('Authorization') try: (basic, _, encoded) = headers.get('Authorization').partition(' ') except Exception: # Client did not ask for authentidaction # If server need it then exit return not self.server.isAuth else: # Client authentication (basic, _, encoded) = headers.get('Authorization').partition(' ') assert basic == 'Basic', 'Only basic authentication supported' # Encoded portion of the header is a string # Need to convert to bytestring encoded_byte_string = encoded.encode() # Decode base64 byte string to a decoded byte string decoded_bytes = b64decode(encoded_byte_string) # Convert from byte string to a regular string decoded_string = decoded_bytes.decode() # Get the username and password from the string (username, _, password) = decoded_string.partition(':') # Check that username and password match internal global dictionary return self.check_user(username, password) def check_user(self, username, password): # Check username and password in the dictionary if username in self.server.user_dict: from glances.password import GlancesPassword pwd = GlancesPassword() return pwd.check_password(self.server.user_dict[username], password) else: return False def parse_request(self): if SimpleXMLRPCRequestHandler.parse_request(self): # Next we authenticate if self.authenticate(self.headers): return True else: # if authentication fails, tell the client self.send_error(401, 'Authentication failed') return False def log_message(self, log_format, *args): # No message displayed on the server side pass class GlancesXMLRPCServer(SimpleXMLRPCServer, object): """Init a SimpleXMLRPCServer instance (IPv6-ready).""" finished = False def __init__(self, bind_address, bind_port=61209, requestHandler=GlancesXMLRPCHandler): self.bind_address = bind_address self.bind_port = bind_port try: self.address_family = socket.getaddrinfo(bind_address, bind_port)[0][0] except socket.error as e: logger.error("Couldn't open socket: {}".format(e)) sys.exit(1) super(GlancesXMLRPCServer, self).__init__((bind_address, bind_port), requestHandler) def end(self): """Stop the server""" self.server_close() self.finished = True def serve_forever(self): """Main loop""" while not self.finished: self.handle_request() class GlancesInstance(object): """All the methods of this class are published as XML-RPC methods.""" def __init__(self, config=None, args=None): # Init stats self.stats = GlancesStatsServer(config=config, args=args) # Initial update self.stats.update() # cached_time is the minimum time interval between stats updates # i.e. XML/RPC calls will not retrieve updated info until the time # since last update is passed (will retrieve old cached info instead) self.timer = Timer(0) self.cached_time = args.cached_time def __update__(self): # Never update more than 1 time per cached_time if self.timer.finished(): self.stats.update() self.timer = Timer(self.cached_time) def init(self): # Return the Glances version return __version__ def getAll(self): # Update and return all the stats self.__update__() return json.dumps(self.stats.getAll()) def getAllPlugins(self): # Return the plugins list return json.dumps(self.stats.getAllPlugins()) def getAllLimits(self): # Return all the plugins limits return json.dumps(self.stats.getAllLimitsAsDict()) def getAllViews(self): # Return all the plugins views return json.dumps(self.stats.getAllViewsAsDict()) def __getattr__(self, item): """Overwrite the getattr method in case of attribute is not found. The goal is to dynamically generate the API get'Stats'() methods. """ header = 'get' # Check if the attribute starts with 'get' if item.startswith(header): try: # Update the stat self.__update__() # Return the attribute return getattr(self.stats, item) except Exception: # The method is not found for the plugin raise AttributeError(item) else: # Default behavior raise AttributeError(item) class GlancesServer(object): """This class creates and manages the TCP server.""" def __init__(self, requestHandler=GlancesXMLRPCHandler, config=None, args=None): # Args self.args = args # Init the XML RPC server try: self.server = GlancesXMLRPCServer(args.bind_address, args.port, requestHandler) except Exception as e: logger.critical("Cannot start Glances server: {}".format(e)) sys.exit(2) else: print('Glances XML-RPC server is running on {}:{}'.format(args.bind_address, args.port)) # The users dict # username / password couple # By default, no auth is needed self.server.user_dict = {} self.server.isAuth = False # Register functions self.server.register_introspection_functions() self.server.register_instance(GlancesInstance(config, args)) if not self.args.disable_autodiscover: # Note: The Zeroconf service name will be based on the hostname # Correct issue: Zeroconf problem with zeroconf service name #889 self.autodiscover_client = GlancesAutoDiscoverClient(socket.gethostname().split('.', 1)[0], args) else: logger.info("Glances autodiscover announce is disabled") def add_user(self, username, password): """Add an user to the dictionary.""" self.server.user_dict[username] = password self.server.isAuth = True def serve_forever(self): """Call the main loop.""" # Set the server login/password (if -P/--password tag) if self.args.password != "": self.add_user(self.args.username, self.args.password) # Serve forever self.server.serve_forever() def end(self): """End of the Glances server session.""" if not self.args.disable_autodiscover: self.autodiscover_client.close() self.server.end() glances-2.11.1/glances/snmp.py000066400000000000000000000113451315472316100161620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . import sys from glances.logger import logger # Import mandatory PySNMP lib try: from pysnmp.entity.rfc3413.oneliner import cmdgen except ImportError: logger.critical("PySNMP library not found. To install it: pip install pysnmp") sys.exit(2) class GlancesSNMPClient(object): """SNMP client class (based on pysnmp library).""" def __init__(self, host='localhost', port=161, version='2c', community='public', user='private', auth=''): super(GlancesSNMPClient, self).__init__() self.cmdGen = cmdgen.CommandGenerator() self.version = version self.host = host self.port = port self.community = community self.user = user self.auth = auth def __buid_result(self, varBinds): """Build the results.""" ret = {} for name, val in varBinds: if str(val) == '': ret[name.prettyPrint()] = '' else: ret[name.prettyPrint()] = val.prettyPrint() # In Python 3, prettyPrint() return 'b'linux'' instead of 'linux' if ret[name.prettyPrint()].startswith('b\''): ret[name.prettyPrint()] = ret[name.prettyPrint()][2:-1] return ret def __get_result__(self, errorIndication, errorStatus, errorIndex, varBinds): """Put results in table.""" ret = {} if not errorIndication or not errorStatus: ret = self.__buid_result(varBinds) return ret def get_by_oid(self, *oid): """SNMP simple request (list of OID). One request per OID list. * oid: oid list > Return a dict """ if self.version == '3': errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd( cmdgen.UsmUserData(self.user, self.auth), cmdgen.UdpTransportTarget((self.host, self.port)), *oid ) else: errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd( cmdgen.CommunityData(self.community), cmdgen.UdpTransportTarget((self.host, self.port)), *oid ) return self.__get_result__(errorIndication, errorStatus, errorIndex, varBinds) def __bulk_result__(self, errorIndication, errorStatus, errorIndex, varBindTable): ret = [] if not errorIndication or not errorStatus: for varBindTableRow in varBindTable: ret.append(self.__buid_result(varBindTableRow)) return ret def getbulk_by_oid(self, non_repeaters, max_repetitions, *oid): """SNMP getbulk request. In contrast to snmpwalk, this information will typically be gathered in a single transaction with the agent, rather than one transaction per variable found. * non_repeaters: This specifies the number of supplied variables that should not be iterated over. * max_repetitions: This specifies the maximum number of iterations over the repeating variables. * oid: oid list > Return a list of dicts """ if self.version.startswith('3'): errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd( cmdgen.UsmUserData(self.user, self.auth), cmdgen.UdpTransportTarget((self.host, self.port)), non_repeaters, max_repetitions, *oid ) if self.version.startswith('2'): errorIndication, errorStatus, errorIndex, varBindTable = self.cmdGen.bulkCmd( cmdgen.CommunityData(self.community), cmdgen.UdpTransportTarget((self.host, self.port)), non_repeaters, max_repetitions, *oid ) else: # Bulk request are not available with SNMP version 1 return [] return self.__bulk_result__(errorIndication, errorStatus, errorIndex, varBindTable) glances-2.11.1/glances/standalone.py000066400000000000000000000105511315472316100173330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances standalone session.""" import sched import time from glances.globals import WINDOWS from glances.logger import logger from glances.processes import glances_processes from glances.stats import GlancesStats from glances.outputs.glances_curses import GlancesCursesStandalone from glances.outdated import Outdated class GlancesStandalone(object): """This class creates and manages the Glances standalone session.""" def __init__(self, config=None, args=None): # Quiet mode self._quiet = args.quiet self.refresh_time = args.time # Init stats self.stats = GlancesStats(config=config, args=args) # If process extended stats is disabled by user if not args.enable_process_extended: logger.debug("Extended stats for top process are disabled") glances_processes.disable_extended() else: logger.debug("Extended stats for top process are enabled") glances_processes.enable_extended() # Manage optionnal process filter if args.process_filter is not None: glances_processes.process_filter = args.process_filter if (not WINDOWS) and args.no_kernel_threads: # Ignore kernel threads in process list glances_processes.disable_kernel_threads() try: if args.process_tree: # Enable process tree view glances_processes.enable_tree() except AttributeError: pass # Initial system informations update self.stats.update() if self.quiet: logger.info("Quiet mode is ON: Nothing will be displayed") # In quiet mode, nothing is displayed glances_processes.max_processes = 0 else: # Default number of processes to displayed is set to 50 glances_processes.max_processes = 50 # Init screen self.screen = GlancesCursesStandalone(config=config, args=args) # Check the latest Glances version self.outdated = Outdated(config=config, args=args) # Create the schedule instance self.schedule = sched.scheduler( timefunc=time.time, delayfunc=time.sleep) @property def quiet(self): return self._quiet def __serve_forever(self): """Main loop for the CLI.""" # Reschedule the function inside itself self.schedule.enter(self.refresh_time, priority=0, action=self.__serve_forever, argument=()) # Update system informations self.stats.update() # Update the screen if not self.quiet: self.screen.update(self.stats) # Export stats using export modules self.stats.export(self.stats) def serve_forever(self): """Wrapper to the serve_forever function. This function will restore the terminal to a sane state before re-raising the exception and generating a traceback. """ self.__serve_forever() try: self.schedule.run() finally: self.end() def end(self): """End of the standalone CLI.""" if not self.quiet: self.screen.end() # Exit from export modules self.stats.end() # Check Glances version versus Pypi one if self.outdated.is_outdated(): print("You are using Glances version {}, however version {} is available.".format( self.outdated.installed_version(), self.outdated.latest_version())) print("You should consider upgrading using: pip install --upgrade glances") glances-2.11.1/glances/static_list.py000066400000000000000000000073651315472316100175360ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances server static list.""" from socket import gaierror, gethostbyname from glances.compat import range from glances.logger import logger class GlancesStaticServer(object): """Manage the static servers list for the client browser.""" _section = "serverlist" def __init__(self, config=None, args=None): # server_list is a list of dict (JSON compliant) # [ {'key': 'zeroconf name', ip': '172.1.2.3', 'port': 61209, 'cpu': 3, 'mem': 34 ...} ... ] # Load the configuration file self._server_list = self.load(config) def load(self, config): """Load the server list from the configuration file.""" server_list = [] if config is None: logger.debug("No configuration file available. Cannot load server list.") elif not config.has_section(self._section): logger.warning("No [%s] section in the configuration file. Cannot load server list." % self._section) else: logger.info("Start reading the [%s] section in the configuration file" % self._section) for i in range(1, 256): new_server = {} postfix = 'server_%s_' % str(i) # Read the server name (mandatory) for s in ['name', 'port', 'alias']: new_server[s] = config.get_value(self._section, '%s%s' % (postfix, s)) if new_server['name'] is not None: # Manage optionnal information if new_server['port'] is None: new_server['port'] = '61209' new_server['username'] = 'glances' # By default, try empty (aka no) password new_server['password'] = '' try: new_server['ip'] = gethostbyname(new_server['name']) except gaierror as e: logger.error("Cannot get IP address for server %s (%s)" % (new_server['name'], e)) continue new_server['key'] = new_server['name'] + ':' + new_server['port'] # Default status is 'UNKNOWN' new_server['status'] = 'UNKNOWN' # Server type is 'STATIC' new_server['type'] = 'STATIC' # Add the server to the list logger.debug("Add server %s to the static list" % new_server['name']) server_list.append(new_server) # Server list loaded logger.info("%s server(s) loaded from the configuration file" % len(server_list)) logger.debug("Static server list: %s" % server_list) return server_list def get_servers_list(self): """Return the current server list (list of dict).""" return self._server_list def set_server(self, server_pos, key, value): """Set the key to the value for the server_pos (position in the list).""" self._server_list[server_pos][key] = value glances-2.11.1/glances/stats.py000066400000000000000000000242271315472316100163460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """The stats manager.""" import collections import os import sys import threading import traceback from glances.globals import exports_path, plugins_path, sys_path from glances.logger import logger class GlancesStats(object): """This class stores, updates and gives stats.""" # Script header constant header = "glances_" def __init__(self, config=None, args=None): # Set the config instance self.config = config # Set the argument instance self.args = args # Load plugins and exports modules self.load_modules(self.args) # Load the limits (for plugins) self.load_limits(self.config) def __getattr__(self, item): """Overwrite the getattr method in case of attribute is not found. The goal is to dynamically generate the following methods: - getPlugname(): return Plugname stat in JSON format - getViewsPlugname(): return views of the Plugname stat in JSON format """ # Check if the attribute starts with 'get' if item.startswith('getViews'): # Get the plugin name plugname = item[len('getViews'):].lower() # Get the plugin instance plugin = self._plugins[plugname] if hasattr(plugin, 'get_json_views'): # The method get_views exist, return it return getattr(plugin, 'get_json_views') else: # The method get_views is not found for the plugin raise AttributeError(item) elif item.startswith('get'): # Get the plugin name plugname = item[len('get'):].lower() # Get the plugin instance plugin = self._plugins[plugname] if hasattr(plugin, 'get_stats'): # The method get_stats exist, return it return getattr(plugin, 'get_stats') else: # The method get_stats is not found for the plugin raise AttributeError(item) else: # Default behavior raise AttributeError(item) def load_modules(self, args): """Wrapper to load: plugins and export modules.""" # Init the plugins dict self._plugins = collections.defaultdict(dict) # Load the plugins self.load_plugins(args=args) # Init the export modules dict self._exports = collections.defaultdict(dict) # Load the export modules self.load_exports(args=args) # Restoring system path sys.path = sys_path def _load_plugin(self, plugin_script, args=None, config=None): """Load the plugin (script), init it and add to the _plugin dict""" # The key is the plugin name # for example, the file glances_xxx.py # generate self._plugins_list["xxx"] = ... name = plugin_script[len(self.header):-3].lower() try: # Import the plugin plugin = __import__(plugin_script[:-3]) # Init and add the plugin to the dictionary if name in ('help', 'amps', 'ports'): self._plugins[name] = plugin.Plugin(args=args, config=config) else: self._plugins[name] = plugin.Plugin(args=args) except Exception as e: # If a plugin can not be log, display a critical message # on the console but do not crash logger.critical("Error while initializing the {} plugin ({})".format(name, e)) logger.error(traceback.format_exc()) def load_plugins(self, args=None): """Load all plugins in the 'plugins' folder.""" for item in os.listdir(plugins_path): if (item.startswith(self.header) and item.endswith(".py") and item != (self.header + "plugin.py")): # Load the plugin self._load_plugin(os.path.basename(item), args=args, config=self.config) # Log plugins list logger.debug("Available plugins list: {}".format(self.getAllPlugins())) def load_exports(self, args=None): """Load all export modules in the 'exports' folder.""" if args is None: return False header = "glances_" # Transform the arguments list into a dict # The aim is to chec if the export module should be loaded args_var = vars(locals()['args']) for item in os.listdir(exports_path): export_name = os.path.basename(item)[len(header):-3].lower() if (item.startswith(header) and item.endswith(".py") and item != (header + "export.py") and item != (header + "history.py") and args_var['export_' + export_name] is not None and args_var['export_' + export_name] is not False): # Import the export module export_module = __import__(os.path.basename(item)[:-3]) # Add the export to the dictionary # The key is the module name # for example, the file glances_xxx.py # generate self._exports_list["xxx"] = ... self._exports[export_name] = export_module.Export(args=args, config=self.config) # Log plugins list logger.debug("Available exports modules list: {}".format(self.getExportList())) return True def getAllPlugins(self, enable=True): """Return the enable plugins list. if enable is False, return the list of all the plugins""" if enable: return [p for p in self._plugins if self._plugins[p].is_enable()] else: return [p for p in self._plugins] def getExportList(self): """Return the exports modules list.""" return [e for e in self._exports] def load_limits(self, config=None): """Load the stats limits (except the one in the exclude list).""" # For each plugins, call the load_limits method for p in self._plugins: self._plugins[p].load_limits(config) def update(self): """Wrapper method to update the stats.""" # For standalone and server modes # For each plugins, call the update method for p in self._plugins: if self._plugins[p].is_disable(): # If current plugin is disable # then continue to next plugin continue # Update the stats... self._plugins[p].update() # ... the history self._plugins[p].update_stats_history() # ... and the views self._plugins[p].update_views() def export(self, input_stats=None): """Export all the stats. Each export module is ran in a dedicated thread. """ # threads = [] input_stats = input_stats or {} for e in self._exports: logger.debug("Export stats using the %s module" % e) thread = threading.Thread(target=self._exports[e].update, args=(input_stats,)) # threads.append(thread) thread.start() def getAll(self): """Return all the stats (list).""" return [self._plugins[p].get_raw() for p in self._plugins] def getAllAsDict(self): """Return all the stats (dict).""" return {p: self._plugins[p].get_raw() for p in self._plugins} def getAllExports(self): """ Return all the stats to be exported (list). Default behavor is to export all the stat """ return [self._plugins[p].get_export() for p in self._plugins] def getAllExportsAsDict(self, plugin_list=None): """ Return all the stats to be exported (list). Default behavor is to export all the stat if plugin_list is provided, only export stats of given plugin (list) """ if plugin_list is None: # All plugins should be exported plugin_list = self._plugins return {p: self._plugins[p].get_export() for p in plugin_list} def getAllLimits(self): """Return the plugins limits list.""" return [self._plugins[p].limits for p in self._plugins] def getAllLimitsAsDict(self, plugin_list=None): """ Return all the stats limits (dict). Default behavor is to export all the limits if plugin_list is provided, only export limits of given plugin (list) """ if plugin_list is None: # All plugins should be exported plugin_list = self._plugins return {p: self._plugins[p].limits for p in plugin_list} def getAllViews(self): """Return the plugins views.""" return [self._plugins[p].get_views() for p in self._plugins] def getAllViewsAsDict(self): """Return all the stats views (dict).""" return {p: self._plugins[p].get_views() for p in self._plugins} def get_plugin_list(self): """Return the plugin list.""" return self._plugins def get_plugin(self, plugin_name): """Return the plugin name.""" if plugin_name in self._plugins: return self._plugins[plugin_name] else: return None def end(self): """End of the Glances stats.""" # Close export modules for e in self._exports: self._exports[e].exit() # Close plugins for p in self._plugins: self._plugins[p].exit() glances-2.11.1/glances/stats_client.py000066400000000000000000000050421315472316100176760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """The stats server manager.""" import sys from glances.stats import GlancesStats from glances.globals import sys_path from glances.logger import logger class GlancesStatsClient(GlancesStats): """This class stores, updates and gives stats for the client.""" def __init__(self, config=None, args=None): """Init the GlancesStatsClient class.""" super(GlancesStatsClient, self).__init__(config=config, args=args) # Init the configuration self.config = config # Init the arguments self.args = args def set_plugins(self, input_plugins): """Set the plugin list according to the Glances server.""" header = "glances_" for item in input_plugins: # Import the plugin try: plugin = __import__(header + item) except ImportError: # Server plugin can not be imported from the client side logger.error("Can not import {} plugin. Please upgrade your Glances client/server version.".format(item)) else: # Add the plugin to the dictionary # The key is the plugin name # for example, the file glances_xxx.py # generate self._plugins_list["xxx"] = ... logger.debug("Server uses {} plugin".format(item)) self._plugins[item] = plugin.Plugin(args=self.args) # Restoring system path sys.path = sys_path def update(self, input_stats): """Update all the stats.""" # For Glances client mode for p in input_stats: # Update plugin stats with items sent by the server self._plugins[p].set_stats(input_stats[p]) # Update the views for the updated stats self._plugins[p].update_views() glances-2.11.1/glances/stats_client_snmp.py000066400000000000000000000105051315472316100207330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """The stats manager.""" import re from glances.stats import GlancesStats from glances.compat import iteritems from glances.logger import logger # SNMP OID regexp pattern to short system name dict oid_to_short_system_name = {'.*Linux.*': 'linux', '.*Darwin.*': 'mac', '.*BSD.*': 'bsd', '.*Windows.*': 'windows', '.*Cisco.*': 'cisco', '.*VMware ESXi.*': 'esxi', '.*NetApp.*': 'netapp'} class GlancesStatsClientSNMP(GlancesStats): """This class stores, updates and gives stats for the SNMP client.""" def __init__(self, config=None, args=None): super(GlancesStatsClientSNMP, self).__init__() # Init the configuration self.config = config # Init the arguments self.args = args # OS name is used because OID is differents between system self.os_name = None # Load AMPs, plugins and exports modules self.load_modules(self.args) def check_snmp(self): """Chek if SNMP is available on the server.""" # Import the SNMP client class from glances.snmp import GlancesSNMPClient # Create an instance of the SNMP client clientsnmp = GlancesSNMPClient(host=self.args.client, port=self.args.snmp_port, version=self.args.snmp_version, community=self.args.snmp_community, user=self.args.snmp_user, auth=self.args.snmp_auth) # If we cannot grab the hostname, then exit... ret = clientsnmp.get_by_oid("1.3.6.1.2.1.1.5.0") != {} if ret: # Get the OS name (need to grab the good OID...) oid_os_name = clientsnmp.get_by_oid("1.3.6.1.2.1.1.1.0") try: self.system_name = self.get_system_name(oid_os_name['1.3.6.1.2.1.1.1.0']) logger.info("SNMP system name detected: {}".format(self.system_name)) except KeyError: self.system_name = None logger.warning("Cannot detect SNMP system name") return ret def get_system_name(self, oid_system_name): """Get the short os name from the OS name OID string.""" short_system_name = None if oid_system_name == '': return short_system_name # Find the short name in the oid_to_short_os_name dict for r, v in iteritems(oid_to_short_system_name): if re.search(r, oid_system_name): short_system_name = v break return short_system_name def update(self): """Update the stats using SNMP.""" # For each plugins, call the update method for p in self._plugins: if self._plugins[p].is_disable(): # If current plugin is disable # then continue to next plugin continue # Set the input method to SNMP self._plugins[p].input_method = 'snmp' self._plugins[p].short_system_name = self.system_name # Update the stats... try: self._plugins[p].update() except Exception as e: logger.error("Update {} failed: {}".format(p, e)) else: # ... the history self._plugins[p].update_stats_history() # ... and the views self._plugins[p].update_views() glances-2.11.1/glances/stats_server.py000066400000000000000000000037231315472316100177320ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """The stats server manager.""" import collections from glances.stats import GlancesStats class GlancesStatsServer(GlancesStats): """This class stores, updates and gives stats for the server.""" def __init__(self, config=None, args=None): # Init the stats super(GlancesStatsServer, self).__init__(config=config, args=args) # Init the all_stats dict used by the server # all_stats is a dict of dicts filled by the server self.all_stats = collections.defaultdict(dict) def update(self, input_stats=None): """Update the stats.""" input_stats = input_stats or {} # Force update of all the stats super(GlancesStatsServer, self).update() # Build all_stats variable (concatenation of all the stats) self.all_stats = self._set_stats(input_stats) def _set_stats(self, input_stats): """Set the stats to the input_stats one.""" # Build the all_stats with the get_raw() method of the plugins return {p: self._plugins[p].get_raw() for p in self._plugins if self._plugins[p].is_enable()} def getAll(self): """Return the stats as a list.""" return self.all_stats glances-2.11.1/glances/thresholds.py000066400000000000000000000062751315472316100173720ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """ Thresholds classes: OK, CAREFUL, WARNING, CRITICAL """ import sys class GlancesThresholds(object): """Class to manage thresholds dict for all Glances plugins: key: Glances stats (example: cpu_user) value: Threasold* instance """ threshold_list = ['OK', 'CAREFUL', 'WARNING', 'CRITICAL'] def __init__(self): self.current_module = sys.modules[__name__] self._thresholds = {} def get(self, stat_name=None): """Return the threshold dict. If stat_name is None, return the threshold for all plugins (dict of Threshold*) Else return the Threshold* instance for the given plugin """ if stat_name is None: return self._thresholds if stat_name in self._thresholds: return self._thresholds[stat_name] else: return {} def add(self, stat_name, threshold_description): """Add a new threshold to the dict (key = stat_name)""" if threshold_description not in self.threshold_list: return False else: self._thresholds[stat_name] = getattr(self.current_module, 'GlancesThreshold' + threshold_description.capitalize())() return True # Global variable uses to share thresholds between Glances componants glances_thresholds = GlancesThresholds() class _GlancesThreshold(object): """Father class for all other Thresholds""" def description(self): return self._threshold['description'] def value(self): return self._threshold['value'] def __repr__(self): return str(self._threshold) def __str__(self): return self.description() def __cmp__(self, other): """Override the default comparaison behavior""" return self.value().__cmp__(other.value()) class GlancesThresholdOk(_GlancesThreshold): """Ok Threshold class""" _threshold = {'description': 'OK', 'value': 0} class GlancesThresholdCareful(_GlancesThreshold): """Careful Threshold class""" _threshold = {'description': 'CAREFUL', 'value': 1} class GlancesThresholdWarning(_GlancesThreshold): """Warning Threshold class""" _threshold = {'description': 'WARNING', 'value': 2} class GlancesThresholdCritical(_GlancesThreshold): """Warning Threshold class""" _threshold = {'description': 'CRITICAL', 'value': 3} glances-2.11.1/glances/timer.py000066400000000000000000000040601315472316100163210ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """The timer manager.""" from time import time from datetime import datetime # Global list to manage the elapsed time last_update_times = {} def getTimeSinceLastUpdate(IOType): """Return the elapsed time since last update.""" global last_update_times # assert(IOType in ['net', 'disk', 'process_disk']) current_time = time() last_time = last_update_times.get(IOType) if not last_time: time_since_update = 1 else: time_since_update = current_time - last_time last_update_times[IOType] = current_time return time_since_update class Timer(object): """The timer class. A simple chronometer.""" def __init__(self, duration): self.duration = duration self.start() def start(self): self.target = time() + self.duration def reset(self): self.start() def get(self): return self.duration - (self.target - time()) def set(self, duration): self.duration = duration def finished(self): return time() > self.target class Counter(object): """The counter class.""" def __init__(self): self.start() def start(self): self.target = datetime.now() def reset(self): self.start() def get(self): return (datetime.now() - self.target).total_seconds() glances-2.11.1/glances/web_list.py000066400000000000000000000111241315472316100170100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Manage the Glances web/url list (Ports plugin).""" from glances.compat import range, urlparse from glances.logger import logger class GlancesWebList(object): """Manage the Web/Url list for the ports plugin.""" _section = "ports" _default_refresh = 60 _default_timeout = 3 def __init__(self, config=None, args=None): # web_list is a list of dict (JSON compliant) # [ {'url': 'http://blog.nicolargo.com', # 'refresh': 30, # 'description': 'My blog', # 'status': 404} ... ] # Load the configuration file self._web_list = self.load(config) def load(self, config): """Load the web list from the configuration file.""" web_list = [] if config is None: logger.debug("No configuration file available. Cannot load ports list.") elif not config.has_section(self._section): logger.debug("No [%s] section in the configuration file. Cannot load ports list." % self._section) else: logger.debug("Start reading the [%s] section in the configuration file" % self._section) refresh = int(config.get_value(self._section, 'refresh', default=self._default_refresh)) timeout = int(config.get_value(self._section, 'timeout', default=self._default_timeout)) # Read the web/url list for i in range(1, 256): new_web = {} postfix = 'web_%s_' % str(i) # Read mandatories configuration key: host new_web['url'] = config.get_value(self._section, '%s%s' % (postfix, 'url')) if new_web['url'] is None: continue url_parse = urlparse(new_web['url']) if not bool(url_parse.scheme) or not bool(url_parse.netloc): logger.error('Bad URL (%s) in the [%s] section of configuration file.' % (new_web['url'], self._section)) continue # Read optionals configuration keys # Default description is the URL without the http:// new_web['description'] = config.get_value(self._section, '%sdescription' % postfix, default="%s" % url_parse.netloc) # Default status new_web['status'] = None new_web['elapsed'] = 0 # Refresh rate in second new_web['refresh'] = refresh # Timeout in second new_web['timeout'] = int(config.get_value(self._section, '%stimeout' % postfix, default=timeout)) # RTT warning new_web['rtt_warning'] = config.get_value(self._section, '%srtt_warning' % postfix, default=None) if new_web['rtt_warning'] is not None: # Convert to second new_web['rtt_warning'] = int(new_web['rtt_warning']) / 1000.0 # Add the server to the list logger.debug("Add Web URL %s to the static list" % new_web['url']) web_list.append(new_web) # Ports list loaded logger.debug("Web list loaded: %s" % web_list) return web_list def get_web_list(self): """Return the current server list (dict of dict).""" return self._web_list def set_server(self, pos, key, value): """Set the key to the value for the pos (position in the list).""" self._web_list[pos][key] = value glances-2.11.1/glances/webserver.py000066400000000000000000000033341315472316100172100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Glances Web Interface (Bottle based).""" from glances.globals import WINDOWS from glances.processes import glances_processes from glances.stats import GlancesStats from glances.outputs.glances_bottle import GlancesBottle class GlancesWebServer(object): """This class creates and manages the Glances Web server session.""" def __init__(self, config=None, args=None): # Init stats self.stats = GlancesStats(config, args) if not WINDOWS and args.no_kernel_threads: # Ignore kernel threads in process list glances_processes.disable_kernel_threads() # Initial system informations update self.stats.update() # Init the Bottle Web server self.web = GlancesBottle(config=config, args=args) def serve_forever(self): """Main loop for the Web server.""" self.web.start(self.stats) def end(self): """End of the Web server.""" self.web.end() self.stats.end() glances-2.11.1/optional-requirements.txt000066400000000000000000000003751315472316100203270ustar00rootroot00000000000000bernhard bottle cassandra-driver couchdb docker elasticsearch influxdb kafka-python matplotlib netifaces nvidia-ml-py3 pika potsdb prometheus_client py-cpuinfo pymdstat pysnmp pystache pyzmq requests scandir; python_version < "3.5" statsd wifi zeroconf glances-2.11.1/pylint.cfg000066400000000000000000000166761315472316100152330ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Profiled execution. profile=no # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= [MESSAGES CONTROL] # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). disable=C,no-name-in-module [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Include message's id in output include-ids=no # Include symbolic ids of messages in output symbols=no # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=yes # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Add a comment according to your evaluation note. This is used by the global # evaluation report (RP0004). comment=no [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the beginning of the name of dummy variables # (i.e. not used). dummy-variables-rgx=_|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins=_ [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). ignored-classes=SQLObject # When zope mode is activated, add a predefined set of Zope acquired attributes # to generated-members. zope=no # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. generated-members=REQUEST,acl_users,aq_parent [FORMAT] # Maximum number of characters on a single line. max-line-length=80 # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [BASIC] # Required attributes for module, separated by a comma required-attributes= # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,apply,input # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression which should only match correct module level names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression which should only match correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Regular expression which should only match functions or classes name which do # not require a docstring no-docstring-rgx=__.*__ [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,string,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [CLASSES] # List of interface methods to ignore, separated by a comma. This is used for # instance to not check methods defines in Zope's Interface base class. ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs [DESIGN] # Maximum number of arguments for function / method max-args=5 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branchs=12 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception glances-2.11.1/requirements.txt000066400000000000000000000000161315472316100164740ustar00rootroot00000000000000psutil==5.3.0 glances-2.11.1/setup.py000077500000000000000000000070761315472316100147420ustar00rootroot00000000000000#!/usr/bin/env python import glob import os import re import sys from io import open from setuptools import setup, Command if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 3): print('Glances requires at least Python 2.7 or 3.3 to run.') sys.exit(1) # Global functions ################## with open(os.path.join('glances', '__init__.py'), encoding='utf-8') as f: version = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", f.read(), re.M).group(1) if not version: raise RuntimeError('Cannot find Glances version information.') with open('README.rst', encoding='utf-8') as f: long_description = f.read() def get_data_files(): data_files = [ ('share/doc/glances', ['AUTHORS', 'COPYING', 'NEWS', 'README.rst', 'CONTRIBUTING.md', 'conf/glances.conf']), ('share/man/man1', ['docs/man/glances.1']) ] return data_files def get_install_requires(): requires = ['psutil>=2.0.0'] if sys.platform.startswith('win'): requires.append('bottle') return requires class tests(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): import subprocess import sys for t in glob.glob('unitest.py'): ret = subprocess.call([sys.executable, t]) != 0 if ret != 0: raise SystemExit(ret) raise SystemExit(0) # Setup ! setup( name='Glances', version=version, description="A cross-platform curses-based monitoring tool", long_description=long_description, author='Nicolas Hennion', author_email='nicolas@nicolargo.com', url='https://github.com/nicolargo/glances', license='LGPLv3', keywords="cli curses monitoring system", install_requires=get_install_requires(), extras_require={ 'action': ['pystache'], 'browser': ['zeroconf>=0.17'], 'cloud': ['requests'], 'cpuinfo': ['py-cpuinfo'], 'chart': ['matplotlib'], 'docker': ['docker>=2.0.0'], 'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch', 'influxdb>=1.0.0', 'kafka-python', 'pika', 'potsdb', 'prometheus_client', 'pyzmq', 'statsd'], 'folders': ['scandir'], # python_version<"3.5" 'gpu': ['nvidia-ml-py'], # python_version=="2.7" 'ip': ['netifaces'], 'raid': ['pymdstat'], 'snmp': ['pysnmp'], 'web': ['bottle', 'requests'], 'wifi': ['wifi'] }, packages=['glances'], include_package_data=True, data_files=get_data_files(), cmdclass={'test': tests}, test_suite="unitest.py", entry_points={"console_scripts": ["glances=glances:main"]}, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console :: Curses', 'Environment :: Web Environment', 'Framework :: Bottle', 'Intended Audience :: Developers', 'Intended Audience :: End Users/Desktop', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Topic :: System :: Monitoring' ] ) glances-2.11.1/snap/000077500000000000000000000000001315472316100141545ustar00rootroot00000000000000glances-2.11.1/snap/snapcraft.yaml000066400000000000000000000013171315472316100170230ustar00rootroot00000000000000name: glances version: '2.11.1' summary: Glances an Eye on your system. A top/htop alternative. description: | Glances is a cross-platform monitoring tool which aims to present a maximum of information in a minimum of space through a curses or Web based interface. It can adapt dynamically the displayed information depending on the user interface size. grade: stable confinement: strict apps: glances: command: bin/glances plugs: - network parts: glances: plugin: python source: https://github.com/nicolargo/glances.git bottle: plugin: python source: https://github.com/bottlepy/bottle.git docker: plugin: python source: https://github.com/docker/docker-py.git glances-2.11.1/sonar-project.properties000066400000000000000000000011111315472316100201110ustar00rootroot00000000000000# Required metadata sonar.projectKey=glances sonar.projectName=Glances sonar.projectVersion=2.7 # Path to the parent source code directory. # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. # Since SonarQube 4.2, this property is optional if sonar.modules is set. # If not set, SonarQube starts looking for source code from the directory containing # the sonar-project.properties file. sonar.sources=glances # Language sonar.language=py # Encoding of the source code sonar.sourceEncoding=UTF-8 # Additional parameters #sonar.my.property=value glances-2.11.1/tox.ini000066400000000000000000000005301315472316100145240ustar00rootroot00000000000000# Tox (http://tox.testrun.org/) is a tool for running tests # Install: # pip install tox # Run: # tox [tox] #envlist = py27 envlist = py27, py35 [testenv] deps = flake8 requests psutil bottle commands = python unitest.py python unitest-restful.py python unitest-xmlrpc.py #flake8 --exclude=build,.tox,.git glances-2.11.1/uninstall.sh000077500000000000000000000006151315472316100155650ustar00rootroot00000000000000#!/bin/sh if [ $(id -u) -ne 0 ]; then echo -e "* ERROR: User $(whoami) is not root, and does not have sudo privileges" exit 1 fi if [ ! -f "setup.py" ]; then echo -e "* ERROR: Setup file doesn't exist" exit 1 fi python setup.py install --record install.record for i in $(cat install.record); do rm $i done echo -e "\n\n* SUCCESS: Uninstall complete." rm install.record glances-2.11.1/unitest-all.sh000077500000000000000000000001201315472316100160040ustar00rootroot00000000000000#!/bin/bash set -ev ./unitest.py && ./unitest-restful.py && ./unitest-xmlrpc.py glances-2.11.1/unitest-restful.py000077500000000000000000000163451315472316100167560ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # Glances - An eye on your system # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Glances unitary tests suite for the RESTful API.""" import shlex import subprocess import time import numbers import unittest from glances import __version__ from glances.compat import text_type import requests SERVER_PORT = 61234 URL = "http://localhost:%s/api/2" % SERVER_PORT pid = None # Unitest class # ============== print('RESTful API unitary tests for Glances %s' % __version__) class TestGlances(unittest.TestCase): """Test Glances class.""" def setUp(self): """The function is called *every time* before test_*.""" print('\n' + '=' * 78) def test_000_start_server(self): """Start the Glances Web Server.""" global pid print('INFO: [TEST_000] Start the Glances Web Server') cmdline = "python -m glances -w -p %s" % SERVER_PORT print("Run the Glances Web Server on port %s" % SERVER_PORT) args = shlex.split(cmdline) pid = subprocess.Popen(args) print("Please wait 5 seconds...") time.sleep(5) self.assertTrue(pid is not None) def test_001_all(self): """All.""" method = "all" print('INFO: [TEST_001] Get all stats') print("HTTP RESTful request: %s/%s" % (URL, method)) req = requests.get("%s/%s" % (URL, method)) self.assertTrue(req.ok) def test_002_pluginslist(self): """Plugins list.""" method = "pluginslist" print('INFO: [TEST_002] Plugins list') print("HTTP RESTful request: %s/%s" % (URL, method)) req = requests.get("%s/%s" % (URL, method)) self.assertTrue(req.ok) self.assertIsInstance(req.json(), list) self.assertIn('cpu', req.json()) def test_003_plugins(self): """Plugins.""" method = "pluginslist" print('INFO: [TEST_003] Plugins') plist = requests.get("%s/%s" % (URL, method)) for p in plist.json(): print("HTTP RESTful request: %s/%s" % (URL, p)) req = requests.get("%s/%s" % (URL, p)) self.assertTrue(req.ok) if p in ('uptime', 'now'): self.assertIsInstance(req.json(), text_type) elif p in ('fs', 'percpu', 'sensors', 'alert', 'processlist', 'diskio', 'hddtemp', 'batpercent', 'network', 'folders', 'amps', 'ports', 'irq', 'wifi', 'gpu'): self.assertIsInstance(req.json(), list) elif p in ('psutilversion', 'help'): pass else: self.assertIsInstance(req.json(), dict) def test_004_items(self): """Items.""" method = "cpu" print('INFO: [TEST_004] Items for the CPU method') ilist = requests.get("%s/%s" % (URL, method)) for i in ilist.json(): print("HTTP RESTful request: %s/%s/%s" % (URL, method, i)) req = requests.get("%s/%s/%s" % (URL, method, i)) self.assertTrue(req.ok) self.assertIsInstance(req.json(), dict) print(req.json()[i]) self.assertIsInstance(req.json()[i], numbers.Number) def test_005_values(self): """Values.""" method = "processlist" print('INFO: [TEST_005] Item=Value for the PROCESSLIST method') print("%s/%s/pid/0" % (URL, method)) req = requests.get("%s/%s/pid/0" % (URL, method)) self.assertTrue(req.ok) self.assertIsInstance(req.json(), dict) def test_006_all_limits(self): """All limits.""" method = "all/limits" print('INFO: [TEST_006] Get all limits') print("HTTP RESTful request: %s/%s" % (URL, method)) req = requests.get("%s/%s" % (URL, method)) self.assertTrue(req.ok) self.assertIsInstance(req.json(), dict) def test_007_all_views(self): """All views.""" method = "all/views" print('INFO: [TEST_007] Get all views') print("HTTP RESTful request: %s/%s" % (URL, method)) req = requests.get("%s/%s" % (URL, method)) self.assertTrue(req.ok) self.assertIsInstance(req.json(), dict) def test_008_plugins_limits(self): """Plugins limits.""" method = "pluginslist" print('INFO: [TEST_008] Plugins limits') plist = requests.get("%s/%s" % (URL, method)) for p in plist.json(): print("HTTP RESTful request: %s/%s/limits" % (URL, p)) req = requests.get("%s/%s/limits" % (URL, p)) self.assertTrue(req.ok) self.assertIsInstance(req.json(), dict) def test_009_plugins_views(self): """Plugins views.""" method = "pluginslist" print('INFO: [TEST_009] Plugins views') plist = requests.get("%s/%s" % (URL, method)) for p in plist.json(): print("HTTP RESTful request: %s/%s/views" % (URL, p)) req = requests.get("%s/%s/views" % (URL, p)) self.assertTrue(req.ok) self.assertIsInstance(req.json(), dict) def test_010_history(self): """History.""" method = "history" print('INFO: [TEST_010] History') print("HTTP RESTful request: %s/cpu/%s" % (URL, method)) req = requests.get("%s/cpu/%s" % (URL, method)) self.assertIsInstance(req.json(), dict) self.assertIsInstance(req.json()['user'], list) self.assertTrue(len(req.json()['user']) > 0) print("HTTP RESTful request: %s/cpu/%s/3" % (URL, method)) req = requests.get("%s/cpu/%s/3" % (URL, method)) self.assertIsInstance(req.json(), dict) self.assertIsInstance(req.json()['user'], list) self.assertTrue(len(req.json()['user']) > 1) print("HTTP RESTful request: %s/cpu/system/%s" % (URL, method)) req = requests.get("%s/cpu/system/%s" % (URL, method)) self.assertIsInstance(req.json(), dict) self.assertIsInstance(req.json()['system'], list) self.assertTrue(len(req.json()['system']) > 0) print("HTTP RESTful request: %s/cpu/system/%s/3" % (URL, method)) req = requests.get("%s/cpu/system/%s/3" % (URL, method)) self.assertIsInstance(req.json(), dict) self.assertIsInstance(req.json()['system'], list) self.assertTrue(len(req.json()['system']) > 1) def test_999_stop_server(self): """Stop the Glances Web Server.""" print('INFO: [TEST_999] Stop the Glances Web Server') print("Stop the Glances Web Server") pid.terminate() time.sleep(1) self.assertTrue(True) if __name__ == '__main__': unittest.main() glances-2.11.1/unitest-xmlrpc.py000077500000000000000000000136011315472316100165670ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # Glances - An eye on your system # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Glances unitary tests suite for the XML-RPC API.""" import json import shlex import subprocess import time import unittest from glances import __version__ from glances.compat import ServerProxy SERVER_PORT = 61234 URL = "http://localhost:%s" % SERVER_PORT pid = None # Init the XML-RPC client client = ServerProxy(URL) # Unitest class # ============== print('XML-RPC API unitary tests for Glances %s' % __version__) class TestGlances(unittest.TestCase): """Test Glances class.""" def setUp(self): """The function is called *every time* before test_*.""" print('\n' + '=' * 78) def test_000_start_server(self): """Start the Glances Web Server.""" global pid print('INFO: [TEST_000] Start the Glances Web Server') cmdline = "python -m glances -s -p %s" % SERVER_PORT print("Run the Glances Server on port %s" % SERVER_PORT) args = shlex.split(cmdline) pid = subprocess.Popen(args) print("Please wait...") time.sleep(1) self.assertTrue(pid is not None) def test_001_all(self): """All.""" method = "getAll()" print('INFO: [TEST_001] Connection test') print("XML-RPC request: %s" % method) req = json.loads(client.getAll()) self.assertIsInstance(req, dict) def test_002_pluginslist(self): """Plugins list.""" method = "getAllPlugins()" print('INFO: [TEST_002] Get plugins list') print("XML-RPC request: %s" % method) req = json.loads(client.getAllPlugins()) self.assertIsInstance(req, list) def test_003_system(self): """System.""" method = "getSystem()" print('INFO: [TEST_003] Method: %s' % method) req = json.loads(client.getSystem()) self.assertIsInstance(req, dict) def test_004_cpu(self): """CPU.""" method = "getCpu(), getPerCpu(), getLoad() and getCore()" print('INFO: [TEST_004] Method: %s' % method) req = json.loads(client.getCpu()) self.assertIsInstance(req, dict) req = json.loads(client.getPerCpu()) self.assertIsInstance(req, list) req = json.loads(client.getLoad()) self.assertIsInstance(req, dict) req = json.loads(client.getCore()) self.assertIsInstance(req, dict) def test_005_mem(self): """MEM.""" method = "getMem() and getMemSwap()" print('INFO: [TEST_005] Method: %s' % method) req = json.loads(client.getMem()) self.assertIsInstance(req, dict) req = json.loads(client.getMemSwap()) self.assertIsInstance(req, dict) def test_006_net(self): """NETWORK.""" method = "getNetwork()" print('INFO: [TEST_006] Method: %s' % method) req = json.loads(client.getNetwork()) self.assertIsInstance(req, list) def test_007_disk(self): """DISK.""" method = "getFs(), getFolders() and getDiskIO()" print('INFO: [TEST_007] Method: %s' % method) req = json.loads(client.getFs()) self.assertIsInstance(req, list) req = json.loads(client.getFolders()) self.assertIsInstance(req, list) req = json.loads(client.getDiskIO()) self.assertIsInstance(req, list) def test_008_sensors(self): """SENSORS.""" method = "getSensors()" print('INFO: [TEST_008] Method: %s' % method) req = json.loads(client.getSensors()) self.assertIsInstance(req, list) def test_009_process(self): """PROCESS.""" method = "getProcessCount() and getProcessList()" print('INFO: [TEST_009] Method: %s' % method) req = json.loads(client.getProcessCount()) self.assertIsInstance(req, dict) req = json.loads(client.getProcessList()) self.assertIsInstance(req, list) def test_010_all_limits(self): """All limits.""" method = "getAllLimits()" print('INFO: [TEST_010] Method: %s' % method) req = json.loads(client.getAllLimits()) self.assertIsInstance(req, dict) self.assertIsInstance(req['cpu'], dict) def test_011_all_views(self): """All views.""" method = "getAllViews()" print('INFO: [TEST_011] Method: %s' % method) req = json.loads(client.getAllViews()) self.assertIsInstance(req, dict) self.assertIsInstance(req['cpu'], dict) def test_012_irq(self): """IRQS""" method = "getIrqs()" print('INFO: [TEST_012] Method: %s' % method) req = json.loads(client.getIrq()) self.assertIsInstance(req, list) def test_013_plugin_views(self): """Plugin views.""" method = "getViewsCpu()" print('INFO: [TEST_013] Method: %s' % method) req = json.loads(client.getViewsCpu()) self.assertIsInstance(req, dict) def test_999_stop_server(self): """Stop the Glances Web Server.""" print('INFO: [TEST_999] Stop the Glances Server') print("Stop the Glances Server") pid.terminate() time.sleep(1) self.assertTrue(True) if __name__ == '__main__': unittest.main() glances-2.11.1/unitest.py000077500000000000000000000304771315472316100152760ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # Glances - An eye on your system # # Copyright (C) 2017 Nicolargo # # Glances is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Glances is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Glances unitary tests suite.""" import time import unittest from glances.main import GlancesMain from glances.stats import GlancesStats from glances import __version__ from glances.globals import WINDOWS, LINUX from glances.outputs.glances_bars import Bar from glances.compat import PY3, PY_PYPY from glances.thresholds import GlancesThresholdOk from glances.thresholds import GlancesThresholdCareful from glances.thresholds import GlancesThresholdWarning from glances.thresholds import GlancesThresholdCritical from glances.thresholds import GlancesThresholds # Global variables # ================= # Init Glances core core = GlancesMain() # Init Glances stats stats = GlancesStats() # Unitest class # ============== print('Unitary tests for Glances %s' % __version__) class TestGlances(unittest.TestCase): """Test Glances class.""" def setUp(self): """The function is called *every time* before test_*.""" print('\n' + '=' * 78) def test_000_update(self): """Update stats (mandatory step for all the stats). The update is made twice (for rate computation). """ print('INFO: [TEST_000] Test the stats update function') try: stats.update() except Exception as e: print('ERROR: Stats update failed: %s' % e) self.assertTrue(False) time.sleep(1) try: stats.update() except Exception as e: print('ERROR: Stats update failed: %s' % e) self.assertTrue(False) self.assertTrue(True) def test_001_plugins(self): """Check mandatory plugins.""" plugins_to_check = ['system', 'cpu', 'load', 'mem', 'memswap', 'network', 'diskio', 'fs', 'irq'] print('INFO: [TEST_001] Check the mandatory plugins list: %s' % ', '.join(plugins_to_check)) plugins_list = stats.getAllPlugins() for plugin in plugins_to_check: self.assertTrue(plugin in plugins_list) def test_002_system(self): """Check SYSTEM plugin.""" stats_to_check = ['hostname', 'os_name'] print('INFO: [TEST_002] Check SYSTEM stats: %s' % ', '.join(stats_to_check)) stats_grab = stats.get_plugin('system').get_raw() for stat in stats_to_check: # Check that the key exist self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) print('INFO: SYSTEM stats: %s' % stats_grab) def test_003_cpu(self): """Check CPU plugin.""" stats_to_check = ['system', 'user', 'idle'] print('INFO: [TEST_003] Check mandatory CPU stats: %s' % ', '.join(stats_to_check)) stats_grab = stats.get_plugin('cpu').get_raw() for stat in stats_to_check: # Check that the key exist self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) # Check that % is > 0 and < 100 self.assertGreaterEqual(stats_grab[stat], 0) self.assertLessEqual(stats_grab[stat], 100) print('INFO: CPU stats: %s' % stats_grab) @unittest.skipIf(WINDOWS, "Load average not available on Windows") def test_004_load(self): """Check LOAD plugin.""" stats_to_check = ['cpucore', 'min1', 'min5', 'min15'] print('INFO: [TEST_004] Check LOAD stats: %s' % ', '.join(stats_to_check)) stats_grab = stats.get_plugin('load').get_raw() for stat in stats_to_check: # Check that the key exist self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) # Check that % is > 0 self.assertGreaterEqual(stats_grab[stat], 0) print('INFO: LOAD stats: %s' % stats_grab) def test_005_mem(self): """Check MEM plugin.""" stats_to_check = ['available', 'used', 'free', 'total'] print('INFO: [TEST_005] Check MEM stats: %s' % ', '.join(stats_to_check)) stats_grab = stats.get_plugin('mem').get_raw() for stat in stats_to_check: # Check that the key exist self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) # Check that % is > 0 self.assertGreaterEqual(stats_grab[stat], 0) print('INFO: MEM stats: %s' % stats_grab) def test_006_swap(self): """Check MEMSWAP plugin.""" stats_to_check = ['used', 'free', 'total'] print('INFO: [TEST_006] Check SWAP stats: %s' % ', '.join(stats_to_check)) stats_grab = stats.get_plugin('memswap').get_raw() for stat in stats_to_check: # Check that the key exist self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) # Check that % is > 0 self.assertGreaterEqual(stats_grab[stat], 0) print('INFO: SWAP stats: %s' % stats_grab) def test_007_network(self): """Check NETWORK plugin.""" print('INFO: [TEST_007] Check NETWORK stats') stats_grab = stats.get_plugin('network').get_raw() self.assertTrue(type(stats_grab) is list, msg='Network stats is not a list') print('INFO: NETWORK stats: %s' % stats_grab) def test_008_diskio(self): """Check DISKIO plugin.""" print('INFO: [TEST_008] Check DISKIO stats') stats_grab = stats.get_plugin('diskio').get_raw() self.assertTrue(type(stats_grab) is list, msg='DiskIO stats is not a list') print('INFO: diskio stats: %s' % stats_grab) def test_009_fs(self): """Check File System plugin.""" # stats_to_check = [ ] print('INFO: [TEST_009] Check FS stats') stats_grab = stats.get_plugin('fs').get_raw() self.assertTrue(type(stats_grab) is list, msg='FileSystem stats is not a list') print('INFO: FS stats: %s' % stats_grab) def test_010_processes(self): """Check Process plugin.""" # stats_to_check = [ ] print('INFO: [TEST_010] Check PROCESS stats') stats_grab = stats.get_plugin('processcount').get_raw() # total = stats_grab['total'] self.assertTrue(type(stats_grab) is dict, msg='Process count stats is not a dict') print('INFO: PROCESS count stats: %s' % stats_grab) stats_grab = stats.get_plugin('processlist').get_raw() self.assertTrue(type(stats_grab) is list, msg='Process count stats is not a list') print('INFO: PROCESS list stats: %s items in the list' % len(stats_grab)) # Check if number of processes in the list equal counter # self.assertEqual(total, len(stats_grab)) def test_011_folders(self): """Check File System plugin.""" # stats_to_check = [ ] print('INFO: [TEST_011] Check FOLDER stats') stats_grab = stats.get_plugin('folders').get_raw() self.assertTrue(type(stats_grab) is list, msg='Folders stats is not a list') print('INFO: Folders stats: %s' % stats_grab) def test_012_ip(self): """Check IP plugin.""" print('INFO: [TEST_012] Check IP stats') stats_grab = stats.get_plugin('ip').get_raw() self.assertTrue(type(stats_grab) is dict, msg='IP stats is not a dict') print('INFO: IP stats: %s' % stats_grab) @unittest.skipIf(not LINUX, "IRQs available only on Linux") def test_013_irq(self): """Check IRQ plugin.""" print('INFO: [TEST_013] Check IRQ stats') stats_grab = stats.get_plugin('irq').get_raw() self.assertTrue(type(stats_grab) is list, msg='IRQ stats is not a list') print('INFO: IRQ stats: %s' % stats_grab) @unittest.skipIf(not LINUX, "GPU available only on Linux") def test_013_gpu(self): """Check GPU plugin.""" print('INFO: [TEST_014] Check GPU stats') stats_grab = stats.get_plugin('gpu').get_raw() self.assertTrue(type(stats_grab) is list, msg='GPU stats is not a list') print('INFO: GPU stats: %s' % stats_grab) @unittest.skipIf(PY3, True) @unittest.skipIf(PY_PYPY, True) def test_094_thresholds(self): """Test thresholds classes""" print('INFO: [TEST_094] Thresholds') ok = GlancesThresholdOk() careful = GlancesThresholdCareful() warning = GlancesThresholdWarning() critical = GlancesThresholdCritical() self.assertTrue(ok < careful) self.assertTrue(careful < warning) self.assertTrue(warning < critical) self.assertFalse(ok > careful) self.assertTrue(ok == ok) self.assertTrue(str(ok) == 'OK') thresholds = GlancesThresholds() thresholds.add('cpu_percent', 'OK') self.assertTrue(thresholds.get(stat_name='cpu_percent').description() == 'OK') def test_095_methods(self): """Test mandatories methods""" print('INFO: [TEST_095] Mandatories methods') mandatories_methods = ['reset', 'update'] plugins_list = stats.getAllPlugins() for plugin in plugins_list: for method in mandatories_methods: self.assertTrue(hasattr(stats.get_plugin(plugin), method), msg='{} has no method {}()'.format(plugin, method)) def test_096_views(self): """Test get_views method""" print('INFO: [TEST_096] Test views') plugins_list = stats.getAllPlugins() for plugin in plugins_list: stats_grab = stats.get_plugin(plugin).get_raw() views_grab = stats.get_plugin(plugin).get_views() self.assertTrue(type(views_grab) is dict, msg='{} view is not a dict'.format(plugin)) def test_097_attribute(self): """Test GlancesAttribute classe""" print('INFO: [TEST_097] Test attribute') # GlancesAttribute from glances.attribute import GlancesAttribute a = GlancesAttribute('a', description='ad', history_max_size=3) self.assertEqual(a.name, 'a') self.assertEqual(a.description, 'ad') a.description = 'adn' self.assertEqual(a.description, 'adn') a.value = 1 a.value = 2 self.assertEqual(len(a.history), 2) a.value = 3 self.assertEqual(len(a.history), 3) a.value = 4 # Check if history_max_size=3 is OK self.assertEqual(len(a.history), 3) self.assertEqual(a.history_size(), 3) self.assertEqual(a.history_len(), 3) self.assertEqual(a.history_value()[1], 4) self.assertEqual(a.history_mean(nb=3), 4.5) def test_098_history(self): """Test GlancesHistory classe""" print('INFO: [TEST_098] Test history') # GlancesHistory from glances.history import GlancesHistory h = GlancesHistory() h.add('a', 1) h.add('a', 2) h.add('a', 3) h.add('b', 10) h.add('b', 20) h.add('b', 30) self.assertEqual(len(h.get()), 2) self.assertEqual(len(h.get()['a']), 3) h.reset() self.assertEqual(len(h.get()), 2) self.assertEqual(len(h.get()['a']), 0) def test_099_output_bars_must_be_between_0_and_100_percent(self): """Test quick look plugin. > bar.min_value 0 > bar.max_value 100 > bar.percent = -1 > bar.percent 0 > bar.percent = 101 > bar.percent 100 """ print('INFO: [TEST_099] Test progress bar') bar = Bar(size=1) bar.percent = -1 self.assertLessEqual(bar.percent, bar.min_value) bar.percent = 101 self.assertGreaterEqual(bar.percent, bar.max_value) def test_999_the_end(self): """Free all the stats""" print('INFO: [TEST_999] Free the stats') stats.end() self.assertTrue(True) if __name__ == '__main__': unittest.main()

S>ohm)mt#(/=tQtxZ)>z`hiлi**I*ɛW7*N๜))w8+"Y/[֐Km1btZ7Ĕc̬QkUTJEjQ8p8UN9(e1Ҍ4yW'Yq!ƕ\Hb^1KWZA[XTXy%\q Xs-\bev7^gJw{7{%SE%`&`FXSuavfeb/8c]a\?9dC~gA9eWFٙf YbgُeOb:h~ ,b3hR#lԨ 5 ZfC . fà8 ad5=Fl.ʈ"%ڑLB)p:\%:j-&C&Y Iĩߞj>/ )^*abȡԉ[jԢ}-VtN룿2 j`Ěj@Ì^^(i6)a4Ҿ/ :Sd`K.1.MxKˬ\.J.6, H%AFi90Ph11@TП BP +A7dA6"4D!hȈRD!5Qj5,f$ QEQF<,|!U#!kpÌ4T&эF*j XȆJp$R4&/ɏR1fM,d64DrJP>TA0TFYQ0!K>C`4-S C6R`*X^Ǩ *RM&T/ɭ\ًW^1,s!ƢF6,W83&8m[*E9 bu˝1^ S$̞ħ:vN~fX@jrԠ-XД dYDq3}L3B7auTS@7sby9,qB9i:am yp cÄlgA02 E;V)(K9㕣%,1o^9F+jQ`P8DYeTnSM1i,lN5#Lǐgb~!7 ozs() rg?'wZ^1OZZHu#:-;hM2\ Duѝ;d6:QH>#;!/m2#H1HS°l!L*Y<ȒR:=H7`]$pA8\prl,\2q 9 ;뀇;! DCιJH& DEQlvm <6,j!dfZKjn816јA)?Kç+-DZ7x3h87=XD}SЃEX28HN\Ap ĺ9̑`E09HH4Ȋ\䊩!EP D:;8Y4 @iĪƪ>SDKT oٜKH؃;pwtG切w<5(Y|G}"Q.0y "Ȃ4ȃDȂ/3=t`=?@t=!/(0 !!$ &BI+++U~\["c#;-Y#\!{/OdhcT2Aj$HAYETC ˰4[^niUZbKc0kMm)˺a#'V@%$$$N;RQ{/ÆY$z}+tui,Lvٵ!2I5T6T7ؔ(sQ0nàqMy5)XDw۩<HNHo̍LD*FOŴ@p܍K`S4ŏ4œ 4\ I^Oh @FPe4h>X Cuƭ 3F%Ǒ ϶CŶ+ sDtGx$QHw4B~.Hy UMȄ pp"1ֻI ("(m"(HɔlI,\[It3##!?. #1L-q?"KJ\D[hK1JMJ4TQɤmY\hKuK˺To oA 6qiф<ܴU%!'dЄ([mL+,`R{L꧊2aUeEC]u͕M٤CSjiS\D$dlN|Nο,\4P ] XO|ϙEXE ^O$bD P`УPƞ"m%-33XmnP{%O nFhHMG}|55Q]Qyzڡ=l `"==#!YCH?H ҭLI,RlI)>0 1 #L4u J9#0S=e2ATA-TJUxo,8vwη_ Y8Pϑ+++3؃E؜c|X`0Z KF9DZ73`] PGr4>4Ҡ PHGG=MQxYEzGYZ Ơ 5 0%'֡1)ڐH۰XhM[e[Yx2[6]#Uc8Ww˳.! \ʫ\$K>N@%SVpc\TL5&mGnqRC ]d"TB=Md#NlڵUy5xyoV\U^;i]NC6^ral mޯ֫9ğ _mNFl@xHloD0:F*ډ`@NZW抒P8`ہWwe:(Pg\ЬClFfos`8Y4 =ht}d||Y隭haI. FτGo{Ahٙmp&钎pYp ' o p ƀ'jwZADqj *q (uq<5j:fA6ѿ1yy1J)*+KH-K1s[dv[;YRv'l傢v'S(ӭ$L%$OsnAL$ˌNSswzpx'FB(CwgSBGll\\]59tMGNotrmjM8\6h#aj(:jȅYΝ2׭alާ$JxΟOd=&MVN*gs?'&R +1xwLk@V#K*n8*蝇ǘ#jb +++آ.B,Oٌ&Oc6C*P+NĠ*=B4V2 )VH(B*51"F52ƁI0*%%)FPQ$}ݹ8D KX)4A13Ԧ2O{$/e2E(*1j\#()\4Tre*/)^X9G/D0pU oD+# ƫ8/8&:J"9HְU,6Ģ]9J6!"EJiH FB& rk\Z/s\&E`0ipla/f&Ʋ mc;5d%ʴuMLb V6H ٬fٳ{~L!JS.Zi򧐲!$f ^~ЊAH0\*-h#ZhEh6^x/V5 hAD)[D`8(S> *L4ҕ>򤨅$ Z20:FQIαq )( a@/x +bM4c 1*)H!1e"c8[̢[,jcc-v+ɫSGSp/ y@e9呎ԷC01hQ 5!9)`83lеDC@q0X`9#`H8 Ny@-{6(TH5˰9*\e @WE,BaP SX)`E;V8T1d#iyJ A/wpǂra7JT RY1^ICFK 6M-&1(P#uLd$9i4!4#7XJV$[HeUEV_§M~W[db&cYxCܜ ^l>mL?\e/ߕH,cv  Kt [jwiba {ئYlv>=&Β7cfJvfwp.7m^ZA292Ԥ&K $֚+*@ ib૊luG'컑& b@Q"℈;a -&X i=RΧ32bآjo cEC7đ8amPyK3TZ刣.x Y˪ 酈k-G[(U »(U1n n' "54kxZxqR,vR"/:HgZ.( bȞ Og~H@8f8A@e# 7KF5r xҡq , n ᠱ`]ޅx6 aZXQCqa'jo_%0<]Ȥc y߮ a,qx aA^pH} g 5q7"183?X41 Y ËX54YpĘ]ጁ#Q#i3i[ 5Dm AlBؖcYຠ /)Bꍍ1ţ)D IB9<"HSA!5dp|dm҄W^tS̀ r!ԮSA.!UYhl[I02H 0\B.əCA i_r9IO򟍙I cBfd"`v [+8 ej"Y`ؖ4x<715H6Vjc 'eCA21Ԍ9LbÐ!fb#V( LtKZCv8xp̣B7QCas:`sD2I%[\tI Gl!=0(L'ވ$V h&=FMC8 RR@Au04̂,mE(8E9E-)".DZl bRJZl 2,d x D0  1,JK&iJ#3Rlk ͪ5RΪ5" 5;3tjK2r*"<[8 BZ'3mc ,{C+{jCz-{;)0\}NB,;%2K/X<[H@*,۱3 2(0TTDVMK|@Z2N=C/DEKhM)N^4 ,h+2ϡJKf9-.N/N)*ubYmun/4reTgD#`3--):5c:HHh)tG_6݂/?VVq4ti9$"W($@N橂34lpQ:-3A0ԏJtu1SdVf3j6䌰 - P3QbH05@Ɏx_O[ UJVp3X6[p kqA[2STC%eL^Q & QX!8dPhJe8<2$Ɣ1\t29*hʕYý3-mQ;q M8'0|7c^ҸS8mSϸ>C6LMՋ#.(,P@oA]xMDG8)1xѐN@'Rwp::R1 X/d58BH4V#*uHR^^#)WRE:~\*tF 3gCAE;/zh/ʵp0u4>:1H${Tbx,#~m-{ujBhh6.CuxvDWkDW94ACj;IC 7^n 8hۂA}vPwwPT^GqR13}GaI*w#\Ku_=uIͷ%Z=0SHQ~ϟX` 9`VQ(W=]8y-fJ$iD݅%wఒ,; MgAA:wA: *rI-Cj+L(sKR&M_!&b(bF/wu+ ) μe1eP~1PBI&Q0gBP;QhĔρ -CMTEӕG!TI)>TӁOA 5T/HRQMS9WMbWiu/dZiU_y-(>IVE`C gYiU#6eC[6#8q%sDumEаyy׎}X)>XYI6Ә)xI 9?nsIKIYe/ܗaymijqX]y!6rYYs Nin駝>Ajz^D z!#%YfIn'3nb^J{o0 +/< o|qX \)|r"T,,3L ]яY3d%T`-2H6x7u߈/> @W4cx[PW6c^aC ߤ GߔV|CQdsP e_?}Żǣ|_r!A NWM'P#(-S`C>R!51lRlTD # Ud5+gѪⴜ,8l[23W5 w ^"׽Ey^G%uD2&1^  21^c[00~(Zr2/Ne5VuE z#v J3e ʧI'p 5Yk Am!'B!LapG!<%ơShM* e,f29tE,NuZ1Kl8̼!=Iݬ3ӋlB3o1: (h'=oG`7ե51P96 b7sLH 󥏦DstQ/_J@SLGB,^1qR"UU ~W;Jy њVcmukpqCb~C@+^1щm⯊Ն(J 6pEmf[Y"5Fͮkj^zqnQ+0[D¤4\l3'%0"ς2,[,a-FSNWeb9Kf@!lB@p,au~!bx <4ߦP.Vp,'n;:3 'jO >{AkPTL,P"j;yԢqF\sB#1(,ґW**XVǬؓ@zڔ:i+JљUMG@$ym  n]*+6U10%,kRV59Nou' gȕ,W= |k_ 6VZ;,bACMf/6W\0Mݎ-dՖkQ̑i%Y\fV'\=bZn)K9]R̺.^]Yr̀׸K(tl01T!Av}pӿ#I6]+@(|H* S8ёtYaYt=b+uI5]ʊ Y{ zZ`hDʰUg=ʤ߻q1^ յ>\.ק!o5k XO}H^lc#yqW#, :XUܾ ʈ3-`xMlUbiURZ;XB} 573 wM0-l`}?ߕ]օ'\t )%7^ 7d%L5;cŒc.l·x,.VǺ(*`ڇ̨LjŌ.p0鼊^R,N^ P0 -.SP>) ̮~(lUH NWn6i X~n&M2+] ( P/4>q+fa&~+ ^\x lR&x ~F핞K! eaĭKoݼ/pĩq0ormK>6xp'E,0#9,l@ncc<0>P g{v 4}G^ANȖ!l瞌Gct#A }|O\a]%5%eR&&m 51 h>( N 0RV-Wd PAk Hf.0q\/ō+ϵp 8c?o/9F ,ӀXTohcFLG) iT ]є`qfnҁlQpL"4x}Qܰ,FB*I/xƏq8IR 19/@r`#3S!"ls"n%jvvd#G0~D9& €>*ʢ೧FΟ(Z |gI,d"G;!+<9<| TLAf?;r,J#!*$5tC|H$$Y DQE&YEt y'0 κ 2R)NUHW+.W`Ґ4W~m ]\-\rm@H& TMVmb:ÜSQ0CtbVMx+TdAzKKEvPAE%f#L0U#T&"J!Tg`3UQi %@"b!0B# B b5B!4k#ġrH 5a3ܨ ̂6-6*k( @3Sr(8a B|WgנT3B1H0g:Sl"vP$O+45N&"Pzl# QS5!&L Ds|qChā+=lgr}RpI0B/R4B'ȨJ8ti{ DC4OVrIp Xv vjQEk%Fcf< aj4mf RT|Gӎ)I*Q))IeؐgK+ TJ ^T, ^[2cf4%Odc|Og!Mx/!"scuqaAA&7dvqWwe!!Q' fywy/!zCewTea UoQ!y7}b1!y{R7/NՕ&jq! GYژYuoIM 'jP"6ovADTz- dA vWwM~L}7AD344Bqi;~#5΢cg3f7yJ® tj!<B#g'$lhYPhFh7D~6CN|DvE!ekYlctlAV ,m Y1GAϊR),M 6nͰUc9W0 Pawpw_J˲`fråKy,7LK`Хh!8@]+f7P0_*Q*~fAh^YG(Ҳ ڠ:ege9:|TU1 c}Sai6TU4A]j֗ *B! J$LB#2ll".D&W4fyzZŭ1+o7x@ R"~hf0`(>u FN!"x~Z=+"3(;["8@#@G P#4h(A<" 6J/"DZ86!9"tgp6Z!AcD+aB<]{FóCRV=8D!Q:!nhn0yf<9CL˔V$DD9֑!PvFț5Ymv `GO9TH)}oY ocE7 ryY o؀dt٘rkfRrEr)|2›-=ȍH f@78؅dk 2T9 ҙNah zt|g PA,^~ Gq.ilM>{y3EWһe> s2lw [A3FWom!GEyny K%fYWR7Z7^qϒdf&W~'K^,ۅƨsA&U3zasb]rn:y\h"Z_A#0{w _aʟU0UMb@W;|@WD ڢ,A!j N&l u}eF'=%(=sRa @Aa@[w`x3[b)1:1nҁ`+5'2Pm( l qeG BE2BCȢiE8!iD# mA (ІmmK fhbIK &2I i:b9!Ns:KOSX(.PӢZѪR˥X+8xCjPJ`K *V΀6,g5 2,XɊ$ f-V@$thtȖ -a! NhD$+a/{K_:0 ` fa4| lXL$@2@.dɎ͖Lf*, ΔSe%s4uĝ8<) 5(Ұ-O!I?'I(ILЄ:4lK [XD,(mLې6ha3rH ް$laes`"]Nw1{8b'c\x ocRB^TcR<ޘy1pgbyNqG{˫׾Yy"t𱐍lp ZAM44Z肂p# vCh@Bq`Ciwj"6'1j&9=dP!14u6% :~s ,Q6Q^!,XSf } Q!;{! rW`m&cnf XTv:;aM 7 VQq o=wQWpzp8C?aWXpXX!q8>w !'rdjsr*'A rZztbDMbtKf>tvCt\Ph`TwRW]U&P&o,~u`g(CGDbBv|dEz$ОY 8Sx "" YZ )Ax %؊ꊯJs\%ubrDB&܅'O'C v''paeWv|bgգRroGutwq) DXrG xNZ*`bFȐX'} ]x$>BZJAc1٦.Pdo Lr:' ?y&Pd""Pd~ZdPA."\`PQc~SM2f~Ui b9 0cƗ: 7B0ʪژ'Kxi97?yi-k6 *=Cx96@  0mfnjVɇԣJo!WV ؙmŝiWp9`>x?KP t !!`"8ERrZW"t\ETR%:+\>CTB7teDJd&i¢=;~BRKm'6:bYctF@jwEE_ Gw~DK*\OڤS)X[ʥBb`T7LRX[(-%{"1Pkꦌ`"3 IxvM"P۩gVkW gTf"C!20K*oѮƑkq S>6 S*a 7(Q+Ac=Ӫ7: ! npJQ𺅞pۛo{VSV 8X ɹY_A[sP8Z  p :D?CO J%a%Fk]FDxrY2e$Ubp#y 9Xµa_{(](Fr)x qWB:*MNzTJV;ypDb ejJ)bjJ1˸1駫D~.<ɔL`' %c 4Ms2&ɰkg21QHO0@>˷;̋I˂ yߑRH05z+j eQz =lWZy l@ Q=\s@qXԱp̰1q+‘e%L (|,"j@[l,r-B ]48Z}l[ID%Pm? ׁx \ޑxqq i)(2X0hBZ9rjC娶otp(Vbm<*Qm* !uul{\b_':ZsK?nȴDJ! "TLt1wə׹܄ʁpS-_ˌmi\B0hj潜mnيGtuWaa9~.۴,ݺ۔ЩtoQm}ݨ>pWgİ ўaRY M q*M߹P'̾"/1:| `Alҫs`& /d]Q%h ^TR^uɒStYfƉ)\2NeJJmwOz*"xD*㍲eGH6>]N]Kd<$d}#{Ez9&.gAɽ.? *3M3\2Rc2\2rjc<l>D?=٪ڪ*yoa |P*~X̭mMឨ  q; gංZ" DԥH=u&PB.O%en^b?^Yng0_)%?F+N)N:UmՋ+_~;NGւEL 0 bC%NPE5nh[VIHi #,1aYӦU9e̘0A cGIb`TSQ>UXn+$G,ieeiծeXTIOrٔ:/+›-.$H"aձi[V4B%jS*OoDfixݺ&رeφ-0mS"/f;p6ŊnRVsY2+SCM%u֫O߄z*r]GxDC9`?T B PDMT 3@8t;xQ6s=5UCSNဃ 808RUu6@USc:ruJ{V\cXb64\$Du6_ǙgM\fa$ 7u~Gdsu;^ȁ`WMd/]xI F(uT]YwisdIb?6Ӎ;ޅ\s{f {O@dN2f rgHY82Z`Ql6in'q;i\drJzl|I wQg"7z]nځjo~檭|p*%Ry,ȑl+.%XzRiE0ˋV6a$ښ 3,6A 5DKVqPKSwJsm8 vpZyLA/+)欏n{d3oɧNc<^=kq/=#@O*Db q g{P4#9jƉhhDኾ!lPGЎt{/<=sI0ґA0 D+IC ӜT>lRV'Iz0@aP,+T((EPr"6YRz21<1ST\U*Vhu-\jWx+\9XBC,k)[,,E@ŋ757юs̢7؆Αޤ9LXRQM.!١8geC/sAO|VW#qK6r rȡ!yς,Bg?!BqM#8lY؂%7!ZIP(a+Q(-M((h~6cfMaiSH Op` FMqbM;GfMpZJ#a0 вf8sёFPկFO-Ǒ ejg͜UwsM]IkNЦ1j6g ez\cc1i:љet3;,˳ ];}iCџY~~?ܮ'PnW4PzbKA PB$E%,a30HBHmf$YHC$'Q/&qIDȄnfE.Tũ.1Glئ8G+qch5C g-=r@0-g)P,Ft%Kj20 &| `@SjMRC#PK[h굴7O=Z*H RǸT4թvZf dLH FHQkH0JPaK ks a`ki^VɛK;W7$ m#! OW͑m {ySZ\O6hqÜzƺ*A] d e(&d[ :giZKk<`͟=_8tTO(f˞nm;G)>Qg*gZ톉>5=?I-0>0r҈O:&Wh|融 "xn6]m`M)¾S놷QF5hpjHjH%= q:GK_szљ!gLF_w0ш>ٱ v4G44 j$b==ڣOٓWi"$Ya;$1;BIBE4f@%ӱ"ۆ$%@dymp9) 4fXf%4k2S3$kj0;]8PqԳS#? e4)bB9c@e[,|JmHʏi0CBCЧXOPãYH5U%Us[@ĈU 1X, b r5 -X3l,46Dl 'x6OLB m6UtJ27XDL(Z,b`+  q8b7u˟ż8[$SgqThh|۠Ń;2N` ɞĒ9Z+zo[ 9qn1:_%!Cۄ;&p HϫvX*balØ mdB<mXcʆ+,,>gL akA0+*>{MDi-x?Ӱ30E#1Q@rlBJDR$<@:P&}ӃJ 4=؃aylEpD\22oI2Yb<Yrt1țwA^^9CЊ\C '"( ċ ҍp棞XG'M eDK$)D@)hO|6/ũ #hXE=u*[SEs3{ˆAhiAjFHbeaT IapCE\im(i aXF^4U{##3MP{{A=QS bJ̆w4M8ȄĩY*- T }A3;1V3(KWvd;YjeӊWk!ˁ ;W Y6V(=T:ǃXkRRspUЧTIڐeLKgY.}-b輾y<\MM?33 SM7xNN#)1>"$6Pd[S[{GaN,oF42g9DAo1YEP{gӵ%t-|\yQ*Ţtȥl%[P@32Ё Û^ٙiQxC@8PCRU_h_}_̀ 0_u_(0_" 1*UioPv-RR`98 ^|)Kdk 6m 8 Vfs# S~`@M &ShƤ$Sl$iybǼ@Y('x'Oq`11TU bm4\F^, "ƫ#{a "RZYViO1KxٻVg=? 3:V񘎬éXPHHsݻx=Tc(FFzhJJ^JݲTS W8мaJ}ed?^-lHe걐Ţ3L^=7N!l>hXfnH\jreY.;p>>,0[ ح>10)/qуP\xA([}hBGy[ k#ۼ(d@\Y)\p(܆N[ɝ\b92w)UO2AK2Чfхc|9%2xw93aZzQ$'n&o2#!ػ|qʧ$}b"D(EqX_u_~l-lþ_(;Ų `ҭl-CXXHPӘĿs 64ީPDD 2#@ES[H#2W47$0aQaq0(@V0hbp7qn"g %6Gpb(b*bTbO9`j 鎸3n .,HjV˺,p=c%S:VVb,4dO-JLVIgGFi OłׅReieE;VSeW\^qefc ``v#rfNeI.m%GkΏ)nSkHftfrY=}j! =<04Zg>+y,"> s+y.zBh0]vN3=xH C@0h@ %Q"^15iTia\j][eV@ $SU%g|'7q^iidm|ijpx.K3kK6Y6@Sjm\(d4.kk)W T&ѴN( }kk ml=l_1QXq l:lY*pR[L5^c ^8Ŋ_&h;uUT #07NlKYPU1XTVhH-ɠx΀&xǫ'Ԥn-`!oDoXUhVՉB9G 9d:pM`p:QsH :pgXJ|{?*W :Ŏz32qW] jMܗwp; XLdYm R O,rkvŤX/sK Rg6'!B%q6+!"*_55Xb, 2lH0F,ʹѣGqDԧ h)dI,&Mni%̘2_i&Μlvs'6A-J4NEy+)8?q9FӧAKhܱc,ٴi5}*NVDTe˫SpqM/`kҁm,Fq#Nō3".۰aU930um$ѧQ[]ag,6Xeht2wΏDmx-ѤM+/}t``G=sӮ.}v[A.*׳o [ȯo>_> Q2,t1*(5㈳ 7Aa,xᅰhˁj(omaAo*y0"/p#9#:F&7Kb-($M6iK+aAXi$cF4*L S&3.٠ wl{+`ʰ#+&+Ģ+o1ЖoKʨ. D˳iѦp3Ve}/5F Y7*xJKgsKs55b=8`mz ^/ݗM6f`N8t3C= sxSH~sY9^yB1$z.κ,]DAB9ԐH1GGsԇl{J*iAJTK'<[4ld=O> eTRm uTf%TsY\efCh,"hYg]eJsG\e8"]8 <.Ën,:PЅe W0Js@„E5KXH`60i prka :汎u괰pl` A p}#11@ HP*oOPC0D i;Nt!C Yr(5@0p<5(C# C"R*^$'HtYZO4ep$)JʘҶT/T6єHUØٸSP&O1\3OXT6(DE^xJ܂LdzBDN2UUdbEx3UD+^1VyР bPK06-Ӣ̲\8Ņ o4 2f;)B!}>C0#86f,%=Gܘ qc!1t<çelǼ̨CJ8ԛd*4yTBm~8c3Ҩ8^wU mZ׾W43vjKu[A?NU)߰*׶yPB\rlBB+1`CGγh,)D aH`uD !Cw;,/%cIKJO usWL'>pa{I^w}R?ݯ[ (_ h ./g@K|%,`9!QsI!vC03=·j.&hA1O rAcBe,(B5&$!e$kBx*  `7$"QrBARUҕDzI5H2))a &1Y=3R-A#Z|5E3:P|< iOlbҖ47q{x21 ox@JVT+fZm Vժf]\wb\S֯c*a`IXM.~N !6m;{3+=֪ywҝ~py{k7 ~p-;+ڒ3-<"Bj0fUB -CF9mHr7ܑ7yk^rSޤ%MLx+ wC,3 y^{|%.EӠu;xV/}5!"rᵳx|;d"6HP;(n1\6~^dF 82@xATrdXBPS!!T=2꽬zXŘ\'IJU f$!n޽>}>> MK͈n5FSߚD*MS)Ә־OMJYuX3pFC\mkS:/VK `m  A!+\VB|۹ Y֜ۼ. ~M3Л bM  BHA`V(!B@DtIlE8Tmݙ0JrTONN  ywMQO! {Z)h!yA__0]'j5܇ zޑX ^}d}@ *p/]RXP mޒqޘ R@}Ҏ`^ޒ 1ҕ 1!1'_!=~ڟ_0JI_$5d5qCߦuڧ_M#vƩ1&GZZZrdZLJBJK', L$![L9dF+OB+z`E9C^ R`1T+- v  1\HA ku봎 o(BC,V*%q!`F!NDuaDrxFXNځY"g__8h]1b#Cj%``k'ƦqAKqb* da+] G,~`e.ȍ/6g] Uт3,Ђw>#EYuHd6rt#181ɘI(^*Pɕ@ Ax=="_>>"_?N@>>_5I?B(5JGVZqv߆n_CbhĊ&xHJd_#EFjfhDê񟌢K$iM&̳IYO.j+|%[3T[ B張J+ D d%MWhE+@qV'C[BFAA)ڥC)^%DC,&\uYcbvyyW`]fffv&}Ahi&j-B E|݁$k&FfC+]p|D)rB sFsB'XV'1}ޅw"wz#$A]g({k8-~:㕸> Y߁_RT(hZ$"@dI,`B_(R_j(b$EZ&hҚd>,IdξdmMd0>)+Cz`J)`riSjd~)z \imzzD%t!Aݡ* .*a&\vmxU*XԐMxuj~*g2]PfF? " Wj/.l"BFO.6Di靰zqDZvA -B>QkX+X'.-x++x>Y*@y^H7&A*M{+|gzB # &l򡟠 =.4Af,d1FEZZ{MZ'DhɎEmF(!R)l K -;ph`M19Pv QRmg Zyqma׾ آar.WN l2AGAAGEsJŰ d +˸hI䰽L.VLUq^ *qNm՚ИQ:qB f)۽m 1 _eue|e)Bi88D x%X{"t\\ e.N mqC\1ESUĠC4 Kra8(:rd35Rr}88CW:mC*.C=45;#(NM0c?tta@b&B?l`2\@F,-IE Ad4q$e4*I`b$+ЬJGiEh)ZH> h)tM O4M>7Q2TOBNXRۭ85b^uM\cXh ]m}â|(/Z8AV%qjm]s!A)` @Dv.b3\`8cD6S`ZthaԐb,~O%S.[j/3E"j_7-LȐnorpcD9q088TwKM܂|M97H"L4Fp7wwwZC9l|8u@;|64D|@7_Y7z,_gp~X 830G`g1`hc:fZCx4.?JGflB`FUPCϾ5UƒB45) ɏdBd̂?H++Bt [=lʚʠ hd(KƠ+L:Q۴AHzn>9*[mX**Df^E͚s6tЙ+7їBb9vLG3 /LMVwҍk29s(9;pj@iqsqMp 6R]tb)RBk&Y,Pʆ{/)Xpྖr\h}`+'.UomKf͛9w֬thѣI&k286YAҰdwqxMn^kgcq;v\ӥ'~u]I9 {Ppq Նկ~IK!YCKG!`\PA^|B{1`xrKrXM̶;vށ̚9'-hQE $ " ?fI\R.8(4!MP0/,R-,1 2O$|S71Hv0RYeYr:Zl%bj1/AmeЂ^Y%&"z~HbOG[Os"Ԉ0]V{t('H3\GMż\Q`mlXbZFyiAV`b[E,yf&$mbhb2qz}1wsb% Mh\o$nvz1cYax fz槕'fRjXdG:8A "k0 #d‹k/zKy#ĔcGZB-\"1PqdA'A!JH 3. -q8SzK8+dWJɢ+kT˶0Eb EdQLoSPl-e~sU6gtZ3w-w TVuQ d[DyЗRWu7z>ÚK>,Vo|aZ /<&x *d^DXZ cⲡ%E]H B>f VJLA<(xx"R0F\!htnPE<R(.eF(鐱 $!b!hJ넆ОAi a풥::! .$N$b!%C% 4oPP<2XoqX2=(K*1TB/:b3?s@Џo֢g.bP"H08)-(C m`f.:5207`Đ,9Cda yv:>n}$ƃ>%ȣ|F#rNJIk떁 H$g2g@< TjC "$kj\N#5LnYMA ΤX4WgjfZXa&-.''clT̵&SlHΒ<)/*Qnr@+dT rUQ,(V--QO(>gK <6W!33'>@t6=ȃ@|CPC\w!C$6CFw  / n@DhE`.`{3gm"xGKnMHQ!`KPM܄c x."Ԥ~$'D. C `O KmrԁxlR!'L_SƩV@۔vWxAMO% U RAc1d!PU Q]X1̃M!ZaX EP4^E %,#]`R )(FCAU̓5ҋcxVN.X.vU(J$5dkXnfZO$ZǞ$ffUڮlTρem֕ oz N)̓2oq#+ TªoĒ!,%-a" '4k.]o^/1O6eavee Se!n!Ĺ HVAYf;f'-3 jzbˏoo~Z º־"lv6ph1Ԡbm0SnAcx88ЀTZ`5:}p۠`ZW Rqc9RН-Zik?i:3tPoġ,*Ý&siWh zyfvdz!qjˢ:7Bx/AB  ma+#Va3w b` nw{g@ /:F}0d}yzf[}M}d4ddD7!S~@Or-l1M%Eغw DV8 r8^B ΁uL@~%|W8a6q`fŅ8ui>%j[)'!ͺ8eJ82kf,:`kOyÉY_"S6ّB(tyaqD55!:⪸t![:*C ^wcA*+OǿP#ϞFfbaǛ^','=8aVg-L.A3re b!y002ymX$A]^h~bCr!@Zgi5kǢ/5,E8ЖcIM991Xz68H .A8 sps]s6Bjc6@݋zl?]<ރCתɇlhCad===7.a9\'%h^ xxCf?F\&i3H7{oW{3  P)ïӷ7JXBf|ÄKbKP=4w[SI]I؀XeAþK'ۚFȅa[I< p@28tf^" ![MؽY:$)]@ % Te;` jLS5p&+b>fTHg\0[.l\ƈP? RX5Ρ@^|aN@AY9g릡jF Ӫư&RgǰߟaʿfLO!!Kh&bq(oVq*ODt)opbsTTeܻteeU Qt*cƄbLb7EVZվ 6QS]l&Ly3Є>Z#ݹlp25ԩ&\XR8"ޚ6ر 5+-h6ܹtʝbW޽.@Ec}_S;~ 9X*[9sf-Zp9ѤK> >Z^ٴka;76m<87'r:0܎tw[~=aܻ{lѢD˛?<߇|Ξ{ѣrEGv!k .`>h%L""2Gqqv}b݇,dC X5cRL^-eU6R c>dBfAFdJ.YdN`bK83MZneTiK+T `f*jfnʛmJ*uI(L:CB0DH(JrL6H$q(Q$:)H(I+ +*b)RjM k>ALl+z2 l;1Ĵb L0@, mN&BLn2 kE m*knnb + *BpI)\)B0*\0 41| r",2QҐ rǯ0.L'QyP6ߌ3Q- =ó+E4QA9A1D? uQ;LSAktcTVU~Q.@9FXYcq[p5]r3 '@MY$w1WY?hM~Z -mlqm qaAǜC7uݱ}L{y|'s~{=ta.`o/# z(b!B>Z"fco?oA%Rٟ?$'! h ,uiK@ɄTrr+*8'; @ G6@L! zZ!$hH 3u[SԨL .+SZ!XEKVLa lXT"\u9 jQ2ŽΘ/SXkjrmԄn/;kJX/|+ {bl2vfjk$/Yqdd +v f4t*PT<{ER&o U\mi/+ ̪j,捸浯mT)7m0~`Ml ?0P )qkgc }&4=UÚKL5}@Hӹ61]cЄNz C쀝xI^.z߱GxiGoGTgy$ݏ:A^=o"#Uf ;ugdҾ(.|BT 5HGkjD$  ~LK_*E ci Ԋ bMSt𤸢p*<&\W\jRuTs Tj`㨪$pM8"cR]zEz Yl7wYc,3r[iEqQ]z[!U-B:c,qSLIF RUe+?ZqmgPRw5L0(slMT&qNzJ7bmޗ'XL !߱1|K:tt=`{F5SP?PzN6pnPPtq0T #GE4hrQ.+ Oc=(IS* 3g9`=^t)"٤h˖X`0n2jԉB;RS#&iGRj$ `ի|^|@nQa%F =Mm哟t¸Ps]ne 6j N"*؄J2l`5'JQ1^. Bk-/ދՄ-d/mElWv" Y/arQr'e'E?y+o Fx5-  ^S#Ys1baw#mM MS7QpPfh>q`r7)2r rrrrPā:3xqsvtB7t#HuAu:c:tPv}C>IȆ dgvq(gv~`pv5{C#efww{w#A$%@ x@yA_z`5h٢A+J`E`8ˆFW( {{*UD"XFXGj[ma%|,rj|kGΧ-flf}x}r}e[+'~}0Z[܆FD ΰ12ٲ213'8^]^ȏ؀T Y#1`8l3ps#_j0#8 PPNv8S.qVO4=Pr'r8&1W%V:ACd#Q`<ÄM#R8цQ)m(vA!2YZvv`S^_ttwC}pPps9FW>B b~g@jhm)@7Va(UhVV 6ysuz)-WzeH  7)͒piu*P.Q1+@@ kH([Fև+`mE} Gyɝ}C~B\IhrJ3 n%I(## ǀ9"  ߠ% 9  ye#597P7~M' ~`yq @ P %a AO4 $j`Om& 191#J HZ@s: ; .qI :cJp`S #CХqmKLda Xi!pYmv]\M1? _f֐D P~& @ %ghgDs{URq & mB &X%@VK×} D @.TV (H1BjI!ٰ,@π+---/*^\ l|tSN=YTPBeEh7vȝc N)R]ڹT]F}uժǞ;v`Agʲekl|}m\s*`cFXaPIFZrï:ZhҡG-Mc̝6샤ig ML7Lj>cHmݫuc+W.۵ӫOYtqʯI\eԥ/VܲjىzejLXkd &k蠧&X5V > ( /M4>$#hX0؄@MXHMljgG!1CAH$dI't|TQK/3L1T2Q13M5,7T\N;\O?4PA4 X2v *"yʗvyM=C-$bPNPcQG%TR8UWeUW_5VYWmV[MV\O8!ALT?#=qR9ۆN"ZiuAZZm][ob@K&AE0q"^,آa#z_~_RwՃ bb ;̓8h#!/Vq#Hy;b:aVanjd;B9ϙ%^d^Z[٥^s&cY(yg4sl(>l ^2e'u*K.oZcǤʚokG괦 <-_+_LF\NGt!z"'u)L,5'wق MfS(k)EyY&*!;Hg: o= /;;ۑ> /*& =(CR_StS4!BbbGl`rtz J2phP Q*H2d= !-IIPb *JW4&&6щdB )R1NmrS3'.֩c8> QflJ̘HpRTS#QY!U<5+BUUpHUW]( c" RPKDgӂ-RrSPo\8WܫXDu/^j-I85LbK #753a>2G c|XSb:DtPIP26vEˬi1Tb`ΑaXA sJhGSZ4PhQ96=$)yȃ.QM#b#ښQh;&7+sO.K({Qpf tcV%*q9*`Ht;S uQ]1v_j&>qLxq1 s,yMge` {r<݈1rg`@w1m–Ӕ& ƌ $R>pBR01M }m8Qp0՘m6L"E/Qb8(Ӊn5ґ8^ Et)4 'bOo|t&)֗M}rF~'g|p]l$*@>PN{^qG $ 5]$Vѐ.d"yWASRC5L8cPC!j01ph@KZ'NSFK+KtMB]ne]V'cOҋ^_JcB3&k:)lRq(dt^';9w1kph ojD;y3Ti襏&i Zk :І#ɃE1Q<5"!IHFrfa$[ņ8o. WrQb$iMwJsB$,v9qrb&5.FSAn0bHdbg;l" $0 *e*c%lbw)ka)[=yw,`Y5c&H=1O6ҷ(੎C?SBe3 -8nks2<`+! aB=+4 49rSlhC)Q7!$5Qh铣t>DwwNQ{s $½L{;x)bp%?(4^ 8Ԭэq EbD-F6Pa 0d{ķoTWUo#1ǎOxPgֶ|lU \J^i/Wb;V-O<}K%efò Q,CrHl!?@ Cs'i |@x L3kCۆ[( n=EqrAUV[5;Sa&\+)]8p?Acӿb knؿlX6p|xp`D g(m. LC< -)71us|w{sHY*>4׉D7˰ Kcpظ*Draȋ.je(먎&'y*cBj<ˆ$s-h:c: hBp,b躯ck9AɆTq ;;񺻻*"#"l"C4qcsɃȈC9 Eqq: kX*0Oɀ(P.0P#ܣɚ> >(Z_0?qKb 2s$ܖ꓾mq%>`2Y2nIqho%-lxQa(6kPiK?E9=h^@w95hhAӘ@ Ȇi@`xl(i@}zM#(9LК bKY[؃ms퓁$;e]kVW5n&D)8>VqWzmjBWzLwU_W%_Wh>M^ob^}-8ދɅ=hhz6ЃGk\;u_=Gv]ԔWbMňP8x֏N__<f-=vˆ` T2}.iC jVX1 &DE> *2[ +vͲ6yJV'Qnݦtv.ݺs)o"yk&MXKx1cŭLI亚:|&Ν;w -z4ҡNz5֮9*קQᾍ{7޾.\Əl9ΩQs֯cϮ};޹W/>.s璈2G{s؈/?< r/ߚ9x ",X, &W_:dAJHbСPb_h+(QP%ƀFL$ ..L1E)d KƀX@SBEV^Znѥ]#Yg af䂦si#tIGx'| (Q{q%eh SH"Zrک$|Ƒq8ᇭ⚫+p_y2BF˅VL!r-B,[+K*~kDB-!Dt\0F$tR+L'\941KaJ*%! GG"1I*L9lMaM93VL^sX{y(q*q\e)746EVJ+45cؚ8}gڪƶmovlw(2p{7p^+^3!'^<z1' ݈JGh ;E,2`ѡ>#BN;S{xr8 !33/338Q 25̗ 8ȋ1"8%<Ơ30\81PٿVja -O8QncwhS8Y9A&JL:qLN ґ6B4t*>BwF"XxY H@C%ˆ^4T)QaP1n=VqV53ΪWJE,[ KXpñp2q 99ѬeYCw\*eH/X S;>> QnH>f\U,.肄юA.Z%+宅!х{W,%$a҄5 ɆV2Ic.&CbL2qlhS\ 030+;ڹ0 Sh [oIR\׊1ISR쒤JI K2CXqZ5O*݂h!ŅgYk qcY]VA.adWB`S7ZLs2/[+ &BLqS&a%OAdBɛ`4)ƒcJy&Fʖ2p,YƢ)g{a2*Iϴp٧Әl ݅ _\ .)^1H41[aFF3MG6rc 1RQ5a ]jjS"2MMmj8$guNV[ӃzpdGx9G!1>eC<#vxH?HZMpPSCf-+Y;ԂRi%X ֶʏj4Z׼^yQf`3F!GiƏ`RI,d+1 NZ8iG';A12LLS.&lCZCy aZMy R/M=>uC<ܡX8Hh]6KB;c<do<9j) o'p`LNa`."a~%̓ \\K- ?]Œ[/|AXH| e"gÕ;WdIV1ӅIv0 ͊zͩA0AdE6;8hdqdd煞I}r֋z=N+ż$MҘ-$OΑNEeD%B@)%8e=%)LjFR*+6}Hz i KRdZ*87}~$z-dƤJiX@ª˭*jFܪ1t9B0Q&'YGKG(W߰nGD+Y` 1DTThPW1g,8_:pY -d>:fn½11EVp'ȓ)x2`eC_TʂC)‹f2F+0ZզaFŪn]HH1oT'rʚ7T3,̒4 }|g0x0Y4d@#wabB0m,@ާ~N*.%b%$vTO$⃲mHI0,AH%Όuz\ 834'VIfC5H6/887G"BE33C3~.!yBE/NB욇3]B x:W /82Y6ʊFoY^/WA|N4@ PG˲Ȃ>.HsEF4B9/ A4-čd)[Dx08Cp.#_g'uSp[G %Kp ӌ86dù,E*BUW9HdQqM?nN]LSg~s{]hB{Sm~FnqhM2+tdžJr);tG SZL*X{l $x'>!xxZxۯ%,'et Ǹ*w'R Cp-~ \C[-E Cj!=d@s85Smnn8p38WcËWCsMsYȳ34X%0T,хiܵ<œkA/i4y}Øʥl^JqCH+ :IJo>|K+ѭt68<P`[6Jy05d.^W4|K 5EA|=H^^Ë+z]DK0-``}Ee]+[]GYG48 3Ԅ0D*XaC-U0VXLjs'X6+ļkYrgh6E'4&1L1>fMilEmc*b<o1jppƦq{ Fnr,q87rBMuZu6!Vt7Tx~8hH2Ra6@yyGxƷgz cx8l[f@a-- "]$Txe݂/p" !B!i #zeU^V׸5ylus5$e>78-IOn#neCDNm,H2UtVת]y9ylU%@c >7l-Wyqi09<ӣ##HW!DҾ>ެ44d@*KJ*Ѳ5@\lc$D%aÄjd6Dr<,W.kbFsRIQ);pP`~4s8nN%LP|:hP!BTCԸi= uk׮Ax*$*FˎUGpI&!iPf65evU56n]ށ n 4b$+s6DmDshPYlQmĄI&nm۞ݼ{3!6RyJ ϐz,J/*or+{S'Xx~Tʎ邤͓]m Zqي g+bĖO 0VX)Ee뤻N P ! P0P 90NPI\9 QIQYlaQEWqqQGgqU!,"U9R%l';=c]NJB(*oԁs#x4 F sAuI D3b 45LLLE܅v|FK1TSL3 *qT)S3XhN} d}TT@EIc4xCYf)cMTGҲ1vYζIY:6ۉFTֺFne5r%v ]Mx ]6%oցq}D d8ڐ^p^6 bh^&=SD.b,ϑaIC^|d7'BXl]CwYӛ7=S=MAaNzqD Dl)5LG@M?.NmŎƏ2.c؅L31{nJl+ i I~f%xZ)q(ž3N癟8)CVυbRYJK$TGslΠ.Ck. =Ҝ{(';JcMQ!mR{Ŗ_K-٘lC, cYޠTBw( w6ࡩ1*cULX7إ9\0(.0/qxP:Ă4pbE4@ ͰBnx"#"lPQh(ED$=(ITRT#][|#mJT0uR<5ʑư(=Qj8 HAS2!Y+EfV*î&I,oN5 Z'A-n4)5hteGQ-` 4̐\A C1Gb`hTK^"$3_Fsdm%Gf7y3=,y؃9yNuSgx#4AS=9O`1f=6 nzsC5#ٴ(E:2 5D! P7+NRΡT :ǺA)K:fuC)W` <.MPp`wMuS{wBqABH6p)M4Є%7a&B>56Yjm͕}űρ(9}+rX;[5E})BXޕ e7!1 B-`)XJCkQ q2q[%QmqqI\4n+F.7VT"PKژ]nnI`1 KHWS HD}ؕ|EI7@:A&@^PŪ(*`r n@K-L+-(pe0 m q3%f =\4po\Ntl;NxEg>&nc,PNjSCܾ7d,Dh|\]HG)<*ms>&`-na Y:EV@)XJX }nH]K*nsNp VJI[y\2]" \Sܕ+eq%ԩ` pZZ,(V5l8'4-zERZ'| 6EݯRD,f]21.!Txܭxq$ ʻG? sd wSEdpe^Ih@)]Ha.i( fp+G!1y &t L6"ڐe)X4K6Gpܤcs긜;9w&d '"@(_wF@ThC2(Do׳9f5ta ^B5&esIy 'Eo ?)3}Q/􈶊hGebq^}|Oۜ5flXjSvִk_E|:U탴XbOؐ~q}d'وm)=Uz{ t8ng٭݂ (k@ᴋ.&0$D"N @LH.VbW n)L࿠ ``Yrafϕ~ )褐4l<,dΙJFfd® ojxF؎ P.mjx0JԠGJ(R4O|'>R!Fo(TK1s(+-jtm*Ԝ* 86oZO 8finA ׺îoͱﲖ PmJZ!ڑ %>$D#9?+@?rBrFR $K(лT2Bde& 84'Yh%Hxia(rEKpE`@Ĥ)2Fm *~+1L+)r FHdzbʐr`J .㲞KΞTN2 0m 03 A l!1#o#)SbÁ6rz7Ri9SK:QBWcٸX5P tH˳%P^@p@w XKSOܚۖFNyzdzKH0{%>ʗP@*N *p]|d ƋllR{M0~EE`~%ME< w`k7tHga{F[A` nD*xZA` |̠SaNC>%@6ZB >X*$A&>^G*%|袄Z6 A:8ρd #nl"%a !lp b ԛ hVE0md&1B[kf>4"D$!1NWx * `}B "#d! bʥ`2KO($sOonAHDY#j6Rm1aYdS15us7Ѫ6灀qg7yjEEw8;d(&IJT7# 籰AWQwMAu9|xux3$ZZA^ASd[ނ { 2(#1pФKX2F2(k 5P 5P5] I^+@V!U7RTTAPI{ ]O`*40}>' dRI b2.2"Nb t*yG.JR¶*vc[ՍN@ 2)san )b *#d~ YAʳH@{d`P"NnʶJZ &"xjS|[oBs~{!&wCԙ'T%'%`yb+##9 d!s!w42;>(,CS+@)2xB#4ywy 1`10b2G4 xzĪ4^q[#< ncRrKHi!5O l^4 t'RB# K3쵣=hك|f: ^v&< qu7ņE+affprDf!Q9ĈCH? \mȗWz p#rzK0K̂/(.a#i4 KxBB+} <]ߢ-:D5MZUDa0e@IVXJC(}A`{ "] f HaIc0", MÈ'2x;pgݹlSEȥkܹ11rԉ#XhJT9xމ#疦eL`ĆIta|cJFG3!$/6a#NPCa$$8 E<%7(M$d46a`ĥ_|NLўK+ iׅMLQ~x1L%(|(Ruȴ jY6鋋aDb5%q馛RhcB& &)ꛛh੍J̭.#,CL7~պ 3mÍܲ\۰ ༂+_ʵb(f *+~J3Τ뮻ͼB;*ઢ○,l0& 8P1aP`Ɗ#41$SK>Xa%7(y:WZ]Sc~ *?i 8ABNr0I5'|( Гp +MXx(I8$c FCm`hI&5MVd&fRhzB.V( Z_r3^&0AMk\b* O/i=5ґsGL UeU&0sbա#G#Ԕ.YTFLMUDVp+fą.]U8+XAMhZ-T|^bwl+ vWEzaDO@SFmLD%!R´hj/ -D7:3U@=iiF8jYּFS=lc8[yGKP@& YOV8H*Dŀ# ĺpXp&ua1n'{k P3E2Qn׫h Dx4`d';DF0(McĀ7qD# cJx$%$Ԍ#y< TPoʣ|*@:&h!Ecb$R$' 3Ơ$YJ%z".Ob)Gida M1I)jijlˏ'b '*Mz]*E+e9_zի%<4f\b'hq4^wZ̴=ٰ~z @/&2RC젛HGf*hԴ|Y*4^Z-)@QL$X3|XPS|NYM0b7E-lbQޠYELĻZO0t#F|2PRָu'YG"; %|}xV|İ>\Z ,ȼB q`Yy `a) PK1MrM8qu$|pDO>Dw N:K}"4H)M̧+͌KӘͬȤqIM",b P ,h+ձ 6hw~ hb`hĴ(i B ti&Ni O₟i&0j!1&P!12 Hq+kH343&k23l.#4dD2"4 F *p mV51@m0$:mrmR 'SxX@ c0dn~# V&0 AF`S zho&o&`0wf0 UF8. ;ϰ w919~8:vU +!1@Cq~1 x6 rQXr'<*GG3]z٠ب=AsEt?9>>ՑtK׎SSR7Tw[ue@GQ Ր a@G~\jv5]\a yzx7^{qax$K` x%|%9CDD2DyymI0ET4n \4b g $ד-&7I$BD%f{$cG% ~Fʗ rH֗HQI]dTJ )KdK6KKyT_I B bLy+zrL p"v!Nvi/O*iӂ0I0g : P2(X6$s-1I2mX"0VVPe#: 2 aKKu#SgivmS66Z!a4CF&y# qCvC$%u#B6'  0A9@Ca<+b9x9Q'J 9@;zbucXCq:X(9#Ŝ}!n).2qv \jA _Awiwwwu)~zA$ix` >'b ;:C%g,R{<" T`zA#z$aM@G DA(KYܑ0dfR_b + L`g'Bh' ( *Jx% {cj)xR0w٠" I`%bp-ҙ" i!&+ b<Ҁ.& ):N$i (xO ӛ090-%2I0Kf1 FX2,V3 QFxkHQP(Vض.R:B V$:m/ QQ3SSgSm~Pk6 5CFg#&mOQ`TP30:b`3 U@&@_{@7<~G"``A<:k 9sEWIJ/iӛ<mp~%G]jbU{Ѐӛq<Р5sGA_{{:C~auzY[כ d< Y{@\vHaV6 !Dzv, ^{  I!)9' *A *q_OҿdZ4a| T|#ۀa)5{iAKA I_\.-KPd I  {:<|_|9 ~z}%vV[^ϐJJX* bKL9ɚױe|YIqyp8 L;+=. i).DiH0O Լ|؜,>x9Q5cT[PXv k43+Ɔ넵1ύ6~\8V\ЃP];ѡk}ѭ+ppd"W&-:ћW!:s_a1]r/]r}pp<>ӵAL7~ZDjH,1lNu|`1KehϷ'k45#'~n-6~n#2O%13>6~h-Y .>9kNPtϬO 3OOܝޜ|kL(P@`A .dx|AS*l4G~ 9$ɐ_NL &NLq,9uӏ( @$Z( &eeS&N5*U"Ldz 'Ď%Yi՞ElΥ[w.x݋E[UaćuΖ2p$Or̙5o珁 9:ѩQVڵYϦ]6cYIw2 Sܸq.\,g|91rM>K ٗWwݡ'_~|( a$`l!_1' 4@HhA#&*l" 1B5 5 &,|Q09LM6 WjF_ %Mlo@0A\@oC2  Ahl[ Gь.j]ԠȆaS-l J%u' vL)UWKֻ[J8kǾ5Z7hw7 LAzs17*7Y&k*Ĭ!aa$9CIh`&j#Q :k%@|W0[ʥa7N?:*,3~s 4>2KH *73=3*ghTX T)H8IXB s8 sȆT\,F d2Y`t *h̆ɀ5ɀ8 ٠BY8A @ @@j6~S1Ƣ Y肨Y`IA#(Tl#,HgPЏ&tpL$1,)7155 $0TP1MYT'J{ԸlCM<T~cdȉ͆c&HM̅|ӭ[IQNҭF[R`Ɓ"ynG/>hfHp-qP>mxc884K`?hnMޠBtˏVožThK5` Y̕L56*P@P@<#I7LwsQ`غ9I)$M,*#px1XMfEO9IS/ܛ,¾lD !ك;YsVB07U}mώCl}̄ӹY@}T,gpʆl|?`lx-I-BZM`o0yCЧ%u.ۄ]^9FL<G[:TX-V&[%'W6pFj{Fܕ/LҺcRpR'+]g `!)oƓE`lPKG5] ?XS1SR˼^ʫNC<|Ā<]P^( (dM<G%*HI=J5 lhM%HpU{)01{0mA? VҌlt\-pJQ;@7e`tJ|*5Q#@5*mD=o G=wpWa[stM5MX \ YPz傓l.;}+WfT;ɣʼE@J}bX~ Bz#'X͢қ/NY8MTS5NMNSZ1b[L1pl ڦWh9bx#`8HC} rEΆIբRCбU0)KժBPխDtJ:KC䢮C<Dmfm%:WTfUZQVpVhDFMkm+^iЕzg;]; S]j/+G`[[#5a22yོ ϐڟhIʋ*^*ےn*dbMiٛ>4ߙ6 |?"n*xi_^Ƚ!TC 2`s7Rl('(hxl[>ȶ]~.7obAD[DNy ]f -QgjN­/n.q*|q.r;sFu'%w~az%Rm/XfZq ʅY^r&o1{A͆Ol?@r}|8*$I gp8ɝ6% T@Ms>7?I(v)[j57t:T  ,淶Pb\sp4BaLk2T>Jup8P$ha2Wpmlp*y#X4u>~ ubp8$$8m=:Bbb141mQMRy'Psym2w$AlMX{2>Zqm8LoqXtՂFxM-)N09j.[\7&Д/OGUS : ppiv\u*qW C*sq{fqjeI@aHF=1ikȆڐ޵/( >@'|`2h1J([J/G-WǧC|!kY~g sb[FM5 (8 =_j:O5*$< φA`PB0.HK63 4k̅GFl؂S5-P@-`*k@ 78u8 Be$lКsK jdxnـyO1\Tʋ.\<˚6mI'РBb(RjD" ,gΐQj*BB bk6r爉1RfӦc'z,]$';3nl7&a+HŬ[˷"7)dLr<z.\6O6mT~%,Zq/v6QRiy6͟1arT7ME wj -K:m8o Ll jB 6 j pʂX!vu#x")"- 18#2r#9꘣+쨣 9d=+G*i*L#>޸dݴs7܌MD9pfSM7[&p7mCLy'}'p"~"p(@ z[jr%8M,c|1^z*´*W\1E L0P {Ä\$:,k+ک8H kZK.eM6e71!us'bHKDA\[AvSAZD/DlEi~iN: F/A/ +\5757W!B/+;q, !bb XEb%lនFKE[ܕ XhKEX05G䌦QK=ԟơFͩZƨ 5,7@gC~|BENK̒ \G45^f+cxo6\SL2)Q;RWuF}F*HuȤW^m%U%o>9W6 8ـyN+bܕ^:;g8>ӄ%eI<.;)X57L+7FzѴ2~jrɆ*`gIm*xS|lg>_6xq#KjÄt7xTfA TBMp"8HJ 5rHD:Q\pD5!Q!QG;b'IE,b p)@alI-f:StQ1xC#d%xyz#(G9 N*,g,> `S~XHU\@) @u( H"WhƣjsN:eeNNȂ*= Jc-mevҴ8[HڥbVW6%/o,"[8F^na`c1f"OMS 2df/\9;c1`¶"o͞`WoZ8$lAZoRA$aHÍ(J6MHl0<6ZOj0k"AZNi19oFXB e(1DZ$  A4.x{(7#$qNz㻣9L}_旾/̧Dɠ#5d! ]I !PV$@IKV@]TW.q%Fֱ4ibUr q&Y,X1s|cS> \Dv 0e|*~h0D\nxhF?zT f6̜5SjU1}3懜aLbo p*i/{߈\Cq }Hp`ɤhZh0[V+KӼ69kn,bոia'?1ғcyYN:]˹z,*?Y  p8#\:&8dF;3.w4/ldQ:=žg](>I,*yIsOW0_Jo lC/Ϸ'mmUժf^cT7zur xbM+V~!tv"Pwmn?; }7?QuǝrpI)kyD9ġ㿢|{4">88  %%`UT ǁA h$Y =m- ܰ@ Ε  ֠ Z`  !  @,,!e ԓB!lA ;?}JUhΝY#]2HAٙ]DFd -]FʘP@G HȌ$ِ a @dK^!A>je Bԃ2%a b iR)N8neWOԙXTd4QDX%F\('^*'b'xB_J 濡 y#!"AQ&u)UuiRz<[t)Ltub&3ہ&f6kffl)Q &*vb&ercs\ȀUA`gnUj*{"yd|'gIKhj$B E)tVBVhIJBTNJ(p^%J+J&XWVP8,bW]nލ^Z\7P]i&޻uD`*H ~,Gricezʊ)1 cxp= )l+B憐[6⩾¾ g(-*c@}WImr.g"sƀ huhm`g٢-Xܦ*`'K{"H6C P°d.NY!d!+*^F>b.fX+bFɂ8+S++.kHZ~,J ,Zb§O]ҥgjmDC"!Bm&g%2)o0A_j/"~lbd)e)ɂdd4g_* ƯƩϒfP.py#k2m:m4nI7XDlp6&fgjf5\ yd ̰ P*]JdC LBi5L+D,dȀg}q+ H 8QيA9֘d1q@Cx1gCqDKf|opa)x038CK;fRf8b&.iQuiw pf& .HPmLMkrH NpN|yD@7C6L9mR/3/qCIN`,Ru;jvȌ0X4 PC7G4̇k5IZ<@ Xƨ0BXXd?hB:xq:G xDz6TeVc{Dv6 $ֽT@7ҼHS?8 S6Hu6˜A?]ԀE M`D5Ԁ;LvYN}AMJ2sMI6MJNNd/!G|H@ D0PN+]<ù6G īmӹӶʫ3}C*G [߂-8w@ DYXR7TbB]2?|;_U9a^uFgEJ_~nd>OfMPmnElFVm0LqWF({ +D!F{6`) t;C:C;XTpo/qLFPo拾ZUGZ&Eț{>[ēviLgyq#t *GtD<IYD|CN)E,MlF5lC? W'' p.?Q@# #1hpQ> s(9$Va4a NdH#?a>HD刡,reCp1WZ3wNrGPFq ܹ?_e\7v;ajjmDON=W#|=p5kX\gݹlWtஞcUWN/q|߇ 7[ +4P1x! $ - zCЫEMzM|x*(,pzA ΑƚmRCv{'x',)PyB șJ钔2Ii)GM832%06SjMqV&K&sMPyB uQW --mK5<-n؋%I?@UmKSc?,VZ7"n DN^aQM@UXM6Ye;jP Npr=7Q]uUyx块^UV|7z`}" (aqMa.`l *@(H>)H2̣7? h?Tx㠚ms& #frqdcZ9&*$萔ޒu9:kp† Ɗ:ϫ>`sJgc2)5C*-~D$R,*4)"Fl &0XCgŶhckM9 :ޢ|x5w9͏ێy\c \ ) +|gnm!|0)jF#EL2F E{DEWt*H)``4Jg 8Tpt&k" &$Ahg`$H*A``ICj #Г 5 PDW!z! sXTl `Xd*TJa 0(1Vx Xm+ۘʘ24sd MiV!A*@fs8x ACAmhX'6)@i|ZHyJ$WZհ l4GN$Ч1eH:}dn{`$?DEXA΁ q@P |[AW8 .b lu,R]궲:=57D! QXvq^UUCYp ?[Ox~ )]:ѩsG^` [RbXo (\@B`1`X6W: EEL5?1E6~0HI6NfCUS4DȦD݇4$F$6 !2Kix4&)+3u B^y*Ԃe* ዟxO^A)7BJV`J# ݑVLX{Az}O6U("M~ 9EV~nos2?_R`+f\,Cg)a؏Ġ6%J4&$hBHIRb&A"(#"0#ӂ*ED"@-$xJ+A"8`%~:&deDXMp+-bPP L^{zM(r-01r+@Z! y2 - "&PƐ sA jatԍ8߬ڢ 'VP.kA -q*Ġ /q "ڢ,%>n"t/K-a<GE4TncC 3>|.j|Ea< \Rj+6!MN넦No p%XĆH!!NH %Qbj+^cό'\EJ ڈ n hbneV&.0EQ Rb(eE:A$m/P Tx^Rԅ[llje]/(g'LCHdc F2ca20|"HкrP+ǬeVjد*/ #"qb.h)&fOn!.mF'l1Flt 2RBL-k$b2C2l'*3#c.@!4"$| N 4&c q3dٜa |B`A)  @ e8L` dt4Np@+6 Vo{NI}w'geLXKb&L.%iM&j h"qM!.NtKW4a^aw?,YV52EV/QVaAc.#I^#E*PjoNrYT҃KUW[\ Ve\H[ňZFHॅiǀl'S)XuXMׇ tXXu `҉ɏ', 1䕜@^`Ik،+Mf8+E78B(C3 }L4E Yto/H#V8$>$u `duqq`~G( rW{sj M{Y9MhDeeOYշLpO׊YQ^4!W4jeS)ҁsXVQE8Yš5P̃CZ̒R؄%a؅ax]\U=:WsՕx^rU戍Fac_x+hZQitGϘ]% BF"8@LٲX]`f՘]:ګ/i<KC;VN0 }:sy@  懖dl`UF22ڮ@ڱ@>8r#,иdq=aN?*ٵ_;mHm{xs>{;rLۛ۹ԟȟYO[OyWQy BY;ϟڟX8A\Xt Dr O,z0Z5\rO[գ_]>ZK]~5E]Z`iFSwGz9\ H.OE5|U<Łx\Ef\R]i=`mEЏ`OFYǻ:]ø ]|ɿ ɕ|ʛlɻɽʍ:7+Za;C-ZC,[g(X{Wa-"; ]E|X+WY5%Gk:uO\ō-i5>Owɾ5Ə\@rfvL]o٘$Fia|̹Z1KDzZ:C  ( (d1"Ă JP9t1ȑ$A<2ʕY6(`>ش)$8#fL %Z@ѥLT3H#\AرcAjUK8}[4Br]`7޽|ﺅhq JTŌ;~8U)6"plUK>:էɚ% ش$m6ݼi3 <8‹3iʅ3o>Ht$ES^]SUU\҄]"Íw4"?Uo*X݀nR߁j vaBI^anar8J"Hb**b.xb*x⋣c/c>hBId )BL Q&ISZD"!|G}Af}!X)-Cp EɩFsD'x hlֹgeRHh>ʨIn{j餚~QD1aM>C<*EM T¤k1UEibUumwi}]5^R-zɹb8d>Ou|K4iv;Q0b&0:Ĉ330Ox.O]_cpkMk|.M&@\Uf;8h aĨ .H0.*X= 39h6C!lF  #r/!&? :[84->aK[:;]5I) B+SJ)n ΰ3E6aHs?*@Y୛/a {=  '%^ּN0k+k|O߾ʵ[BJς-Z1oM׎0c$ȁi}RXֈH-H9f18g N;9Oaf\։ *j 41gT/jT#x NX2] ]Nt͆O{UvPxa na[ǿ"*{tlPA +x򔇛+@‡;X, uã8 fKX+&$a1OZ:sn/J 1 BOb f G`[*r!^v@v0H}ޙ]8B/C:0AuXRR}] P ]v $Lـ ;KL `0Pke `pPX.Wn.ITl&LQoe a@f!v$4QT^fSM`xU_pH S; H'LdVHR aOVQb$RxWHK~xWLTC}Qy 0XGCH#_vrCX QaWEYX . b b{1D$TtK \teİ4Kso8[UuLuE bv(Kψ OVOHvb5fm\\# k[ w#\ĠvOvuE ^^"k"E5i5z8Yy;ɓn_+\y4ady$$ÔM8G D}cgP)QKg;GnX$L`#~@Tڅd_;\eӖgnE_jyIw ְ Q @@'@]GFe@Fܰ~ P#xK1$Xʑkـb`\{;o.SSOWg_?] O:,R/n%X5"@X?uk5o {_yAAH0nhX7RIhk߈C S^Oex QsSꤘsg ng{e_%4q?5  J @)LqrE .G ꂡU|4 ePdЍ31XdXd`YtV G]@M! Q7A ^UCOpbuU „# `=Uva[vE# ) #a3[')6Xw6nu")X; VegaaԪד>9s$bC V5tQMIⰥK [  +(:tE +J0](I L ypP߀g4vڰ~ -Ev3'| s Ac'Hk dj*Խ lvli{0׳47)6aEI<ؓ7{7/ e@8DH_ zELZ{$Iz-J{<ک})ǐQ_+b tٯU ǥW$#h n#zܐVڀ\ [@ eUƙC\6 LOlò0˂MV1U($֙F[ϰ˻lTV|L@[RbVϜ"N] Ԟ6K!I,lVR 8:M[w|67ʷU.1жYd M Ð Uϡ  υk<78_U|!k5_eY%}Ҡ$s.Э(}. 24QB\cz^Kq4M P` D\f_O]sh2`@V_U3”L]}U{\ EI#,I"hn @v'{,!̪ӎ MMުgf0m8Gٖaya{ HB B\ ԠP ȗ{#<E8<„$ȋ}#-zhEHeCQ;/y)]v7{kM$ ׍(V\!_=J#{t<ܲ7k++X=`PN?@ Q[< Xmu&-?eVrH AώOI\ofwzˋ?2bDAH,LkoH1o\`H(O h {U<C՛Vk~Wح@J+.r ِ09={mO]Z5g_[.",bܸs d Btc Fp(~,M E5Y1qds''5mylD*sET*L>}%1Ur zUz 맱̞EVZ̺}˶mֽܳW]  oKrˉ+wXlf6M3ѰQ]]5װ^ &74e.3`2u[ϟw /slʉMܯtY̯.3R+<qnƭobϽs lgZpH.TH#wQ(b<< ` 8^!q((Lgn %d%/\r;I #OmQ..| 0i"$ 1#7 Ft3l∁EO垩:L#$pA0#p&}`RK#RKO%M45TQCl@5USʄ5Vbe5.ls5Zpb-3sq $#>$ 1gIYeKjn_YVYce"CS8̆>W(J?xgm֤$ Q \u啕~跉PSZ^lfۣa$V"UZa%b"?&Pה&*W؂71MmlJR-(MyFhO7A l >b2h"9*۫U֠{).(+g2ЕJ* i+Yb媌> qD?B'KG<-/;3K1ш0¬uᇿGgq,inӒAyqcyۤg˚v,y 8;uqGϦ?`/}@@|̢.hF 9P}vQ>!&-B簐0nhK?k=R>}OD3K` r(@Rd%":iI,","FHP<(+-SA'M߇%:}w q7)P1 Ѐ#ԗx)MUjT9Q*BdH,ZX 9aQE)L߂UH!DG|ψB!anbY'i} I('PHv%`@DZRe5+akPrpE 2 \DXBGkqZ`"8X&V3bTHFJ2"NTgdC ܙQ4qi9=a &蓟ܙG浢klXS'Q-#9CL>#m&$Q8'~O 4oR|Ŕ4` )QeA> n*XE(3t;S:UUuTeԭbKe7=)X4fwƺծZկK_S1cRxxS7pG8TԮȈyL[7x ~a]ZLew=3*RL̚UD4Gmki %$vy3H=z@=tL Hnn tC'}0uv11LD<"xO: YHMY.'_ ޵ĺ>r~!+kG#L^v4MwڇnsW. nwW0O=ыq0ΪYUկ^jSYw5~wyLJ20ɲ*Xe7χ~+#"y[,!YV-g˿f!6G"[sIUC.ՅGIꓢ:Mc/3*ۺGNT9W@V+<K/@aӯpI/3&0Aܗc/eCkg6[@ 4,:,! ""?:3@$".K+90LAI .s D@/$L-@H@ô|P> 5TDKȏ?4Ē $ĕdg\+64Ga+ASKE/V~ŠqE{<2aTJtJq >*н ˴Kvt4LDLLT˨c>|ʫ(,~8G"3,H pX3TȄDCؤ??;9+I݌BĎNE ?cT@d<2RAIܮg`N<;N/$6Uɟ/J+k[ʧϏJbfJPGǷGAK$k Ƹ˸JЯG2K⩞P 幋P[+dQ8Qx"fb%0pxlX"ȃ Q5 3L4?lМ+Ls)" B:$M@ Xqa!N\'\?I.uNC[$쌏ܮ { %s@m"AD;H;UT$" ʕO<7 Q<k7PTegƍtKZ}U; ;xlYUl$cș"(IbUfmg%j= kUV+*քC~V k8B9q m4pbɩH\ ,R#]H4'h,-9 IMH"|/hM0v%3=S XuX Xn.:5-<ȳC$(hW ? X;A5/[YqȈZGԤOJXTMN=ܺlHj@4߆bM؏ ]֒,޼ӣЄ 큎<ͮY _M@bNaj^Ygp (R(*% 6 0X_6IuTZMO57ux6Xb!&i>+t$C>2;Ϫ[,-d+$G僾% P]݌ (z26c` 7>,0 1Fq:'֬ !sXc =DM!k؆zVa#LR%36$Ӓ_&=SpeW@::^`dG>MȈZcF߂mIe;HS1<5dhFJhH^ MehbrHM1gx!]*xd6\z4>kZxFObᄙhrh&Z£ZE1JD"i"V+*jD,2+@+b_8Eϰ !c=~ޠm@jU6 &. iem sj#U3e Xu)sThHTC'^m"vp初.4lk.Y3Xi~;fFöff7ԔmFT9 g?abq8 $${VL(Yfl0(6.EFhF~ɃJvhhhw.­NլRܲ5.o* KR,pp۽uP[-BթpR>wن<hP8Ǫojrp-\ ]acoCeRxs%> MxHkq);LM.TrE9Z9o+fQYlaFq>$9ӟ0e5%_- m6`TNmpa蕵RVf?_mL*V2(6h,n^/|TYKUa CVUBWכ>Kp䃽 baj0299&eдΐ2TG@& Zbީ 3 ݡerpPqy "UdK%Fd (due ,irp 挘:px'n9tjlQfH^5Hf;SˮovWp p(p`t_m,I>7AaFI}nJRAAj76VWOXYMV$N֞im XP62A2K?V- 7JqHָU/ȗ|?·|-ZM>?/˲,=*g*-}?z/sk[~&eҲbӚ3?D?sWojwŀX/ڞ~:^f}uO@|_ `~>;!P5s4A!.[ qEn)8q C" jȝc1t/f4. M$4נdeshMbq&0ըm *ҦNBud$M6d+׫O~$fϢMv-۶n-RĬ\Lܽ+w/߾~,x0†#Nذ'E?v82ʖ/cάy3>mhO4ӭY {kӰ |޾8  g9}A#}9 vx]vܿ{}'NП ]4L;<óڵ"ckx@[?CbhM; B 9o6pBH\d W5h}7o' g|v:4Y9vP6iUjf |nߒn٥.ߨP:ii驧 8f@kJ#"1/4cB#2R">B)#ˁIi 1j\WƲpq#̕.z#QN4iH.j)LjSt$=uSv'bꓟLCw*)OyJZ@BΧ@teR"d]cLV*hc.t\-K]#Ck:ni&y=c8=:ѹHZ=9c5{͠s6 2bs}lvc% mu}wow^oCV <8t>8#.7ɨI)f4{{I9*I'ִ!ITu*g㾬AṇŰW ugo# S~gjROoT>ԡ}˅T1t??)2⿇)}#2ge_h`tYVPgSh%"`ߏ%u1:^9IԟQ D[}` Q!NT vJ \vڦ^ E䞅J\S_$RaZ1f8ݚ`a_Xa!af_E!`bdY "Xp G1LrT]ٛAs"!rbbb(Q:Q )b*6)f,b)"&Ü!!e 1Vh 88;3 "K^H}2܀\ZN;RO I=OqO=<\xZjVhDэAL2 ]|:;C*\9,#Zv~2=MLjOz_P!P.FM^6- ^/N/}x#6bE$r}q/ YXX64MzCXY[[re{T>'ҢI` RvQ28\D3l,ZC{h`f3@c}coDe c )l&Tonp= q!?ҎpׂJC2d,9$MIH&߳P&8X8pC7ENEIZ| _elaYK>LKNa!~J%RR>``]T^e՟!G ]ڥVAW`Sh&ZgH| M4|єC[~]͍n֌Dp8"ñT>1#IAӎ3 Ώ ਏ8㼎pH zekbI6Pi0P Agɤ^ RF.D@A ChO(6)}cfDC*PdȏF|#HZ ɬ {{'Uf}X*F"&Q$ad_>AR«b-2k:un G rD%–%u>&.\ b8@S2,` %|TlؕaVL YEP,^hh,8leVf\1V 1-5fP5F5lIKJ ,D7B ΢AV`bP-Rϟ4-`l*J'^@ 4.)@DK(Ø Hj:PBj~96g*k+j9߱F|e\+z!`! Ɓr+vkM^M(nO %Q~fͫ!GUlZYv$sh"^r,(- U*ZG960[n'&p^Bf6ثZLPRIn9dzw7f h PJio @DBm6&fHupezD;8-=q>EEdo1*.q\B㞪B0B7C,H+dh-${ y nB2tHD"V |R+//2EPV/*r,3Vo22h-o*woT/v+s )oȌùyݟNGFbd26ss7z0p:!@#B`z:8 &bQdiT lp|J)0d=[Θ)_D1*1m35|oNqIwH#H4.nqd,D|㋨߂Ex.JѝO*yKR.NvCFRa'{TrZJ,u\u++;o0M5eX1#3UDp66GvSدA57]XLbL'+,jv(^V~6g+jlѸ_f,6ҥ;iG cp@mlFyv1vD  0 tDCK4>Pw'19}IIYF -3`2-m||}WO7Mܠ~9dPO M@lNw;zDuQuT+5DRixBk$cRC%xxxXO!(X2Zu׸],y?0C/d/&L6m6)bk/bܕWuV؁dAhyva_oi k]3K) i6)P7C4|F$P@%29p7/t?ȓv|E-wCNw V4A 1S4cޝvמmhzhlva@1qj6**:'jB5HP4COE4\I+{ojP%8jX hGxD6.RoK"_UkwQ8뿻bFZK*5+9| yKS\[u0o+7`c6(s]ɣ|φ6 x9d.4Gu lpc]гxoҦ/o6K H:7d'}g׃w[cpw+Iuz7ٯɚ`GsۭIϭc~s^R!u:J|n Vi/ Xóܪ~n/h ʋ<&O=1򌧅\8DZ8[<|;Dckr9ǃ+|`#)/9.bʻvA 6kD@ P ,8P!C !"\( /F$H"Ì9܈r5#x`l;yR57qN=wde3-e9ʛ>ϨU"ݹgVb {dOЦUW^wଙNօ.[޽}a gfȝӄ֮/Z>otm܀t O.-j׭avm۴o]xqǍ~F|9¼3(y9#ݑ|y{W}{ꕳᣇ(=\+9'1*k+1X#VC !0Vv "T$Az'ĘKeѹK ,8p>qD $R!,H"82$2%(R+R-/ S1,3LS,7S9;SOO &-C*@@7x>"Î7TS>' ($SQ(S@aSYiձ[sU]yu֞vV_W耳nSe2\ViBaZM6XC-Yn Wd17KW]2`wk%} X(NXa\!a7&1VR*㏣ ,QNYYr6Yf_A:BBНetʐ4RJ#CL`XR5r竱歹1Ğ\ Renٞ*[+4[P;VҒv=7k{oW 67XbkƁI/] /62u;ɑC0Inq]w`߁S,ʱNJ`д|OF(6ZiI5-ҹXE.?x\ɾG?nO^}ퟟw>ampղ-غ۶ZnM&(8tp{y!4 4ax$/U_491t5 ke I<|dđѮvX*D%.dC<)J|UTނ,ۜ. R)MR"6)mxR5ő)yzcZQcgi(d&HE*jaH [Vm 7 ni)׷ wt]! EJ L.= X+BYR`4-qKQlHD!3vS1?De.ͼR`6Eiia 4:؇3qRnNut@e-l$ZN}:Pj&UI\*8 M [IKNT`PhtQftGOeƈRRId!R4wt霖wNbr6UƣidShT.MUSә2U,SUU1UrMdEYy}ތnϳkPK AZ6yE(VVPE*XucICN)HR0EZ!.IYZюe|iL)rz`C착J { [\||$nUk#kc[" YZ:9䂵1] w«_MyJr` ` {Η] Ӱu(B%\=AIZWBIDN^nROxrfOJsYLI}scz*=^  Y2 K(Ia޳@ne1ǚ2WG.<Ρ/ pe:ˢs1`.3?|8"`"\fMejuP8X1(Y;ts^h0`󜧔!Mgw#N|e q5u0 Кu| .ds[SFm"֡lw@}41&툍$61A¹M Uµl,gIY}}ISa\<-jW;',idbb nn/)7SSiApo5ndqxLDX*gk]r 1sAw`b p39D洃S8NM?JVJP*-^sۈ@AwnDWaR+zZ *Pv;XaE~Dx8/w]9% VW_Eks7Ί_.:THA aB#cv}'~0o. $$!&f`SJ觷o{Vw';t1RVKIXɛ2{hS8.j 0{%)AV4 +̇-u;?n2?!@ĪTc "/, ޾#^a0ZP0RVpaWO/"4 ˈ 2҂R )22 *c0 5#p r0dKbQ"6ES<\%) WRn&!F&ilrr3Pp ?hfpY@m')qb2pBʦ)C($/JZ"o b.6B'*%/ т!!@X NA+a"? 6x PρJ-i/>:2ci2#,r3 3qE2;#@*Qz/,j>zS;,J8/J @1@R #|q +A1U;"/,%\$a1޳w.aM  #: s191A9!@.ZJ2B'4 !0s3Cr/qC T1!r"q4Gu M.GK(}ĝmzƫ(hNҌf$*e΋HKKKgLt' &s~ll&tMȶA mCز CZ) @#245VP1/9KJ1OqB4(-/![0l 3UgVmu>^8a>hX0D7;B SE4?qHI6U! M7 +79q8Q`  &?$4@/M;E5;!ԯ?`V!^)qb44ܶ/Gt9JJBE5cI4 D/T> FJO@E #2|!@` 1  ?K0TgfQttjVNODL#d hmTX`hˆJz雼%0ng>AchnQZ@omF'?N9X̀Hڅ?Z2NPb+qql.C oBqsI& *?TUB;VҀ M!-xw w)@y ꓜw[5m6a+Dqsu]3.QuqH[66&*]ٷ]k^d?1NqAU+<;;vd?V ʠ M c2%M0!3ad QY)T@7J7fCf!e12RhgDYivgM51xYD;^ԉvXKƝ@"l˹D̖'t . `a']bNjl'f`Nu7AmH3/,W0 5+1 ,’T}OjWV)`U)@wVw#rMVpfW[iVk]{c|3qh,癝;OZ4U/367}}] ;֙;ݙ09L@OX; 8a #% 3./]6$:GFݤQޖJbagAK|vNhMi% 芠i:MfL_ ($*tQb`ʸRRRgxGK:O 1 A +ņ!`zfW(& K\M!{6yMx8;Bc= #uI;@tuI6( Q_woUck[#svU5p2 \%G9yG#,# CCQ3=]Jɼ]# |U#YCCQ[7`6:k:@C%c]c?F;J:fJ]K:LiUXiu ֈFZmKDw?Cyi폨:ʥK m2 &I$˧z  pn\Mi!Nsn%ؼ&>V.cA!ڰۑ! QA;pBR#VAC34(.]cgvCxN0Zt2!\ =/-3"/-ymc6A![{q2?Eo>DIExCGyқx]85 O薓}_D S0 4/ѸǠ# %!ATܓijA>u>I>G݄@ڸ3 L?DAAeXhpRޒKPT@( Cc_Dlws[ p!i;p\4m:3#:L8缩:+,j)Z5omYWZcCމo  LB@+ȵ{wYՐK 5sM̦:x +ZYC\1(%RDrs୼&Hp.ϭQUʔVRU4b,mzjS1sZ\NQY3nlAH<*n2f^6߁{nڈ[;tr ϝg:[g%k\S0aMA6BN-E΍lMaHΚ9ͻ Nȓ+_μ@}կK@&O| OA 7o؉>ݰ@a'v h]% *(zFX wVhfv wT,hz (4֨!P<@ $ %"Q:2K6$Q>X.b\^`ØdgyhBpC]֩x'*b*RHAhR@2:AE*E#ƤN*JK:FPBjjE*QD#*Ĉ%무jOq8MYz+]21U E+Vkf[:H睎Ku7*A}w* .u6,au%V.'1Wgq݀L7y$ '7itb)sd hPH'@b&l:A\X֌SEQu6=Ʃdu@ j4B4VJ*bV "kV}.p1˜A=WnIo+y$v8߻z {Ŵn8;v8bn|'|8ll}-gr|U_Ŝgz9#(JNmKsݵآ*і6S T( XB*o4&HFXA\okIN7A̙(L-δ[BDp.tK0 {֕G" uA:NjC$2E O+XC`yhL#4Qӓ|F x{S$>iKtDT4(y4T UQ#@2ܟ$)m,<*2 UVVVzt p !oJ, .Y;9ꜹCH|3D؇vX_b "rHB]鋣<-t1jgMO)Mz$z;,qcA& ԝm_GZtzZ&7Qm2SbC(F2RAWԥ±0.8 ˙T[E(g\!zI \MUy 6: tӤSDx X*ť&tXVQG)= dcXRh>US"Agpk;"+JыZf7f)HOuR4l*XҗւiQӛ*gHmgqfLE58LOQ>Ռ{)խk[/4^Y'BK^HA#MFN՟M}̿`G.TRr!!*N)T Xଆ7\If*'J)i1gveXB7"Ma6!,pEm yuF3|yGZi(0nHi;F7oNlMJHV!vH]p!N4Ca8!3&jQ s8^$.xTI64 Pqa!)q+c@r%W"(Z.g6"bBs6'8'+.s7+KU,D7=KL[MBKAfXxvSivSVf_w5uv\K6UdHeg]H\cxTe7L7dSwtvo7fy8wbe`fBbua8%"Q0OwQL=0PxSxEk!0h!2@ p T !m#+,_/|Rj1!xXg!RGlB~Pf=n!#$( po#v!Hjmِ<$'&BG X%WA3`%> "@ @ yr"8p*b&E(VY)Sr.&II ( a&@$!6Rt26c2abe~tc*S:84 gFQ B s]Az Jv!3v<sm4JMFAȓcؗl6{A!%m)KaF8u Ygfu8ndSQonGfpwa懾edg< 2 TO:cS%x.X ]xCm+hh"y'X#Ҋ r}v z*m՘0|x% P$80ٌtqoA!k׍Ӈ/Q _ѣ#`5Y~m#ƶPVk` m #j#T$M0("'~'r8,P> (>HO'Q HbHȞn p2eJLSqjSæ%r/ْ/G,? 7h Г#A{ 2* V!|ϐ%)-'(*E `'G rfI bd9Ac3Q~~ t)1 w٪zwcwQb|J7 -Vp2 1}P)t#9 l,8j'H j2Z\lن몮ivgr=؇eaV9XG#t3:C^e9Ow0!Ҋ{߉hX!y!Y%;N%iim'`H 8`A!1qm"08ҳk7X=[!!ϰ %#C:r?tϠV# ]#\r"4Q{_'bl>UL:[Q*|TmRmK[4&P 5f&am([)ࠒ05y$1"K9A Im(A rºnXIy>]  ] Lf{+=p, ),⫗@ }mqac{Z~65+~c % /q%- j_zuzHKvW&4$lxدHT#.);)b0x ?Q`Ym9 'a++I_)q<̦*?f+\p7ڷ%qڌrػ!W^Ѽ5Gs:):XB`G,uQ  \Y$5㙥J<qk6 tjLm+ KIu- GK'%ӵvt7e@[D]ԎSPN;Eg{;\BLE51W"IEA 'ˍ4 #u'` M瑱&`j)j%1:֘@~<pׁk|\Liס#L-рd0V0?rW|"\}Aŭ3%RۖY\`l (\PqtaY@>l#yL}_FKjfV4N 4CRGW-Ot< H A 4khMyjM^8b".*B- հ %&}d!鋐 ~ͳ}Vڌ): /hvم-f˵/d1<\'^L{#%9s{b419r\ "-Ԯ4H]Scqߝ]`?&~o< y]H(+jPP{׋+> AssKXtoA !SR)1@q=8.1_bdž L4M\,wa:s{M5}bw\݁ZN?3UdC<,՘x[t߱z0ъzLY~#~zϊZCɄ&}G&@߰m@ ŏ~}! /|۰W{  p!?}? =K~XTk٩ٜ{.Z: f 4z 9ZŎ>z'U#0eN5qq߫S^~}[XrA xIru3w.C5nŋE(ŃZ3.al,eS \6lSYYC\++A'.s|6fLgb9&b61DJVWbyjr=5[r|J [B GArU&M8+ [LULb {&MB jnRe$jesj>kU,JDb?ka؜Mg갑zu9>wiٵo~]s'_yՇI y}:>ޣ/@TpA< P!<$ LCA&xcE[d(.Fs1{BD"RH$LrI&w..qirJ.D  Z 6DuI,xT G8 ?;G)XS.D Й Aw,TOp5gQp݅<3]H}@{L3Pp(C!k\5b+5bFt 6 mj͆Cn[pW 7]QWp]w4*(bW0Egϙ5`/ԀSβW)hb+^,p$._K6d5:R9_XR ! %fi݈'`2 s>i E UT Ġr1K ^܊.!2Zl|:bl",癢Pl(sz`;?39~ 5!tQw֢ܞѭq*(6_܆#61Tn<_uc}vs}wup?7^ᓟ>ou裗>S!%]E`Z 9T\]$琁F%t_#"~?h`4'8.]SHS(EPG#beP`) V@ !+jpDݢֹ\Boy[& d@I BF21 "S"3{PS`b`1(F Z8 Ďd[bM2I̎xc 6a(̫vǬ$jTD h4s T D Mܫ9 V0f=~:pL p8"6P3/dT爑2TcBJZ0~D+-,#ZbMmEt)iOb$C!P9v TzG>qlM C&2j5P%ZN:+2gLzzWֲ V 6;D&smiAzП$GHvqz8&wu!d/QZAaH{ ,K'Z1 YuWTSĨDQ!3z7&uTjTB@R W5! X}k:V>X6%]{a peՕv+CX>Lv9$dxk UФ2"e}CXPKB$+غs 'p vc>sd-ǽ?5ȭ a@r&ЇyCy s\Q@){=9%jĽ uuļoK^+ Ċ[OZ_{Mmjzci}]m3.WAY~_\:VdV !+#iI O<Φ6<@!޶ߑ|`<޿䳧}qHhx,6M8koO|%W69D$Ý[B~(S/eUF~zz[H?[Qf5]{^B*0ț;+h0 +!= lܱ6Ďp!d")3%Kß9h>!-s9[5p)Ј+R[C8XC8p?7|CÔ?;45Ӯ/? 9:*DD(BL aǰhlE;B K< ;%p1NJNWO$1R$K9Vl2347(l"kFb2HFq( b-܄.̲,T2j ꀈkH nPs( ̰L<$pp;9M@͓ LyT !cG9ߢ @B5˴{"-RcÓi< YࢇΊ^nΈX- uP ipIl;Ι" JT ?D;R*#tvϫي*@D0( JJʵshx@dKuTA\2HKQZjQY H'!0[&Q6K8K'58Ì > )ş(>, *'jZBI"S-3ES$1gHӬ$`SLXӫrq mbX!M!ù IT s+ 5aY NMI245|tUN"HHԚ/htІ0 | mXb=t!lPd# 5j`;Чd_P IPw5ۻɛyQQ\X=A4vž47YRl2}R?B0 qB>>>Zeiո(-Y!1NbHvYKPMٝ3h)hmx`T9NV dG͉,tx'xb"KeIV!P/ XC[ՈMMV/p58Ce$@h\պ]=)8ֈ`$ gMh* 8mQ;u +p***t-$wMx;{ՁGWUX]ӎ)Kūa"X}Kr xAKmَBaZmh p p3' >h9Y?ɓm`Hp JP ͘JVDEeTnI=2CU V (wphù) [88? ["T=h Y4O$v--^ \?0 vL.(b`N_.Hҝ pPpuݤ | ݍ]aV <" U;^CRMPwI^O^=DX8R Xt:R%>>_e&_q `!Ip34^&` oio bs8 blifzqquF8lEmԊ ,6a匓紆o _ٴ/:[D@`U6#>b8b$ޢ?VՐC8V5*.5-~ܐnhDՈ*cH̝1։Pp,G9Ɇ -T]h;j݊`͊ ꭰ?^hE#d~@WdOk )AR.eSV\kQg$:+4X~elee>8--`1] N c},# =>۪X J vN%um Z|2 2;M 6vV m ZYlVa0Ă&T,p(T[hh8[\8p >sh5< n?-ne/F陬I{4c0\eppP *x##CDdʬQޯ. kO.z=qqqOk˫OWዣF=k$ll'K+efJFĶ7kn"/}Yh`1/a'==9F2jF<%, jԦ:-P>O>dasmlK28}"qK+҂74Y]V\8Hj #.4FH댃^m理hh]#^-f/V.vL fq8r9=8cG pr5p] }ApydW^4 w Sq6w QykWC˲ɒ;r$GrD=T'&猯 L$/,r{L,L,R{δ3ytXl؆ WMZNm ٶƫMMOVmհ2`tF.I7}>(ʴJ s/*qpbI. iU]Ԕ9u8oۦ_uaaW/N06}gٝ%MM Lk xwaBƊn?Tx 6Hw{O+!q/3g~y;Ag1j~>zx/?ih *0g[غ9sRkDb,hAuk3&Rh"ƌ:Z;x"ˆ9Q@᳓ =4!̉vD sxR\F;&y[t2PjUZf+XSN2,ڴfm-[-ru4ږzM͕cUa5pi8Ȑ{2ʒP(mN A9s@Wwc.J-[m;ܒMvw/nxʗ#\1^PE tϸ8 JCZx!j!bhC `%xbA"-"1ʨ+H:#=#A 9$?ވc5*$5$Q&y$U"Ej%jMZ-T@!Pofm&}Ei'Effgԧ :(F*ӢS-x[S`1iZB&iA:*ЩTQ*TPU[uUX` eUY\b1\z),y,_,Vnٮes[ f;n xv.ǹ.2{[{oU { . 0k0 1S젅z1x!#%좓Nx\21 i%4|MVX(3%bV 0 rfMyH ET9djz5؅jSOetO\^R!fEa6ch7>mҦ}8QT [ENX'`.d[j,\,{ElbY""C.i;<[oRgK?=0= W~G\Oq{>I28?cH\'@)Ie,`64)@d4QPNrZUVB(B?Uoz뉨zB.p(| *] t@yn!'ĺ Q;"eŸ 0{ZЂW7nty񢲞A+u;e࠮Ůn qwdջ=N\ W)$x[u<1`s@0Q{{tMf B$(C /*URK[DRZie~" -I&DTi6EhSΔ4gnҚ4 rkFL4AMS2lN*桨i7h=}ʉ'{u]1XXT Yd)#aȺ4эc h z#ծ#yH~髑.%2)I ;Oì /$P%JPBE(dJZ g|*Tw#XCU7~rI ScbbaӘ`znݼʨs,4/ pB27ՙ`>#+ٿVe!r"䬈m{ JǬ/1A b:IC`6BFMG!QѶnL\xy)U)Etz0  *@5Nm`1I a*|*2"-5~*Ȫ_VRWo`Ne,Ǻ_yI g [4>D>i ]^y'MOa±ز}=Xz}Yt8&筄,F8ggY|rVh=gڅ+.kl0Yb$*=a3q[Fn~3Gˎg?8Ƀ.W]+Lz|ʠEa8I6H@P(HUQǬTժ #Sr &´v"P s-BxAĬ:\2w"VSf \h ;4y& 2ʼnjNO&Z-wзXyt ]k5[3qdo5:.qpη=Sυ tZwbp(bQ1 n$zT.5@5Пt%Yº\b-糔Lga]Vk3'X@neo=2ĵ׫0_[e'_#~nWI(8*ơw/G6Tʗ s" ;c#HcrbjXRt#$#)խnݮAәX{/a̲o1?2 P:! Hf#";QvY!G?2CAKWNt{5tCYW.dFs=ûc!L5OO_=H~PC.4){aWHmX} ͸ZɁTq.Z MUD A؉Љݢ N=ؘ a8A,ά/CbRaeێYS]|8 |t@v͝^EJ!ؐ[ :.CId36p!1lM^6[XN $ֱ\hj^͖%,Kf7|8Bܸ8B)Ƈ,,\/*9.C/j6d4XC90 O#9r%GcJG*T#à8GP"7DCtG6a*ߠ9N }CX{UtZq B C .%PER] י‰eJ z e!$]6 EؽBsd9tyd $$PFCF$%-%\^w D| R9a ^kVCTx@!:f@4?AP8$Ay $H1@Y%ru':ԗFw)jF+bdVF]fFbbIt# C5"4ib|mFjVM,f5D6`Gha7DǝG~E*`_:GL$VA~ȍe`x\vKpDǡ#v; |\8$fg͙z@熄LB)1B6$>$=-edTyGf;!@ BI> %>] K dfP`-a48¾K (>UDn(eĊ$kLX!]Oe籡kP\"e14Q$eI5lCza|\J|h$jYHί[` 'nbVmY H쌥,dv+NW x,XvԞ jY#-YƇ- l9kf2f X6Ƥ4oX6Ǧj!p*Hb ű,+8@+׉d+jktkCҌ+T]hGzD@«&ľJ^T8lAfad[jٕr/ Y^,lhf)+Ke!Ǒ2,X2X%hl \0_0ភΙ"mN5|CC,GuT׺nq E5v]Xim`F|܊_݂CȂ\o .́s%􀇂0|@ Di6$`H8'_ܧZ$6xxq:18y:6OrHAzO~-VXgN2yUqaG(+"4hb9(*u29RBMV#20/Dhb1[%(hlޡ//4݂[ i*0k|YHϺ@;ojтT ҺI>AGkY t)"m'_G!mJߝx-ke)lć3 fTj^/O.L{_eqI'x1T'A54$J C6d5M݅NヴRSqR 2ʧQY&}vU9#ga$%.I~ n'!@ _ϝN_k=[>M/x85PfC@#$bOPc3f+eNJ uleS(᯽O6k9/TnOss$pw$AB"3lb|LA 07/"xtBgA{7x$6iD,f$hbpvilٞ&x cퟥ4&x,6KG~Bu(n~WAXhZK7J98؜ボxx6h51d@vP|!2Y/ЭZ#5y u]`z0 I!ȁ `gy2`Q|ALaDeAMN6۹N7azǪ2le?aqsfl6v9C 0V7UiS5®e.sg0\\@j) =vs~x50\I@A7׊wxxz뺟R:R-2t1 j12Nz !n4oIf#a08x<4xZ zwzb*$0*8*"+8<: |Wu8 r캌x-2|[p2<9˷|L!x<5+7!_7ޥDx\ICby[8P#*gDA^3PODԛ>e^]? Jdh{ DmTé:E ,KʢAx xCA ~0!W~:;^֢,HMLDn{zƦHH_e0 ƽDۊʅjy^r.1@AB_#CGw@\%?GD1V3|>8\ k|8{)Y_I\|+[{ɛ BD 4x> 6tѡ2*PxcF9vdH0yeJ( R$ō)PYA 1cʨOPA :f 76Y)͖SVz+I.v媑kح03$MQ+,e{SMs5ab]&Np`c6|qZrd>ٰssfxtt=I.h!"DV z$tlٳɃwnݻyekyr˓ EnztӏN۹w^Ɛ/_["e(Vȥf80U}!8|%d - 5ܐ=BlP8U\]|uEt(uܑ} "<$\& 1*,!BDx0V:s&ML‹2(~2p@(+ CǪ$zHRJ%%t*2TN+PE/:aTSV ZlBەhuE_4=z[Y݂+Z☛VlV5)U(zB ~h<ObFm$-G'5ޘ㎕H#ʒM.HK-UC\eL4mV$8Y-v)N[B)@=]Zgt,͢i-kRMaFUղsƶ`1c[n+,^w%McM=}D` _9kf]8j%ϖ1s|;/ RYC?,$3i,,N _B\V6iQQ FoMdS(k6-UhC㶷MVLeXȆ6/M>[D"vXCn48h9qSPTr=9tNKuZ;36hvhFxqG$DyĘ${R9 ~S"7>4egdi8EL`N_Xbr4Pk,%RV T*O騨SH r  0$, O7,2aJ6k!6"X V"Co"ӈA"N==1nwȥzҳ:Fx1՗XivsB(G=^@#@mH{YR|d3F$8QfkN-xMj N) P1UJK[rTxT@e/6bMj2BfutCVw7麇%bq4-h(WKj63(I̒bYtu@ǢarH@RЀt[]~EgxQt& i(@.#9B ӡ>3\pG/vAE]>fo}S+5oZ25@hips qBo@ 0irӋnCriC#6태}3um&‡wRpA* .gtV(8R(+蚳 37ů?T|E(-ʶP~Sft5 L,m)lj PGelf31>CMh.&Fϱ}O6Qxr3vAs4;7I>Gdq=ՊOjX8!l3'8G*|}s#.x=5 c;Qò*SN뵭e{CNc;P|1 px<7![4֍"`yY,,v #Vӱ K̡A9aণo[; N pƃ .*.=#]@8Ћ>$._ 60RNXvH`zn.||b{{BTI- }FL.LFˬkN@')knņAŢ-"԰0PPf#v01?#?M -0*c./..A@j悃Z01v/@|0H[-в1d߆O-! 7q7/7fpgA#G#n7Q/p#Q3#Z]Q8[q # $P; Heˁ*  ͲAZ!@J B.6p ABNTL$ $XͶav0̐@bj%Js{r(xk|G0R#5TP*M,0 ˦&0I H.* $,Aβr-۬-RB./e/0݄F>-F0")"ca/O1!>l00Qāb@4UXe ۬a^65|Ȫ| 86/6)ܢQίl 7:[p ;/#Q<E(:!PsѰ:'w"vb ;aN-TTlA A.A%+B! ̬$08Dװ t@E($& Jx'sf''|bzGbKHԷvJ,涤GG)2|b *Jw*+d$:e)-2n쒦*`K%3i)Ҕ!/4Ca1m,O!4.1-1O/U>>S]R!/ TE1 2 u>`7ـ|sq|I99[/R[XJݬ;UT33;!Y!82c]- =#U[Q;".F+n *N7 `WLŤ60."%.@`D 64Dc $By%7cWap#tCLB`Fi*GypH}G}$lHyvHzlȂL8}䡒 )oVF̺,J*Kk)Ǽbk+jkNk f4D״-B)n)b6C"OUޖ,zA*W"A!آpF^>Or@5a4u5 _OH΁~>2lWCW_W}4jXgx_uܾҍ37uY\-ʓ8>M{u:h[3?;UQu_* ,`00T%r@A@&vL(@A#5r X6!EW~ ^v fGf`jHpPuufg_XDDzȔtbzFiie,Leڲj2@N L 8) Pش-&/W κP@⺘MNA2N8DeS>H /$1.B"E$a. 5%Q H1V[0%uaAv|mV[r`UxזSY98ZW[79<]>@R[/(S|hv^;wc?><ȃ_)LY!7@ԂSA54-x 2eaU0%.3Ԃ1Xٜ -A&AHEf.WءZvq6dJ|Kx6:2:5I5fydB5iJл"c&l`LLmO2,͘)p ) 'N+-mШ":b1 *)Be.P`Xqe!׆ͭ0UV0qVSiٸ%Vm!]RYw)ʭ^3$[XoqSyK×yCۅdA\#3ԑe23ٙيa's6'Fƺ)Ba.vJ00(9Zrfܘ|uen3:<{Sr!xW#|iyx3БνOHc?oc6 Ϯr#7VU\;o]Y{a^ɣ{o_;0C tϙQ$IE%Uv%$ټIv3tb%t$ Hbn(cnJ,1*Ig:Jӝ݅{j',]9<Ľ+.@-n֧q N@ZRx|ŜŁ&L&:'(4͐O~)bui<1EE-/|.z -纾т-Mb`]5A*#[ᅦі|Wfxgxm۾4ԁA~%җm;8>f>B=d4 f-]o(9 : ~o-% ^̎e3"e}V*)8E3\F$D=G7&GSہc=z.E$Gx'¤߳_B -.,[!:X.ߨxPk'SS.8.b@. <0 :|-1&R1ٰ1d6$K<نʔ*[=z칃͝ 4СD5SΥLɓfԧPXœ֭xh6XjȒ'P ?~a 7ܹtUF?nj71_9818~̅cɏ+[9(Ux :Ѥ}>:լOB#SrR;ݼ{}ۆċ$̛3בFrASw>={u֧Cvu? hO=ۇ>p~hyšW^푷 >X GaFana~a"Hb&X*(-"0V:>$& I$=X#4hr eQ% uqA \$-xd8]AG9 "Igt@"pB}*B QeFG"=JR10a7-uTF-"jJ%ՓS6UPUuUV\qVWcVYqph];`-kb `YYA!} hK.kPxS8Cm>ofa{asmzϙoݦouzp6l!=!`m1?(!&_2q s195ۈ32*gpyAXSae\N? '3(n\ìfbaأC,3"T`gr'B'P~OQ iJZi.eSjjO>My{X%[eĞz2l~9^Smymڹ҆n|5p /7#}Qx_'0~Ƶ b|a'-hCY1P jUԴ% 'm"£ՏGK@!d3!'Pn4 lhnuDo !\)QqRt)rTb䒂9U"F+]qul VhE LH/]33C33nywGD*6k#g1YO{x/h;#<6](@60)MYJR> <+# J}%K-M/A&2iĴ pBdQԬ,%LIvT~Er B-sD_V@-(ȟ|*8N$JD-%SV, zІJ'>N*/v=ƐEa :ءt+nVgYИ4jzG y&W%T_ T@>*ZYJ Ҫ'Wo˰M%0*&^ɛd3o/-q ;D4eK$B@YXӚ~ֶLl NpH"yulN'oxC:iT> ND"!э 4EAD'D!FVT\Q~`,(J7.$UaT#xj˦iN}]uP߻\Ԉ@(fԤwWS91`#*]c|Bp$!}uΪX/лqi{+1tbAIFHbcd3(#Y##d~1opwVDX#p7$5Y".`$r#pd7$),'}bVY p`  @(@@l mbtKW(Z܀rLx㐄K SX|VxV(va( cX $Qfvۀ D0a8Qu)U*ywGwx SigKf \xeƉhfV& ^KH p( Fɢ{i]{{RȄ0;~fkh\|'|PfiS٘ѷfb)RY'bY촓ĀLAJ$; .Cws1wR$~BZ1İsic_It@ |jw fFDij4[IDh &}YzGvp *Aȇ@8AK 0.w =!/'~iPSx` fxy(zxf 㚰:$ z %wqQȈ~04kĢrz">KA9-H;H;u|鴽ɰشipj q|w<@J np, 0|\Òg,ȲRw#AK^RⵖPK- ɞq|̈A|'~j;+zpҷP rAL!l<vkd`_+Z ˺,LqpZ@ L,̳Q|˷|Ts6ʵ( D :)F™ ]tw R6|zİ )x/-9⾍ZdCD)k?~N&qLlTf& .|e:(.@O"wq18 *7S d(h i~pD3 um%AtɆ`iΐf8ewp|ŋًyٰ砰Ɵz>ɭ96A",:t 6+z|:;F<RhɓF{ɝ;  pPzb VMgؐ.o˴A1ϴ! mkL.j0*@6硛Z` M= *N0ٳnVls6rp@Мfxw ={!>Q u.\8* q|/|(e{lZ#Xl`f A z' ~@q|Ht $(Ak=bD0ۢÉXƁ!S/;霻0lC?CFl왡lͣu&g6štlt+"ۈ6ΐ|"'rJ*ɋ< |4 "M824A ߄3N9礳N;s+O?쓁 %BE4QEQGmtQI'P.PC+@RONBAdAuUWeUWgAUAQ# (D5C?5O6Xa%vX,NT.c.\vZj6[lc@6Zj 4-, mua(jc؅ n&b^2mW1^-fpjT Prhx9md!6Pҏ6F&d%>!(;td~IY:#&lǖ-:RʦGg<I$.ަti&0fZ~`q:V)&teY+B*-ٚ+1R͗-#]/ȼt.*b,1,Akm5(E`{Qrs7^·Iezܠ8%ġn@2od'0Y$/(|&C@䠫}̧lGG e(@:C$mh PÞAMuՐX6jts!9X$!yHF: %\%(EiJRfܰe)\D(4QZS<'*VъWSD.vʔ 5(8WծX,6댜}e(9*AԐWяJWwDd" ,I Hd5]׊u/lM‘4dOZ@2Mr#ؤ5Z#1x/+ fChq#:fsd -16!d&&@:(MLf4KEhl+¬eu2SP&8AzÖ`:ޑd3Z{? D䳙f(L6QJ'? z u|cR7.h=)=4o6+K ǽԞs]\ΨC*_|zh tO=]T-Әx*j+4d`hM1(4C:VxҲxqGZ zʱ]3Hjd0%?S8&V"9idMy" :b&+N0H 509XSUA!Ր.1KbF1a 59$Hi7aFj-d)O" ٖ僤-3OކQ(%E3ᰔjQR9?w3"g+_PCR cA0P-]T!0jJ[xtG"0d:zk$5s'>VկnudŃZ;Λ"Q896 w: ǎ* %N$Ӟx%)Kԭ6|`3ĠvtlrZv5,&/ F'ooX bF Z0.{$1ނ7bw`9ļ"ܸ8UN2|B&re,"&Ou*<8aql6 'MLqsK 79ts.vYss⹽OUL`яLJ[Ag5-j‹Zuy޳<|WZ =up[w~% | [_\$}졽!$JX=~% `ΰ8rm,χ~opiDj}w˛:ALo~ XjBp)L!߇>- _;;+4ÀĐŠ;ǰ(䂾4B+,,č ;0r˻<CWc"gC8d=L7 /Y7D,7>6˾=y>IL$;@=" 0Y.Ph?It0{s??C$1U*@ExԱ 챗2;"[ ig\d:\8 r ;?*93B;9$D&t¬ZƐ()K¿ OƒDHhV3tȅl:Ѽ͓89HE᫒cD>>qȓH pɗlJə,(,CN7OE[iT4ʄ[00N$NŨEZEEDF3T9:m"Kd@c#ƅ@jtK{(C(Xm$nLoF:39tLGu3vt>,@.8NS?,#ʁ00 {X?[p.=9=>u=>{ӣSiOB ʂ۾KEcJlAX)pШ