pax_global_header00006660000000000000000000000064147525720150014522gustar00rootroot0000000000000052 comment=83543dec916c2277fa807a72d08be1129f8a5f52 yamale-6.0.0/000077500000000000000000000000001475257201500127755ustar00rootroot00000000000000yamale-6.0.0/.git-blame-ignore-revs000066400000000000000000000001001475257201500170640ustar00rootroot00000000000000# Run ruff on codebase 9fc3c943c87fc876da6e0a75f621e15a2201cbdd yamale-6.0.0/.github/000077500000000000000000000000001475257201500143355ustar00rootroot00000000000000yamale-6.0.0/.github/workflows/000077500000000000000000000000001475257201500163725ustar00rootroot00000000000000yamale-6.0.0/.github/workflows/codeql.yml000066400000000000000000000015051475257201500203650ustar00rootroot00000000000000name: "CodeQL" on: push: branches: [ "master" ] pull_request: branches: [ "master" ] schedule: - cron: "14 0 * * 2" jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ python ] steps: - name: Checkout uses: actions/checkout@v3 - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{ matrix.language }}" yamale-6.0.0/.github/workflows/pypi-publish.yml000066400000000000000000000015141475257201500215430ustar00rootroot00000000000000# This workflows will upload a Python Package using Twine when a release is created # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries name: Upload Python Package on: push: tags: - '*' jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install dependencies run: | python -m pip install --upgrade pip pip install setuptools wheel twine - name: Build and publish env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.pypi_password }} run: | python setup.py sdist bdist_wheel twine upload dist/* yamale-6.0.0/.github/workflows/run-tests.yml000066400000000000000000000016161475257201500210650ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Run Tox on: - push - pull_request jobs: build: runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ["3.8", "3.13"] steps: - uses: actions/checkout@v2 - uses: chartboost/ruff-action@v1 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install tox tox-gh-actions if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Execute tox run: | tox yamale-6.0.0/.gitignore000066400000000000000000000007261475257201500147720ustar00rootroot00000000000000### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Distribution / packaging bin/ build/ develop-eggs/ dist/ eggs/ lib/ lib64/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # IDE dot directories .idea/ .ropeproject/ .vscode # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports .tox/ xunit/ .coverage* .cache nosetests.xml coverage.xml # Virtual env venv/ # Pyenv .python-version yamale-6.0.0/.pre-commit-config.yaml000066400000000000000000000002321475257201500172530ustar00rootroot00000000000000repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.3.3 hooks: - id: ruff args: ["--fix"] - id: ruff-format yamale-6.0.0/.pre-commit-hooks.yaml000066400000000000000000000004061475257201500171340ustar00rootroot00000000000000- id: yamale-schema-verify name: check yaml schema with Yamale description: prevents invalid yaml schemas from being committed entry: yamale language: python types: [yaml] pass_filenames: true stages: [pre-commit, pre-push, manual] yamale-6.0.0/LICENSE000066400000000000000000000020731475257201500140040ustar00rootroot00000000000000The MIT License Copyright (c) 23andMe, http://23andme.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. yamale-6.0.0/MANIFEST.in000066400000000000000000000001211475257201500145250ustar00rootroot00000000000000include *.md LICENSE include yamale/VERSION include yamale/tests/fixtures/*.yaml yamale-6.0.0/Makefile000066400000000000000000000007041475257201500144360ustar00rootroot00000000000000VERSION ?= $(shell cat yamale/VERSION) all: test lint: @ruff check --fix . @ruff format . test: @tox clean: @rm -rf .tox *.egg-info dist .coverage @find . -name '*.pyc' -exec rm -f {} + @find . -name '__pycache__' -exec rm -fr {} + release: @git tag $(VERSION) @git push --follow-tags --all @git push --tags install-hooks: @pre-commit install -f --install-hooks -t pre-commit .PHONY: test lint tag coverage clean release install-hooks yamale-6.0.0/README.md000066400000000000000000000514421475257201500142620ustar00rootroot00000000000000Yamale (ya·ma·lē) ================= [![Build Status](https://github.com/23andMe/Yamale/actions/workflows/run-tests.yml/badge.svg)](https://github.com/23andMe/Yamale/actions/workflows/run-tests.yml) [![PyPI](https://img.shields.io/pypi/v/yamale.svg)](https://pypi.python.org/pypi/yamale) [![downloads](https://static.pepy.tech/badge/yamale/month)](https://pepy.tech/project/yamale) [![versions](https://img.shields.io/pypi/pyversions/yamale.svg)](https://github.com/yamale/yamale) [![license](https://img.shields.io/github/license/23andMe/yamale.svg)](https://github.com/23andMe/Yamale/blob/master/LICENSE) | :warning: Ensure that your schema definitions come from internal or trusted sources. Yamale does not protect against intentionally malicious schemas. | |:------------| Yamale A schema and validator for YAML. What's YAML? See the current spec [here](http://www.yaml.org/spec/1.2/spec.html) and an introduction to the syntax [here](https://github.com/Animosity/CraftIRC/wiki/Complete-idiot's-introduction-to-yaml). Requirements ------------ * Python 3.8+ * PyYAML * ruamel.yaml (optional) Install ------- ### pip ``` $ pip install yamale # or to include ruamel.yaml as a dependency $ pip install yamale[ruamel] ``` NOTE: Some platforms, e.g., Mac OS, may ship with only Python 2 and may not have pip installed. Installation of Python 3 should also install pip. To preserve any system dependencies on default software, consider installing Python 3 as a local package. Please note replacing system-provided Python may disrupt other software. Mac OS users may wish to investigate MacPorts, homebrew, or building Python 3 from source; in all three cases, Apple's Command Line Tools (CLT) for Xcode may be required. See also [developers](#developers), below. ### Manual 1. Download Yamale from: https://github.com/23andMe/Yamale/archive/master.zip 2. Unzip somewhere temporary 3. Run `python setup.py install` (may have to prepend `sudo`) Usage ----- ### Command line Yamale can be run from the command line to validate one or many YAML files. Yamale will search the directory you supply (current directory is default) for YAML files. Each YAML file it finds it will look in the same directory as that file for its schema, if there is no schema Yamale will keep looking up the directory tree until it finds one. If Yamale can not find a schema it will tell you. Usage: ``` usage: yamale [-h] [-s SCHEMA] [-e PATTERN] [-p PARSER] [-n CPU_NUM] [-x] [-v] [-V] [PATH ...] Validate yaml files. positional arguments: PATH Paths to validate, either directories or files. Default is the current directory. options: -h, --help show this help message and exit -s SCHEMA, --schema SCHEMA filename of schema. Default is schema.yaml. -e PATTERN, --exclude PATTERN Python regex used to exclude files from validation. Any substring match of a file's absolute path will be excluded. Uses default Python3 regex. Option can be supplied multiple times. -p PARSER, --parser PARSER YAML library to load files. Choices are "ruamel" or "pyyaml" (default). -n CPU_NUM, --cpu-num CPU_NUM Number of child processes to spawn for validation. Default is 4. 'auto' to use CPU count. -x, --no-strict Disable strict mode, unexpected elements in the data will be accepted. -v, --verbose show verbose information -V, --version show program's version number and exit ``` ### API There are several ways to feed Yamale schema and data files. The simplest way is to let Yamale take care of reading and parsing your YAML files. All you need to do is supply the files' path: ```python # Import Yamale and make a schema object: import yamale schema = yamale.make_schema('./schema.yaml') # Create a Data object data = yamale.make_data('./data.yaml') # Validate data against the schema. Throws a ValueError if data is invalid. yamale.validate(schema, data) ``` You can pass a string of YAML to `make_schema()` and `make_data()` instead of passing a file path by using the `content=` parameter: ```python data = yamale.make_data(content=""" name: Bill age: 26 height: 6.2 awesome: True """) ``` If `data` is valid, nothing will happen. However, if `data` is invalid Yamale will throw a `YamaleError` with a message containing all the invalid nodes: ```python try: yamale.validate(schema, data) print('Validation success! 👍') except ValueError as e: print('Validation failed!\n%s' % str(e)) exit(1) ``` and an array of `ValidationResult`. ```python try: yamale.validate(schema, data) print('Validation success! 👍') except YamaleError as e: print('Validation failed!\n') for result in e.results: print("Error validating data '%s' with '%s'\n\t" % (result.data, result.schema)) for error in result.errors: print('\t%s' % error) exit(1) ``` You can also specify an optional `parser` if you'd like to use the `ruamel.yaml` (YAML 1.2 support) instead: ```python # Import Yamale and make a schema object, make sure ruamel.yaml is installed already. import yamale schema = yamale.make_schema('./schema.yaml', parser='ruamel') # Create a Data object data = yamale.make_data('./data.yaml', parser='ruamel') # Validate data against the schema same as before. yamale.validate(schema, data) ``` ### Schema | :warning: Ensure that your schema definitions come from internal or trusted sources. Yamale does not protect against intentionally malicious schemas. | |:------------| To use Yamale you must make a schema. A schema is a valid YAML file with one or more documents inside. Each node terminates in a string which contains valid Yamale syntax. For example, `str()` represents a [String validator](#validators). A basic schema: ```yaml name: str() age: int(max=200) height: num() awesome: bool() ``` And some YAML that validates: ```yaml name: Bill age: 26 height: 6.2 awesome: True ``` Take a look at the [Examples](#examples) section for more complex schema ideas. #### Includes Schema files may contain more than one YAML document (nodes separated by `---`). The first document found will be the base schema. Any additional documents will be treated as Includes. Includes allow you to define a valid structure once and use it several times. They also allow you to do recursion. A schema with an Include validator: ```yaml person1: include('person') person2: include('person') --- person: name: str() age: int() ``` Some valid YAML: ```yaml person1: name: Bill age: 70 person2: name: Jill age: 20 ``` Every root node not in the first YAML document will be treated like an include: ```yaml person: include('friend') group: include('family') --- friend: name: str() family: name: str() ``` Is equivalent to: ```yaml person: include('friend') group: include('family') --- friend: name: str() --- family: name: str() ``` ##### Recursion You can get recursion using the Include validator. This schema: ```yaml person: include('human') --- human: name: str() age: int() friend: include('human', required=False) ``` Will validate this data: ```yaml person: name: Bill age: 50 friend: name: Jill age: 20 friend: name: Will age: 10 ``` ##### Adding external includes After you construct a schema you can add extra, external include definitions by calling `schema.add_include(dict)`. This method takes a dictionary and adds each key as another include. ### Strict mode By default Yamale will provide errors for extra elements present in lists and maps that are not covered by the schema. With strict mode disabled (using the `--no-strict` command line option), additional elements will not cause any errors. In the API, strict mode can be toggled by passing the strict=True/False flag to the validate function. It is possible to mix strict and non-strict mode by setting the strict=True/False flag in the include validator, setting the option only for the included validators. Validators ---------- Here are all the validators Yamale knows about. Every validator takes a `required` keyword telling Yamale whether or not that node must exist. By default every node is required. Example: `str(required=False)` You can also require that an optional value is not `None` by using the `none` keyword. By default Yamale will accept `None` as a valid value for a key that's not required. Reject `None` values with `none=False` in any validator. Example: `str(required=False, none=False)`. Some validators take keywords and some take arguments, some take both. For instance the `enum()` validator takes one or more constants as arguments and the `required` keyword: `enum('a string', 1, False, required=False)` ### String - `str(min=int, max=int, equals=string, starts_with=string, ends_with=string, matches=regex, exclude=string, ignore_case=False, multiline=False, dotall=False)` Validates strings. - keywords - `min`: len(string) >= min - `max`: len(string) <= max - `equals`: string == value (add `ignore_case=True` for case-insensitive checking) - `starts_with`: Accepts only strings starting with given value (add `ignore_case=True` for case-insensitive checking) - `matches`: Validates the string against a given regex. Similar to the `regex()` validator, you can use `ignore_case`, `multiline` and `dotall`) - `ends_with`: Accepts only strings ending with given value (add `ignore_case=True` for case-insensitive checking) - `exclude`: Rejects strings that contains any character in the excluded value - `ignore_case`: Validates strings in a case-insensitive manner. - `multiline`: `^` and `$` in a pattern match at the beginning and end of each line in a string in addition to matching at the beginning and end of the entire string. (A pattern matches at [the beginning of a string](https://docs.python.org/3/library/re.html#re.match) even in multiline mode; see below for a workaround.); only allowed in conjunction with a `matches` keyword. - `dotall`: `.` in a pattern matches newline characters in a validated string in addition to matching every character that *isn't* a newline.; only allowed in conjunction with a `matches` keyword. Examples: - `str(max=10, exclude='?!')`: Allows only strings less than 11 characters that don't contain `?` or `!`. ### Regex - `regex([patterns], name=string, ignore_case=False, multiline=False, dotall=False)` Validates strings against one or more regular expressions. - arguments: one or more Python regular expression patterns - keywords: - `name`: A friendly description for the patterns. - `ignore_case`: Validates strings in a case-insensitive manner. - `multiline`: `^` and `$` in a pattern match at the beginning and end of each line in a string in addition to matching at the beginning and end of the entire string. (A pattern matches at [the beginning of a string](https://docs.python.org/3/library/re.html#re.match) even in multiline mode; see below for a workaround.) - `dotall`: `.` in a pattern matches newline characters in a validated string in addition to matching every character that *isn't* a newline. Examples: - `regex('^[^?!]{,10}$')`: Allows only strings less than 11 characters that don't contain `?` or `!`. - `regex(r'^(\d+)(\s\1)+$', name='repeated natural')`: Allows only strings that contain two or more identical digit sequences, each separated by a whitespace character. Non-matching strings like `sugar` are rejected with a message like `'sugar' is not a repeated natural.` - `regex('.*^apples$', multiline=True, dotall=True)`: Allows the string `apples` as well as multiline strings that contain the line `apples`. ### Integer - `int(min=int, max=int)` Validates integers. - keywords - `min`: int >= min - `max`: int <= max ### Number - `num(min=float, max=float)` Validates integers and floats. - keywords - `min`: num >= min - `max`: num <= max ### Boolean - `bool()` Validates booleans. ### Null - `null()` Validates null values. ### Enum - `enum([primitives])` Validates from a list of constants. - arguments: constants to test equality with Examples: - `enum('a string', 1, False)`: a value can be either `'a string'`, `1` or `False` ### Day - `day(min=date, max=date)` Validates a date in the form of YYYY-MM-DD. - keywords - `min`: date >= min - `max`: date <= max Examples: - `day(min='2001-01-01', max='2100-01-01')`: Only allows dates between 2001-01-01 and 2100-01-01. ### Timestamp - `timestamp(min=time, max=time)` Validates a timestamp in the form of YYYY-MM-DD HH:MM:SS. - keywords - `min`: time >= min - `max`: time <= max Examples: - `timestamp(min='2001-01-01 01:00:00', max='2100-01-01 23:00:00')`: Only allows times between 2001-01-01 01:00:00 and 2100-01-01 23:00:00. ### List - `list([validators], min=int, max=int)` Validates lists. If one or more validators are passed to `list()` only nodes that pass at least one of those validators will be accepted. - arguments: one or more validators to test values with - keywords - `min`: len(list) >= min - `max`: len(list) <= max Examples: - `list()`: Validates any list - `list(include('custom'), int(), min=4)`: Only validates lists that contain the `custom` include or integers and contains a minimum of 4 items. ### Map - `map([validators], key=validator, min=int, max=int)` Validates maps. Use when you want a node to contain freeform data. Similar to `List`, `Map` takes one or more validators to run against the values of its nodes, and only nodes that pass at least one of those validators will be accepted. By default, only the values of nodes are validated and the keys aren't checked. - arguments: one or more validators to test values with - keywords - `key`: A validator for the keys of the map. - `min`: len(map) >= min - `max`: len(map) <= max Examples: - `map()`: Validates any map - `map(str(), int())`: Only validates maps whose values are strings or integers. - `map(str(), key=int())`: Only validates maps whose keys are integers and values are strings. `1: one` would be valid but `'1': one` would not. - `map(str(), min=1)`: Only validates a non-empty map. ### IP Address - `ip()` Validates IPv4 and IPv6 addresses. - keywords - `version`: 4 or 6; explicitly force IPv4 or IPv6 validation Examples: - `ip()`: Allows any valid IPv4 or IPv6 address - `ip(version=4)`: Allows any valid IPv4 address - `ip(version=6)`: Allows any valid IPv6 address ### MAC Address - `mac()` Validates MAC addresses. Examples: - `mac()`: Allows any valid MAC address ### SemVer (Semantic Versioning) - `semver()` Validates [Semantic Versioning](https://semver.org/) strings. Examples: - `semver()`: Allows any valid SemVer string ### Any - `any([validators])` Validates against a union of types. Use when a node **must** contain **one and only one** of several types. It is valid if at least one of the listed validators is valid. If no validators are given, accept any value. - arguments: validators to test values with (if none is given, allow any value; if one or more are given, one must be present) Examples: - `any(int(), null())`: Validates either an integer **or** a null value. - `any(num(), include('vector'))`: Validates **either** a number **or** an included 'vector' type. - `any(str(min=3, max=3),str(min=5, max=5),str(min=7, max=7))`: validates to a string that is exactly 3, 5, or 7 characters long - `any()`: Allows any value. ### Subset - `subset([validators], allow_empty=False)` Validates against a subset of types. Unlike the `Any` validator, this validators allows **one or more** of several types. As such, it *automatically validates against a list*. It is valid if all values can be validated against at least one validator. - arguments: validators to test with (at least one; if none is given, a `ValueError` exception will be raised) - keywords: - `allow_empty`: Allow the subset to be empty (and is, therefore, also optional). This overrides the `required` flag. Examples: - `subset(int(), str())`: Validators against an integer, a string, or a list of either. - `subset(int(), str(), allow_empty=True)`: Same as above, but allows the empty set and makes the subset optional. ### Include - `include(include_name)` Validates included structures. Must supply the name of a valid include. - arguments: single name of a defined include, surrounded by quotes. Examples: - `include('person')` ### Custom validators It is also possible to add your own custom validators. This is an advanced topic, but here is an example of adding a `Date` validator and using it in a schema as `date()` ```python import yamale import datetime from yamale.validators import DefaultValidators, Validator class Date(Validator): """ Custom Date validator """ tag = 'date' def _is_valid(self, value): return isinstance(value, datetime.date) validators = DefaultValidators.copy() # This is a dictionary validators[Date.tag] = Date schema = yamale.make_schema('./schema.yaml', validators=validators) # Then use `schema` as normal ``` Examples -------- | :warning: Ensure that your schema definitions come from internal or trusted sources. Yamale does not protect against intentionally malicious schemas. | |:------------| ### Using keywords #### Schema: ```yaml optional: str(required=False) optional_min: int(min=1, required=False) min: num(min=1.5) max: int(max=100) ``` #### Valid Data: ```yaml optional_min: 10 min: 1.6 max: 100 ``` ### Includes and recursion #### Schema: ```yaml customerA: include('customer') customerB: include('customer') recursion: include('recurse') --- customer: name: str() age: int() custom: include('custom_type') custom_type: integer: int() recurse: level: int() again: include('recurse', required=False) ``` #### Valid Data: ```yaml customerA: name: bob age: 900 custom: integer: 1 customerB: name: jill age: 1 custom: integer: 3 recursion: level: 1 again: level: 2 again: level: 3 again: level: 4 ``` ### Lists #### Schema: ```yaml list_with_two_types: list(str(), include('variant')) questions: list(include('question')) --- variant: rsid: str() name: str() question: choices: list(include('choices')) questions: list(include('question'), required=False) choices: id: str() ``` #### Valid Data: ```yaml list_with_two_types: - 'some' - rsid: 'rs123' name: 'some SNP' - 'thing' - rsid: 'rs312' name: 'another SNP' questions: - choices: - id: 'id_str' - id: 'id_str1' questions: - choices: - id: 'id_str' - id: 'id_str1' ``` ### The data is a list of items without a keyword at the top level #### Schema: ```yaml list(include('human'), min=2, max=2) --- human: name: str() age: int(max=200) height: num() awesome: bool() ``` #### Valid Data: ```yaml - name: Bill age: 26 height: 6.2 awesome: True - name: Adrian age: 23 height: 6.3 awesome: True ``` Writing Tests ------------- To validate YAML files when you run your program's tests use Yamale's YamaleTestCase Example: ```python class TestYaml(YamaleTestCase): base_dir = os.path.dirname(os.path.realpath(__file__)) schema = 'schema.yaml' yaml = 'data.yaml' # or yaml = ['data-*.yaml', 'some_data.yaml'] def runTest(self): self.assertTrue(self.validate()) ``` `base_dir`: String path to prepend to all other paths. This is optional. `schema`: String of path to the schema file to use. One schema file per test case. `yaml`: String or list of yaml files to validate. Accepts globs. Developers ---------- ### Linting + Formatting Yamale is formatted with [ruff](https://github.com/astral-sh/ruff). There is a github action enforcing ruff formatting and linting rules. You can run this locally via `make lint` or by installing the pre-commit hooks via `make install-hooks` ### Testing Yamale uses [Tox](https://tox.readthedocs.org/en/latest/) to run its tests against multiple Python versions. To run tests, first checkout Yamale, install Tox, then run `make test` in Yamale's root directory. You may also have to install the correct Python versions to test with as well. NOTE on Python versions: `tox.ini` specifies the lowest and highest versions of Python supported by Yamale. Unless your development environment is configured to support testing against multiple Python versions, one or more of the test branches may fail. One method of enabling testing against multiple versions of Python is to install `pyenv` and `tox-pyenv` and to use `pyenv install` and `pyenv local` to ensure that tox is able to locate appropriate Pythons. ### Releasing Yamale uses Github Actions to upload new tags to PyPi. To release a new version: 1. Make a commit with the new version number in `yamale/VERSION`. 1. Run tests for good luck. 1. Run `make release`. Github Actions will take care of the rest. yamale-6.0.0/SECURITY.md000066400000000000000000000015631475257201500145730ustar00rootroot00000000000000# Reporting Security Issues Please see [Releases](https://github.com/23andMe/Yamale/releases). We accept vulnerability reports for the latest major version. If you believe you have found a security issue in this project, we encourage you to submit your finding through 23andMe's [Bugcrowd program](https://bugcrowd.com/twentythree-and-me) so that we can appropriately reward you. If you're unable to do so, please use [the security report form](https://www.23andme.com/security-report/) on our website to reach us. We will respond to your report within 3 business days. Please follow the rules and guidelines stated in the [Bugcrowd program brief](https://bugcrowd.com/twentythree-and-me). You can also find our Responsible Disclosure Policy on our [security report page](https://www.23andme.com/security-report/). We appreciate your efforts in helping keep our software secure! yamale-6.0.0/requirements.txt000066400000000000000000000000141475257201500162540ustar00rootroot00000000000000tox==4.13.0 yamale-6.0.0/ruff.toml000066400000000000000000000001051475257201500146300ustar00rootroot00000000000000line-length = 121 indent-width = 4 [lint] ignore = ["F401", "F403"] yamale-6.0.0/setup.py000077500000000000000000000026051475257201500145150ustar00rootroot00000000000000#!/usr/bin/env python from setuptools import setup, find_packages readme = open("README.md", encoding="utf-8").read() license = open("LICENSE", encoding="utf-8").read() version = open("yamale/VERSION", encoding="utf-8").read().strip() setup( name="yamale", version=version, url="https://github.com/23andMe/Yamale", author="Bo Lopker", author_email="dev-api@23andme.com", description="A schema and validator for YAML.", long_description=readme, long_description_content_type="text/markdown", license="MIT", packages=find_packages(), include_package_data=True, install_requires=["pyyaml"], extras_require={"ruamel": ["ruamel.yaml"]}, python_requires=">=3.8", entry_points={ "console_scripts": ["yamale=yamale.command_line:main"], }, classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Operating System :: OS Independent", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", ], ) yamale-6.0.0/tox.ini000066400000000000000000000003161475257201500143100ustar00rootroot00000000000000[tox] envlist = py38, py313 [gh-actions] python = 3.8: py38 3.13: py313 [testenv] commands = py.test --cov yamale --cov-report term-missing yamale deps = ruamel.yaml<1 pytest<7 pytest-cov<4 yamale-6.0.0/yamale.png000066400000000000000000012225011475257201500147560ustar00rootroot00000000000000PNG  IHDRZ IDATx^} dUuZzfvP6T4 KLD_1B#ĸ&j\!F FQ(!&Tve`ޫ-{^UWwWo3=]]}~W;we(JXh|u*7hUC}U` ZQZyO^b ]}Gojۈ5kc8TJtnsC!Rp}μC!D'DgC䓏??v }=;kع}v<I\N(9E{=-jʁ֊ɣ|i" R!3w p.Ntjp(n߇V>2#DK_v?DrqXnw˯Ywp8"/Ys}v8 w==顭`ǣ0gjc sx2>Be3.qr7z*̾8VPKԯx謳h),<rBc k!,T' [>ZYz.o83;PT J_Xfr8'] rr8,&ւC!X!<wl}۶wvm/{okr_ɓ~xV,F&Vk=U.3D 1ψ-g\m!5גiFyjW YnK/=kY]İFF:α<~-dv$v8Ay>ԋGRGWcOI={b혓N(z9%{Y:p8׾㒮>nǶath#CȪc EJQ;! !p8"d<_gA нfcv̉OrvRC!2p}eλC!n]V7k}x븴ŞlMu*U0GD$\^:{?@ XugvҽmgǯxDE9-SC^}?;:ڵz|h7TRZڬ&SbB%LW]zOBWҗ `iQWǞtGvDy!V:f]za< sƙw2饠ߘvU:]}U 0mn}z`X8fl)AHD)]F8> q#P+}~#~9.c"\ k!ph.o~䎧{ kqʢSB^ff"DBKJ;ʕ~Ȳ[@ElN>O%84ѹ&Pp0\2ӶR^0b`Q67 ǧat,o=: c jE 菺(A$mea``Gv&"?3qTOlMDEJԲ2E %Jc׌M%©&8(9Ҍ0}4cǝ)HG̨SMqw>$9gDMdL\`ׁ/bi uh~Kh@H/伦(:{2u:Ij<J܍9Dٖ##9pxyN>E`aW;/?/㭷#!4JsLrTsRh_iipDāt4rlH=NQf'W4S3!+a3I# "U@0 P| QH䓎"G$;a ̘yfN\,߄I+&O9  d)/xK0P/BO7Զ?U52U BE 7BmxGj7kҒb"DuBeLѺ0\7#mCχR/3GHT! Y䵢k zd@eH3dHfjB&L!I3(E6aJjdJ`5^WHYHnA)77Wt}(~U@}o1˿zEWJF'D/OzcCs^c"}BjmB %FiluL $]`֨OyhPZKZ!]zU0cQol976j{|Vi}LZOJ6x%*iܶ," +7Bm怣!$daxI/SEDB(iD?$%r!N2T38'd<&hB3~Qv!u ýt}t $٣2?;_/g}wC!8ӹ]C8JO:=>z/nbxN-"oR О*db9Gn2HJ{ 2ik0ʆS(H8o&"OC4b@gs#<9 4 i"DL<܁p:e0uA6XAM{Bp,B-Hի}XO[h!r?ӯpn\sK*xۏyv\:{H3AϷ'(Դc/jR0oP0:³NH2WXB#`.SO{ƞzܓFnP} אR9󋬖' 㩇 `Zhc,C5QK(-rrYDb8V|2Z}'ĈY1**D^vx/5 `z.1T`vzXyt 7 ~~߯NR¡T7G69az?@R# 0z 4⠁n-<*F%U9ޢ.em%~͒#/7}(%D\+FDȕF?G6e%xzchhsE"A7G= ~ =6cB"~? uF'^s|./BwIG<ᮻ޶WC!pnps-;Cn-~<>!ٜΐK@4{`+Są *dX[†U -+.@d;C^C=PY/&pJ=۠J0RͰg,Î!GvU1 >j( m7Fĺi例뿹@'5J8d|۶vr!pt#蝠q8C=s5ER o̦Aa̜WŔ<*E5*GԏcÚ^_URH(ǻ!}%jSO(&D;fC!0sO”6s9mj"Jagw=mOH3J)P=!$'ws'=yzp8&APp8 l=](V=۝fmڽ9 pa8|]/jD:fI4qQQuFP|Cȧ/KpFٙ<͜!XL./GIxe#_ވZjG(l(>Dqt#6#gv>g5;;!Xʝ{7rC`(wSjȃ$Y.@)Gh<뉛nFA{p8!0sr.=".}A UKI2$2wc)(n8__<]OC`:Lׂ!p8~ ߛ ݩ'߬d(5N 0Nvp8Me)`gǯи R֭{,+&z fC!0WA+xC!`ظq㡯==rB"z@JzU3܏5 4!J~6sF}p8yuwSC]ruKYn,p#ߺ{jhM Pp8 Oӿ/M{!pL#ny8y@qGq{18Zᣊp%lEyD>+d2P+"zR9#=Ԏk2:dTa;94Ava>1Hl^5\;y?ŽCY[׳bW55I-b,"B׺2509k76T997%xsʓ\r< dDQʊȭS\K֨xZͯ0Y=^۞!BM-˚Jʺ"M6j2mʣ{I]r͕Z&w.٨0q}1~pbtIn{nC[GH6rg/E4TC` "4eC`!pgD7qkG*xޓWMz㪩t-;E= ".o#C>G0 kAQI6i#'K֯:Dmi:7Quᙆ{D>3K=(k<`GI|Uf!e4GkT^Smzj$h1)UsHLLK20{aF*I"m1ͷQޠ"2cHH,z@&wyB W貫"}~@A=Q!djMk# dCoS0gLi/V)C@Ę1'5EChvJFQc :jxLv >,W'o<71(:Wh1t5+Ppt_n͛┆WVM'? >-q9G9K_I+j;ak4yJ6S ]Ǽ|q"[=i'D c3aveD2%H"F4YΔk{H YDpi>Y}HS[) *)"⬀į;/K`S?ϱ(+Lx!jJ[Nv10-$l(Knh`FF e5l5bL!1 #T*m9GdZrd㺣PtK9J^DNÎ;7|?( |C*r|~@2fbd(>׈"MaP3_^yR{t>2" bN )(6"#ɵT%O9EɊGOp/mp+Mǟ?mlTC` n"d"\7eN(?DI 6= [ x)NᥧB1r96"ILb>sa_+6Mtlw!|`6炂5b |JFbc.P!D*CHRUVK'! I$E-cLy1QΔdO*5QBL3bX<1a辴|9Cd C9l8a\眳Msoxg rm0l oYJX]0EIg4Ը$).FghaFDȕeƷm>܉Mr*\&EOue%Wku- Y'2Fp{! 4BRbrR1@_GBB# (%)P@`D@ 1ԣ;) S{G\A3n|"/^z->Ct眺 n!e 2-ZDCJ9(`bH5+TjX1ю)t;ùɫmɄ첷YLgQ6y4olf2lB]og=;!0(S77¶Ėr|QP eOqئzz_QPu$޼mOG'\]ȼ>IzC䞯{+wYAp~_3=T3ӔUS,8$Gaޔ=wӸAB#dbQn<3cC`ٵ;G56""'9%0"pzlt/"RL*".G3psKɘ7ŰhM/_]O|v4b:\vt8wz|} )0›'^_*u 7#0RErzs9;!0ss|~,\ݜkm>b$:y>^,H' 1,JօTkB(? gr(VGT XuS2_k?#DY ?*ᔗWOg\s A`aVnAk齇xۍI<`ѳrayZvTeVIܔmӼ FqVlqaϭ5'?.ل'''"vy')qk3^ q 9*𸪖OMj1IIۃGMmm>@]NP( Jq)-QviߧԖُ}6 s;~ '-i6>yT}!ˮTdSb#=ݵ?l7| ՗o(@LOj[qzɳ}ϭXؐiJ@gߌ|nwO^d^IjC^"ռREe#ዑBݰ^i3ˌMr/h¯eeoQ-[Px("stE7;m|㢓FEUWw)6vs8Mˡp87{޻~ Mة0lx{AO3kRAV~rE.E.K[z@Ʃ D}yL<4u)9丑(PGr@{U"( B?@Q eމD~,I-@dX7Yi''cɈPKMu:DH~W`+ )dh2 9g -&l^z+nfϚx]Y{<ע3mc 27+ ,bi/r*VT0EVC%1$i,MYT dDY έ|{6s{,,5JڨՅ/"1k^-1T"4Yb'.|M&L%$>_~Ý!X~paFp8:F-goAL? RC?F*ϓ"!"HwpR9+*Ov<cc'Ou"Ĥ^x=⩥/L$% oxqDO(hR^fj|l<%o0aS[yՎ!~Zr7/߅wuAiS-řb5e=W\[>':oݘ+.L x{%zj_'/}Ja*CI']n9\qjŜeDPBwXӎp Q#(4~ /Lֈwxz+mIƔ!9;!p,C!p,+.#f~h61Uز~g,) Wᥓ>K$0?+Rp'ߤL]7U0aC53&}b-YiF1Dn9$H0 GAdk êms{Mtj4{Bcx8>KyQ;sB<;!X)_g#~2(r҇=#ڗx{1m'%vyȆ҂O5$%\0@:t]7܃#7nF9%x܍y`/ɊnlS{/鼢")&T+e}q:kdZsLPZ`e=c LlϬ|&?}sioǠHț!Gc#Y& [v X!n3pT|~h_mDLKx0aȖbҙڮ[B'Mr~xoY^Vï]7HS{Nɰm!PutE=Fw TWZsv, o h="Q)+He#q8^E#e՟zD?9bAΆ%uw{]^:'qu?~垱g;!p7=n@;kwC̱\󉇱F?CI^(Q4}Ѥz]S;QiQ@r6 fV}"_c,ޱ*vt[qP8wv&q>JɃ򉠗zo=cO7IsC-C!٬B=RxmB?{ه},F m,"")yyt <])AE6<pqXQ?t!-2VnlJ9C#*U~/bI9a5OG76*G&Jgt27 ~=}k"OoۖW=cnwC`E#n+zNMNEmȰ~}n"Wܪ7y% ?"PaSL8@)ܻ!h=SǏWn>ć~F#eI6٦+%TN*7qōCپ95Eln/C"k|=p l6A!FTOǯl7Eann Eek ({ΑAV(|@iO?lVR0vMg@wԃ=chwC!0ǚ@C!^ I<0R&"zZ%ԚM*yEx: zg8jr'EO'v,륎;!X\=w;QhߟR(͊2ڑ m#yM>7Y\zmDwPXDUpw1".>|X=Rk6+"EFeSXڝd|ϗLLC;E뙎u2 4Q,2$JЕ9!p<9!287'0EL(qcYڗ1VBҸM~QcCo}N%De2&H浤]/蹮w|gXGg<;,9o2>yw6n/C3C!p8 _}~~Vŕ1!&Ĉ9$x9=8=%!OE\%r qaGbuYv>ߘJQc&m,$om# bAay;6Hıh, &/aLP@O;fFpccVtCy7A&В'kԐOX ϓmCYn]:Р0XXznM |{!6g4BfMdUi[F٢IXK Znl:~dh70b5QyJ2+ᓻ(`?㸃 :kpN%\w8szp,qk..q·Lє%՚;jQ|C֯a8CtK/*2/B(H7s"VeA8tFxDF}蠑ΛyrNpZC`aP_16O>՞s5y9#bO^($|B],XFw02_)XN˶I{)SjKj]K>F* b> Wǧ~M +l笂}nU_^'kD%h F` C!N轿 UZ.x#)?Bk '?ׯA~~P{ak7b u㎴^:wTOZ MR"+eůyP);^MY!,R^]żt}xxx/P;S[t]/qA8}cA,,s;3b;C!EPtP*ދ=#C |zh 1*/T 8g jr[ȉ`qJ122FQ!#nQ8+3?=~@;%Tת ʙ>1w% x\e_.Sw8Sxy4Va` V;2nF lmOy>jMgn[:~:ek{ol y 5 @&֬QkvY2Ñ8a-M00Tþa ML1v+He/;(+O/!2/V`Б:P(gf;wC!Dp7%2Q!e782sٜSNU/J*̦!MCqgvεM7zN#G_MkBWxQvb"6n51SUС08>w>R=std ࣫Pš~;3&׸C`"nwn6||!|z@HY XxT>5ٔ.- { q%xMR}_R&oDٔ#UxHDQ H}B mq!` 7VMk`?H9ER9hGG+Y܋֟$"aP럳 FqM18>#G?z(u&/IQ@ f_wC!tp7;w(~/_[{jIhU ZWkP$F=Rط *F?6`:? ͖l3"I?D_Yr77#*#7Δ'37z>p SPke2^XL'S#Wat¯kfꞱg]+y)wv<N?䃾7A䅛B֓>;!55]8z(T[B8s,<%]V0UglE[c\Z3\,b}=)P#Vo| u"LBr7hN@:7%1 g<%o0-XM F-띒S6_wKd>- C`Y#~k,b5AgRoA{9ܞɛ}߁O,rsϩf:4мlT*z(}P {S7DӘ }F- o#V\iTh)>"'M41xRsԒKuc*WئBȅu5W/F#"R&zpCU=Zx\eRN0{9+x\DIw,J F3 < pǣq!>=T/42M)OcN{.|\" k!Xb7C`NO^߳ C}+^{}b?ن؛|sw[`?ְ@ː^&Xx9~Cq'LT`ifח9o$@5{Q.Q -&[6J`9}gQ;!0$jިԪ߯5%1ۆ ($iiȋZRCcI0q.oLc:FrpH} _>NHU9pn {k!>v> `ةc/{ƞ+5Xʘg7JC}>{o{OӜczڷ?1@Et=+ZFw)"bDj۱{B~j;D Z\(ssx- F_O&GA!ehcϹ4HĞ"6k!A$Ԥ4pI@kcr&}:ƨTkUb^UA ~D[*8݇Dj$hS] 9g :"Hp"-4?$C]}>:V?\;OESA 2谌BZr/JކC>xKaӦࠍux!'͵p,(IrAw8V:]W{7!rN-J@JD*wq8wT& >t/7XLJݏ>2Jy=C#7 WJoxU~&ѡVٽuF\~]Z2bR ~bB0 \1Q,@𥰀Brs@ϔ hɷn1 tvU&ژn<vϦq\q`v,TKv[ۯÐd.frҜ4$zIJZC$灋mVn"un6Lt7-ry(VߎU t%(ܟ<JJ$'҃m~4G#Mq> |ThuW-%+_䕯tغ\:+>wɵ?KFҶ'(f ;y8XJ5!D>k? 6icW#  ]\VTat2 U-7I(- [S?=ZV&ld#D _gKA jn"lsbd Z1x[ü;v+6,bV /牴Df4jHh>T(DD)e~20W )o>!4 2[ɗFdTIG\R6#DuU<]AOCqak\CO1E9 \jªa2kw>oB ކnKW=s~[w9K u[j8:K_v|{?Sx4E{] qȑMkpŮNza {j)AgIr@yI;"ܷ5}PMu*y-OttI兵J>QCy3X_:愢*-L{ڏ}3y_+ >*R{>G<~ZrR;h3&3nYiinɼ9v*/vvA r5C0T}GLEt-d8h&2Q'ǒI^IZc7)ghz[,AC빶SMx851<7_1 2cӿV*XӭeC9@WQ [.E6Qҁ26"-\`du'^i૾ݛ_8|ҍ!x랫+(c]S(P>kq\QrlK-vm 2Rh?y#*Xcs8*1=GmWX@+1EF)B\h^{gl{ kϓzz͵M9&lFc5^FlR,GzO^}M5Qu=/]uMB|`/\Wy9NkLCeҖ 4Җ'YNcH &_T {]6''ݒxSwR25qM+wY~=5|ܞl%<WRuM1n6)&\CA)~El(b]_z@@•8Ҡ]F=.Nj݌46CV.8|?B>.ft!X68l !O{FE'ETVxƆ-BdU?|z7O7ciA[J6`9\\ɛ^%! i$at2{ #]"*h%p;vxL18axTcv 񄳥6Bɭu1N|=Op8V2ryq H3׶Q@rA9iR3O*@HxQ;@ozwyéE䐒t o"d%hyy2p֫߅NTC`pQã۫3Hy2ԓ] D6Q&㭌Jʼn\ pр\VS[\.v=򁈇mAsv'\&ʥdt0iIRzL#?3bN6@絚͚;DӮ7D+{ ߆m~m0!g(Cλ>V1[B_WޮʡrGTY2g}JaL2yC}`y~GKnM")7+k/t.||Jzwڃ+}a?NOr">-I=wC`  /B1qzөV1o|S|qD4^p9HziGneKԁ>3J48ZVL`UY܍aHwؽ+ÎQ :C–`qBI//;&_W'Y [^@m1q-.*ro Hu]鷹 $AQY^'”D"r+C@O#R?+Bo}ݔ]Dw1DDy^*nq |JLP/'ݨ:[G35<Ѹ79v,M܅4!x?G 5M7W]Sڄ$pK}{jD?̲aK'/ S8DٸN[A*"kEPtD!Q"]`oUT{>℄<Q]5 02Vx%A5󹜜(W]\X1ػ/bv,vC$ hٺ\VKzmĨܳ5Kְ4~H؂z(pxߧn@ >Ňߜ9 pqGv nwo79⑒R!Q85xyO)eD O2؍Tʽyn3!+͒T4DHl)$Jeg ;O;2yhc@6YJBD41":[/=s:'Rg2$*UcTj X#Sb#UI(kr@rnjY<+ڛRe{}qpF!zgz7Ivw&A]f*\GN҅n+3L=G"34w~F0iUg%Pl&,V>TG6!@"RCȎ#B^ ˕>HJS:_&j'vO+UktG?#:DYY W%2$R8SO2BO=$>aGc蜍쌓sss뒇Mdh2,gSn| A0`J#1C%; GfBFlV)"bW(`½#?@T*P0Ј|! M9DEJQQ_h6elb$ B7GK59D-PWl1 94< LDX<)WITC #X_RB׈ -&nf~ f^JȰ %Zn ̒%L>9^W,e1>uL %W^gܨ]XRW,)&wmHكo{#К1qs"Xfe'۳GAual.+ȿo%ubf4%XeW4x(FE5b^ ,UG;Ap, t{r7rM߶ҔqʳKDx>OrCx$~=;Q@䬛†U).87rjOB8DV͐QijhbDnI(p4O{w8bh';'?5Up?'[H.8߭ C`I 9MGOIK9oFrN-1ˀ7bs)syk6Aԭ+E.U_ /N*a^RE*hJCVɐՀ 0m'gn֗!NnH@4p` ~J>9{Fps8!_pLD<۟0Kw_2Ԧic}w`ݣX&ilk&#BޢB ܅ZԷlHZs%P]9Ě㸅;XCV[)݃N):o9rv8 Z㧏t~z($P(<ﲟ"%y{|*&r\euf ZNк8; 1eҡG=<?};^?p,>f$zp,cnVs9Vxs7Wet"0Cҟ!K۰yG{ }52W},I5Ioop?{Gqߙݽ;u!@^~B !I(%B @ Tjjܰ]e|3w'[eYw:I3yiowٹy~@Jܘ @tQۦ5!*WFkGO xIXxոy{p#'9*"m9C:0Aj]nfz"Iނ<6i^ZB@* rn@uMw}/azAe<@7E>|^JJڼ( (!.}!}RtvͰ @PK{w@C3y{ON V WuC6]`@0 IDAT{{Z/OŸl .yD?7= |2!;{腧ȫݍg6l^&IO+HBbĴ]PLA 0p0}νA8-LlPK|oM$y Z\~ģJM?[}8 ꆧty1 z*nROM,ON(24iaCU*iU+!S)RaucILYB [m]tJ!0"34wO0Q'^= }CDnvm Nd7[`MUI-n,ץ@u#۳ay"8,`<>Sc`,'HŁvKkd b:vFK~Zh!4+F^ Yu}xXPGNL {J Sӛ~,t%ZzHV@*…槗r  CěaJ[V-TD*0LD0yGf="wSx-!)[K.O|i J I _9[w3+d|o"KMX pcI#W8͝ }6}KAxzgffiw ť7vkr.XW,R.: ]QQ2' Qum6 #TSO"Fםt""\J&s<9O(R#Tz'*s6 ЃM42z^w|{:=g$&a}|"(Wǫ5_,c0[Ns7Q@k[yb%`jhJm@j1z#h[h(Ze5ޭN Q_2${9%Qۨ2}AmN'g !`6Amd0t,~g bU`M>|L°uWiQ($=<´QluS'IԤ`3)<$e3 5U7 $ez< =)TڇИ Rþ̫f yAT0Tg 0@8]=s1NSkA,y}tգYߏ>ŋO|Kh jk8mTma$&3*X$¨ed]D$Z# !qqQmTZmO"ES,Z$c !:3_W)~ULj1c2cIZ$ߥŻs[5˓JZHD<'Zz_-ÒnǢ\%1iL{\c$dɳN° pg>mX]UR95 w hHY1~;n[x GWOOʠ}^71G@vG2P RA݄vI{_ODcٺxn9>~w}|/j#"4[: 2R`ƍqba`π37k8P%~$䪗b5(wvNoF{!< FA\_sfm-q:%R/(6ڻOFQ&}XP^Wm8*oTlxutj7DR,Jr +N҇|+@iE`h-4$xoZmBFԞ[&/ bma(u)g 0x{/9Rh" 7&g6Z/j6K{Cs-ۯ~D:0W C,$Q(idT|;Έa8ljSj=깾%h G\`Xp"t#`ͩS亢E!Z?m~<]guImpyT&SH\*IDkGk< Pt 0 A9υ>hI0.qw䭫zU<Jj.4h$Rb o=ۍÇs1'/? ;E n%X2 > 䂢(4@ #XYm6i&F#OtDkl"eceAyۥzܖ+~sc ߕ ÿrIڇdžks҃DI+59eaW^*\* ߥ @RYւW%| 2N6KeTQK3nT!bc{mt `((^ssA,\yƷ.u$kZ'\冻P;a Nr+CR 4pƫCEz)| &P [:]FT jf9Oa1x`#4y"7iB!G_,KWwB!mPI$\ (ޟW?k'ˑei_$+,h+oJ"] 8{=?>}^A ¾  ן'|;N;=l# 3!,l|"$\IsQD)e]:zT)0i[GVepC '<z̷Ch (RK@fJSGHV Jȓ(/-(XmXFbuS)azB*[d :^IMO,jjA 00G c >{c.XmX-IH!!0x#S|FӞmAU8ʿcЕc4#.V=v4bsgBʵPPJŇ,~Õl4M % J`L у )Sg ?Utae,d4UIgdJў^I VTTGj]Ŕ6OG\)n c\?fkr+,fdj$C`Ei,K`ED}x HxAGS{l(#rNQ +ttJ{o.ZқD-Fr)ޗzKPp @l| `Y***Fg* <䛓&_+\>SCcv+ϙ-0oQ^|s>}TI0xxX(c^Mχ|l=bUY7qRP&`q # l=[NQU"X7<(V"|(>8{JC9h*2EfTSR/A8c{YhS;[;/,oF9)?6 ca] CZu.0*C:[אX }t7t6hWpP b:G3puϨ$tyM__s&/AG0Ainf0t|[=fgމN2ǝ+کF9yZ}g8.LSM.OV1j|kԏ^纳YwҜ,P.ŐA"1v Ø6Ǝ,;Cjbbpl1cGbH i 3@]&%FpwRA P<Jz/, I@o"O>we~yѾ64t u+u&M9H&KykNX:[pgKއK&$S|NJ+s:We|aXiic0 Gfѧ;Ihw"6u& K RؐDZ㤀m|cAo`!B)<ػldGsJbmDCek3X&4ud qzO2z-1ƤqñVc1vd5E9aXZƿN~{>a3eo}07P#7}3!< `Ϗ6 zOHy(V [W::W&| <ȏLf(~,ò43:3+$i,t7/Th`(Gr0|Gm(g֩3I0Xy IςhujN0^~2ШkBbw{ւ`.TnVq-9+0n'gFյ L 0I&6n'4CycJL4S'jӆIz? =k+k`K5>ˊİ7N}ܹ,73 A`30'| `<6ifް׫ 0m*n#c$ogABEzZ~RXZ mxjM mYwg:UG~ܫ6%ɧօuHy锌"^I>I iAF:hhcXt--oƚ]Ŕ&AasdgG .Ӱ֓cA.R5wM >#P^BU`'wigC#218櫷OA#0cڄ?FuyoBU^m4oA449(Q5Q$(>|->o~y91zzt ."T bITDc"?Q6F P]E,[Uv"tH-Ik1ՙ|%rN#ɭ[sLcsƒqt&8R" G}<V56Aҷ!EO!G 0 'oqQM.Wqa[5#0cXL?Rj?{AL^0<^pOЁ^ 7yt@_Dl}qL r|;W&֛uLKhJ6DD2VJ:T>jGI厃2H^;uPPUY+KS2\SXn]Jfq8,)wwqTB~t2G }2M>g2kO5-yL)re+״a8-oڌb4$M+Ú2kP߰sLdP( '5( GUf)p2%'aUK]tExkmY7w.\d0fC9,͝ n p9? zZy]{M j%7Xe.w)Gt"vrуn1*_V/}Btjgi1q*yFs"a3}f~^Jusۓ 77?, K0fd cGE0j#l ؖ %u=wLᨪi{xŧt;†Н / "Zwȳ!R n܂2Z_FaBy.lA./;,}{c],8}JCp hlNq VHPǷw>a$Lrpи1MA7Ht*IUMW|3\^mŶ[DMu Kn;"}F9qԞ TD?zi%>gw{ 1XAS1]2׾3遦=$FKd>2@Mi$1F-˵ʵʃ~⥏[E㨍 ¾Ƈ-+ ]}Rǧì PGlapa`&XZE"8(2ODM=BCOXGS\ "!2mcH7f4a-*} Q3IS5*>Y؈,0`IȵkU5 o%q,kDScQQ -0zo6jޏC&Ab22òmbF1l}w(Ob'Ydal$ǧ_4~ tmh~=>gfLA!`zQ3@BDNƵg8ON_{Sqҙ5="*-(F#ϷQ\]Q搗69WOWazEü>940*ɡP#`u;bԁ*!   jcd!Q7Si/1Eh=p߁$H"m1+kPOy5'kgST( .?Ux'<4XꡱU-ݚ0[y *yG_*:B Te \F Silafl5y(F Rdb N*HCw$Ts6|pc﫨0C}_ez`onb̑A"[Ж%`DЂӶÌ]k,өꣷ GqA*=kzgkxR8@FxxК&I(!%yT;Uc &9ºfv:m )EJYDT$,)P]b Lb&F&yQǞJ\{u^?+6;zzG4\YO"mlSO1X^DI눉bBt{sl-aF$UNjFRƒ!x9Ԗl0E" ȕbzj-ہGNp"$&(2ϱ%uXZ׌5qo*E:.UX7*"ƳpE24GW1W p*ÄdDb} c(zp,zw;XQ(aNOۻ  Cls_ C&.p0bR뛍-%,:9IJ$XFC<ǿ^XXAu-*qwPJ6UM{%ZUW1 #:Tk%glEZB7QZS86u,9#b E*+jk, P[QSePQ, )J, :GuM6a\.,D\fΥ"0 Ȧ>Sk, BBKD=gd]5QMZ m8 3S/H&2I6%cmCG2 .n6P&t SRǺS.7}3Ϋ0vd-4 ƈ({5TV>XH:.?#n_/1O6:Gl fu |ȗioO9ʾJ΃}JJR.}+Lr IDATKD/.y5׶.8~kRx"&@ju=K+l*|o-"<8<$[@T8o*ג."ZKX\q<5UC0|h9 0hP QR}iHKÉ|KP3yiMPZTC|{ zMIO"hR En |&y@cskZXۚDSC*͔{LpbB/0v:}yMR6-CYV>\iX EdpcH=K[I 4$#~h_:op^yA P^ceǮoST:l ę~רO#,;@Xktp混NӪ{-jhJ`f|E:CBtJ S 7h͈ *h `)[sR^{%q,q&Q, bpND-Ne;m)EpNbejs,;K;\8?("*T\ 'BUPk-CX#M{ /ggp}pC~ϣBEqژ"I)*Q.Ǵ6C󣦩*EI^fu8ja3 Il2Kw`E]2D(DcU!ȦT7WApnDuVP ;:5 8ve[O[O*QGGaN z.0UfCҊz_ lII%x|qq^Uro=T$kk8Mc}(Wf-\ӊyeqշMw3צ@C xrz+6F ¨QehL=Q. }0PNJ/W CO7_B]>kyb,?Jwנ5}\ׂ4bE։)+>ֱA"`6;w>fww<.ݺ&4 dm[a>;t\b~wKAy'",mpC[A4L9=ޮWyw4ń7yd,W*~tkH⍷aeHI E3 10-&)\A(y{i)09i6E12p_Prj95zH޷PُĬ$fL]Ck3Jd%d/C<&D+EWR쥖p5Pmۻvx39bg0>DA}wy8 __YD=I;c}(n՛p-7Oڬ=̓y"Hh%QWׂ$)Lu.(a7 f | PڧM@1?sd,󨴝HT Gmg %|HR+b[yKpXGfp18 ס,b(ګ^~ozna^g Q*Ij/!]\ePJ3X@AoxgU|qYEl{8}0fRN2>Y>\編ĤA1V[%,QBz(GO/ `+O]a^B] 5'>+YpOZ>>]o k[xP|ɫ Y#wvӞE@ d"Ri/y%>ՠw᪺s/[1[;>,9q1pVwx7 ,8וR;-lsʙxJJ⭹eX41q?!EXZ@p} I_A{TCa%` \pѥ gq C׍кu!~Cj%.^TC@ȬH!r٪Op|߳jpӃ `Tk3j7h<{E$^DR| М`f$oVi9}0X@ =  ~Q8p؏Em!ƴU7 &O(SP>et8j1tH ƘQ1tj*V+XA3)a`\:ڟ 7sԳM g~~>ng[{7uĮ;X2 Q; ywM `(UP3ce\~7O^cXE|e fN k<핦iD"j3DAg,GubH0aߞb{ep2Mo&[?Cln~(4qpcaSN&2mv; >3@_Fl}yL }s7 ?gy ŗS5y6Da2Ç ȡ\K;rf-C Dz *=k$=9|tS姻|#90 O ":I ~ye%2#<ã* i̾`Q+i\i{}[S@G'A IO׼}WoH_YW$29_ΔMow/V%n!24=o)8c;Q ć u$O .(>W&I[k;A)jN i[6!Ny| 1.Ľ|Ru2H)$Zi4ҖDK<ֶ Ziw[2TZ rxp=ۮIUpMi!ր1D؂tV-%cVG˽wQliMGk_͸1oȔ;G@ EBem8XA,j<"Ae%*mTW"2TGUsǐVCR܋p<X>G_$dt$/>zEA+{-NkH2pyt@W/khaNj[qSYF^m\y˗(O fyݦ/h ':v;X^Z">=Cm7% ±'=U"^>8q/wv[UcC"GI2 * ٤tk] )ppԀYp ZXE&ЏITFQ򰻾hMؔPuMRHJxJj5/HrU{U~N&r]VHȰөV@X aMo2l ;&+DVp e3bvPrTP[]T,X؀msyƱUjʺ; JW4bC2HzI H}2mph;'P뚌-)zޡ(G*X6w|`Qi }c x30KЃE>W@EvA %;r+Kw&qRlmM^o;t~}N>";"Qw9lL/=K+Vg>JLa#K/P.9ˍ WAcJ.x"sk$w R# F$.0#dGȟ&܊rҮTEKsi4#ߚRDC:s|ɘ Yˉ {2P ׆>ïFC@vK+y-*8 (:N"jD#6hB vP[]bQKy;I'\4*:BGiy Z 83oxxE`zMEx8cUZGHzf^8ZZZ:iD2$f}i%ii_UiPvekFډxz~.}4^< `(ywcn:h\v7䊏_×>HH, NJ3YV!6lXvm+Duxe!p."Xy#C--qgoA4 d].|$Ck:ɵ-"]$ZI\{! RUI&mS@PGBSp.(AluIu\|J,)@YDbm*BNC2 B~ϗXWJ"D41FiD@կԐ֍jY_<jťH<`k46gsm۶"Q#!J^혃hFyY ]F!8ذɣm6`Rm =>izvf7*6C^uޙ?W 6鲇Wz FUQLaڔ812/Hi;:>pU8doa2wNebu@6E@(>Ҳ'_ 2/l*C`;vX [:ܖ)iAV>欇4?" ?`$=gӒy-Q r?sogPS%6:dଛ;H<ȝ~cm7_AWdS ztofWpSeAȽ;NEi#\bMr|h/_o2Ab Q<͓ sbzi<?~xV"MF^=o7)^H(t,OTr,H>!Q%l:˯{ | \tOw6]dWQ慱s-*+p$W`\zH7+~s{kq9_ $T:UL͗HWfg!Ҝq5'.mA9g IDATў[)_JZO^jD!aS3>sR`Uu˳يWF ԙBC#we4 RUϠ5 k Tn=ˊZ D.>VzȃpצaC=6]Awu fzyUk[?;  fҌ ٚԪ;lO;]QѨjKQbî"Qw , :Q- /WɧduPV۽ JKo5KV¦\IQGT0 ͡X:,>G{:DBQuɺMPZ*cYf MaDп|sE64TJXqtHA1yOsUGd(]8uN<<)E >)>( ʓ -,YjN) `(  A/y00 :履~C[v}UbmD> Y"*IH/`Ɇax]iȸ g]*?B3͙`_ܵG>o? Ab]T;SՋXDbe>S'|4'HaqQ0a5C*Sp~ήzI[s{KDU.. V_GNbA'5WG4?|ac߇:W/.Ej"eTڛ{w<hqßk7 0&1& Л'wkDU,T#Y@Tl / 7âw$/T'}%2S|!Z'p1zXa?rPo-=;)'O,GoƊ5Q,dQxAWeΰMa'Z\SvT:vq58( G$uNwI,t ~sAm~7CBՖE? [+ d ޥ< ȣm%AAgik~r#jMR0ћ~ww>[S-uKkJٸxհ%!Os-SգhM0װ1HLa?̼A`@ `61f@)?3J<!qOG3lx&߀x ,P>xXҧO'%i ?;9d|vi@yTjrwb"$"%k ^+8/ѧXQ',rRf#OmDTAVZ-jn{FxvaX( מ Е!TSi Jg(?=G5u)GZ,[[on^cI{a`}/Z nyxSt/?_p8)_M-H{^Eӈ/L|سٻ4 P2Mdt WH7wJ7Un2$KT$NҵtTb]H2Wi6REz~~L8g#B qE{".Ux|6ڒ.e(;:g<6QpRT6[-`صeY\,(i=.gcCO7rf$WaroJ)qMϵ\~TPɛH]K?Ww,.݅Mq=7.4"C.=j/ <)ᚿ}9_4+=6#Q[0 àfO6{1fǓkf(5~-$B%3wվy/!*P9rH6, @x-w&$…kBcMC lb""[M_ v'h!#k\w>Ja i/AF24>5}' >y%-]7v)vÓ+0E."8Ś4Dp{tԸ{(lќ(C(BmbpcI9 e-`eܓc){q)rGiAH㎳B30F4m&V4gz;N?ء/^|{9}@s}ނ7_v_.ub`0.؁Kwg@8GEWoP-f8W@Q97GU=pkM!OÍZC}^T$7lj|`,,FD؂[w>{I,Ak"Ji|sD}i*~lzD"hAl|}K(r⢽ If? E^ރpAu)7RP26Z-|Ĝk@O8ot>ۄJ@A7*t|oH.& Nckx6Ǿ{NVUv#3j_`{&-6\)\Ewd,c"ֺyr2"Mw Kz"A_)#-`P2'Dui_H[7@)Gq籤9%eQ5 KxIMW70EܒmD9mAw^^KLXL @pIt `%ng/?H̜uFL7Bn{;3GU Zp_?jO` [N J09\O%-hw:r{bj( IE.,E֬i9 fZRMQO:TmUZo.V8GH\1utD*o] VV CZzMSU jd rj5tTAi { 0,wGy*]OlTa]rz~qshLGN[i--8a2 iM%XYq?>#4^dwμ/%Em:l`bMAƕ ?,Avo;`ܵ.'M7O4`%Rh{0Ow ŗ\u~x(C,6eS{WZ erU/k0ed :e oy145;~jU~mzW7yE-6>%cwB+^)M žB[31rճH4.?eեz+ A]jO5@ߖxS)A8"ㅮyiea4ߩ [fʊW-KF?b;x)R;i,\3 }Ze`(bDFw>:ڎXI!9p,h}&vZkoP;3~GSC)aM  Q 65gk;(Cthe|W^oT#\XbGjHj"W-F0ԟZU7XD'bCJS:D8('ʪ20ShTcS9A'/QvC%,):V׭Tv˟cB(|cq٭zH{_|r;rKO5ey)|9Bn-z.wWW "cߤP๫B_Zps Z)m#,H)F{Vn']~7@UEᚙ`xMtunS|yv! #k^UJѷœ/-3o._;m ]aKwM %@)y%A y-:6f^'8pL Fɷ9,K@$(AϺuyq)Ol ||TTXTg<̾q[2`ʔI4u"*k*T;g gD9";:8k(vUAJIן7g^E**KNfUIsdL cqը/7KErKq3n|h^(â\y{sZum6,OUm\k-F弊#frWQƄ @0}xXN,ў\uqƻ[DNNq<)v2^ w>:~X;OƯ9]E\ }[~.X5Yfzg< 7;8}_kA9or$^CԻ09nK0^ϚHtn2t4%&'-|8i <>h։y0Dl= -b>rS {c,ڜHcdegY!V+Q@n `*xY3 z?ޡ\H)䦇$QPA)PkY׶ֵbU׶*wm+e QP#=ɭ眙fMnBnr܄g_W=g9s{_#۷& SMd @(A'Xl<ϝQCqSg%\|+8tPtM4}d\AO-]y| SP_Mf鿫BW_n;5)jy&m{U<,шT Gt'" X\Ej{™nF h-[0_Azz*,F_WCpa~[cúLR6 =P(KLT p)a 죳S)H#e0!ڧ,=MM~׏u'PBh!'AkHfmPIM 4ɹtI0LxxrE[0:V!xa ]mlu tt 8EG!~9O'-Π.P=m6[ssj¨D(~ j69 g[ Eu1p޺KC^]1d`y%XQGۉpGC$`iDű4(>xd/~Wq-Ćy ƕg=7lh%OoQ̰I*M<y$.ͮ=H:|DsG~^U`9wdE֪ [50['Cg_*"P1iw$e%xჟ%c:{YY5A;% ǾDERA_/PxUത/~AEF :0l9h7dNs/fgH)9p,rw5*ցmmȟp\=eLfV`P">ǟqF]O2J$[e ,A[,1d/))z`t.$d:g.K'=B 0BUֹ  }De~ o9,ķSE OQ.vF,ĜdڍsX*{ sD;^Rj&j0ɨ1)UkQ^Z)'Y.-S5;E5&aӑ2"Ԏ +cޢ"A u&JH^~ E_,@M5p``܍7~|pٝ2qW(5 6\T`عmBH-\=.^ C]L=D"*Ȧӽзۂa3^_10ڗz0ImygX#/.A[.T퓠4oGʱ|~ J{P8z5 Vf$ڨAHzTk"~v= ZB= U3?PmuFF=>lSUt G SThJ:RKW[]{IxBgeCild 7[BrZc/Rj|c&\j9<rJA}nVGt/a =2C£7 ]ȕxfУܕF:n{ (kN_ǝ8 $^˵N{ŤG 8byVTWJ9 qjcA~HuQJi/T͌ADSU s}!J5rHtN1#y?I$ޑVL!iӖӎ7_SD0nmˡ;v,X -lmh\֎ H \vl/aqDptb=G1N2=:Z0N]3Z[Џw=XXo0\Բs31rpdv"-FHOm4fC;r Hq+Kh颽w/7pn: pjҷmWZpw p7nhg`[EV Lıc:p6 gA8p,Ц8_!zWRÍca>w6=2xڅqdktTzئ؃ȤHEY{x'&".KhťbА2l 6,r9e!ɛ? 6 ()-Þ{P^Z*Z"Wx|g/ GZj*r:e#K.MW@lt+; WS, o GIq Nli9r@1tIۇ-X ~c["1h}Xߎӎp@ݨt B,[ pX[8S]'dCMW1휕`)=m^nr7ۂV"uנkc8c\:&[ {X-٣()`h@o)i''Mߏj_x3>XRT#!I膋CrbJ]:qUË{g +nYoȄu닙shhzr+ 8gp6}fz~X;/«0t@; tEjFSbjrẢp@8ODz)P[S}mӲr31f(^/ ޠMlxeEvFYq** `Y2n'uo7.^As.g6{nσl5' uS-\ .ڽc\B 8x`5WeVJYjU*Ih(a9%Bx‘ei)5. F@@u"4D,"| ԧMړ7g6Tz:Yjn4.5E?򠋻چ$g-C7A#G$"wgs+*xjU9tR->q)QW"^K<"аn[%y퇸 yyl  8[myt;s,kGEg ,%.};ͦ.!5﮽2c5l { eW(`cQTR 1sNκ&jp1RY(GՉ!:PVZVcOQ` }pMf-D~| v 2e՛qDm{ [k (4-"šȪG9%FмklY/PŇ^{6zc䜺צ bxBм kn}v%Y+*ǹqXtnH3{KéOE|c֦О.pa"ލH僯j \9LݥG `X3n>tc#\X@wpXh:\Mܡ).}fctoX*Ac_*cc"<@?* PU7_jP/F5 nKy~\pL:=,LH:]]d ѯƭ0<{l)ZTqK(N%2#eWi;Uস kTŽ1pYt~Xi+;u,밀v9cLQL w=~,Lj%q27^(cQW[E:JkX>O>S0ϪqKt=6dȩÇ`s_5:WWزe;J8Zuإ u˓@u lRw' 138pY^-?1SJ<z`W5I k( 3~ !Lya!^<w{BEiյԽ?j8deK}yږGT &wl݁E  )Q>C؈Y"T#SqXt>x-BB{.7qcT_v Y-`q}0Lk )v$8䇉 >",5JŜPfqt,X p6$ѹ/iM]{k~PT?0BeI \#/9nhm= +$}굧hY ;t\{CYmI #›w+c݉Z}A'y&2iX/n ln}z Nr$I)) ,EPQkV2XV+5(9u+Q [J4`KAy{nٿCn$}݈z\~Lċ~l[|&Hi:9"a Ƞ~}i-mqTRA &,̼b@=A^XGɘ|l3"^{™ɱ⧵Xg)tjQK bD .<*.EIy6WWUDRm$5*dy)/Gi؍[f@%i9]Ox싞fs e5-J>;a[+yag:p, 8FRdGk_6 bX0 y8L2GxKL.MKB_M==ڸz3j`>kP <v;!'PC/@z]ټKfM:oK?e闫aP >(piY>3y4斂/[d*|~[~q0du,J5KwI٥b/qg>PfM>)#-bW vb-C_r[ 4>Y"8a;sRfẑYjbDB%$;fu6#g|O%/vpESm<WPL}X(3ԦgcqGBq7?Z?Ѡp劕wIH6,0 !# 10Mojnz<7\n<RRPuCT!'H(5]gUa u2$; L;)zf$YCp3 vzס{\8Z'zKdgW(q,~TQ?IKw/BN Nyα/ v~&pk-V3 IA_C}aîY? HKYpWkoccQ]x<5/:2ξ젤I31{2oe( 8qVf"?#TT^Ad7)ϽA.~,ZM,z1ji5vl/B8hH\ ۝i(k"UDF9^tFn4WAWvJμy_dXDTTjv08` p%S$GB1q p 'Lh(ΡX*+pyHhL'qC[BKgf$3Ї?zi%1MC.|#j'M= YR khPM VVTbTTT"  `D@LjBޣksL(aqU*PE ^[8nϋ4!-#-BX&ϫ7`%AJ8h|?Q1z'Ď M0{ ̙v$gN\` f]"BS{_ bak//X 4P0wϾv+DI|Ε td ϗ#[/\~v.V(R/c}bt=!;75t#{^_GDLOIvKzE5eFE6yFF v Ĭ +YP͈&Ol sCN24A %Z ޫ F)4W,[]e"XI_K7e,/ \ 虊~}RP"#Ղ0()O㱻-2v9wI CzZ@ dq:+:Hy*Vhаi5*}c˰YwŒ\"!3uՆ2_J5nʋն! h55{lP!f oj,`4(vg~Ӎ+&R\lzDiRNK1ɫH,Tlv_]zt؉5P, 6[J/F@:wh7"NYݣȏ(=)l[6t]8>碠3Xh)LFW.@~HÂ:B <"(9]'O0pͬ( SqtB($/p㥻BK : %|[zy9d"FusE&jji vK,mUnpEZ'#MkvuA&s!>h%(Qۀ}1tĐ:;Œ0TWaظqb&gTPj$(A{(ItHA0?RwAo"[Ԩ)4w5<MSi3[#ZߏK7ZM|9A׌f`cޣH?uѫ}9wg^= U ԩ8L h,Ɋ7nА|3o 2Ęb_YYtJĩ&.A(򽤳.WhKFIk%KT#S{ tSo<7eVʹcqY=K3MS+4mYanqs.`ws M,! i11ns]])G>hÑj+2eggx%۶moVgxq^^^G\VsrR4Cu"$K+ 9p䌠c)K Z^77npnG2+drΏ[-{f!R5fՋA{rp߃)^[8mmO@:XW4 ÷ Wd>78+@ƞ2 [S'ۓLrѕG[uClp0l>/;}r\SDSA$ifK 0$ϖ1+`BS°r Rdd_zTAIڈK>o`;'&5[FVo4-DŽby`.)ƣOml03|)nK|8H?ט IDATvY2p$ w]fWWDZ8nCB1V‹"o`"paap]hkzGq( zm\j&ԡuk &܊ j#TG#/KE,r2Pbۥ?yiE${ VE. g}EOcAٸ A'3͹} _.݄w?ZLsB_Koќ'8:p,X, 1`+,@- o).vg2,-GY$0mKEEuKZT_]EKNb!MW%# =;NХ{wgEϖóK/]xvutX B 8}Bݑ"r# C(lb oeK6-Y~kB81jxk.1DˏZIh_J}Y 8m2d"p\;TBTaG=yX^h6)k .Kdt(ȯԣsPQV__n;rU< mٱ(U~x {= DiM4owUa8yL4nI2d7|x[ A[ M$23SlDF2R O.Y:dNFFr<@Ka{P4Q\i\EQJ*LB}BLhHKTPњ(GCcVB8`IPDq3{ρUH񿋊M >D*{<x(}dA.n%BBa:@)`Ld:N# o/Ú 6F"tS=3ok>gNO 8p6vO6l/*L &Mr yR54`ݢ$v ff*20<<}c_8^*^W/$T1Ѻz0qZ]5: z0=6,`LMa~'| g&@J8#A {w͸v~Lƕv&tN8S7vХcFsn)yU$X}M+= 6eТLӉJj،րjTcp  i-PooVv H}Y{Jqfg!71f7xkY)cRO<*l-{fG,CW \z^ FIq7Q-2F!=U`t T{DT4 Qꏂ9n(S:=(@3J,I'5!-&[P@@ CB&\!ӑbb6 kQkKPדV3"]dy)4ƹAiظ?bܰ9'䆪/bd'=bbrj0Um\[ 5" x-:5 :jRAnMQ$Y]&tp?=jG57,o9N0L<zv- mej۵3-lܴaSoӦMQZja[rY檥̿p5 ӡ7Ǩ ]Hv$Cue#@q,F,JX5 >Uqޒ!E݅`wIfk-0o.Fwd١DN`Īȳ0%r].wŶ)xJ«;d<< }eA)thafB2bJpqO}!;rbzd^J6JV!t(N#mAsPMq.ALC0<a]R_KU kRHӚGy Hk̮(g)>eg˹ Eq@Öa.fka,&I[5݄0^ոh|*\B54?{~ qWJu :8 4H֔i5=W0(бpw#xR; T9xtEX$j<3dx@'7PјeCr _}G!E@kt'?s8<ڀ]e]6=eTϘR8[$rYVKQ[pEG(k[Xƭ# Lhd{"maT͢,?UjeyA#\r@%Չ\dXRSG|w彀6!9™MeKBj\׹Yw|l7n*YL N@=*pQmBiS ]FVK'V;)*uSQp̓Qn4F{I˳ꁩcz&5(ڤ}<7.܁}bigxqpa@h8qU{~#n>_듰M  8p,cAor 6okO>k+0 &?Ri,}e"ӌKN/TlT0`p4d :٣ zN9@yE5,3> /NB @ ]䝗5_wPRh!HIo*!VM?& 4PxC 缁Ye֊'ar|U8eR&Fj"KoOB3_[[j4=:CxٚX_b7[0pr~,&I-$Ȟ܅xr06 PGp!K94KfWyyBRlcQ=tZ*&< ^`AF&nx#0`z~P?7ֵLcP"M@%G`"ܯfM^ꈎ KX1 BV)sDw;}X^).VGbf.cD8rxQǟ~a8gG)|Hi5)p珂F TGkAU <̗q0]voFDZcmu?^twC,`{DԈ܆ -lҖ.S Μ{Lt+VC8SSnr.AkaB %w۷oK/,iǎ+.לtkd^vpRpzj?LIֳ.;u s^ŝ|9FjrY vj69@҉m! w޻wS.נx㡵3?",~3FܶftNl3죎b }mHr?|jBT!F$s?X^*2t0 PQ#I#",B*})s&gMrP .a:* ]}A!x4`!ɐ-ls;/J[TSEaEZS*B Q\u7.<2J,`>\0U i <6m2&%\#o.+ŷpCOgdҿդl5vtv cP tݯǞzt ,ؼ Ֆ(R͜ Ahkᰍ6ZkZ7&5t#ĉ aeu?uuф1=!؊4P*t~Y4IF! &[LHا"G=nFug<'E2R89h`8*AlJOvaI :W=xOuۤ3f\]U+^\wx0q/80X, y@q75e <,$@R;`B!+HcT ;#f\QrY2ŕ’^l>0M ׍d(,lqn (j؝cZYM{-`ُew:27-:ua6E;#s )n)qA`'9~'ŤkogYS(eڍA]-J;$Qc\?K@ݣ۔S$xMSk;36 QԷS=;Ps1f2W 8;eߕTE`D.!E O b9V*. Y82O0:j[{yޠb} 8vd>Ο|@- ?⍎f>+WK ^ܘzrvc(tgIjB% .-kpӁIJHPIC5*VD*f! TDht Czj2KI4a2 8HbmSA:Ll_Gs%.kGY3 )/\u!fg &[]Xa|gZU~נCixWE}z"}98|+̀ZL;mh RI5Qڛ82_5 \T"JgdPDj0v+Bu&M!'S=-e%Rã1|OEAvM}GwX*aÇK&kG%%a&й3ł&. ܢl%5  *bOx0x$XM0wċ^5`;!pR 7aj.>c/|P0N><=KsݐӜ7JC>,+ u& +u <|30uv":*M.i ^{(}hs&RCMFQ{10utW}q xمSo zkn::p,p6F 67WAFfhNapA> 22L ^/2RRf{ǍT^ )\ 1똇E"6#'!l B0G"O` *QZ=X_R32gL!JKh &XwYulNc p۞[r_ulܸ)!H(?2w ٥c\^~F^`eAW0vrwrIwN s "Q|ɗv ~Έ՜)tl)n|!$J%9YD֝05Sʷa')l# ː )*%$-DHBޢLjV+w׋+ }yrrb'F0<`, &3}\JteB>$K:)GfSrcxn,YP96ܝ7еRNo)"Ojuqӛ}ȕ^y:aF~m5|Q]^TG&aU o1L߸ x8]7wKv&ޑ4tp?qۍ7Z{ȸ؂ 7Ӣ:8Ă&2-;d,C!\yM;@8uHbjangҁw/q+S?HhMaH?wskmmҭ\'#-h\KfI c1h@CmI peÚ`PO{`C(n$@ZQ}B8, y^%>$h_e@:Bb6 WTc[~"n7VGJPyx㒫ɕCsqqMt!iyI#MrU%pNHO\'JOT2sUzfu"wq,X-l {С#pY7#GƚSbɉ:2S螛~] зsgt7M:ٿ(ۙkbDn۷FwG^j |.$401R_CyNj4=Fya@`B|a3[K|8Ɍlع waCvVa 0kdW -H\pp;o.oށ0wiP/v5I\7ovZ>:qӛ6+9IuiP#RNkRvSb^{m+jkuҎ9Awt@HHH"y"ۼKk^ʜ39]g֙T1V %F30i΀ \-%9I=ıHӍ1 +h,jNvq蚓>]W2p& [NdnP1++sƤOVTozBj%j"d8\pclJ?ҍ$2k6mq! ڑϝSGvGQix0 RDΑx#"p {i[#:(n9p,X`;U.y܏?+T, ;S`P7)* <ݺ7S&c@.ps@Y 㟯`BL"i9 'N@ Lz׭ CuE.x4nMP5,W2ٜ`IYmgpJRl(܆*JHJw8$b' mv\݅n‘t%l)Dib]vl-+AH"*j-?wsRᾛ[Lfq"T 6NEE|rN`JNx.]| Az Ȉ&.q4 MLǿAK%r77)QZl.b=Rߜ41O9lޝ>- T%G\g:x5G< 3SZ 7=I[GCLD*fuĹU tաU7v3#,( y5v ?v( G?Ai"ԭ_1*`CGm +6Tc[B>»vcZdߢGyyiiP]2æ F&H8F#ň!&(Kh}4ǮW=$J"LkTaY@'wVʳiatH>@ ƫN(А IDATl%^!ș}_yoER/4.AP}: OD/,)% 5`O[JKPXV☵$#—sECk$4AvɛvxV\zɮ//ybL4˹i.9{$tR)k ZQ?ŋsߴ\q4O%mFࠠlsk+^xy=>Hȫ{P}q0LT[cp%UgI*2iQ?䕼2JP]Lr{v!Ⱥ uKTB8b::\Ҝ9HƵr3&tL0 jdgq L;E7qEc;[bPgH-xX8On8shqqɁ?]A`F@\8h}m3 i|( 1 ,{w_q ivŭ<<"G%PL\Z2i#'C@z7է o5l0֥(f)P!5 8gQ( 0j:CP?ʱhc]p 5?)(Y ۭ_e呶*s4_mۚX[^pϷ;ђg}x_;w—ڿAf-I֒4bCJP ߙ3 8aPFk0I A>~\vQ.|bYZSNkyg)DS+rI=:3̼(tXۊ,|WL_5̚ 5Yx)Kݥp#d]{ :סYz-@IR"6σH̺m!Y贖Y CikrOebc?ӜF 3(> 1DO>? 9T&ݢG` T14;st) pӐ"`-_[= Bp1\^x1^c3z#X\|`=u|*=[x͞H6n.B(|ڵknTz /[.?XDŅkoѓ,X0YouJ5{78߇xC*Ie+po00tQ--x$.=;r=;>h ӧ޻ /+q߬DJm7e29LR ;_j=;q蔾&$/EH⍋vDٝ[!$4DuWnzx2{ YE SP==;{p#o^p >\Kr# LSg?CUCpŔpqPM8Pҡ ̹`xl˨\3I4o'rL /pQ'#Y12\ލ40TU,Z澌C_}ڑy  隄巗N6l(T:H xi!䠟|dvqcƮ{2w"{ŻF_PkRZ, *nFEkXdKR0m|*$ugsLcZcB +ŜWK7YIS/W @9*nqj: n)߭w)\DE*v ,?i eMS8MhEK9n)k 5>蟎~7Lp(Ъzqy1{z^{ӹB1+1鷸ph$- 8,l"bp %.Fb06 ^}\TkbN"옶]#)hNz<׫W5bVC݊p{e=DS#E x{5u)"| ,Ke8[W1p<=2s/! S>>E @$@Ynd ^ַ1 BDf|l(55v1=i@v}&܊.jbo+mG *$tkm wU][SH7Q(((w^)6,"]FQlPRE*{/m[HrM%!|~Ξ9=ymQ}鍔{S6mZt:a`e\y4?ϭkFQ4iΔ;)k0g~_S|Ϋ,yI𧍁$eoQ4(4}Wu:tz ky-?ؐ ڦZ鼊ЉA`Cb^ڝEck"̈ęY(Peh#uS=u٩i&o߆Lix`e6;[7GL17 *TM3w: <&5$:S~Zn]t{}j6mZ+Z98ȩqɸSLEo2fဒ|q] \﾿/Nxmj&l;<F@A锋ޘē̈́a9m;24l96`z$d|>c+f> z;W; 69!%5v" }F#q ttȀ**d3/VI‘?Oa854]0bJhTfsU40wdkT@x ]xiDI(1f{\ V<\f;c uڽ73V, @ηR&^XǕʥ+%ܘ%CBxҰ>: g8'օ" uRj,N-D-knj|,Cz^.r "@@ @5hadZk@ˁ$wj%$"91 IHt)pp:lȴy|HA)2g͙l8]']GZA"Pq(/>N6Gl;D OӠ>t]; Sjŀ/Zukjyٵ6byG7B|xoӣ@DQU$c1;uh{ķ+E-upǝ7 !>{t_ I 2F61Ő$p4Lyj在ʡٺH^j,]-JkBŻBROܩo- bR,r|/N`]c4F~πcT^((Dq=wy0"P4-J/m.05فGF̃x>$7N;Y1 r4ɕ)&{磾p֣, XzKr_K3_ ]r"rr3Gsp5e @fCJ 뤢}Ҧ5'u)բJ X̞0#|,29YUAE8Ccά? rp 7~?Uw8P<+ ǡ 6w 4/$FlgCZ| uBiۭÒ%KnzPM9enʎX^r5eyh;UZGE*;NRt8_g$${RO7lB˖BV8.zh"5Eb5Κl&_nǻ %P̼ĺ RlÔ.]D߰2O~D}"ͪ(. \݄R{TR@5`\ov^wKdp8~_Z,uiěЇ:TCUks1BO Ս$NU>76r5FˍtwP8dbQX$`Iต@<0W> 78 KzFq%$$IT'rtp@nsWӴCe{1t" N2}#__b0:$#6~8 YTQ}9w@eB/RYΈI!b$ɅF,֝G3DDTGJ_VɄZ=Nxe+kG[4W2WS"Ȏ* Խ(3ӏub?=@wU0t󲠼H7f2qASr* Qơx~ȶZRE_8^pl<ժfyA|;o'.x鞳ѲWϩ^?'=>|2mE4!]mDmj, X8a%Pj> #}p߫0鐘 lF;ãu]"FMT\wF[ :4rA$Sm4{s`,_\QJ~E:Jraύ7.c}໺[t4=ͅ~\ZF4[`K¤j d"7kH_"FbN/} )?[f8X?6(+]o3OuAV:{UdsLvTSh'T%xdZ)YAcf¯'@WH')z*Dxvf({W42|6k~[yv??i]{8X|OIơOq[Ug[$P3$P%.'~l0`3 C&hl% ]&8 /x n?,Բ+eW<(QyF(<ƾo!zxS*łǎo@H̏#.]'k_)%oFA28lieE"Ы"EJgD>aАx*l$Ȯ n |u8t.նqrʯe]]$@V .KǤC.w_wGUaX޵x T1R|7w_9mFݙgЋ |`y IYaxh<^c< 4 `fhc_bp&t{in2>[->Fz'ɳVW1Z#$`I b XI"+!55}35؝酦E"fXQ眚U"G_5KYbYl`4! 3gyTsH}2\ ]IMFD' 0k2x^ c_oCf/HEĶ/P.}#ԂCF8Q+TܮoɞbU ~1 ڢ;9h5rrh؁eB_xeHϡ~6j5g]`I@Dgj%ڛp6d!( "sAsf;b ^ CZ!] PUȉ~EА"x+q}h<}WЬ þ"K0ao߾gLGa?jNĄw^Xc\mNu=3j5`Er8$@/]tC!MM¡sHaWrPqxhEQtP^Z rYہ/+τkcP% ~V|1mfI:Ə6I-تorMt ; 8y޺QAٲ$)bijcgK Y!.ՇApќCӉǬ q([ .wjHiyzhhD:}",uݯ<~Z'X8!$`m&f2/3ߌP@Uޥa IDAT\҉JEؼJt{F/^my-Oکp$8@ԅ11sgC;LQ0De~mVZU!\#YBsF&(KWIOO; R-ICϞS&=DoB5 ,!F܃c BCVoa;+h2Zxf@GPM>!&ku{ vCR0XUkܛb?` I Hfx$Y=`ztp 6fak@"U`d'^3U1gEd<\@ӓAuĉ'2»2 {y1᳿P$'G\xU:fI%JK텕~jArrrivxŲ9mOQPE#N7 ལ|̻ˣŸP144R55{MGW(fI^ \4)6$̊b v@1ӓBF!&ML ޡ򞼼j>w^Q,+'yҜxhpSIFsR$6@o،ysp$&1^<*/#bNF:x6<"+90k]v\J@˰vSW뒂5M/[:nW'fo)SWB[oLfNNS-Ȱ\du ]b=]Ц!41wawkyPs^?ÑY$`IKR hr4m/0KC.hH)RndR+aX MsZ1GOnzA~~9LWM]Ng*baw#WUM#wR =r@'d;XtaT}4x<aO8ԩSD8b+ . <䬬tRm/?c 1%̄4Id BRWꍸ?ϧt@r,Z8[i/vNxk !Ly/f`^wE=LgTؽY` ОJphMr! vP;nn+{5NcW`QWc ^ RVGi a,'D݂Y+,A/z=QQ%ϥŨRE(q: 'qbLhX׭37BFp!:;/VZcv'lfUq, X[{D 4m's0ϭ(yU|Wu~de"='s<"3],8q( DJB-$%#5!vt"e[q";΁w?p"g~65?^{|lAڙ]P3΅!T#JM D}ڷsڵվlZ(y߿hۃ@DϏ5+|+'a 6> i/<>^@B8Sm^IąL{ ]puBt<9heDiz~ vwp"4wnX-WڔZ*UM7'S t7{}oC@Kt;>۞׏#`&k?jϼ>͒%UFXE31lSDŽE6sb#&%߷9!ݐ%T݀P ?df vKy y 8volM.7y٬"X(_AY70&=rmG^[lљ,GZZ2r "'#3''}1]5:vJ c"Æxbk, 릁ux `sR>.O&ʃ4Del c#n. ^|E1zhTOd2UAWz$9{'hF<6 #^)nE+!*լHk5{txf@g.lM ¯Kr#\0ѦZtE *8 a4Yƫw%DJѕ<p`!bi[\ $aNxqiHP, X "R=^6țΠ0vfp3-yjs@e% n]o'u\4"ǧs䘨"xȃ)geeӈ%1?rpӈc& ]QRdu@0fhܸaFr/ 9OKBFzYMܯ:&MGݗ '&خ-^{Rvh $e &-;(AzPEϓ ' ^0p;DARd3`:} q?{ؤόVfֽ, 4 XJhF-y8 d@ 84]Cr>a:3I))8C{ڪ7n l6DXhv^ 6i3lצ虗ڲIG&fl s#?8N N6:4M"L!CS M;!/oߌUZgHQT585 B; o 0_X9oW7$ 'NmR߆zBfeԋ# JWf)9+wJ7GF8V;^%@87(@˘|#SιkxSWzue*jpдE{_{ 27vo J{ 0e^DE۟}й\?, X$ZZFQu5EjIfV,)FYG]/VC80Rr'=S8Y>-ڸCMi;xW(?T=W3i&n  nt;{-ˤg*/C4Ͻ>Ӷ<ɊJ@ZOt8dD trKxmqazɥ8S'$)UY`˔vPv *Kf:TUse 6 ˷iB~أyqaǮxb$RpO,\I7KL?En2.qXd|/Rp,$$Fd3ci/Q4;TUt%;K/2{l>ޢú8Ye|3.H~xՎg 4׎f(.m#h/M]oRˇ}{AUEc&׆~cGxp }Vͨe`3J3Ey0gހnuرU1F뙖, L 0CUM?dsœʦ.ؐR!&o֜@f8r'#'۷oۏaAWh2w;*2Pgn6^{aoG7R8ll۶('냁s:Lİn!y@KgڛvASNadF mϪUL0_3Hj8@ héH[KXx(Tz"˵;Um8 w6:Mb]ZU p݅V`|H{om^=8Վk 2pó Nȶ w1 0Љ&U$Dts)qpË_؏ X0 ?/`jG23$5kaΪn/{1YO$`I 6(@3daAEd:VvaR[0s@vnkn 6W<^?.ٹawXw)p ;r@Q' .^X @5vڏ/F&D2ʧNﱌpWϟ=4jUm>ѳcRuCow>6(fe٘z~1lp74k`ߍ, Ix y9W^쎖ltX8(]! {|g9X ?->:5B<\kHZHCbJ>**xn [Ȉt|9 d`@[⦇T`l ݒ%KT*)y/ |QbXTW/\%({J 㓡 s1< IP9y / ="+oyB[o̙3'B%6]qߚ5>x_`KhTBxKW+(S@Nīc&&F 1*}ċ$D1t"HMrA]P'I;Z͒@ 3$8g+w_$xI@)PmS\( t^vL4d؅hܴc u *d]Aģ#suvzBCzF~ONrj`||8cUHG+c+2QՑ%K5O֦R95܍&z|2u2l"$$( p.@繱4fAS%B TLL0-2зaNH]Õ_NǪ1k'cӖ]Pȗ9ڏ&p qM:alҙ< s"\ rk5C =iq]#s09jp/r1^Fk/Ь/?.C^fIW!;@7G%B{w.3lGxq1jH2& Kgr[i??quF2%Aҡ'|s'|Oұp\s}Ə6DI}mϰ#Yֵ, @Uѐ;/ᆛ=ݛP۷E_gpHINF\ v -R_eH`\f|Aw$^PR"$-'s,7c7tܑ`Ä5б}GwloRiӰyd|Vv'45l߆f%bWCRŸVcW ۄ `:|y|AQ^xe!%"S8{ED {xe 5np;LZgٲPw8{čRIOWcb/DMVV:bTc൩85=D}n=Y`0?߆%/Y@Wpiճ%K'*p*xbzzwUM333/I* 23x]*2khҨ1z-#9awa K8:NOǚ50{<7U%V: dk~*0L)Q?z\_5W/Tl t{ dnƔ)|86|D;0 X־-ex$4TKߺLIc +MR@c- Hψl 9?Cy.. jECD=)B@pYx3@:Dku}WEWnR߼L-GS\_ؗꃦv 3ά0W?m!x qJn l7`R usss3eI)˰(g^~y6g6l*).%'H9;3PN*ڴn6GrrRQD?MM=tX?xqGnhT(pnF',@hWTp 6"ڒaZ4N2ڸe4*"oaŊeFσA;?gQqM7/<>BC۳Spwሆ F!vXiP!lNTrG式!9h9Ý7+.naSE"gQU}gaGkyѵm @ )^,ʭu>)FFVz2څ;HDπB5hnp'4HR ܰc;"In} ȺaiN T⬹B0C|?TtTʀ]ٝЬI"2G*Wm<߸s- ɑg9Ѓ/H zd^r9Ӂ@l~`WqbPS1bkͻ8ll/\}ƍ{^ofڟ^x2r@awWl sS̱.ɠۢjG-Y2I Kv@''C~ȁP un*E ̂ĹR]e~G>m7.I*o6e "ÐT۹@h3<|hT74Wum{$@!3Lq3Ʉy0(GйqDFקi=8[o5] Ԓ%K':vHvgM3i<s98IcuvnGp$mB! A}xOyԧ7㗙~f|kբ5u-Cs8PistԁX)NXmRt ;t&(em =Wx}*ܱ}O1;bu0z{&h;>бQ2 DOviOtCB7 L9K`w2y3@RWq 0zx0tǫE]VZ7wXzX+X/^"%g`D^v3.2Uzq qN-= P[$Yk߶]D]);V&c^GjJ-)ٳ;4nyńwL,[&`%;fP_V:)6)m؂WMeøp Be + ?Bо =D'27sݻ}+/'Ehr*);цK 0HV;dGz 뉡pʘ{4d 4"0aeHIp^ye?YWc iI#r IDAT|64=ðzVPo,US5"$7L&ܥ;H (u{]p}: {0#vEZ tEؙm|+QV;M![*J?0/r *KLTou`I@͓ o`ԭ۬o6'nX<lr(hذ>R׵ 8 f o(ȋ `tbHZqszdNN&O -Sjr-L06F@A]8ؿ,Аxq%Hm0}x^gxH?^dlMčkB@Ab6Qo7ʭ4D]r DY0d0l17вN.7S.2rrkalt ;φ<To*ie 2V I*4I :ڞfGvHI*, I+n.!xlv% S݂Ȁ>}07eM腰c;Xv<4|6 7^u_}<&~7v1sli=͒%A'!K\ pvs)&D-.M1kOx罕UѰ9jxld3hd؊v ]cGn3'3` n#~Æ QvR)\ո2y"0ܵ]%L T7n̛u 4(O>N va uѦ2@Vㅜm 3T$8$3B0oo [$nl?rت|iZLC![օ.%Q8=̰'ːg;Zt}DU, TX'2r9UQ#2J)o_/K (wގ=·n3=ǑEJ$P]eŤ>N:)$X I2mvp8qO3VsH9s+JLo|7z\ш~y3ʌIN?s9@al(i.kospr;f6 8/Ge*)y2(榃rjl0M!B?,E2&Rbn$b&N&a2Ce0# "= >. PɽM#co8$/'p~.(9L6r(=k#?[ {&@'glhac_|# 3xt\g`gΖ/Ç_,!$"w LU7cI jsy)-Yр`+-jB]wb;LFQo_.thAlpQ,Y O>(@b×NYY fv-jpv888Aɔ(h,?]Kwf°)xh6YDMDM}o^&Hl(obm):@ӆYF8Qd#EETjECxT&-|8_ܐ {ܬҍ6 w'pT:ïvcGO"/{KKwNƔ*G:z]t!n$'%Vؾ[{'CddfƼ $L9A)ʏ=p`u|"{ ){ "c{]Pՠ^}ĈđMi-YdS<I xkhD~ȉd V-t8L+mTŰLEkـsbq(8IA1Gw/f)^}k]Ԏ˅,k!]F` 5-O3K yS&}=1:(Ly C8? (C!I,vdߔ?nʟHSwJ|*jz,b=˒%c. ~Y[ǔ rR'<@CiDS\َŨ~rĻÞ_a݆-FΉrH7RKt!AS$²wF# FX4W;D^.)&؏~?|'gAԣLn:>_~q´R@n75fGtWh#!IAD80=*$PT9Z4iK_tF1N4^ ԦqM%bZ`wާoʌC,AJ}|ZS1@B_kgSWJAyeA߾F/T,oP), # 8/I &A\}EoCdS%P cƒ+ioh:1Y}ua4dqw"^4|ۗɕ!Ek /!$kךTK cbp_u@ 9=$ ɭ`MJlXV喈ΐj㞇D:.VڄbJa?.+Ԃ{&&A3u\e*Rs)seGgݐ3p\Pл[S{g nxfNGaa0Z\T&8[ufg*ڶ>Hre=L8\@ۥƝae2 WGlDyϫ菁GX$p %P6>?W)dG`yjJ2.tx #<9qLÜt{S#Pu|t,X^’ɜ=r؋hvr:@[up F`תm^u, kBд#&tO@Q@9=čÃ@Cmw#5%4c!"O:4MnVnN.CKo~|wXfW8ܽE >;4 z U#gS:(2+GM+'K1~4XO\>pY/*@70dHHEQ*$W/8R5"ݻw'Öٱv#^ɕOvD\&`*f- YSxKK-O&ԿK()jpSGtyd7]D>(y4tEDopB^,I<,d1Щ=;>#O`SPf0܀jċϗXw»b:ͣSslY$\ 11N;2[}pP2\LǿmdŲaigzU#{oLh\QZVWaJ)9!7*- X8&:&CCo< ݟ&zᖛ,^9q/]q0k/@Nv:)eP/3vEBɈOpn$׽* մSR*3G\lpݦ";qDdeWnˀjo?c#z]6{ڄO 1R:LHGكF:BN[Gti =(ˇ ξqn{5c_2>23j!tAZкlEݸnZ@)^RrLjrhw #*yz6=SjND%JL`re.ޯd86$#11^V"RRR !7'~?wdf:J.áx@ @u+<;(wX=;O+dBsqEL_$ТHާk>Cf2t9dCzuj"݀88O]t  东8oUbIJl2 C۰a\@| >vښrʊrAt?T[\D<Ӝ3vJ@rr"s&V+׏Ͽ p\<]٣[N׆-{SH2 ou+{U* {+? 2 tɏ1]f+8,~AI'&UgD2#LkUإ\yf,ۃ9q EF\]} ΅0}|HzтBqTI9 hN6I~_֕TZAׅBU}34MMu2vإZvb< @:8h44;)Ԯmo\"b/A54:-[c鲕ؼy+ n/eț;D ";}.%v[./kH,s%m`/N_4ɅSb>%{c+tmYiEzφo·]W !)ۤ ]1?,[yn">ޟ ! c$`IFKFl2^~ś)MHfQב37WC^zI^9=gddʽ4CG ĹhܠNJF+ƒe9\@+ֻ6&~$cp4Ġ|l}^/)9Aǒ%KK W$_~>F|7'n`,6U"BѡhCRjyɅ=?|C?gǞn hڼ32sy )bqlQ>cWdl EBdt[Djj2SRi<ه7cMHOτ߯CS|:gቇ㴓JmdwJH;,0nHĄ7!cv##$Pz~Eo UKUmI^1A%$EE}"tt7 *bҊ"J(&[psf̝[:}v]+叮{m<QCrvŵ]umWbї7nDc͸tGY] ݿJGQаA2D<4E R2DP$K0!S+]k9[` XZA'9 &QW!9rUȀ,+ `0)9-˿> }(ࣀ# "1Z.Y<*twOC 3y`HLJEZVdSN'"2<#7[9uΪS4r?q.pmaZKp(H (c$%EBM9q$o*o۶!7u鸜y,$P)̲& ֿAi] SZ2"qJ!S(U D潳K:k ރ59\:9⎮I(3߬ici Y$,#--\G_YGp.V@ 8'bqS+7< [IkC߄^1L_a3ٸq3Vn ֏G g$J>bQz%$?|[>Sl#Ϙ?f9|6ؘ DG95ƍy|bEy!kHYDJ΄XB@,@= F-r!d]b +Of)TwlA͹+d6v@ {F.H,fЕ1t t$)i rS8~vPǭ>ŏ{h{'Q̬$Z֭9?$,M"ݏ"DYӰhzo8o y͹G iK@:1An~)x㣤U)犆i>k>ߌcPr{ PijVNȁa HVҫ]L9w&[ LR Šy#DgӲNº,͓EfU130UC)[LC,ȸ>:eU$@!gO8ϙʕ"rѼyhu:7o1ڕtotu,6nIJ\CRyE -e A 3wL\Q^8|9t~, pT\ |V0|C2h%rRC‹gątﺮMq ׮EˑJ/@ Y1 C#"8byȑD S 9a48:(cg7י[?wq2W}eҳ:(A ?3qoK^7 ](zO2;ܹk'.sZk+!MJfiوKd-m@6״ kF!O5koX2  CGBrSWoiFAp+ܰΟ?#:+5jTϞA^2Wޟw1֌|q܊B}-+7ySNA\m69s+ԌH1E WhJ;YϿ`^Tl=ezHը*2-ԩSˋ4tw+ɠ )Xp Gs, YI)-xYO9g-ODSYb36}|чxmbFO @}N +dɏGaʾWY# 'BPP`dx˧H `#dԊƨB7L,lB&%x!v(D9eEV 8c0O3ԩ\Ng-WZZ,z G%EL~0̊Sơu9/-ⓐӤ)NA6A[Bm=x, k}~v0l\"E{3Ig]#+K.EFFd ƺoT]9yI4S:Om;Gyq~h$ U51Yzs"E0QZSE`{{%z cǛoDf!􊥿h˒+Wcæq|h+@+Hs *?>Covsĩ0!Ybչ ڮ߂ *PS)xo<Ԣ4 5W3 >! ,k144Q^]jAd gƒx<6:Or.Уpa)\ *3RB6V k`)VYl'L !XR"hiPק> E3s'N_,= 1jEaΌ)6ta'd/[|B 3!li-h~ɢgnj#<}V"e~{c㦭J LXB-\ #/^Ѭ]z5\4/cۇkqE;w~d3?^%%PBk!pw`wuZW%0h`",jJ斀NlF@E/VO70 AVaT[5 fx&ۻJ֊'`MHKVu @v>/ǿBwD| gwDMWmBpYlSbtxPb4^G6 r`X_c /) II6M?sxmEn);@0&xott%~EĈmvOAe++5!4oT*߇<_((@h(wc Nmիav!Yq4lXx*["Js7(rPb(Bl͜kƆǎn[;tLT\M5MzlB2[k.ǟ.:`oDx-+_8ŪzPiLny\ /mF݈:Nq-w0rBw1-.jd ~>6`$\[X _[pa4?ޣ;ʩC<$owMԥcܐ Q5N]/"g._)4%:&k? ?}*:P\}fv$M bйdGtyI>Mlq?8?BRZ:p+~oQKNƒoP}oL_岬vRaz֨jV5E_`h0hnX?m_C [0{Ş!. _Kpi|](_7_]{ek~ L,0huذ~\Jvg!!1bf ,ѩPg A~Z)z5=S0r%L<ۖʑæ@V|iMf+]V͛7ifzTŋi3^>Ӷڊ Qɘi Q޵(0=JC<!#Hh<Љ%wS-=?KVm 1n\6?1f1?VـLr2?"0WEdH"Fp*7*|ܹko|Ό5˞XKO*8:֯=h]ɯQ@\`)xGWthZ<45U+h/]ǒUkCYn՛Bc$HP'0O*c̜sE 3pX;T!Tۻ0Ihsw~ oMߝ~(Kh7bnCep)5eT|Ic8^vQ'S{NVgWjˬYAq CN՗QK Wf r{j+^ϣdX0iQTN̪ mJIȊ Q ҳ" V\ YA綱/ 'LFjΰVbO-"hg)Wt'`8 tA($lW_(/6Ͽ! !o'bڸJ rm>q>߷h0 Z{ 5xhP .h*w] Mur=.=klBOչ&l q]$QyR _x1Xd1aqw`|)l,Z4-_+RCNc&S]Ybx:}죀> @)*FJ>:ԭ^H FL19OfbZa2hir-nmg.ѴiS4lx'W$K3PjA]k=/QOHS`9 f21n4n;s\Xխ)1qs,FBx0VXPnϏ>7NS4 fL_8꒷xOj wn+H9$10ĎcSjaF#N $JZHٹ7U"; Q޷2_ǏAlp%,P^l4`u'$z tOiż),= 0LdR(̲=GV0qcC~NsR& Ȃb@# yNOOKpZU@DfsiiRc}H4UAMބ#ŖARLGt-9PEC7*5)(is] / (@iR^6aFvݰ&GaCOJAjj6K(7ไq\x 7nUWc`;q=wrʠX 97**K/)Y0j4ʹFo3d=|6(vb%_ldz[e _|? HキIIk&[[E,d3?sXE-,U1ocy:VFC{Уfdycg*!&p:2˒~=JSpZ5bQd:EBJM>_P1qH$UM/G /D!þňiCk~AFVf6Νߎ\DRrMW d%DHHԯfM{Bddkvo=Ȓ. ;ۄ .٬0 2t G$ [#RJ9^5+ f ̕#uDY4-&<9 *USg ©(>0=Stoj(g03:WmcH5?\ F3\DV>% (}Ǹ: 幭dENѪ#ܪN}yT֛_D͚ՠ!ϗHf'n} Ç͚x4T5:'#![wĉCzmpG)w` rgvE@x H1gMpsōl9k\|ljBrr{dm`u PfUL::ѨJ/9:IB,;3ku8hxsQ'ݛA}YFhHp2mq3HOJ- :W`m_*o꽕d koEhhP'!A YJzodATFDȼdUlvkرcs322\dSGrZklXZ5h$iiŔ%A½YȪASAQMd r"(AqVd0qv<3C!w7)ɾm?~$:gTݘKV=yF?Oaɲ0Y,=_CYe.RiPJSƎ1֣wpʝKBҘ5?B[wpSoє5R/ځۿ6Kd. TTt(5AÑI!Td"DXз1mQy1?(Fdֱ~o[m{.c͘''g9y\bW|H@u߳6|Нs룀> xJr^^xDt87i\Vz$EX,s?rgsϡaÆmq{e3+*VG9⾦l%6FK`D(8ip4} ;d¥G<+}LL,}qaxN CCGuG،n(/^rśBFDѳ[{,d @P"@w{*`N_ э@ά07)=ͻD DLBQ2q4]6U~@ 0sJMFk0}J S17h,\ues# V)O&kB+j+#%%R~e@xuY3C|0.nw.m>C #ݜ+yeQ9jl:V܋,D夷r (PʭpJ&⩧}Wl+OѣG/G{]lS,vߏm۸N rL-yGUprF (etsIvޛ~ ¥yË^ \a? RSSsܨj;"F^x[o$<(MrJZi=?j իWGNJ..9344EUs7BJ? |)M/EP -BsMBb*Ž٧~s;Yp%ھBzzzrl<} E(B@ڇXȁ:h:M` *$`.[+ ~Wk=SۃMsҹ~t IDAT<[sT^*U8L25b[@WݲߋctdyOhָ"H R|UyǘT]Lsv (L # x5lwswЂ_H(ٺܥݿ_]:gP-((tE5pE: MCWA+ Z9n ɫ<ڑꖀ1qV cHǵ}V۫'Y L:yc,Gg (h[9s?jyddv&LU!w(v3ql`M 4FwJ&wYƏeacmp2X 3Ôx&//DKiSݕza q [݇ C@B]c$w{=(Dk7zc~Q.ҥw|ym~WnqE;cO*ʱ~:u Fwф ͑Ow4@;NPJe*V,\zu;viQ.NcЇzE Fh26_jc>(+cđsG$&Gd0f4$q5Yx6٣Iƭ[!{mVJSӎί1e !qW0a~Fp=QubJSE(E&yҔ~Q-{81ޱ_nVcG+( ۴^jtQܡ]@0at_~o傹ܩEMFYg#2Y FI+uh0╫8pg۟ kbR ^vBWKbeT 9c+xng6#B{mmȩPݺ2Osba_d*̲LdxKWyvGA"NS ny~CZ^ ACR(jIJBYA'ҥeTưw3rmb4]iSƠA7~ՠ/ގN?K6]RPiPr%4o:AxXg SZt߱ATѩ#NbHJcjޓ 1(<ꔄEQ=cb#Z^D^-L@g|,_;ߖRڦ(*ڶ~m΁*c”zV: #Wz8`; 4]XMoGGtלĪ7L N^_$ z?']M(ࣀS\ g-bz .HBӧOHJ4,'[Fkռ s{7ׯkscFt||?#[ųdEФIU!~g< v1 ϝ95kwgדdfs%$bMq Չ@mwfQNtv}g y\x@whH"+f8&9`VĜfu[P%:=Լ)Fͮ{sVC >Î]qa2!/=c C֨QS|r8&"̌K-՚Q) Wn0L< ?+FKR $ I14oCBQKrl|QMO^R؈S7b ƻdwDرѼ>}D`w]X{ԨV{+ZsQ(GV˗ow_`2F]P^1 k Dž50X ƕ7mX^ LV+`ͪ(\$DG 9M p*}\i(Oۃܣt=ŖYˁD`.`bGtfdČQ ?+_3`BѩN' K'߹-֛d۽>X(4ԩ#7_BŻ}|Б2D(,QOsʉ&_6~p⤝ kg`&[hqU*)oGL Y4x4Lfz`Kȭ=p-J0!X]:ϰ}68o7ރƘ?!}At>sյMu4;#).,XbS & K+UGw_-|wP\^:o5Ԓap/JqcƌvJp&$$8~ѼǸ?,*s9J.]bccͷ'w:uUV^CK`!R1/\Ya4 )eբ"1oTk_DLūs;t0poP A7_n^,>FѐxկE0 w$x[wkB@dDzPlwp&jq@QѥSKydQ+r*#x߰} ]~2SǽUԿ껔/Z32Coħu~/ix!l| O]O0jjo;SwfxU Gkqȟ=XJR&P FLFzWg"11Mh"^kƼmQ1 @Qx~g.bxղSh0s5^TBiʛ7|((Knq ( ByVygX!e9s;w1ܚm1 hhK< y)"++kma0Ib(=3fFf@h|LrFxCH" NY7_aP$̦@ IfE̝&SX46=.Ba#g;q5LߢŲK R (@iHE&z^;*WV }.Pй[DGxc]I^ZtyqD:m;DrjЮMˢoЩ~(vIi S[U x 5D3+֟B(wyz?OF r7<A{0f5s';QDӻuz/j*Dbiufť\P4YInL:71k@Kh &y[wģM"=X!.aC (J3bBzH5jgrK۽{7~buv:9[lg4i,"àpcՏqEbbÞ}6ۢ-=t($v؁?ѢYÂj|F7ŕpb4GtWS}͚5HOw6m|7F\4P3⹻)1x,&]ɐ0T Q[W z,! ;'Ae0fF&2Mi0L9_f: XttP[%[};e1SmFge1d0X!hdNN鿠GаT-/E4XAƙsEp?-hܪ ?;,[)ӓOp/8EE{@D X$̜g^@3Ώ{gU[iz K<Ρ/;bt8b;m0y/ٳ *)\5b'8LaE"ԑZl\>4 _> (@P=1u{?#7uG-ZC9HNNƍa4nJ-3=|jQBg̱)O'$Mc3WҺ (q%^⮼mlqj#Z'ڴz#0/ބɢRBNJ^ M+gszCj$cEDu+" {( UBgAvh9g+@e hh98;jl#!]o~ϠK6[p<[kݠTtkC*#n@%8vA]Ca޻#"4)yL#3 0*Hxϑ)4w!%5ӣ3l8!c䉣p[*Ɗ۽l pueg޴[ ~_ڍdWLx16&}ê"/'~$ϻf1LYws> =vWG$"c/W zAAd'XнK~_k> (%=zy^y?\ڵC˖-믿r˹;nv7 c6xjDoY<}NlyѣGnS'1숖 Awy\1L G`XZ/ҼMȎr X/WsM."44W.Z+gÝ;wロ_ќi/ag:?={ZY!VQy saY<Ƕ@N(|I:,x <)J<1a?' AB9n" ]ٻ0֮‘м#-n3O=swxY"+ۄ~oCarH2C6g.t/,e@@Nb1gpGNapehVn דLy$SȆ \WiY"o,> (P(OY;ʕ+8̥th/w}ݞZ]O8}-v| PYbw>x:爭 #\ǟصkS'OQE*'iøVGd2t֠ti"t,X, *i0"#&5f`ER=ᱎmbUvࠚo'be8>FX5y :~ AU\aEF2Gmy>Ђ> `~^FGyÓLcȩJXa:4$RМ${N- #ƌظTRZTe̟= \A(0yHqe6e01r! hOI[ >X6}X)c[( xwnXE}, AYeG (Oo2ɛŵ:,rv5łB7}Ѵп7m@/Jp,;C! # 2`p2wOffEsPN/0}ۊh_p=:A#o͛ m\ߛt+muOֆ 2$*ңZv<"Q@#thd,L:S\.K#3ƏǐS:Ȉp:0(Pos-\մ`0V0Y,\ ŃV\{jZV[ǙⒼlJ6h#袐`L\ AWQv=E1FmDz4[ :g.UVaHVy:zE{'1o*P 0({wM\X|c{qQ+'7pDH!WHI;b bUdPk8'T`s2"^s=ٓf#1=^d4ɴtd ,'F;ze6f+&;⣀> @x^tZ۷;nW( p._㮲.Ȇ) Ƶy#!kSG0Jc…+Ѫ(,\@={z(9.Q~hύ':d>CM(0B)mQFR"<6L!VQE¬ei|æ\P<%)܅/ɼ%E۬z ҉PU#1eHqTo"=BflsyVAbgD@c r8-؃IqйIyEd0tj*`"@'J뇛c}z{?㼼QȊA~ABޯUGVs7:)mSZS{k!+ìt<$h/"Zq"DSSڛ#A.6OwGKY x<7gY2mr59ʛ| oؙL 0Vu TKYV v0ҿ>~6p&Wb1{fk \ SPf5(BMYXx- :P 2d&Ap: $&V`:wіxwO'E]`[nEW3iBs96)_|u &Zm."bS1~ L~Ix NCjUTx>S&Dv6{PQ ㆢ="S]ׇd:PM߯ r]bo֬p/azGqލ" $TaLCxN!k#$|.}h3M.裀> 8ע Q[tF~w;Kϣv G IDATya ci'+--?ݏ~]<ɖ* FLDVa{Eۈ.xuP+>XLD;bʤjUuՆ BHQ°PB]$nf<Ζ"MݙU 䖟GL̑+?YSÖo}vv שwu 5%Ɵ:=JצMK<д VA@P_Ҍ Dǀ B.\dIзТySY0KȎ_ sd& YGSg t0Mps70{)e5@fiŠ2l^L+nZwػgYEŹs}[u "& xɥxȌW8JGci#D=l6t,)B+rC@{i+S=-EpDzT8r&Zx y B$h~6x(@quHg)$0[8H ČkGmVs--8C*(%A ..f;5uXT<\2 az}PsR4f5 :HwF0oޡ]kt{yP$UR[O͜,ͨ8cwЯ̢Z':?~"7onRU$$'[p購_+sp"maw;xsYloBk)z -] $pW渚 4A] _bȢoA)AIdc"1cq$zP>p= 0foߋ~~ꮈw‚l|_DaUƀ#n( da!XpK.Ȉ-WFZ#7I!@n:gV9?Qƕ׉ظn)4P@G-qe̜Fn+WUҬikq vdP?VZ}ӧ&MLjE+CYkwcJcx/f7 H3j/[RO~Js̾}QKғLHWzgZ+hnŃq#sV$VLf &fP9)UMPP^ v $ny^N$PU7ر7G@'AM܋ʒ()2lܸP?g~q__FdJZobN&{$6*[6"瘐rs4xPL-8<.b*5oKs:ED0lx$eqP6o,LGyHq9L̆3BE)ӝEK`Fd'A pJSn&#]XEh@OE/isf68u!ף%ye3 O@hBf3.z[v[>\Zse!WHx] 9@: eHoS,΋,L6QBwg/NP#"i8)xxpkIjDF"2" KE񠔒gpftϘ,0Fu8!K Y[\-_rteSY8~Oo.AF?qɅ7 M*Ș1@4143-UJàpd 녫lDZP )|lNM `f V-0يY'nZ&P >34{םcޓ.osPb8̙Sa`KFBǺƸ;O qȒK̐I*+a2܈ ,LQ#{y_оXj=~וzLFhH0M*U*ƮX"EL@fZ3_T=ۢO #սد;̢Tʃ dVKŜ"0+OjV k:toДǤR;m;rp <__;p=ZQGoRdmoXiK۽ *Zr$fO@?ՏvnOd׏[,Vgd#19V(0S-F1_E  ̉/=Vo݅ϿF :oÙU0xfqvv"X[f- É<ץ^ӽSЩ5)[HI#mZIK@X(ޮ&" ,oCoZՉR\I ;+ A9 Xh4J~b/1j"bbDzoI9"zhLBŇ[?Ŏ]{d@hp 4ב8z)喷C:=g5cƂ0yt{<Ś=QI1SYȭZQB{^(tc܄r-,) ,, .h%"aƭ8pg)QU+aἩK7;v㣭_: m y3_̀F0(v%d{A)r3ϴ(>x({G}^h]&ІD5;r:WS^ x+J 8"-)5#M|K3+s3w*f =͸$dfl(\HR {r/O.6nC)An^ %,gĤ6`4Iذ}dU*bǷzksgd\ZVlp zZZ!>! (g]T1K&OS(h÷ oew-B5o:G'#J2b߆F]%cb3?WL2IS~qu?@-Elk1dTRɳi`qAY aXd>%2`L|1[:<٨K+effeSm0i@(e2ҳC1q!k4ؼi[M:o LX|vWl#~:= ~E g4IH n!SEcc%<=e EF>%D -3s`³:N(i=ځKɽ UnR~OYH%"6$YNɬO?=1|(ࣀEٻ"GzcBȜƒ3@+϶bMO1٩HJ!)zJ ?/!]}x5+:qsՆ0@&|B Ot)0|w"jתPs?('jњތh:jۡg7--c`4)z-E~j f0IJcDy5TM]ȅ-i_J*}lk^z:sDGan +Z,VKJS%h``ޟ~L/`c#_5wP\$,f9XыcnuoܰgctǺ@Mmu V3QFJ\tK`!q?ʪ0nМ5m<' 7@tсHOi܊)DIBnT(rv`%|Ti$8bGшv:OZ8 # LJ$DGz1vŨ1S\Yox N:&qV~BNksСC[n_c~0 'N 7A;(^ #\r1k} 4$7uC >^+Q*chbt޿ҝ:ȧR3 dL45aQdaꚁ ` J ( %Ju*e-/J믿[7"nW̬l8T-?D2%d t.vΜIĀ|X0t4?FWnʸq@%SOmntMx #ʯ#qDS)0IVG4"DB[{ :M> D\ < !4Ȫ3?!s_$bps/.09r q| EqㆾU~?~?3{!F̚5Fc˜š8Yϭ.iVeFk LHP<55djӠСηdr|| dA7"f |by󾳤+תGzu/q)K[WGཎ kp ӣz3~OD;j8{qj(2w8֟2>^~إmmAqkvs%ӡҺ ASẦNǑhD$S3k!OV JISg%ط&vx5Fz_IB\R|Le!:*5"KYJλq.)]x,hq zRNÁGςqȴgrb".PLeeZ߲%~t*퓵@dž:5 :/4UO  5pWHИ%H8g{{[K]9oDĐ?݌%_d!<1p`ص5YeL05kT+9m΃=e/Ǹ$nYCeQ<5-ZaWQ=>S't_׀ Q5b{DTs\\?i /%#ك1y$*, 8wtKZUުY AQa["v>Os|gQQ>g!kw}&],vy)pՁ#&(H!؎IRvf_6l3}qǭ9(8#ˊ,X.+gXRϚ b#Q%& ie+O2;o6mޮ5bءe ɠmJs'OϿ(v] zTd8Y_̯n_>WW5<ʵUu]1. \`uGGi txtR2#=J7i}X0r."PC`Q^*1P LwESetp?>TkR4e%>['DRY4:<@^*.HoNK q9;cy%I8`qʥz/T,^8O7yYQzzx:w1lOI/2vLE* db?{8|y8r7iq49Q*[/]/;v%]~7 0v9=4#g0(!OI =Y ۞{gu 3.vy~⯾+o4X4(P~I D,SzjjfϞ]l#] :t1Ν=zS_Z\E-^8z~R<pBkNJ LՊ^Cyj9Z"hv}CJO՚6`A.ᚈ 0%,dzFOATpM+C7lY7C''̬p  - hOw,}o폴4A +W1ty7YZ1S1%3,O@CI' UѳYQt|4a'9$Z 25Br6ä%pG/}8dT%L#`\OrgK #A>@PKR-eVk$9\ 4 x=?4 Arr:r*' k\Tks "7*LF+1ܠB/nyJL9blNJUũ:qh"TD<[,|1 E&!&! AРhIb1>t2q۵jWhg0p`vwJ-IgM0ކx7kj[*S7m50`x&NʶơJ ]Bv =8VY5ArbѨPE7BOBTII)tΙsBkXh~s$R.$[K%U͒CxF!<.9+h~{3t"[ZWN`՟9m,bc(<3Pi 8 V 4 `$#Xy)Lr"͢ %Ê&u"Jm3Wjq`֢ʣsx޾;+P;tfϋ~vwk䐳rH ">D&"sepP7X|Ÿa@ឥ^7JG vڲyK^U‰I4iTÆ5[.ΟO-M*h\kԋ£n6ɨHʷ+H:uU,UՁ!ǯX,Ǘ׻Pd10e+N^GnqV.mbz73H@WK}YB&`^5KȎ'ec3!s؜~&uj_goȑLwJ=Fïitz>~\dN%a*Iײv,6MviMֳJ|]  RwUUyhԬYkF\\bbb`69<x3/m"BP- &ȁǟ;0y j4ՉOMADY˯1=SN :fl ] Gi{P3'%]e`n j')R 0(v9l5?edZQ ޕXͶ1~u_5|2wrC*}o܅ش_B7`[0bo sbϾxl8(uDx{ў>ޱ}q=UįeIE=WFۗ[nǡbW_|,fXC%N!]'z.Ӳt tcS x`?Cw3hvLnbEFx*ن1f+`*\OGP$&|BSjSӦMoJL.cuHtpH&a5Yz!h^)P0EFT&#;d6;[->'CVT}|WgJ7 TEixsb(&we! ;{$ UӐT NͫlDCYYسg;,,)'m\af^:˳cKI:+Y5~FFx> [i3>-UAlT TG!1`N^p<Ӡܭ7,t͝«Ì<q|jmphڜFLkDjVU̘6VGIx)d] uwCXWKw p+ s`j73U-LсLϤv<¡}Oc3<[q"bٮxX"##|luʢ[q0d&A|J& :tȽn%YYzjXRʍD*KUmykzZ*|5g18eNgA *YjLO?3[+>*2(ۚS8)D0va\]l%:44͛ߎkUTR/la@)jTn/y֖u6O,1MS|l=[& wA$mʔ)|2 AHBPh 'y~,{Yrһm(|%(X^/2nOI՛Z.ɸSɳeC$Xs*+Qcn [C!33Ԯ.&{۵kxnR)` Eq⢔}X|MG^>spi⍩Vk&O/6ـ1qKsWш (/o* D(72™e/UЁ2Li Q:a} 0'xN$- `PO_Hvy* MYƠ DJBr >p4, +d|L. p4سfY Gkv@ZLMʃf·?q")g`si!8u*Y<|+o҇bѳ8Q4^Pd"S>l3Q&pW,]L?e9.vAkp3xѣGO{!6i϶r./!O3q"Ȓ果T$CD\q*B7h=h%΍v1/Uu5,ss:--[qm@KUi{ 7s$eBJG -c#)Nm+=z \j~ͥƍ㮻D58<]wAY"MQFZ -]Sg?wԩ]cG ٛڨBPcgʃ'cbqcątq ΢G*qY­իV5WXp r2/%(=Fe=TT7 !w=w<| +i Zr)6nQp [Z QV oϞ:u8U(sÃswi?g2""pRP [H Y CJ%wѾpkGEUla [ _47Qҹ3xh>tFx zF/#+́/0lNe8Yʀ}ۃr%n3.Ao$^<ӣ3zӑΩ+)DrKܘ蔅QQC $ZQL8Z}qA׃%@%@eL^d؀\tqf c'awrGGy&A+C!Rjժ۠^zɥ{1ׯ]<*z [[ Z.D[&ctCgHO,+(&lLPa\LCk7rٳgTR\|UXBDJs}>PUcfƐl9QH T0K STA%U´)#u|ya5j`L;Wex($Tn>)fҹ1@lCJoEES6W86(HOD IĿVz 1ep#j!Wz7E ?Y-zUU>}[n?ܒWc%ק%iӦhnmqё E&EPZĮ_^z9"ڠޫٶq+\<@ #(Gۋ__˛lOi %`¸$OEz1׈T])%Zi_+IQm]wZ"ٳiAbYXs6^C&W7п',Qrly8r|!@_l4iZWkdLar˻餤KY %2߿^7sJoAy⍶5%;Qdc}5й'tY :6Db_'に}2>&QEY/3%tys&!:|ne wd$<FL/ގZe4RL'xG`j ُFOO+Ӄ.K{͚^K H=;2ٸÂ{Rߕ.yX/?Jɭӟ4I̟Ds+.v&lĻNh tcy4$ ,ơ=޳k&%% J@FK}rm҅y 1Lb:mW\1a߾}ؾ}; &:t+.),b8NWDnS#74א3o͛n2:K,"BQF,Fāiص{o 'h0s8DFDxlX68 '(GB#/$#3p\p6$ Y`zrtAЙyJ;>NM.1qG?ike]O3E#/Dt}cuоsDн?~:(**8b${A7*P\l4ƏTX. /x7oƑ#GAv9,߂*QNmT^{ i*8}<=,qO'Fvq4LDrQ.r_Z\hABlLdav;VĂ]%6Ӧz5^EŊSgRI&U 8g4"[1 DJ! JR-͟^}lGiRjRV\H'KU(3eַSƾ~E=<9͇UAu1 Aţ_V⩱UN V aBR'h i$$Yaol3% {a!n~Z,ۀʸ>WO3NcvE8) ) ˹wa-K&<O4~(~)#.y`ʃ9sќ> (4R"j XsFw`C^WΕ6I)#Q%6Fx7$7TrPb 5 T[wid$X68 UBlqW!ZS$q/DxtTFTht04t<4 WOܸi5`PA %Klo{O*ٓ]j} H<ؒ;w.#h F*q1]&ԯ A[U:(d?CGqI!''*/b4qGZ@CΝc6z1 _{ܕsjXjzΞOJA/K*| [hж/ZQ}鄖3@RAq$2 ܍M=\0eвOf6NT]apKOm5_ .DX!^ Wa +%7?j}(%@GN&l."+/C2Jge|ڠ{g4nAwaTAEr(Y/كûͨ# mNP;'9vE"A,ƙ8];II7_ytaR/2tWB/hp[ꆤbX'{&tC@*$&|dT"6İ:8I P%~&dN+z%Ԍ@wC-[:*@(;.|̚St24΋J'!9I\VVM) .lbV}:.Wc_mQH-C Dg4ꆇ*GwfdZHx_K\}#)^I:6'h#=eJ%ԼUbJ2<+~2fs nĂ_L `VG : {0*)e4y/Xtr2|Ux/V bR 2/ KgA$vy+ o@16R'ͨ1S{aa @WJEN 0[h8NutсwֱVy<ŧ@]a,a`,)\ڱ7K~:\ـ SUaXuuWA7t"4P?q$q!̉VydkW;~пi@PWfb/f"%K.Y322yݻK{o$NtS "QvMms/nF(Yթbocqt",3;(2ڴi&M **!QXW_-uKX6H~6&s_OvIdٳsg+O>+Cx&9hΜY oOp.'ͪnnO{h%/* ۺf1["0<CӺXOazeMv㊤b|&֣:(]54‰6WLBW#<8U NDAR ɓ:> nlp^x(׽#[<ݶzJ (@;5qqqQ뜙_p'SOur Q',33.?x`tUqgqgP^ozSCT낐[9.^3Μ:S@KbUe(qhݺ/_$sFwWHM]CN,zWXQlFNa shu[5MuS3;QhĨеmb IDATYşpA>7a޷F1Ҭ YHtyS Xξy.Ao++&bŠJ xCyPQY>.Rf͚}Gm |mذ+M%5:*7|<,}VɀL ͷ˱ߐEiJN捀\!-ĘCPv HoSҳVSŁ#ux>Ndٶm[F^zUL4āiǎ_S}ٹ:-&X"YEaVвf~_n\(yRϗmQr9@ g7D'(p!@Ɣ.pª s&:_$Xrɰ9#JЃN ͙Hcテ9j*_;3ShE1i$922Aߌ6a55R R)}^S "$R(Hᱨ*̃"}O}iG22-aX|(kcx>hI $Ņ{|bD'z!MP4[2Xna9MVgWTun'*u>3lA %PvDDDՎ_ ]!뮻B6~ZNcNmD"14o~Z16ݷ)شi3VP&h‚٣k +ǬQOsĖK9Г}_\ xfl-kk"3 R+^S=,nqO=7|(4ox/c18x@ -:$ h̎ aPwJ.Fq0:PR,$Y(SÜYK)s˾:u8[/ӻi٢~@LZ2,އdQ>n痮( dnw_~aBHDwѐkC!!)<:b8~%)C*C{q!]YASaJ؃J/|$ )dѪU ڤpm?*pʡ<~ܝ!l gfUE5mګ}J/`J2KRl< >5I+!nժU>t===sW}!hOyfC)T2u!Hf`Oq/xD, vb۔ 5_v9==ÊĤ4dؙ?>RRRm/.Ѐ;njM8w1}ȕ\0KCg_B% g_OR9 03>Nݖ h Sd+  <_Ec9:3 &EI&8,<%*ic_%&|rJ*`4X뮽"NH 4;!˹0hNtN"jġ?"7#Tp(C=Ш+XAB!CÀ)tF/[KH&#>? 'enϜ\so9$T m=žyNh0RN,=&axΩ DPT52%*@PW*&䉂NsmТE 5_j5_R  .cqV#g*@-bkS.! 4͉]ag_ ==mMcjA=3"J6wv9 `S2.◌HiVk4l0RS #^!+|fexNnMaa J2K#|Z.%yЩ%> *,X6ͫ B+qQ x 7t OqEvlq^ȣ;RJGʂNG|&.*~? l_{ʼirӋ jA!wAj43OtU@v0K A)ߠ0$嗢Re7uj(sy󵧩8tB\14̚6q-,1ϙsCvH5^A zALN0i ~l[rݼcQ i.{:+MA qdCh܋PD^Q )Iӱs^MQy\bBs[^Wye$L9["#S*v('ZX3~ؙI_+P4NU֠Dx; I 1cοH㸲N1gAsOF-dT#c6iND9Q?8f~E"V_[|/(pIGy4w Z*y>s ` u4FFxȽtq/G!'7Gǒ%pI 㩾%T]Q #u WM9si+%?5w9z[( |W]D,mqq=/Uu#Q0qF&{ 4 ǐ#$0E=!Rr=^hi eF8궐&'㵞]q߽--b#2V⯗1rd‚O? 2 j}e@)gwE5R)Ӻ{ AȃѨnxyǢ@A5B+UAfW/Դ47p8-n {޻ٳ&nHw r&0 !Zf_51#ƌ -1Ê " ZLHUf'Qzy~bľyNTpyF[A %p%PY6._9.]4*}o1֯ثT+ܠ3liþ+vy`}1 *dQ ?3 #\^2)L(hTBC}l dF_YBt0jϕuUa.(|@eٔ _|Ñ^"Ǜ׫[=Zy{\} @ߎ5pIeu.!߄fdJRw0U? G1{q2uTQ\IXyW>;f> "r+nݰ225 P-iC z:̄!]n#^o+D{8ݵf1/—}l)(QR4 3f!%.%e*>eT4-V+zgy>5e]m܀(3<g| r&!3oFME15m eُ~ݮ#IvCo˗caYP-„ZYw=smmm29FVzn/\/ |2=y8g-Z(fOuB/Ji;Ӱ0J+m}aIطpM W˭Z=_邶3˅-e6$v_.^N{.Ť҅汻M2#!BC'F|(dJ$l9`͖p&r^LVL&t3DH ';TڳɺucyDZ#T^a`F<KVTEaa5 32D#N9#y5E`dKӫYXωqK!,ªߎCts > h^& V@PA  TM>lhTp}&xй d~52|D|eV ?_={8uOT͉!<x+q mf F?iY-w ֟SDC <&Cq_s3ߘP-L6oG%@P@QпFDI/g"vx9F2=\+$wł`Φxo[xAEBSpY8s%8|pQ[qС?k j|ԚI2r "h=h s_G|xr5UB0R ,ՆJ~{\}.k`iԙ :sNvv69SnMR}-5kZY[ + }w y ;>~Y۳XRD 4־;YBV汊,Ն|X򲾇3kNT}_7f!-+V@݌*쉻xxS 22QHMfV!ɱN0nXFKМ4 J(t)?u1!9͐slЪYF"De$HcrBi`I舜Uu/"TI4°0J](AU5? @N@:ڵ/bB/Υ*\aeBsͶv4&ZFR D(Ҝe03̩A\Bn (IL<Āh9`@˪h0=\0iNـ\Q[Mq1qLR| (\ic2vpGf`v Owzw| ?QtO$MS!F#11DGh cGFB*e%I`}lRdС}[g矡e)"wdD>B^"})ߤv,֌04[co߄=pDꇊxD@^klpF^qhXؾ+,ythw?vym'2]S5̚PÓL>Ȝi[Wq:Aɟ^7(|5oꪒFI(9؃q0rŹ ~Pǐ ?K+&BF!\'qKpJF&DTMNYyHAx}NYIaOD$9~z}oHx[ٓDl dIU{r >?G$$:a%N`*"#sAC,34QC&&<__E-c*M9 ΁F8Xr|4a%+"bp-lg dPA @V~%[V d_@˖rەfRl }n.tUpih^]q^RK4MKK+r1r[vJ"okjO#`fvL yᶥ~8Ł\*@u&ʵAwD{dg;#'}> *:m~mfƂeȚY0)M4} & IDAT) q0|$J /\FzhGddcgYK^X"cd"k[7g;b؛]-f乣i fhX+oQ4"RGpO2$QD:2l6wMQ ¿2P9;8$' L$V^vMSwYMz YmO{#1rrD?kf( `CU\exqŘm'Tv!IN8!㌜)X~ߨsG"y*QjS";Q%cx<> !L7>P/Bg;*a_A2jW"{+J (#2ߡY1%Rd y7Д Ns>2t}O/Cq}d8u: vp80yv\ĉD_!J)#'Ls~8JfĘN+gkMb*0hl;Uۚ_/J}%|P4 :c6~;Ss(šafL?QQe0w/&7ÁW{y0"Nݺ58mW-%̀p0YDptM'ۃ00bwoȥK>ͫQDG(<ڥTRy{Ksaqp]I{7B0g{5E,73HG6xT}iecs%?4Ch:PݙPTw)iP sB!8(&ۄ  E֞.9h/%@P@S,J蓱sJvRѺ51fs^_~G?AOXnw"f- US9 AAha&LIltE@c^>%&!#pi7 M eFՐx>iVt5k&8%EXj7]V3%%Y!gš Ȃ˄4N%ծJ,RVvه?XD nv n'30~n'0٪n{27݀~HAn׏9I!9 S7 6_)nI,c@:ʛÐiAN/b7L?K><̄9&ڢ{_E-FB{C={^QQXP좠bA*顆vwfv$$3>;;s)p`)8cz53YOf_{rIM @mۋN>+'5uh~p`U4plZ94=p]pi=ۜN2p8hY p2-?OddEͦ\,[kIMOӦ@Qʵpٞ4oO|@Ox8a<FUC/?g5>&!)م}5"QE$sނ)KvJw عl >7NύDVqs$E3I]@?\יz<"Sz=IEf7$ҊT}$tڣ{Ӟ:mjTHLB#٘YK[pGJn"9nHR]Vݠo& {Dd: o1Y3u+;OR!wG;aș4(^YzmEi5IYJŋ(ߎ"9.<s r}ڌ ,%{Xp"ɨFD֮)81n~ʤv K]SCL|\(pM^D3~jʋOAWEt<ꃛEG̹ O#UMxTpU\$a<=F'{w?`Ko4jg$gKΙ۷@UUE297^ʊE&Pzzzr0aSW8ě= 6LN%87f\}4#X1 ,&Gq+q]CH qt^ 2~l!FfvYmW7]W>CΌHC**|4 rr}3{v9CwCNFc?%$}AFQ:"բ77DmcBN*Ho4'l{-es~YJ##JQPaTC 8 EDLNwATBn˼.zbgn0 /"aL0j{g yx8;ے2sava=m3x2}\@XY ō>/^Z |WBaÍr;Ể.ddP)NҞ!-QyĬK6`H(Mlep#|EP{k@%I ]7eo a4^de;RQZQ#'OaBтbQXMD+_x]kC2m6I'Rf&b%雼hbq?`t1@DG$fy^tݝ/N2SP9Qv`}u:6kQ T*N;:gI&#;3 ];+.[|3%Vs2^g|wB)iI&A^k2aغcn,K&fTڣder͒E :1jB, QP*R*/^^ɨb.Q4PC2te $zoYB(T'pE?\尳W)F[>C& 9{ukϺj\RK_v K]RmEg_! My\N<}HMK4)gTGx^.Jz#Jî"Br.=>#fX2LzRA^u;ߚf!6 y 6[5]:uGk݀7D>-v9?l²<_0:]†]TZt\~ˑ(H#cǍk [z3B‘Ĺv:)n#P0T FqPm02%X%q՗9D0 ^]5׍EH(pHkGTE{nG]bȌ.S2@|$PqF< 6i!0Tci=sT#.IP YƘ(5:pE6{?3Z[SL%~?p,FPtU ?ri_`<ߜ[ʙxG5~ڌ0 4Yػ[ 7DZ!o="o:(e&b՚ 5įɀ[ cCs,ײ3R_6~ϩA h204SE sX2@E#r˲R!K(,C$rRDKEŒ%X'$}Ƹfmch@vUܭë}+`_.ۅG9ON|.3!F9׃aTVPYuک[SF]B`'\C2rMC믿7CIYEiHG^t߯W@{~eƀ/W߭&ו3&Z/[LCB/^[ 7²T U4!.,?ᴮr YX0 P 5&PO:qg6~gXg $ؒ3e-X׵h@#6sA=쏥[FF qX,gh |ɚJU 㤍7R8XI&`*F:.yX2ʡkذiKEq[qM<@U%Abոnx}'XlYgH}~m|K4S~xZ*NCQpb%4أ<RG?Я|=t!sR,D$](<ōRYpyO5 c֯QBJ 2 %1CYi G~0`wYDw\=pP_ml:Z&i&js 󇟆SO_%x+߃D]64}h>1 4o7]6 {8i>qA1skJ݂N2S$| $ݓOqk-39'OV<;BKp<a^KZQClq5oܢ]ߛnW^9pɶo1ql[BL/ăMRh`z'hit(4~o-2HEEE6텸txm6snzW~R=8Svڷ89:7b~rPzGVs['22ЕX]Y7!-}f}Zhz+9<l6{#D<$,{Q(.sƯ Ѻ ~h1f+k: 4ahw9$#'oAJeX]H_: ^!gJDDfGPwRU0pQX |"NL7v8,-Oa$n4mj/)f{N? |*V%M;o_}|0xŠRU'<&E}6#*oK䩔dQ<)FJ1&\fhZB 9w$q(` 4% *]a!RQdZS?8ĝS@y1Du&6"G^Kd Mڵ.v K Qh7o5^nGx;e&;]o.)@QqY o Ø33))^tP ;M7n¸n$fIo4p٧SOha1id4O챉Щ`}cJ3p O8=pQ:ο޿R/V y3D6RR E)6PJ[PF>"K,`Ż`954ER Ęe( O1rą88AKY@"'32d\r(/kq@e0nCMa7T<[v"1ۉGt.kg6",yQd915daoh[JHrjuHOu 6QɟSF=L\14%&)Vq{ àa0 I'B<˛9`C>Ņ%pئwcͺ"bVd3^YDҤZ%7䋢DRa IDAT°=%c;:T^?-e-[} N sNHvs+l@7r;*Bܡڙ 5#R_r!P@'qfkQ4)SXXAqِ{xĎY/B>#dk/F\%J= gGd g80Al]h@%^͛˕#odT׺fdw0T7IB AaaZd[?-KoA(:d/ȄThfa ϿFupM4kI#oȉar$>֬Y@Ti n]s1qBenoѮ9o~nTɊ kg#2'Nؕ"bQN\z@5ܬI%NWYd_ t3, 4ȡ/]OJY2 ./oqk1 ̑&ɖ)† 0vM>ڰ %B6Aʭw 3qw!EծokhHH4=AycX g2| 0h`?K2d,_^]9>4 In {:>$67`|(dvĶjqt ˮ@QN щ%rY%`rr'ͫ[@5 LO㗝Cj =4}cGt|շd\WV~6f}338㎆C$z"NN§{[5s ׹cFya+wfaSZorzXDEf-/7*AC`z'T4hUH8ɜT gt1j.j%(Fcm71k?V[q-Rww_7%كY-.}F}M]#8ZB^͈:1CDcXn ^Z̙CQF}~ѥWy^גj13F KVF )hA=K2ʸ\;Am梠G|Ưy$%3j O7;(Dݩb#";;{j K!eE K`N'L," F64C+ic[M00[0x`& sKW0'30\X7_st#, Bn}5"fD8x)9.=(0ѩlɰjd/c%|mJJط,:g2]KC%vv2:* Fi6\.0ϣ W-I~'q@u KWߖ2(!p~_oi/: 햋o ,ƚ 'W?ƚu9ό"$n@2Ա#;l < 31÷5cøy](6N(Ɣ p;ԁ%q7&ٸfnj+~u_JǍXL)n a|e576֤$b''2'<7e:`OnՍgX[Xi.v J K‹bbiq?c8p0k|C009rϠd¹hIW7> g_f5gm$A7s>VX$aYS(<2;d57lA1qFU=xM;7n:чn3geWU}ǦvT,)QmshWS ,.#S-`XͰ1A&Tk88);6py3zPس tRTnvV*m_*; {F~I7-ۮ0Lq OFe2D†j\XZ@Q19S;7ƨ`3j(c-#iW)UV.CN(R ƋDZ<\p.w&NVIBePM.c˜ϡɨ-[ѯ$1@s Fz. c8Ӑg~OZ0EQErOa|^Y>d^, E-øQ'_xf1sji,a= nൿ3'tYCTkzgL,+)&O FUJ!R2ts_]c~'AdOgvd8<r0 A5 l";jLdO\r6(2SsP"k@[ k51Y<šł#zx3F_K`cPPTspE 9(."’>wP`G9Qg/S2kQ!"t>Jv͞.U!bgr$l3й``umoʁw.v Kuh3FeW\D^8aI! [ 4>>uj֯_=z4fVT$#+= nk4 o`ɍљg|3ЄF}CosJ|!a$8}AG0iM>/~ϟd/aEF+ele%CV#|MX'd\;NVx@'Rk2 7%9̱P}(P<DŽ_q(k I b=:숡zEh4g[MTG#uଯm6d DlDՄ6(\pp*?dMݠ(^cGCZȒhiT(c^7;:9uKkPv OбOly!k[#J֝_H43%H59Qj]--PT%ՙ΀n:á]3ڨːtbD& ;h:xp"Vh:9L+CwLyHRWma+"pUIՅVkXˀOvƮVUÉ#5e0r^9ܻp Z8l) M?2HkcU%.H -&'W_{3+71:uńGaa9JʫyDJ0&f>`#ZCDFF:eݳ2wԤ41%C{xqP(G$>d!lTr1EaDP]0=9}y,CzC:r4ͩY: Di|"9Dy)Z*qQt֒+ΧKM K{;Ltxɡ*у"т@81q~ ss峢#tW$;8Kg8-r@xsUW&NIV3wHȶ4/uE%x{Q@/ o rz;BSDNdšgc֬/`!"zŐP>NG+g Feov>a"( A%04 eO5{3'{"4Td-?DYz{V!r̈́%%yq}wWv}oѸ ϱSϿ/9sجLt yyy˅D<{8%Spo .3@0w )%cn;X ),**}VP 4s\F4Zs"৒I9B<\}iOsc3&`=@\bW:V@#"*" lxn~UH࿽3?U5#;Ӑ̺EqQgPc ZߪCEs dG QRA"\S^W!"kbjd4zd$!= LDs֮Q-!]CkG:'"嵆=z ,C?ϬH0'ʡ읕7\^iigf7^u{˦KK+GZ9ҹ# ?'k+xx[8#跪d9`JUڵLJal.yc!/Eѹ:6!aGw7^6T 㻃ѽ,We`]uY/9>j_2{^8_7d9’tYL*hhRw*00 Xn ӛ=N\#+E8+?z7uh@%VzS+ɗw>j>={hZs,ۀ!Kp)"à1G}zI#A8u3vYإ3uv3*m'6R+++1gذaCyhJӏtFXގ]b&6@K*"Fů󿃦5^Xhg8xŊrc7s*D'@"ϋNc2Ugrfq]q6w?sZQ|8o%n;.b0̈;uj!ey$[Fc!/G @ Zl| ix%B;d2c "r3+"T5OlG/i$aV - 7*[.IFnj4 }r;W^R^8e6Nv%=TYQ5?AY0~C~9"$63x,l<< SkjFTOv܏uK~Z3d+1:\y,*Q֚-7,(J7b]j ?ɏOut({[8#;<Y{2,ˁV:ov,…/)'2ѭ|ikzl`p"):xaV"< Awдf62ed{8X-xK UM& 86, >;|R̎:4\ /{u^ΏRC#kq6ΗyGؿ,R]L?T2f)a e9ziQ)._/%= 1w"PÉPӨOʧ67W҆S!i~9_ی ?.v $Ц.\$}hzz:F:Nv]ϐuS^6gta \BN:0hVSUU ;; p&?D_TTKaѢERj=pȰCqHPSPkoDQqF#DӹaN*Avffzk%ng:}z8zU\?p9|<2ĭ͉8SCcUێq zNd]ʆ+J00B DNLix Һ7`P;d?v5pCڇӾUf2x:,FYc :>1W䤦p6l P~=Y07c|V%ıbpɗ<8:ݜ5lghN͍p;T>ZfFX-"3T8ma\{M1bq=~wDq>Rd%xdZ "r1]j|7r(2l, ư!e2RٷhH:})dxl88oWȲp 4۝ә ׁjpBE!ӓ }bt*ql4ʀ6iﵟ׬kaCQ816^q.Nk њ 1%~?wHJ[QT'¤&ᰳŋ?XV&y3fAc!(,{'T^"r@r%f*{D/b/a Cˀ0O|sjĞ+c9fi}#JOCv<+̙lyڊE%sUPaÎġQ!-ō\iLέ}ayMRDp]Ct *Ӹ'N +^ݺuC>}@N UUBM17oUU\m۶mPPPani 퓽Mŗ LǍo¢2()fΜ+W5kUfקhMS7&e~a]/ ꜙbCL9(c> aEEYG:j 3 ֱ@w7EjDypemKXz?ePkp.z׀/COTc[)s@p]sS&!%5 WI{iC-dQ=^5UeG#@QPh:WЊm 0d-[JD(wE-C~ҥXY IP8kzCMe$u lo<=S;Q e^A6{h=]=@y{Owd ;^f$a;!h*3Sqᚿ#G~ a`=:Æ]5֟S}XE ^ xEK(jYI#fay%P\wh IDAT'eq؇f!bMse*zel+0tJF/(G3ӆu`>#tp 0{g| .0ɐu33ÂXW |؜>eJ64&$+ϫ=XLC9N$tP(vi!*Cĵw9݃O~K5ȁQga]s3^5gͼ1_oߌP0ԋG(QDsyk u=ڒ%Kk 'һw++K$M$v[7 _Gvݦ.z߸o dffqkVs2 l:}S/ %N@z^=Za8p ɓ@T$1 瞒zx^0kB:qm NVUURnS&$o&!B Ҟn'޹|87Q?T ;P 7k-i^'Oh4=zv*-JSV̟-Iq\7n] 7HR3W!$UG1fa$eCQ4S\K6iJ'o,eܦ. jrI91Y_׫ش#M)Gu{甞5z{/Võ/"]2<Լx4(m$ {$zeeAPY*b@ud sk7*JQ^ӄH2'TVJ#c2M3iTZH/8= F7 OOkZsC-7꾒dcr4'.3o{0''J>w 1Gj0?fK &G62ST\wp ػ9IRUtGÁd\s`HY:eY dꁳ/\Rѐ{^B'MMX<= UpG0 2]HUĠ݇LrBQ`H&A)ZߐO?#ܽ.7 È;\x˱O,j۠?o}[q,ˡ[%S/HG/XRmɽP!Ia~,/B:gԪ= I YgVڽlҋ2qA{Ĵ|O{+ ʪ0mnL׺p3T[Aǝ}=oAyLL_ΑurViN:ЭkG|Ё~՜UMݻwʫo-pI; #)Ƀ;OZZZիIwyϿ,|͏:Q/71ڰcGG$Cx"ϕ-NmgCбڏ}>j;ՐاzѺE=DW)[ b֘i6#\ $nċzmOV<YOᛙ 3ZQxV!24@_ YG DbRN=?dd) 𚭤(hVecaAgC8;40YAœ"( bӽ^ ;-,pƜx<(Hd`2_f/~O1$FN΅':ey;O`Uč;gTZ7`60pPGݒmP'$"B[Fd,݀܅<4 9y7l3p ۑ ף'#vi A\p8o'yQ#LsU&p~*"T\"0쐜;y J84Ka Tagw7"-#CDzf4>ߌ-{]WS|&[b ]_ 'e2@2nոf?a .G_*e^ H@:.{K%eA p8Tw9ڝn+--L+diii]~q~EeIJ+/[xQ^]]]&'ǠxMkX" !;;G){w4]Fn) 'db OYk@zBA2uy5(Rh{nhx11O>.X Ш`H*ʝ?/+sKp^1}To'd$wlrSTݎ09=+ M2M(\21 KhSW% VlHwxZЧ jT@qlG(r (܁_| α7cosV9'=P4 [sV7 t BŸ/)r \3H >GqgfbK%M\O_~gn凨{==:Ľcn{4./Ds(:Ldzar!CĨkF3*=:6 o7͚@㹫97vK.:uEygnCr9d#Q#b~}qYg{\ZN׾t}yqNc/Nc9Ae* '&JKMqY'~uPlpeI-cm1-Y&شO?o11ݼϺĨg?n~cE {#FI ЪCu9JX'^%\daBZYy@sW^č&] c#ol&d6g|T$R=.lrf@: )1[7"- 6<5ڎMY ĩTbY*Oci X݇v*J|}1t^[c)Zsd#!5@E3`ӏeEP no Jˈxҋ0C:GUq )#R&1(d4ӏf{2Ŏv,P3] 5?n8tLFdo1 f:Vd[vd|b<5{B9vE.$ؙiαMZ`QjXM< g4l4}WE>ܑg<ܙfd Q?Ziڌ  3-0<9dHIƜ]H.Mm /< n"꽖 `6D(@ae%p v**^#*t;$ (N& .u奸幩BQN!t<Y8wOሆ_ xT$+LJ#s\$[a3)Iv/gTC2yk!#P1qڏju A@>4\}6bb/ž'4P۷';ߐQ%j |E;JTD̜ ꍻ9mu"K*f+j{ yUW]˖%6w!=̓4HTϸFPدVIy1,t"u 蕞Z,QtmWRZIBDò?އ`RgF9pE\EXawc`u 0`/F_&eP/zEppF^T^豭X3g~pkc@jӦ>OMԩSzKk\DV/) tsq8YQVR J(0R1 7R6xSa sNiŹT3h nrM<@# ‰Ǿ♟SK+!^t睋N)\IgݴM2Gz! ֎d%9j.zӋٖ|}9^h$IԎ i7~ҧLǞ0 H5qYJ4_Rp~{bg[6ߒJnJ,*D@rt;k>lB1z_ z犭J8@,湹y3X(xg"Sn/λbR:uŊBK<瞏;yӓ "jVH[+[oM677Be"dQ~f@~~fw/A^zz+׆`&=8^5up膂ŕpM؈>h' <{MVH/?G?Dzo/#el,zKb*Mh5TY mH:߂^Mp*)()qȚN]=q=s-GsV5(Q)Ʌ K_}[Ev=_%&IgQ\k.3v 1?(+\}nGmK#w~ݍ5k6KE#GĉSԮ푣2A70<"A-ĸnN׃[hd?G(HIv-gO@=Xm4e&IdHw1b' $˦SC)-sCD>ILQE)ŁpJFe@uBBuʆ&#ܱCGU̅9g6R6Ra3eٓܧ؉4fT)Tgd%e`yp $ b26J2w; YD1],H |cxz9e j]IYs"|A[C2r>7fIz‘'Bpr0"pJcHr:3'E#4Ud'C[]O]+jM\BC儁n]Rs{էwrWLyYxzl$BQ@R_ IDATkW9zpGC8ցfvmĩu%˓ JU3˅!C`ʔ@F{ È!~0?4sW>gmS7?)2W_>7O\SC)$Di;4Pm(ʤ`RqDµˆ# E]U-"Rt<*2~?z~O_A(6Bie˗Vle<r8pI:^ 8"iMO}4](fR]Lf/|'*TNXf#OIuos:c&^:Neb*, n '"8_wq)$)#mw)N'Q"ʦ;(?cb%˛m52 ߗΎҤUI;†3$ g0(6-4~6*kMJVd(uʹ&qÈ" FXGXAn4:ύ.<5!~l!vM=$| vbm "vg2X;s(>=a.d%ԠB*5I@TC~dUH%vz NO+SBʍgqni"ͥks0| }0 OKt1aԖJ}Lsu9D4x$(A׫qoe&" !{ѭ8p,OGSJ>|a΋dFt;5Ժ0ҎT,QaҞbË)ikr̝b,d^,'9UDN,ph:|nvv0<@/!w(8y9N9?==I{&ϡ Tcm1l` $ٿHn/[n7 ;'L7ޑr/9qhL 秿x˹&NlǑa2NwsMbQWUTyO磚#ļW8ANN]kP-Ph\{"R?~iv)wc-ؙx7h׃@G c~/w{}gj.k%qnr,v ѣG~0xhӉ~JvZnSeEE3u%&38fTKѧOoI^ $ǂ6c=9^O osⓍNh93;Eb<,7ʒIwpP/'&hxY"&!B.!GL%ϫҳ&cfTuy!4Y_i<Κ{qPSNYBgAI)[u∱ tzKQ?oncF 0 Emu2VUnFnCNyBnR"$9+qrDa`8p` <@*Ī5\+aH[7y'; 6Dpϓs3̔t__}={ Unig_Iq;`]5 ޚ~-V^P(]&3g:%ȬUE(<0YOnMb:{9ts w(uËu N$=i$(8o .DHr*=>%7.Yl2nܸI#nj{8Ftk%AdJǠp`܇MD&]vd~9Cy>j\Ό{p)˸45[8g᥂BO_w_H\ &jj85S t:ܢl<=_=|$Ak"3 0ەO/T&xp˛PFo@eJiPe ~Ğ}qn+'KAdݐ-w|DR :@6c@lI܎Mb5xu{{ƻ f@|B;tm}Ym .ߙ )yȱQFYW}j*nqX<\=?;wKn$`Zj{+>ԩG`РAYNבiPp%qpGr;Ź=n~]sSz쉧7˞Fencǎ;AD(nNP\^{[!Ĺ})~xl;'_yޙG9P jkp':bkPdwp4/ ֽ7n3<)\~ЇGkg< p ܚ ?[jC#ŎBӞՙX-\sYR 0wU)NwvfV#'C`ROkHw lÖĿkAr, 'r Z 1cLZj(RN{Oø硟D]E8RĖ2l̜_.sD* :S]eo~X^lu]y[Ms]<:'xGжnR+0gN'kߓߕ)c _lwY$] '|2gϭHxWr/J>?w_?+kWZD=ztLj#'fGSxI7>y{(Ng}4 2i!Sѕ 3.yA,l:tëGZo:4!Ґ_]N6UŦˏ3vwɭ>S,%#J3}Y>Oàk[peTdS6 qcbyylTQ!W{NuwNǹ^8E 9& <86&`IARqTѯ{1ߧz큞=s!L \*׆k<66Y^۫m"?^M%%@҈U[EkhpUm5lM"EYNA&+(,"0AV "M +9ћ~A2m"oWEl]HL&"I?f^ӳļa?n"^B YAkЯn9,i#8i`{Y22p{cρ%CHLJCM5NJ̧?ԦbN~}I\8`#Pd Q)cNU3@X3gǬkGCi&i'5jqd!8a!EY /,+VPBb7GFRTjpQ+( 1GsZ"p0q#@lE>>'@g21[kO)~~_]7j2ƫTW__PrjEU iooAk?gL< -T:VWWc֬nݺzrUOm _~UGvüyTUDy7ZoӯE_}У=b,9\:yX/a/ b]!LTJ'_B\CP˩ .WK#clH̖C)&#c=*&!/~)Vj1DEa ԄV^Hs;\^yXPHQD|#dPؼ"t^z*W_R cfP ӦKOw >A\ 2 |q_#G)%;4[-2/dO0BmpdEBphPt.-)b,?TÆpn`iadI;4ҕK j{; oiiFK}>₩AH6 {6<^:-}7C2|q1uB}IŸZ,O/L(lZm(`BJr\7 o$ǹ#l=ޭYD%ipԾb[TEb)RlLm I^1/^.zzmE/{ϾD](p4*t\yC=X >?[Iy8oW/|T!p իg sR(5gr{@p{ȭ-Z,[vX{>~ag?JRBP8"9=)™8S9l]gI7衤(Ra%goٲ3fiC%>/hak?p]:^f/q9O?>'>]ѷs2L-'YAڷ<%uY>٫B#Xڶ3PP Ua"}^i)`-/[N F=$yo-U#pA`ZTV~CFrMRcp+ .sm+onT" EJ~HEF@I&.BRnmxcce mps Mh]~thpc, GK`OC #  ȓQ㓥m-l͜(?) HJ2C^ID:4f ::ѳ9;G 98&!I.|sӝd'%pX͵=`wgw =x @`o}бDkB\DuCd\+{:Ty<[q$)l|#wUgHB-ކq`\x:z8O$}Gy{[.⹴|~<Y4`.E_x t8{Cm}3n?%ioμ:47 |'~?d;~ îZ<;Lv mS4>8șͥ$׭24X6EYM4IATׄ-ntPHOmfC&ߣU` pR1SZJ:VҀ߃rJ!h8.nʶd:N^N/M=^Kҧm2[]|VEDޠ]'省A 7|g IDATxܵ"v{70kjfE(iT8޾BAO3gbҥ94Qe% 9fժ3sxO>]fvKo/o;tDF ?AȲS~*KC,<<+D ’&5OH[jİNpoèո@SB3LQ;?- N@N##2&Sx`($2#Vi&Q)d'h >I0֛hYwڛ,wE ZL'U4?Q [7 #IF$M3+n4K6,㽕u&zfe8Y#~[}oL3̖YƭN:_ۺK0kO?C A' .of`]UW?">[1r3sW`aĩ¨4 l063%`m@]3$avSq=3NV!E!!d{ATyVmHf0]hđLU@+xQlڢIJXj.$֮_uKC{׭?zq."ȁ1Y)1*vs/%P$FQ!ɜ2:UmdȨw( (EzvJ2Z"5nJH†)/>(?VV|ERZʭq "G:1tw-D]]]=lgǪe`[KQ5 `. o[z^TFr/S("λV#$qmNW 0xvܯY2-_ 4 AH h[,"ʁ):\U؝fЋߨ؃(QmȨ}+ Fy""֝x4]l|B(%":,̏"_*_}!6l~[/a?~Bh0n}h4_]d`V Q$2!{%MŊg}<ú2~v>^~3čt+ׂ/yet(w NKM7Fo Qkf"?7LMN8'lȝ*n] HHsi:iz{|qD3AdCgʣ9K <^9Om'ee)TĢͦѻNi .*4:殭?5+NsʩSI3;Ty)9"}158d0:?ʉMi*-]i._33٪o>y.>%0ѐmJ#A %7CUz=O#YlN0<]>,:6H2þ$9>0.'3JiDq>̫0Ӏ~8dDŽg\m>l4S|b0P2e/$)*|}uҀi "i1MF:y3kVo*>i:WFKwPWQ6n@8Mb"aϱ)@BJrq3!|,'3|FĔRkɹiiYpsDS.'NWf!%$9k>QgK<zßO݂&=Godu{IʃXC;Z81K@w\7EBQnBVqe,%L 4 'HKht,q8q3'1 ?bf ծc >]!"Q;7wğ؋HZ'T:o;ݡ;I.wstovno{>ON%3F|϶oa(..ƹۮ(A7(}^l6x,s&@2!:Z7.hl|dk΍wߖ41ՕMMQg "ѣ?Vtiz+ܓʓ l6^z)Sq!fԸ!agXZZ]w^y[\n,zqgpiܜ&$0WAQzݚ@7[d36qGv|[!U`uYb:$ ⠇$ ǯs/R1)|+ Jp4D*8:1x/;n`j }\3"][l&"K[Fa!:q\ڌs J"k3~X65 +V-s6Ua^ݽ~l2XI=gtfg6C 3ÈJ>[of3cGp2y;GJyu2T< FoO> )e4}&E-u4c0 pFBЕp]ڜ4LN۩w(ۡ&AX'z7.hqӨ`(R#mb IrPEqΝ a'~(TZ$4HX[I\{xI)N(l1.?ۄc5:s3g\w:v]zࠃ9eʔqBBH l t O>}Hҹa^THWtHNEgH,Ppn9ZB[i]2ŀiG0E놪6qq-ιWrΡ ͱ.9ew`6[؜MdKtx삳G9'-nuաo4D8ۆ•ڂxsP<2%3VFFxFأGw}M"s=HG?>xÚ5;0=~5xnrcm qg(k<vfZ<=Y.lOyF;y,.$"B0%ٱ׾ۂHʂ, 2 <]fC77]gF[cgYhF >Rv9V"fڌDP4)dԦ{+!wPU8ZyzA3jIodo;v:ӚdRط_g׊;oXe=B[7}Dy8\lܞg 6IB7 d$@Ė 9 =;@,`ߑ$ l3#R[Kg+ʥ\F&H9ىy)G1$+Uwq "kA.cWUxŐ=nyH\ B8iXcbp&\\ qGKpq1}HN/v2 w5>hG̮ dz"&[ 2­iʏx<KK; "mbo =JQYx&.3H0jjÈǓ %thpj)vUD~.vja`uoTC'p4bRӥ*um6дuqSNƀ>=hf ȨSnNsى(4 @pӳAY"wS io)¡cp,!(lI+h c¡ozVb Kf퇅_B攽Y|Z61%~ݸ}`XgpJRE;$  EBY ) LrA$obF!Ɔ>P<iZ9Ӹ(|p`JMqQ7~6:K6JvA֞df[C{BO7Cq2n`AH;~Qnuk{U7a˖VXhDt!ӎ;w_/TVoyʽOd3Ex=1(/Ç4#G6@\W|yI:3(]L¼U`6b>56}x횁:䧬|781hz]x^TpIvpdCГIֆqe}(:n$C5PY^WoX΅UkV"i~%խЃQBV;a l _c:YS0@dVWyp۵y.ߘ޽dڍ$3Æ&2}:&['?Ŗ=z_OH(j}( }@<搑k"e[6U<- pd3t[H"1$1$q/ Ņ,W$xLӈpg$k2="x)m7c% niOK!ǀ_ %1 $[@]Lpdqڇ(oװm+}̷?0^xiflNt|0`&MڏK^t\N P!*u>fZV37PAUV#%vv;sUٮJpUr;9+;?yq,3Na_g]8/|lvԓӻ>%+َvׯs[h{Ӭ8t}&q0\y!g_J'DtoNDm MJTqo`Yyf's@,*m$pI'q]Lc:^J F 6-;yl޿LNT7FJ'U2йo[->ΒHV ~hqكV7تwP-n?FnŌK&"AAω+ TG[ڌ h lxy&OyZm{8Ԗ~\d%$V[kJP2H{.AUANVI3eZ`|J-!U9T6mh zjqNhVC-}É,]Sgl+UaB2"qڞ` IDATᐍ;xxx9~Ԣ/_u hweN:OE=m=UUzZ*q*ۉ\BߊH >2<[d(v_Ӝ8|JuRO輨[˵.%0k,[sψ~\wXea`9Am-tUzzP//@bAđu};9>vpc{7ٛo(r9 6+ZN&zs2aݵx۫ήMuQ1Sco%wm<Jo qbwv7B>6s-G"tާsPc{;6v ~`M@i>fyCA1'*3?d' Q z$rHh76ޅFъ,^1XYQ$c lf ,q CƖ+={6˄ c3qF 7.dsp_}Z 42I7<=nkP!^~;$mYPʐS #ߺFYD r㪩nK۩ +h枧_g ![g4x *KsQbm ]%ZLCyUflQ $?g&Ԧ"kB!=jϥN4"\:TZ3ZE>?&ꢥ%$m01i3M`ORƒ0di`sL" N Ν64K%sni/vݒxe&\&Ă AZW28fRp_%9}3+;nr`ڴiի'fxەgI;`6蘋AqAO Сk:tՂ_O{ RB"vu$x44ȅ86T,Ծ0.j~^h9zގ{lVj;6V|;I4zxvbpRDG L5khP\ӮS$5O̼TeKX\Y]/OblNCnj# ヌŚ`ݷZ&;ebǩI)G tu @QьZY:ElۭB%4SE1 DA ?w>gGx>iGՍk IF*MVi;vTf֭،ϙdոW2urSyy6t]xyϙ?mK7BLE0lC圪nfΉMAf֫iw"C:cF8r ) *ӹ-~8UDm5TICwyAq`VBU NEAǸ]g9D DQGӺ6EN2|GVQ*Ձ[n~}R4DlH$]:6pJlF Lڎ:iX̑[+u]?8vj?>(ۦ\r҂_Z&+1g\$PrEl|3]?ӑl3#CB L]WpIޚp s[4kqVЪqN{yp7/X[]mcO]P~Z]H<Ձ+|]@{c}H ;OީG' lwݨCfA[/b-d$0?o@6h 9HsFw4!TrM@d bm٠6݅:X!Te3PHR}Ə]D-wIQ5Ra0INGK =vXt "#x\P̆A>j\wn[zz'u&E+x$s{!҈ ى?^G΀&,eQPP0Î_[><| Y BJ(=+!.`w?dIoC}؂k|헿k1;iQ[F0rtla # B M"".5.eK Ɛѡ6]ΉjOҁ:1bͺuy뱸KV6Kub7qNA*? c96-#0(_sjzN;]kM>` x~(cLt<ᬑnos(m0E Z*nַ ^~+$V-6}bq/\; PM^>{Od2cdzJ,h%gj-VԺ^g~ b X#P5]5A[ ( A )qcCMq&af|x@AկeY@BrBHV(e(v _Tf-(|@ LGԳOCA)ā pPJyɓat2 :-kl/غ1ԤbKG 76YJ>?N* W^ "a 'W?Fm\ΟP5!th\spI><4 Z֨Ztpn8̹YBn1d)K~^! r :z֬NG8Ub-LkΑ8p4Ǿ\rʫN,V( PxiCcF;zj(Fkp۱vdYfx3U|plpo/ '3G 2H6I( & =^ c@uvlшޓk6iuKx{<5.=o`l `? oO5boxa4C<d ղMbq d]Y|)$lNX;Aa?/K(CGA+L2 kEO%KlhVUDԟ4|ƍ8/tHc7|ײF$v)C t҉ׯk@36.7U$Bbm:ɜ8 fAyYo̜dZmo>- {&޼Ï߁EGrҾ2qX wXx+jbp[)orWo]RRAo[ aaqxz*|~U[  # R>-E#qc{jॗ^FEEER$K:|fםS_^GX~! ^^z4%B6H^#m=K2T:g"7dNyf^aDZGnnp}#Hq-*l:K{i)_@GmpG>yYA&C?a 6 %,]8U@@`p[̔(8$~_u)Z$TPb? : )7 :xﰱ*Fr}拊vx=lÆʌÄN^zeEM&9v66+FOn;qJ{>Ҟ_C0B\~OL[3HgpyuUbq'52 ,pkdD1w"Euv{Ւh*4y[X=99s73l~K-qor?hv}h?,],z}Jk*x"Q\u;ϳ.G–{~ ){JB:[ T 0i;|Fd.PFbPn U#Zؒ=on)n[>LѸt>5A3LX*# r3V [}yTbɄWQsQ-F%g#J PG:^(KCش1W#չF 8vOs aR(GCثWWJ9YYX. 0՟ea{(zxK {pQtyZ\L cJSI6{b[[w"lLFCPug!J1Kܗ8rZȠux2tIs|`xkU3ۖddc:L$ VCY O,ҕ|쯾x79-C2ؖnYmW?˨n'@89}Pv{w; uOZ\Wh%eOСC:縢-ֶHp;l(sf5CnY҉ z^٦ ?Ô_Oʸ2U3\fmڅ,V޳e ̓}}|c N} 5& `Obcy BWk7oA0BGf.誐{z :!P0$cq ᷺ :Ս⹋G)֑ÎLl&0dZb{p%6n` JÒWnaDMX2h|{^7o$pM¸צؾ)&y>€Q8g" V~_1h'+Mha @,zּe-.\VE IDATY +1d,C^9sQjeqOӪ"/Î~3" ~ӷ. ,pipPЏ+lB3)&1wtE6W#? ,Tt]鬿eXI~_ Pq9kwM]H5&"Z_>wur!k뾫gdp q}G~rQ^ZٻfG֐wx7b~CwaCo3{cxgK3NZwP6PjBnoʩ5bRqe ?4ť=O:g4lR/ypH `F@N;E0R'@TgPw?_[[Pw|!w)ghѣO xNoK.]vl0 }^SC+Щ'o */TO,f.QbO0GT +v?_t3̟LKaU$.[ԡ1HE+#ws͋Sc=8[.x]Iۚ׶K1ի (DQtIQ{ɒ.1`8 p4EE?N$ * ~xb ۋjvot@4(W9ϩ̅A*T0HA a+g4۴[Jm${#q? zLA'HP\G17.StZ!4(%{J!Kn8l95'E?(bA77nb``R)Y23>y%ņߘ7Q?̺ޤW'SeuQ@Ňk`FoY>ݼI4 ~JPnt:fYagk68AW^w$>1,] vx;]0@#N?'>|7{npEf3R%yᯜUvN1#RyE:f=]4yLA4;a59c z҃kS+☥O6,[ZƳ]aA?-CB'PlV'ּ 4{zݵ,x/a Rn=)EV!ވKqÍ鿔'^jƿ3>7GH%b@ }i-qAQE%4{2UF"2yDʯ*(r8LA##Oec=tB 6BOU@^Vr>t9B;LFY dD^'~!jqu3K=<z4& n +< 5ܽ)s(xEX&E`PXхv$K/7xޯ á!XЧN2 o=֕cҤaҕÀ x} Y|vآb>6h$]*!cD ]ym uySU9Mh26Vա!-=uftqHUQ9$W )Ǖt )'|#p|*,)QNNOν JpG?T#^K:zyB9iveA~{[*m8fbGH 0D{&̎c2\W^(zwhM9,I ",g­P%g5Uut 2w(%HW >\kTGygG|^K6m17Ciq*_麩A)t@ee5^z5,7ȲSVw+Vo⼹D#[ L;n kh7K'aqzB; w_`On1 =p+( I>;B[,QB5@o!lGhHY#dg n|4OvsN+kP"3g8pU0tjN!hc>c(rք =?F :rOmp`L:8t* |N}6 *z|R~}bP>[hf :R҈+"+㋛q&x8D@I(H&:yrf}-[%>>=ImwVPcK`ʫP.^f B-.AAav 2SdaS$IAaj, GjdBb 9L83ӊ5L@+׮D^Eү4)ԟvKBN̩'Zhxk/fHFJ9yd9Æq8l#Y\j$C- uxF_]Bwx8Ӿ(9&*o#4Eu[p(n }:hͥ6Y% =OvIA?ZV`rD&")o4²e8ب2gaX/Ƹ])",)욥o#ݚe T:!'ktC{}ٗ2"'P 7ə .6Ѧ6d|شWhȜ̤`2`2}* #SQ1߽͋ޟ:vO5]OE>%lF޾JwO i4ŋqP KJ Vn;vozZa;DfÀf/7rlPe^ x#XlAm&H7n ƏJk 三!| z믛ݬ%bK{UXWp̆]̾=)_\0\;neS睌ANl~ *t&V*(9`w QeEzfh+^@s9EEdaHQ͸橩(I8O8XWǽGBt^z\i_UC}0lE''(JĢYYH٩l/՜u LU tD⴫09|+yR;.cǎGEW*c^Pq>?u-΍TgnsH[sv۰yXޱD못Y3AWe01)`߷7yِ dh,o'cزUh!FX[YҲR.(tºF2RLW rЧO |pVC;{wC%~[c;ɴ,*+VЙuftX읙#ߘ>zI_ 9J$tKP3Z`]rǩEGf>qy8{BYw=VlZq. U^p\w!tMZ-+X)aJ4'<4 k֬a(+ɦ5dPI! o (4>H;IeJ12r#9ȆYc(E\aǛ0ן8P#_La&a` G`߾%|<fFܰFhfѱ4. y5 ʂZq$(; /@}"mԳݯ|ƕ f3{qڈ6l#az #|J\AZYjJNnGSw$< T6CKFȃNll6_lcE5ߋΕ,؅a{y]cIǐ}a=L2qU nMuI<:ӿ_o̜1ftK[>f_|rIQ?yϙ6zoLwU  Zk=+άyM^g6eB/**BAAN[dR g#BM}ȏ[E2(A~cЯ]7f0GٴPEW8=Vp'n;7$EY1iPxNINbps`1]Dkb͊ okD#c-|?zXtT6BF52WТ1E0N`<dnsmi.}pHS୼cPco+_J G$p h5h!)GR{:.{Wa EN7,<};Ct[ȳRDTHwz{N=nNꌟ*ϱJ yA̫˒cbH:.b|X^<<K:G_.! cY)v>ATvB1h&h֫pξwX}UjDo#2YH܋~( %b0Z%!׿/ӦtY͛ xSyHeVܻʤ$Ⱥ AJEeLݙ]v;Sc߼lPbX/RЭ7B6`a tfJ$)CS~.s9HNy ~n &.{THIH dWg/JGuX ,*cŲ5Hqr2f ӑ3>Y3"ZL !o=E>'`uYCpϻ&=sa2t4ܮ0ҳQH U7$;$tT _(# tfOqh ęSh*FC$ÿ?3";_|!&&q_^P$Ϯdp_>7 x?B&@SxF.&D+xF679A֕(:lO"NH]DgPuǰv%-Tz'`ĈD( moOyzm'Sxw[e]S_<{_q.9$,1Ĵ2^R ȥ\TmذES6V7OUƨQ#ۺĩ 555Uy+'ګ˖Ux!ADtnUh@I$tϢ~޾o9T"^D0n;c:^F<1Zܸ#)K5hO.l4f>{q%{/<Ήf7 WRF=9'9[och:|~ɰGpjwZ>2=_H%3a/45.׿^Q2F f=eǢٴ{_4-jG{S"w+[|ܹs;=+!>EES.zіy(WU{ Oy>GU!$̐P(,|:X &cv(\n'F2)Xn0iQ7,$><F"A5<|w\1ϔmH !U~_!CM!A2$6k1YLAkS62ш/a2OZ Gtَ.Q͊sO/KqW> F'r9+q  ;qt%xű}<߹7<=ӣxV'q㪫JaR,9vf-rǗу{-_+X22rA05dO-.k~o]]݆C [;=<+6ï$ފ~OΐxQ9Z6UIU+GM{u5_$ 77FLFTE{q0 ;ÇB!5m>ԜsJ*0p8xRiw@]~4Y3>iouKɆE(+*3O<33)-V\uǾ0[,nHKS`*93!Pu1ekC07G~fhF+vсX :}Ʀᰐ"brBnZ[ZN3<C6bki !iC9~aNINXJި5y&]GuLy].RE7*^d &j(+NEA.&sCӄzp B&o3Rt%Zjw"bv"h[rK5!H;t>W2|ҼVdJ6U،:ٜI!uA[=ZPyӼ(F1 DF4\r t Y1u[mecHuznrzZ#_{pl} N?"F:(Ek 0x`orz>% |>K$nUYSN""L &w)'/K?ӉS~s豧/1XZ"V0HPY<Wv8!2dgR"bE?G Euw"S+D.'u9j0rQqr`lȏ?C7'ggbPQ{|:&sW۠)-vŘ;[Hv\<[)OGITi_(x`g$Bkn@Dw׉[<뜂J'O_fX`5EO|{ݺUwHdhm%.mN] 7T B(c ̽a鋉O>Ma";v]"ۉV8<1}O=ɒ!ո*?+ר]|1 '?9GD Rb@x*UVQlspn+%1TusKn_ 0!M_iFlGFOWp,5I*Wr>FKL36aK![NƏ?U*tf2Qh`av)o!IJo>dR{ 7 Y]nԙ}|F>̋u@,S o銹rпON)StωDk9tGv"_hY}/>7'򥝩гxәo~ }9P,N^R\IH6 7lŠUr|Wbuc=qWpZ.@)Ȩo˖#E8ҶxEʜͷB.Pc7#^_<7#ּCOx*[ˬWav\vxfAIM_s(!'ϙ} q4q2ெ-vݑd Α0XoӺ`Xk3v1d KgZ#.lCkR`]q=1'gʨh݃^ v ē {"SlZ;Op#Cbj*_{!>smP4c@qiǠeakb)ɒ:aq"6Qx.B~9YLi{ G1=_&_3:]{0lY훑G RHkC̉r<;&Y/&SAQO q{pnNTipߤ}XKYLs#XqDZBC<Ad>i427x{]Cm*"rpI!9YJ QÄvӿJ jq!(/"seW!OYaQUk (zL6'"yc ,F5&c,E;aaXʇW?X|$ :mŵw?1l[["%d…^QJUhM[ öJaS)x3=[ʤmiu{L@W$_߯<~ٰQf$F2a,09cʌ6%E%EׯbK{z hoR 7rtt |1j(o.I 4|B~ 5Cϭ$mgL`d* #ǹ-yi!P~f6JI?zs<􊇔v!A0Pè"Gws+P Lx#mDiDŚlӚKRxkgz՜o e!#Bɠs@)>OLBnN1<OQ:e `=?' Mư[#˰~1P.ʟ|ߩot=?s0Qn<&cF {4s1oyϹoF>M < N5=qV&mln i @3DTD;j,G>U^= O+ZRCZSg΅^$`SuXx.~Pމ(}:Dxf0g_3;CpxRwBFߜ{%d_5s]K:koUVԥTm6+j( 0d@/L²멱. qѥHt+5x@itz37B@?ŽO$p1#jxw.Q*,bʕaLInO@GKDgG]]g9kxNq .^w{'"#(Wkkk82dM<ǒ65|q5]IADM0m<ܘ!77 oNV*=E6vG.XK,$.)orɏ[w^wgwMLf߭\Q Pw 9z)nBZ~̈́"cں" 1b-OB'_܅@Mh~-qG`S}ty I*zltfI:b΂^2۠g;dy^BdhJ|лw9;Ttl[^ NzF/jjjqw@{=b7_7j{׶l.,N宷SV6`3$ye蟛:0:-<(Gx9>Cg;29(= +n+oKu555-R<!Oa2 yqȠ{-:d^\qD}I=2̡ kv5 L!) 8}e%R;Y>jEXˇ0BݬP 8c{֊Έ<ӎѧkLf*uГ2& yzcJ cPe 9)<Fo=Z V)(9sPT> =AAsTa/O|ҀhdVzN#g`xeEgy.r  {zu= Y#3p~8{=s) ы;9 3Mۧh{Vӟ<.YE͑|qAga{?-ôֲ0  chuJ'0ݠÂ:+f~ŏ$#h6@Pń B i-;s >9"Ⅲ(Đt0g~0ߎУg{57+G qi6&ZBEOKWܦȐpҝ`4EwIгl7$aCp'Ôזt,#:"r$@?o!6mH@*휲#EUvvvfb w?tA+HUmb(-/&cs0:)C~ԇ|s]oDW;Qڤ`m!N63 z!QcLg0+kETL7RȂW繭rš+=f)ۄ{!u9NK*H*YQoZ)½銎ں-M9hGASHq:8fR,s q]pPOZuXsȘv!QDH<"r+Eo N#'4\ƀVXҗ !o$"27Z`ऱwJ^Թ[ITy!3~f& |k&#n**>} *8UȚފ%_ 1c=gȩ8Wȷdi@I%ݬU-KwܤpRC91,I-uS5`6^&g -uNyFqRģ(0tLhLxu 7yfAY؝1~fIa@DQ1xجlUbHeˍpHȋ3^w뀒 {raT0"iukκ0ꪬ**0`QA,9 Թܪfz 0:̼Pu^ |t~Ax4HĦoS ]tQKA 9pP=qTf36[!1jm;,%wV:b)rLdJVmA7;u1^Kw_k~^dk DEҨqe A{C/*aTf< NݙEC=o0#.^FnkN)ijaEm1#Ulɋ7EEYY3b5؍v `$aG,crК L"ڱ$P ʽQC9DuIpi6Sv O6Sq yti|,*h2=uO`- { m :솊KUp*4*ݗq=eZI!SEuO#|a/#uBdP* Ȣ%8Z1os>N9$l-ކ34^ӜD% y-LRqajҰ| :W^sg{u/\tuD%t z-2ӷխ(^A{Vmqq ۲23=x-ާr}ʊ JQHb|w݆B''iګQ,I) kⷕk{´ݥAo$f@tOJד +$ET߇BT%oH5n>XuiIR}S8.* ~UF7;Ɲ֋/[jR84!!J SRL}o"9ڡ?6^/1~\cdPq!ûqX% ^[V\JJKmZudk;JjeCq7KҤ{HxxpDcAUdh@?_߁N1n٭J0>:֏C=g !AcP`kx{  rڋB<ÁB/9!R]m_tj,_obodf4-6 g:4 uϵv'lɤ"~V6g/l6y5Tt("wᎉu t``Z >IB.j@N@JR*Ad1XGxwi57DsMɬb@zz#Ap:HD"$(} 7_@URMou'PP@Ŀ0Z&{b\Y]KqsCԩSc;mN; }` I& `5i?}t[-*z׽a-z{I1Íkl-m޴/} %?xfz? /8,[*NLĽcض:)Q/Mg@ԩY8;qOC#_– gNpa1_}6=SoN;K;Vbc5'viA|zbXԶb`mآHɥs.THF$DpiqdO;$fEDd Bo=biuA;]/4-lF5HM9C#k*cQtRl6pO#`P#w5:i(RVuLd2s׸|V#=*UxwV62+7W0Ï;p*Dė`u]3l?㬿XdѠj< #PB~bT;3iZJp ;~("Eݎߜ5Jm]|ynRV"KHG5pc[9EhL't;@J67*蠁pYF߾8y%ݘK/%܈\pطWA&@Dl"G{[}{Rv"x=֒҄k"(+졅-i6*d;Kp4˯+kx2كCm܀[>#&?W|RW>0K M}HQ7kZ04{η6 Ryxw;, E>~w4Rn@l/gPd;AِpD`~8}hnQ|ҸKF׼")FX.:Vp?A2dezDJ X5y݁gm\Ñ=j?#-ؒ7qeইm#O w?-#snx1ݺuE]Do t4k :%!=g_ͷ>b^vd xc(rKg6.7gk"F GPM,t,K&<ҕ+Wc TEcmMvŽOLFiYiυѴ.t&OϘ~_B+/)Fzƛ=[_gWq±G]&@t8Vy;nP.2kF!V1Vow~-L¯yxty\fV'v,j-kRshO>Ҷqs߀ѰjFf4޸SaQTh_I{Ǔico̎nFyʃbˀۑ07﷧5vg=0`"x'x!*475vIQɆ< F7>^A7+ ] >6HalxX_nmfw,bpiٹdל6 2*J(t19 "(xy؝Jv #}aT|B>D>Wpj@r^ "xAwAM$XXe˷a^vK樮XkƘN8/cCz;)4 IXQÕy`#cv\m%*yGfw rG _ƀ}0-@QQѰcN܇A{xqYIeEYdKT_$V Q]CDI)w^-e߱_|!lhn!hfnhhI䛯C{iPoKXH?5~?h:JxS?1#N]L /45OG(A#E00$1o$nvOOǎ'O@ntph2(-- tvnA, Ps^5| ԉVv~G57pD1D;C>" vdzZe,;PݟNYkՕ"QTfgCڟ [cND]A4Ce2tمmQ˔[9dTpa:<9,AW^"S#]xq)i!R$ ,391v7y ̌G1V'}] ,*8> r 8ah?uALDM>*(7 Do:+Ӆ~N3c VbBTdfcgN3>K*g$FF9CPOJ#x:73ްAdQ0 cv"tw}")"'(..pbhf?=p>DW!.4߷]3vޝ ה7`@2?כ}#F=| 0pASOIBhD4$n1%.tPS bmڴiUoܻhs#' `іDt^4`$Eޤ}PP*")L "RQYYM`۶-y}Z'ͅܜla, h95Am тcٗR\\ G>أpmkbxaİ#=ο H:cV%rB&.SĜMf94fZvq' J5.D΁,8[أB~eXYQh.¼4Ĕ3o fRIt 30MUi!hTZN(Fpb,!D}V4ꞎ"s,#WA7Jmr U„jyYQ c,7&k]$6.nS=y('2!&^b@`qo -}G1=2\&9ٮ9i. LQ㸭@ͅ4Ü? @Y0ao VC%Ǐ)ŁAwO:.fF]S(P~Z^ ZbCL#n!j%l 04$%i^7N<3v 2YiA:Äimګ` $0߇ Xeeuy8wnK aSABѝ'fMQ\~]?6nNOOS0PLSnnL/p51O_滨:~.\;+<\+lXr9CZ[0{ҝpƠt P^iCZ3[K-b&8c sncTM9 LQiOX%(FquӭbC98t=xx;ϟa_77C `y]g[Cspnm Fuw\diwCg:0/ YYQ'y;EyD676ʷdKsjP> sp"M2#+K:%mt>NFQi 6uyG+=.: 1[ϧjY=oai A$`߶ p};o|Y24}v0 ϖlS7Q7^^Ŋ+sCn^Z!a\:D-&-Z=]99'Zhs5 *2= I&weI.Nj`PA.=aF \ Td&BHcg*ۑa>"E_K+Y?`jItZxL g!QZ*!ZĖ 9L^$e8zzB4.h}|A\}DFXdWX?&pIb2«fzCcG71is urɗvܜٟh|#GGIji^#k*쿨cK΁ʟ~C슟/|̙tQO"j맽g87׾m AJP];wND&0e?2hԧr.RyEjreLC4b "("07Aar.&e./67$I,<\Y ^i$D;oF(T*1 %H U,[͸e˖}8Y懦7exϑ(H̍A!NNH(Rlm@g""M^]̒Ez=q93q#z/m%['|j; D@owϭ3xdVaA\2& D{sBET>Zx7^OƒOB0Jk:r  `wJGU o`)dtgS%2n8vJ}5v@<{@΢j]K3Ok6!HQn: ,8uYϝ^B9,u@y`"t:"b?7S ~;htޕU!~;sXR(o>V3'RF(h=< rD@wBApxWn$z[J5<1m~-i`eM}sww/_۰8E͌=GJJ"=;'%="fw,])NE4*P#cd|RhYS[rW wTSFl1_2j8v80zU:)bK ueswNDz̈́^%,A^ЍnI 5.I]|p0^I% ^10^3+V]:iJÃ>x߇zCC.w)bZUuTSBiI"3j$ b8Ȉ 7qvaOA=Yy'QN07GakQhML] mAw)ՆorcbTBܷAM ?i0Hvf"nqhpꍓTn:sx$׳pT=ڨc*VW>Օ4 JB<_f`3i,Tc5 益c#;_#"š V݀ЌT횱^8} 2ONH{%a_ʎ_jQUM n2܉tdTR-l0y7N)uLV6%x{c2_ sr\,>u'v d05U8a{"_ɦYpqC@'wļ"(W}SU. ?~#㺩wr wD?G1Ғt[цR=9ǟ.`m\LVL\o2 b ;W➉Y M*D*DJKK8x1*ƷX]zS^>hTIZ#}ܸq>|XR7R*dnv9~E{,zWJ:πMpCw\wTfh{QGi!~l0Ć#E&Ɣƭ0SV5!_| 4 ԵNR!_%=f'{+ORE|i=ޝ@jl#fE ãEpXȇ=p?0Ϟrz;'+"XYȰl\"@?i6Љ4 o(vxpRJ- }]y<dH'm"^)KsDWangA`/V 26 }GeEftNIAycJ_~OY1'l3b0q3Sԣ橆CY՘q'JX]?Qd,Ɉp8/z0W.( ; ms M2`WtÝ8(/J>A?鏡aFT m+XAKyw Q| ^ XRZE* Z@:x|w(!醪3{ +`ΒX @sܢ/A`k2z;v?C3#ao~c尣{"yƌ $9X[[Hf)/be@VHgι$-$*4xQRYk}=jjӟs͵'mj|VL a<0r;Wl r@W_rv%%=M׽⢕um!蓕7\i-dm'0r8À_!ݧɍǟPVZlIπK[J aÓ3n4K F2ɟ+x4,=#! "i|ύO]{5| t N=t;䠓. oMCAdT!m"D1qo EJE4<8I`y3D $&2+X1:Eǡ~deH.BHK )1T>j@OH^;ns#͓Sm2kJb+[Q`\F0m3ʿxy2t?`L!3_`mM:sq(6G50 R@_-+ 'jk GN8 ,F)v&C%?A'_oO61(tG25A}xp)PD_2qOF=_$a m¾u¬x'ҽv09nvjo#[$BgG)#T׋/P(Oz1JT Q 3qX5+HfPM9 "眡er3̛u\uNAVu޳> W\MQ2Ӹ_SXX *3'^$wq6숤$E䤡 ;_wHʨ)+~YҠ !e|kSz@\USS}鬚%K(,HKCE4i)u\As1V?ü2&Bŝ9,4;SdcDa>5:voǫ# ph S_4=~~.>?om:&w:5ےA3WR4O'&W;.h!J]hN+l\L*W T4qQ8BؘqGR* #LƵD y=iU+C{,jԷ*<7#=D5yɈ m5xU1Got.'Wƫ05+E580sٿȈP=lƌhJVF9,C0Y!đ}<,Fi - {b }'+G!/Mdhj[&[.-^u3~9bk;sÈG+1d{\U\gf a r~DQP#ƏJl-_(IrBex |9L J} Z6N8smӷ9z~(.krz!!. ƒ D4( hx4 $qŷ^xk>}EIƛRZ^UrGp-U;w ZccOb,ΫqQI旔kncVVV_~-mZFf:"B=lɏϙ=;e&@ȳ-eBU?dd O_y)lmq /Wh_4EF_KXd6l,i) pQJ23۫4dFl$Pp5zu>}MQWwwsw^W3٦$7HtIFN*D xd'^_I]pko(z0W<-ENini)O\윷ǀ}w_ϨyUDC0ݘ2IOK7PLGĠY Fco,:cjnGtjS ? _j8<@XCwڳџ>{:҄mf DPpe!O46NْȪD87.@XHoG< JlVpG`T8R4mYJc2~] s!lAؤ&ϵYQ['ހxN ZTb-2k 5iaݎtu膆^|$Ҹ89U0\.;.GV:nTZ;ג's.#~}w$ؓhOY2cbZE_}:8qP/s -#y JtDiXNm4;GK|lM0֍0&)\kM6FC84[0է۾Cm=6zޠyJc'A (v!㌗Ij&PmÛKt/ܨBԁY0|/5eV6s#cQF]UprĺBui!3lyM^WbvAeF \9 POD[ W_2Νd*=0#=԰ZMIv'27K2ʷ/P;MB6aJXޜpJ?vvhh9hH$4[/ୟPddp`ELکY} ^<43UN<;Ľ9\\up*cT]@&'+SsWQL[bCLt0<ErBK)b:CHQ}{j]Z JU31p ~R-w*kҵ3.< ;y-~|vq57s/a%К@-03js"EED+{y+TO`B$ĜxƻW B@|u<#HKoB8LH2FcM! +ͅnE ]Ŀo]|^D8{%7nr9e? ݵUO{WٜzGnK} 2Y[ ڲSo:td* HM>9rNEUd[q;m1ᐥ&6I/̃doJH{;@il*xOV+ ^u-:aB>v0}H-q}KhKn{xr:S]k2@ס#:3 Z)3T*&65+$Eҩ|zUK ! TQW"`3eF6c5;ܬvm0éOJf- 뉊ʭ YkJJBp`k 6bC0c&/Zc52(_ީ() n=N^:V[ Bb,;WnI/%CҨn:0w Æ8kT:;(N}h Yؐ6jhNj.6\qȺzDX HHl`,xo-[}J4 dd * Z ^MGk4{0[ C ߛf*:uǡѣFkQ!DCe~֞MAꩅ ~|5{hIN6ǃg0 d,bH;VFLwYc}  ]O}'',X*rvgo}b~益F!N:1[DID>]vc-hI. H\x<U}rѭ$ÇD&x-3jÇ8jlf{q 􋬈:Jo;r&gn灑XnGѣZhtlظKH2KFN֊[L!3qYm6m419X]Qȟt"=q} i+ҀÆ3~RityX x#<] t&Q^kvn\$3^Ը5co{@mjN|=7Vt&[uʑEYXBf@ƺt|t HJR31IR[= ai* (" @M8%Q|0=I-'OceIN9$\7j6ӱ"(6a!m*f9Aj8*i(f"-3DŌ:˜$?hWm«/cF8q] m Ey qj.DsV^lևrE0^LSVU:) Q7Ӎ4PpЃp)' /vl &c^KpG6Dxbڀ#A}*1rLc *!PV\zz}t8 uc, _Ɲy^vsU,<1`Ċ/<(NB /ꥶ>x`ϧ'=,Nd)OIߺ½PāPV^xխ)kVʠSR1Ⱝ}fDb;SG=V60Rs=rjbO6>fKlMjMנ"%nʴ;R٧z|JkwLU|ѯW?Kiia[+| w~՚G%&w;H\uŵ)q_ IDAT>\m N&@޽qy,/ 2Mvl^s7%@( a[R/ةh"\7YۭQ#33q<~i{97vdYy.ai '!7ۋgzM~&T\ꟕ qGcF [#"AUowMXo/O?-Nr @%<li#{e9-5x~ZVAjZ:2(FphQzm u){Ih |1<7S:|sB#&u&W‘ze~(Ə?.d)-ádtm2Ӱ`S%-OM=XJu;9^{W0o'6I+`e1WA` l$s`)-ˎSA'ka$~V&fL̼YT4mXʍK xﱬ$'bbE`TvMe'.:wEgwSzoaRV19N۶S&qpe_`7SèA c(Bg䖀Onee^D7#/,hxmzm+"/`, lմSHS\0hvL( c ZE105s<# . %"ͩ#-i7uIȰHwpہ4QiFKQ=x^bcyMlZfv%6XuN6`(I..Yʦѽ6dh#1hD@x߫M$̴RDBD4Af}Xq 2u5e$sY%9;M"A&kQ}F= mw{gؔXe_f=":=[kic#Uf@"]e/W2LbD?a{uEEaɏvi$wf̜m ت3t}pe7 .ǓOlGo =#7xhrKA^aRk;}uj;()vv,Ju%ptb@׋H(u7`й8X6ȭNy~Xc?RS|K@]wM@do<"QNaժц/uy<[Fv +Z]1;3 ʿpwēSC'7yg3*ctipw_zn5S#XcK6gtpdLzB%A4ն}#vDEYgۋE,N@bb&/du ^ `ŌN3*YnVb(PUd <*9DqARn1FVr< @d mî#eCV 2\VK, UdI,L&g%4wZP #3 M+C`k33$˒ bէ0eV4" T (BZ !MF4f Vi5#:1G}+NyTRLKלz&1#ֆq### yڥ3~{h:9 v;\=`RD?~njz~ޱoM e.zf~f)./D%u֩})@zB;xĤ:d0w "Fy8%tav\}ݭFuMBYxчY1k o;=A[YTF܏v3-rb+~!ā`rwC`Я/<to许Ͽ*֭h:f8UѬB̟?5=+=p/eG4ݰ37=vMbZhb"ܓҚYFcQ|WPURd"x$43\m\p g"y3Q%oS Hel~[{֌6>1;+/$EqNi7 ]0 O=㜦#&J{~f-c><H2ʢiq~ƪNT(NDLQ>lHT)n"+C!UJ<vG2 , N |r1OAh-c|9OQu:YpR%T dFQf6υ6PnwpCYF|ce +t? yroͿ *gBŭB48ܩIެ]X{}sʏ^y"XdgXGn,9 f t5 =7D71g3(iZN!AmI9X[?& B6²QQNoB♡mmr,̀GQM3tpw3O9y`ݼi<[ajLrNtGF<<Iδhɬ1lmˡ@ʪisʥv ,5 v81p:KkTf˼%mgD)n1f2C[Dhu}j'e1s6+,C68dȈa<1)vo]߹&@P(6<_{s#`qE1f|Gm튆cE-c[`M~"!p]xp]蜟 t,ZN~v}^{ rrrR9A(DkC1쿡cK@w^ZZϼ26 Uۣđz#n'V)QPRd& tv5_V0fժUԝߝ=`6O * Q]GX1sye{Lڀ~ ,Z\"`hMZENxpPd#ey5_B=|,ܼݬu`n )8:P ,LpBiNh1%)$'“eFpLBڙp$=F EM/밷ђ"c 6x6/| mPx̌@(H%tdJ:$=s蜙yK}p+et(rj}ÊqޮW1gf38<@p\,*bjOX8ϒeͷcJ^)-.Ctٌlpl⍾t9"BY-]ǿ.__?_P>YX\\㏫c{76߾>ȓ,&pР뮉) u%VC&N e;kMu XNQt3W)i;K"y{Xdƫ?%nZdd 8rPpݕGRU w6l-1|{ǖ0t@y l+cXԳj7f}'ր --9hPkM_R$̙rNƛ7&Sy)0yUсJEgsqpU\ T'{:ч/?dָ̝#1Xxwn lnX{ r1 .|m<'hU3x87_{*dהٶ Hj^3?RP̀k<ML^T N\gĄkhxDžL{.4? a8 E*}W\q^.ab |<ƆOʗ{hqs@<,|B"uRڽ`c/|r?%4~|D֭݀[>} ủBqx:g>TF9xuڻ̔Η#G,4,簼mar.Y_Y_:%Fu}ߧ'vRwUBB IcA]׶모`J&EPQ{Y]) wғ-ߙ7y)ˢ-3gΜp 7lI"Lb̆AAE6KC9xd-'1 b䥗g췤raC։S% G]t\[ʕkbb$6X0I2!H8]uUu뿁_pYABGnk<=>CMy^7Nۈc^,AVB?`Mq 3DS߅xDDגbO-kxi"Jig&T3z;tqAauѰȫG.n #dž> ۰fZرrMХ?&k$3U0*E{ {BN*+ Gu*`D6F:z_Ԝx 8s5$[ V/!5]Jd?>+u䑽qW&KLիN2 /t⧨v_~&x<^TUyP\R כ4Ɣ2>č6U$rznH%ڱuk3O0[TUCYQx'N;AN=_L‹`HL|3~_,e4N,Z K~va;*+&<(r{X) l1rQEWx*Yޕxnl~n^hpf<+lR裧 t+K׊&:-9 J*Ja10)cڪFGQ<D :T(8)eXY?d&tnj( e~O(طvbn.~pڲA,uJgj,їfʾVx})s5ɣ4Wh0>8@Ӂ̬Lsvh׶ Z΅B( Βnng_z-Y:YRp%2;xOUL4bu7q$zVkV[%L9_}ߓ8қ<6F*''w Z~KY ijS'B!jH3`tpM7 ͎rngߖ" ||gXPl:~*B2fNnk$1Ya\'q߃trBEz'y_߯|/8T,dۯi3c0 +-FȪt{<1QYt r·[mY,I+X؉w~^pȇOQJ0ʂD?W5$ELr,PENv&fLl?+ae13.D aKЈ* k`349pkܻ}}3\3*"q9vFk]jm:h o9g7Zdb +cϦ?e(--CIi~fؓA^Cll7ޚ 9Q)3uej5l™@^^k"';T(/76 v9l6Չzp:~ck^xi.hmq>w?Daa1~JSozEr'`J%,r WhOZΈnvf6(5rM۟ѧ_6+as:su1&c'a] s=$e#wiV _ )>t=#G5z Əڥm'f'Fr&9V lN{t1Ghg:3@M[aZ%2TX'nu%E9ms`ϨQT,Ʋۙoy ܌$ L>7TìGљ0t /ΘҜQR}dzŠ 3/^dfVͰ:/gsC8V%XXX)NGly߭i}Rc!3'·ȥPCx-_WdRd^QtE(.' +2Œy=nx2LgGP@FtVrȠ&$ ID"x}_ g *7H&3wԒD?L?s   gXgyHּ>ɳvF̞77la^ ;uzExNqWc?&PzSFuP>z-~__F AR!a]T/C-- L~z|0kGowi1iX~&>$f{__;ÖsA˝lt^5eUiNoA~]߃'NT?÷s;nGVV+(79J:MVj.QO~/9[zQtqâFUx??hXO?آc)fI ;?3&C QD*#-u~/XE2:z=8W U@f+;L=zģ`^Kc>ٰ ڭPjL|Xq`-$*t{PgL"y9 ]|w?O%JH!9z-&e;[v{0s^Qf0lyDL\"$Pw?bXt9Vee\q<5cMkP'Bȝj5.oC8;ʫ7j*} Gc/|qvl^uuh'A(߅SN::F?tAׇS ENvvN,9k"k^-K"v CH].|>";pb.ГR%v{0ٙXn^/aoMi(1rvVЩcWbu{ݣ6 2%1:"8K7Ქ{KZZ#ѯK]1 HTI# l(t愇ܑe}c!+i8%|#]Wݎkc=uoOѣq}N:*1XiN'nV9lNªBҲ YN針'TDf8lh[Кb&.FH)#~UM۰rRx}><-$V y9֭3Ns:uK 3mDOPK2mQZ۬WĢĂ9ggtի F!b3_<}ĎIJi4颩/?l+IfkACvu RVU*59M-,cR9ROAT>&sry㍽l2!Hz踈w^_vE'ŢM [J,[BkZ`琒KUH *c G&xj+)ô~]đD[H)Eq3+Z $AΝ{+1LI*;r3:wGnk"B{Ui TCw*ǓΈAGڶa< ceID( +2ʋJjZ̙{ 9>HI9 Q=@/p# 1_v8ް^aExB#f?nީd29R:v.k˳|70-sgrx3ϼj~,Ąf]D#r8{Lı R)*C#0oH.S+@Z꺛-ؗ/Zb*ype%5Z[I}d<l gC&X75JD6͏륱9Jp?/]t G-}X[k51]xa!hs`/R8`zZ?EdO>\z-tMpKi񌸡_,J4Ċ+jl;9)#lCGc4wŲe˱z#DͿUPpI^۱>fD"i&E.v&#Er4J *HomTTTUL_H[RjCU _v=~/ g| W۶mq!U:wcP߆3cg;wړt!s[!Uz 982CNdPT-峯ҥ+ 2E@p[X9VZ;os߹s/ƌ{nO2pA r5&=5=Xca?y=C7ggnz pkb}%wW:IVXMX! eqvbV8%Qb+aD( Wg&g_ EYf#o ht%̈́l}SHVj٨l5`t*%KlnQPidK+qAp^=9O8(LDFIIIulzAދhOu1-SfF t7_(}0ݘ*>ވ_, 'DO"]G4!)J1w fŮ W^0bnn WMbHLeUعc+uyiyd0Z>t2g\P>thh 62е .JkG0%UK֍ !Êm'o,tH.fѩN:~ ޡC\wu)V9ac(/EsE(-'(2g!3+m[VN݇m.~Ksv,?]`6ѣF]MX +L?VM;WI԰aum'FS47~צ[1jSz 3j!}~j-|z-t;L^?蕛IjRԒ*=+]YM杉ݫeWyQ\Z2VT`0Ey !ƄK'?0\N'r:)DLtG'I5R/.jsACZ {ʍ"T#=^S#g5 (m9*S#} 3 { HY/θ/oޜ \MN0Y6bAA wN"䀈)#~DY!UHhLKc,i + 0mY & +_W]j%\ $PS -(㏕buNTTV1/WV%8܂=aqŀP NJ*̐㜾C(V}F)XfÄʣ2Rc=_C7jG$$pGsb %Mk7p=CNGAn+ޗ@^Yy5*PqD 7CߙХS{IK&cB-r***ݵY;Mw5 0K2+s⍷>`ȋ"V;o3ށ6.yv1 Sp;qTmuI3јWDJɸcBTYQhۘFLϭQiEd@5_@Fc>sc6QQU7cwnx p| ]ETII6zt텼[LtP+AU 2~4Hh\Hv3%J ,&#=훔#=Ns2ϵru{48e?N*L gu* 2O߯ t: !@\Ű;aajf["☾t&*XKoXM @n+3Uy]9h2 ="P.F ٳsm}r!'گ ^H ;(Ec˶3{>6nϳ&>G1;@CvCY`6gON<@ꞁuiaRZX!3vW_๷~BPPk I Dr=v&8K[؉Q)yqkzYÜ|Wo5Æ>1n<6b"K#[cv)ݙ6 \xeX7(k:sӝ4cJD7nڊ'E?Rm/s.PpYJ>y~tH1^'k{ 1ƑBd޷n`qEd`u /~#-H M$AB- rѫkO/‡ @*PCj7̋o&/3'iv8O40#FFz5t#~7,8hVtWj/_9ŢrlBE.m#+3&=ܲuFPVF":Uko'D;ڭ=+ "#|))>*E8z4eʪʰv:l޳Pe E:5.h6E艠RA L*sVM,.%`sRɦ 廛̰bP_dTa-C,06[/ij8TtE2)IH;\JEu:tn7R8=CaE}Ts`&,q\ZO턋N+f7,P+f ߋXWΜdi|#9Ca֌ܡ︹cs/CH˃RY?.[d2a@c 7w)F36ޙ0DEfC9)hFpfN3>_?G'c DHfے {u>}?׉sp,N'nV75Y@!l EbTTz5S"3͎N$ 57߻F<@PwmtP*3S&(:5@w<`T<*|,R)ťޡH2~Huy,#U4_9]) +#=VPs2;gQD0fel7s!,@LJ܆fg?R'FeLPw & v2u",߂# a2z,&6zI[iCx5ZV.lۻ U*ϤMjU)jվ6+@g5r{ %f4~1C$ݻz#exS/{c x]1%DkEЇ@2P#wBuᣰ,c?+DdSG~SF`TaóNIy wl]!X?/퍆Q'\u8tP M9AU|Y,[v >3'Fsf!4 g-R! _s+r"5d =?㺁"f};vؐ3in׻c `i x'g@ & VaV(U{ K9DUW>9?s8Qc `tt{ܼɠ*/Ŀy935:[W_s}8Jİn* >X$Y4'_|=iԼN4W1Lg.yxS}Gfj6|6SA4`?㎇)EQnM* \>`1ǰ@EQVU՛bm~f&?qepGpJM0,aҘ.)z}g`_3驅+Ls@b^^>JPXZXvY^%1ETX,Y X A6<492(ںxjgmIޡ\eCf9ۓc؎mBg,]C\{,ssݫQQQhäaB R%B FHc BӬR ; j-$>:^k;ĞGlqԑp٥SHs) Jwջ TFZYBiY܅U+Wc۶GWZo$@ wrᄏ _HayXw"U OZ w@=/|1]P-ݫy|Ww5o;ud vD="ө&rJr{Y'7/U9) 9ڂ?7eu8I&}gIٯ.jՌc]6Uwՠ{F/y[cL2%e ge80sԔW\US0mkyoQ*N>OWԹH<ۭ,ȍ(1pZ A|5j8ll"W/ &T4^ҭTT{]XfvFe:7FL<SyY$4 _$W*BfܡcDztsx?*ݕ}P7(&UW4cޟ{#r-IW0 [tB7o-Y d]WAA,ly|ģGDv~ʸڊ>gcB .͑ak;z}j\ wPH![J>NaP8 oM[nnxsNSXf~/sTx@MW6+rrЩs~j_uToHIg}Z;%f}+wگD(UJJJ~fl޲{Cii9\ jJ0HH+Mf4kq&yMq=0V$Jz饅xXc*'ޡCNr~{|vLxq3xXzǧղS8#L6l\r s\xE:ɧS<%@Ƽ?oǭ Rkd6t;Nc!|JbN]|#fODJw̨M8WOdggj?,܈ʕ**.ߵL#0.W̘V:f,8Sp7D41(+t.-},Z#<xiZ_1|D]qimߺvtlu)7<* 38khEA6sLͨ _/ТDx jW73l<*\Uرg6݌V ⬊F}->j3k.R)+ IDAT2j} M`]ۇPxFc?@jUL0x6ۂuZKwvuRg2(2rU~<^7/ 7x^con:,2NN#Fb>e|z&3r,^@7|"D BˡFZG~ EX+o5{\߯ўF?~nz[{bϞBTWyi389]Ԥ&i 8uޓ㒜ctlScPW_UW1e]űvR7$ x᝟P7{'8ry˯D|g>}pi t9*<7@@BFv+V΃Dg.+ǟ9z{QRR JX,Z,쿹@eVJƐMW_GRSu]|\y%{0h ѤFirL*J˩Vs5 fƳS!xteر}ƍ39u'=UׅM1KzfsN)1˜bvkشa堨C奩朱z'VNu V+U>dMP壿c?7=C}%(s#$Vaҟh4KN$DߒXnC;SB DDsǹ#!1MQ unlHȄbleQ7F`%k(WGT3_ TUr ;M_Q5z%v<Gq{?P7F|^zߜ쌊;ܝ 9K=^/ tMXB׆94߁5N`â *}#Jze%`@וAD ;7RZI8v9BvvZeg"7'yOvlX'[ϯc\ uExv./*zP^Vb(/#ûrqCD0щx{r}  *8g5bI0ڭ`۶j{tfTX#Mw|p+/4a:;Qs勧0H#!xuR & =uWN\'_}gz:JkN'&yr^@w\c9(**J%H2ЪU+FѡCX< u?.;MUxcfz2R@t89x<\|>سCQdd8HO#ƣV0 5ΆR HΛN}5Ąg8Vݟ*Tf|7w7S %xnR@j+3#ӟɢgLUF0%"0AD=[cƭ( )T#;SQ,C PeA#$vl]"}3}5F F|"LIQnE QUTgʏ"htFna5G؁QBiP`m_:tO=; c{JR B9de+M=] }o<fR}lD>bx%h<5~ Ʈi:bQC™SDnn.BV/H:k04ږ"  bcoGAA~ͯ54 ?;[R䠌*\z٥8##"!eu)?Uwǜ?`~=? M\ڷo=[б=rrZ!du ø{s>؍޽܀\!Hz7\Xdz챽ÃY_&=<~_9xzLƌn]:bksλ;4̚9T e!HRk|їzZv@!}Lu|_s0m{J h4vW31C*\ě6)oЋ W9% snt Effd 5P ZTIޘ9H T MC *,_1WX49TPeUCuR|OEJnJ}eP PȲTO/ ,|ђ'/[j}JOܸgFM|/xZt׉à q 44D-4zDGyܷgG}M=(Bcrq.y# N{aشyw佸fE{iU%3-ڳI4`1NB $l0,ff1ȣlfc?¾dE5=hAYfQNB#h5+1C m0P;`פrxB9dQz{񳒕c35&¿ڃ)UMT *&b[<5pʲ*陭`AupkDS7#\FOjnTs`h´yJjvbKUNgޕ2-\ɩ3<gyFF{ֹv5&#.~׍_ϫ=X XKoK7EdO-1"I]Ʒ9i~Jf(R7ܶ(*"UàP)c| D^?3= j\ *nڻ wmaи.F8 sŚ$@h043-s:heb :'S釷ʇ )[b^D䥾TZ|#Hj@jF &!]>n=%׊9bp1`W5"s֭ވ@sǔƘu[ ÷@XO=$lٸW_nҬvdŊ;"Iqk+>rH^0ЅZԬCV[}/c.y>8OP!fܛ1gl_[N9jc n?4`o;`^{Oǟ~oO_&<x̘"T2\tzW0@EIyV1ͺ hJa{4`A@˱Z 9E+fֲ%,771mOa9oߞ4wD. :r`zdE' \s5 mpАlV ]:{cz'˩AY+_'3$hTݎH>t~.7ti,S It{x('¤hU f֛s9=i^ ~ĬWf\^:{RLzEIӰrZLgkm;8]5ژ!E^w~^/o9Hߓ L!Eh` ހq!]Cñ:ߩc~&5n`i4ZMxHٙG-= " ƨĺ\3|c!7FaWU%KQF' (2 ɬ:Bq8=G 7 I<R BprJ_u Xi]&ICN:jj=UxOh3\ҞyEAcPk~F?Fǎ+#$G޽4<뎰?4W؉%tڭ7] v 2 ^Cj6Ǝ-$"46lqSY\szu--,e`zQ5QמyC3Zr#'/N"-b]6||j_rkET Z}n]/meYdL -Ad!?;f!i,G(K{ ư`y^SbO1`F~̓EN:˫AN{ظy[-܂DQ:wltHM՘ qxXvιAr:S o3R8MAoJ |o 50xm;ĸJFNr&]1Q 3PD W\R  wa,)Fǥ쯧 .M[tqs3N@F"asZC¹\Q(#j̓2H5$ Q ^wR^J5ZzfNݛvQ{R_fSK ]e U v9M0}w w0w>ݦ Wِ1`W?sUUc/+QEYR\8Aҗl4ҮD`FJ@9 j?@:揆$v q'd ѐI˼.t[3rㄵg,zMc'7d `;u(kr <IFcRe-`'@.LQ"2Pg%Z)ʤWab("r9"RJ@'\<'|W J!T`2Y92ҭ22 VhӦo&t$9rK+678ylWj{\x)J=dF6xӐ@~8R n}nL%KA.B6I}U4)ȁ >)4x#`q ^֭^S .FTgLCPL4平pf2ʹ=Ilܴ+J5 GÇ )xa+Il*lq$_kXn&NzIc6*>pĴ%'_J6Wce@_gv38\עiSkJP=Wذk';SN  {(*Y.ȂA7)#9PS)68J +!Tm.7GodG\PiNyR$f+Pg?45 >j3\\ 74C 9i kׄ71PY ƓtXDJ+Wŕv tJ珅(@W) I(mVװޞkX2qd̤a`U/2OAp]<y(wr'A$SEUKEV%DzPC ["SS8d Af |1sOҪXEx$ U ɂJId*(m5c!YM|8@[83;u59`$L}mWpNjr<'Gw?j/v7Aۥ89{݄t2(`D dj~D[z,`Oa}٫WDu+Sn^1<ʑƠ+f,灮Ì,l6+}Z*RMݷcm~^Y a MDƤgªDiC'ӰeV]]Iai/;l݇(>x(YZ#D4 JPĘf_m Z9q'C(1bS#$r{"J)N:fMY "[ M0` 9Ō 9)r^f(<]/GnshDD)Z0?k:g'ey7^Iά |OTE}{ QCZvsNݤGO 9^A?61n1~GKLM"1}p'65 }ǡu)>lW`nM L(K0-M@ $@T/ˣ,ɳ'󦽽QeT˾/e<F@J/<.Q. kpՆ$4+N;3 rōGk rdp15}nou"xpt&/ n3UڃeKV6 􌪕zw6c:$iy}DkhR4|>7˓AS-аˎD̘Hz٤mg oX ~i\"$`[[Ued ^Sh"#DD)=Z99wu?,sЄjMpw*Qɋ(YV.6N7æ~Z7X IDATی (aQP(nPKPV@bu05&3SLL!Swlq҅|+X:r.cmUݺu5\:fTLکwؘ. Ckoy7< 5q 7MWݗE,Zg /1u1 ͉9t3^Dz+p44l^R^Zci5Ԍt'fN{7qtZ9Hdd ]SSgF @<8]׍nޫY~pQż:13v_g{u4|WB뼓uc655>m Qfؿ_< `KH˴–f,W86p3mVBX"A%dA1rV]dK&zO<\/ Y;)#\XR{jFo<vF6G)BDȻ1_M)J˱uV޹G?)>oa tG*wփTsN1Wc¬pβ7Z,zUc@ZXDAP@_}M ݎ Bs,4vͰ[߫f~2iE\q33ηT 2#>t^ǏL`& _*mLyZ/Ĭ%ObԼwd˱:tTS 8eV-5bO{oD R9y"6Sᖃa*HUhQsIر_w~H)F@d=wϵ9$pH/fk|iL}Ѯ] t)1=s0(`D;v+fK݄NڰRld0Ylc|ؾ}'^| EF! z` LDޭ۶c㓢ed8⴩Lťe|:A8dMyw8\tFaobʳ3c69Su4%s校`u'Pp'V}*ٕ7g;/aކ8y_u.ѢfAZs(o;l@ P pcLc]l5rQX:Ab[,tHܭfQtAR-ȎL:=Œ*8zz%]dضe;6xwS+X=õ "~1?F{BzRO +fӼ?6Y{蟢2ג ]zq.>+>li?E Kȸ^S>U3nJkE $d: 25 jp2F<6΀%'ZHEP~OxX# FQqTm K5й9ʪ%=+q XEf,$\6hBݘ95<ߖ=ˈPG{1S7#56̢ `wXS`r^u뷰|HPmł~?d5a`Etj_b"N|"EKL<{n]:aGx"jZL|rZUt2FY`m3je魚m]ǝMe6?~^{="AL̈́߈Ϡ<8APQTsy+W\zu FxWKXe{ 'jSi8DjD!wD/FϔxEeT>#".dD{RUF6) ǃJ\(/@YY9ceHwAj<Ō) m&A@z =eooͦV͂9mm䎜z(/@#A!S[0A=yzYzi]mBV}oH@i zG8Z] "W`Q)eD1wT`;^X%??9JmYTQį93^NJAd6q6M$6͞z=Ĕb%[.Wo?cEv:o.; p1u8y`3N0/c!RxiXk(`УT?3"ިݤ 7`{Gz*h58 ]Nw#+4F@PgEQ1©2|[|Z;Dz2 JjXYtm UDF.r 0 pgk< yAU L)alҚVntB(xyŸk7U4=Q)/.J?c,;5&PQR¸gC6wqB[\zN鱎oѮhLgу{q^ ?[nEe߈U -*rU @MM!hhC p^,UE$3k2kʘ*{w_G)6\OIqx6ڀ 39P=:LLb*>9Y_w܁ܘAfN+' AwN(wa)YXȾqDH]QGŜ Ng;Mn|؝3ڵɅ0MsQVF"λ;\,@{\T3gQ2ka1Lfh;|=xP1 =1*<1Yl޼5j 2TB8,7xr=ˋ~*ymMxahOGhqnT~yy-9îo'gYP*&B**,ׄGé7PH\l4 mviIC:x^y+нSo-O$ndL4s.ݙy2Kk hqK:q &~-A Y JMo;ΊWz fC*k[4-&jlaŊ[b7-`^EAA).ma{~ޙݷ˾}BGݙ;NHJW=Ǡўd|VbHu@ßN?C-)і5ųAf.pn 2~~03z7AJ.=$IYBaE9^3qVl%J/@)_pR]SDh#5#WZݝev ]3gw),xl=5 WLC-Rb(!@V j e51Lq?:@ Ża*v; \(NJd2nr&t 23tq9':=KY9CRʻ\4U 7[E4iIHC ;͟"3?fbDsN#Q I? E][7^d#\@KWqE-jwGϐ{LA6.Td `K :&l\(\5zrxH7fK!=﷫QTPP.D#cE,pF[|9ZVS3K[(폪&$G>AeN?G a$u]4noXG5/zOk{1@b\PARրV4Ucc<~I =j&Tcmb.I(Ețs=nHs/W_c_}n2A~)B-hF^-:#46U!Da3*#0l3ltcM`YlɇҹP3 gi~/x*(,:2=ZYU儾vɧqz. t.3Ze:BEw9sfT*-(daB8hN'@.*{u󰁪ĄٳgqmWuO[>sQŅ:#bY3i]Vi-^<Կ 0}g>jMz&cPSN<G57oe㋝|Q8W73Ͻ|tƖ #> b3Ͽ7l6S-lz$9`N?uX.u7uk h YԷe?>iprs-ue+@RܻGBYCrʠ}{>NYO&#m>G Thcm!\W!a#gc0, X."R|.۶BY]c^ÐE1.T z͐aDlCE[յPfy4Ð#cMB9ȦZS8RY<F_a+` \;N]t $!¤P9B*ҹ|V_,ikrvR,/cH iUx-u,m!!)g3={=YB270_]?r8Xh}׮>[}iByZypbDrMSh(++Diqjg݃x! .Bk+P3'rUU矏X*DCr@xz/"RR)bvprƟF5kᚹwAisZBL^}}ydx?')|p_O?CVwqxD$>w;ozkaѸI9EIW+]BŧpR?e:@8!d"lfhA8 uS$) \A<Eo㥁 ~A4/"Q+z" n(xkPF|չ5}~2t0 UI-y"򦎵er"I'2w[;N &{*ozr#};R}nt0B`8x4}쓨J{#TH[+^bրݞM;P<CX-٪ } ABt~vOOV!̝9NÉB9rw@ 2fAsC2HȧPEWxЭ4YЯ^QxC;g?|=$IDs/y _o Ѝ_k=mLHfEEr;!WD~_L\ĉq!sv'g!Ep:ܜXl|PLoS_zFK)7tJ pm OqˍWc=K+',7͛V;_<߽6nc= 0$;6&UtVQ73gj݃CJsakiscϱ%'P7yjMW5 H8/SVS+Ih ̐Q.D+.~"R^ǘ7x2NrpȎvK3 Dt _$P$td8ޏ?ˍ v~Zk> »Bk*>}Z]T)9JAw-#B xTRз:: },M$gۥ퇒l2t Hrj4e@ I}3Py+6$xr@%uJ)a9Y4nT˄W(RMDj/[D7LV'<.IBYR̕frtqjZug)5sTrq:IS-C ֵqؐ"#I :y(qEy} [O|zk٥c E8IA{>4hh !ڄɰ+xuc]2qB^\T^[W}Ioߏ ANҕݥÁ )#LA |HÐdvT]CЗ;~m J=ELrw.,ܓ4js9S^D75-ν#%5~ 2CV$pa6L=s1ynfHH& *-Euv6Tn'$;L8#~ C8)GDew$47,Xlv3ӏS.eɃ^Եc?RO/aa7~gL:4"]ZG4u~6|e̙CFYi1 h%<>y;a3 #<cƌѨ'H/[XGIQQ>6?Ww5k:9476ʫ_4uqw 箈ǢX0rצSa7VV{9kwM ^itTѬ3cFB*[vb 2 =XHա| HP `HN)\ fI>i - TnǯPmzIux:-qYX`gg6nT$r V9[5"0W~.Tp“1݉l$κ.CC){s"'H  _}X\ 0IџϚEKJE=n. W]70۱zm%ڒ>~/sr.s0Nv`D#\rOy^Z|JmS5 IDATth)'P.bz+ij0$cf,Gd6$Ns"vuX3?+.O?+-V"/ȣ4 T<6`Y#u\}M\YNF*))Yg#QaЦȅaCݫNT`<b5Kɽ³1mݱvz6c=RI Ih 5C0x*a0pU'$F%p2O={ז0-$d.R}9RIL%% kZjQno2\N{80KQX:d[͕M ţdS $5GD 2z!ZF"`3Zޤxfh yGTs:yRLJYy@V|2a٢cgco~;sl!\`Yk <կ O٭Zfh'\Gey(83H׽,OP_e4lDt8Unh@ LL9Rd5鄈W?>t {/t`Z/*304Qq' QRZDtEYdI74%@lȀ"ᕢrTdx>]0Gb:;B᳂/ha`M )#j[#56կsX^Ǝ/Bwvt_C}IgBvn& 4ntLQBWlNoAm"JUqH=EBN v9lyhŮHXsy one}ʔ8CFpٍBMnn JQP@ Ǻeز W^3PO68T6l# +&Y H!'oY1èX瞑qLfKy=LyGOŤyDnsgp;y\xJy4숤! g2EIV1LIJZ;-6DmrQSuXu}z<RgOՠLR;ztQ'+ yP3 /ĆVhi)R?Ym;Ӷ8 Ƀۣ# Dj~,Nw2aۯ|7uh07g"M*LU@2$!g1rcCy5R߹ȀGn¿B e6ᙈ[ āj:,64lm=8IQN-˅|ɀLCNj/taPK<=%faưj쀵ϣC5kRƉwW0<&,ivu>ְM1C{5IhjhEIL81ivo-ºy/L2P\T<(mҔ)dz0tj2mM#*8"["qk0F{l0`inIx pqTCi-NAnO$}6t-*DESDCv+Kt~}ȶ 1:#{NK"rB 5[svy?GU:;Dx\.ya]UEI-UoشF-%<+\ѣGcΜ9(..ͳ&B) ŅyiҤaG>7,B]NGV=eIp.Th-.뫰olM̙3yt^3֮s{N},\.'rp9BJD9“NK//$zFߑaPc@B*юs =(υI`P;}͵U?FdӇd9x> M5B ;py+ 8pxG3v~AE0)?x](qgԨQS=~`́?4ա`=1dDdJՖ*|Uھw!8ꨣPTTdk&NLщw +[<"߭Xz P$eZѣx4c"=[й,AIa>\NT}"紎H[k_4p} rLD8Էmdd> |)ull\*yMsOO㨗32/-Yx,$cP}r3p@Mא:pm)ipVS KCZ-H- h_U^y{Y'@ƨ~{<yC;ʗY`[Qlt(yw]B˪/PCAnZVh|aP$s3R_PzGI0@ lp[_݀xJTNF}GT%6JU\Ȟq%`N0@IoCGWu>kg% 2uC~ pՍL#Y9eM xşaÆM:-ZUgQ`.pg;=Q> CMU>x)_nGrL6 {rrr코ShƊ0Is=כ|ȑ<} :"Wg3BAa.rP̈xpZC'<xٓOoO:GyOMNBέi@Sݷ~?ivh pF  ioz G&a3«9`U*!ig`1g@ULhMZXDٓKׁ2Z* PU|Gi$e »|J[lV@+0M{Ey(ރS>̬wˋՠa!\ Öoдnh0H%?Vɀ4mbs:"^@<ܴ7ߵ뿋LE ݾY~*'K3jnYșr+\$KskD,bD\<"E2r]i3@9u! x9ܛIoʕohiEK0$04I ʎ/.(|"`P#➎ca awsF`M`;ʏacA]-`8Kk9((4u\t׋e2g_}b"!Syr<}p-s'۰W,P!wq۬qUU0k,PD5q.tDP91@}1B? =!j3^C~eE( aBhby_¶ J3箛QXc6"B7m7!</OhYs9"N#G miߊ29t^^^|E ;EFמ: ek Zw[]BF&COo(F8 Wu 24#}щˬbF.<^ %w4;2 ??Or`6<4n} y$(#P\I%̙MյfQ|ŃRMʕ?ɠJ9獸{jͪ =}))LF`81 =1g 楗}$UK,D$*~3L,: /Q[Uk!ۏuO{rj˗{g`0uw70i$HnPss8z;eZ#Z\-#Ag44`ku,x~*5i 87GK?M)*Q={>,X@`kfM{"Ҽܖ)GO=9-NOm&R*Jen?~8ll"BD [a:^Rl`@3YEɂp*Cͨ 5۶d׀3Ȳ裏Iᅬ%Kv#b-zԨQ8"l(]:>rdbRnwء2ts˰-^}qwO$'|FOZ5uMhhh5 4>ZZZ K/s }!C.gzR "FeKɑ<ۖ[-@Q9@a*2yʐPP5A>f_+)? IDܩ#BZ-7.AR#P>̺Li\v$tAeJ 7i$ǮceSH6|W5 !ed8qV!]mT4 1KK/j%^NW\ug){ ~ ={=&Tr(ƧƆno1aQ"Lr'?fwdQDJ""3lB8H:W,lvFpo]Һ%4ix.h>T3 NYMw;?'u) -[CJdH, ޠ+P<$JnO7a' J.. 8:x Lb9m*å7퇒aA#eRt*p` HJscd98hE^$mE?,?O}&(R([tOg"^G^5k^I_gyX : HC8dq@(7p [b_C/U 9B%ޱHC8bs/!p॒"T  ~(>Bg{Ae~ AHw$+mӈ!{83 FǍO?pzg+tysLT/) |2TrP: <Fyܓ&Mĉ@ezkЙPUU _mgESr3o}z׾8 ܫۢO4<Ih/+9lzvAUI&uqܚkhjim34ꫯl/l vp5"ӖnB%,d zԴEe)m{aY+9Ia0"V Byn\>NفC5 P9"t~oۂ-#y#vWWAɠձ -{'+Sj жwn!~}Ȱ%3Yu5lbe J4G_l}'lBo,1kE[P6r? ݿmPPЩ[wbIU"K_G!;Kmv',0<RHt,V 7_#ܐ;6pǹé+iߦoMBTQYWEml]V: ?zrna!B+ )q.BWϨVZD-'̀f ] M sGFgߜϿ~GdAB_n\UW(Q_q{a}Aeؼ ^o^K" 屃'TkzBb|8gy_zi!V^vZ maa!N9xe9rd1OX'={y硠 ǚfrstfdĶ6k GԊ6mv:y_GؑYhdHx筗oٲ2ak\;W~)\, >n-!e8E/ s}Mhl /P8l7s0hz|:ӣΒ,WakjvȖT 1*}u!Cl}FNh#A/bzQ8ч2׆A/~޳[u.!=erO:CqTN:UͅCj3}րuG4BCZ(iݱ1n0t[#! >N50Ĝ՟C[w5Uw&w,vs Ě5~U9dM$U#D 8mKÉGP<>4j "C*4|2ɇ'^ 7)#}CF-|t#)t}<|+&m~L||_E&9 ;ZVd uukQ]]p83.'嶨O812maIjtЁ6zatrQpqZ~x#w6n܈7x~O9t.Z8xߧ7L o}}pGbHEfnc #ǽzm6Ì+#v.f\QhBfvPE sWi.$sP[sƖ ''I+7q螭mBNxZl)"qFN2Pn(J[~y7 2gU P;%.إTa\EU<|gX#E/JvfQXU#p([Z?ޥ.jt:6;; (--EQQ!y97R upMڼ<: q/lS%0yL<T7>W^ņ 8y"s6{'ƍ'n0;: |R׬YÍ vk2x&tG{<1L8s7H')aCKFĖBle")9",. Ŋ^!5@:QQyE $0Ox,: CFEz32^yR;lº*  }-`Jlv9͖}ŭh!I%\ !p?dw82sg3? QI2P*jHQCyeNV\<,Ν -}z9a)WQ,h}gc"Dfx0 t]d(|MaCL|hC(#/.r-QjyZF@R!,fHhdwt/8ip$ 3GpO|hl42|./ż+(Ĕ_Z-`cwL%]3~ Y8y m]/>[t4{ޮa!dyL]^t}oinr lfM2dx|ZV%iJNˬ}1|8nE.-$ EPtѣ1l0nO {JtW2Z[۰|r,[ ^/ᗤވτ0rH覴EID22TVXKr9,vuoZʻz'^UHJȔeqQSg"[RE(,1ka1 _,]M+6l'M QҎ LRK'f:{7'6ņi%yܝ$N°ӽ^(^y =Ӫ {л"7F]P6tSAg aG04&I2>{g3^F@sk<]yn 瞲7󝩃P:$rCNLu n@kP1 y2 HfZ)H¼{ C#ALW(P4)W]`5~umndſ⫆3eğ­ Cş,MVd&:#"t愰xidXCX]g ;ÍK"t?a`ЙD^{fNM-1` -T毫 'e9&gfˮ&߲F$xX.fyĩ1vQC~3' t7녢|mhjiZgref):͵\wZ^| p#c(Y0o0TVny3Ѣ8ÇvcI"FAZ hm,Ӿ>)# BǼ˯fRv*c3oU(0pQ3e8vs}K=BM^'f<.aD8e&РE F4hm\J׼A <0HGBdPIE\t*uɩ*1`.^4Ң\BiPY"(Kujףp 31hm2K!LH*:ĝNѠMg9^jG‹ b+E[-Rɻ#'BY9W Bx- ٞ\d7~b!-WB;H.Inc=BࢾPiez0`o@~( f*U~'~&ρ04"almhc7"h+V} tG J0~ !*:@dV w>14F-iPPj:M̓q^K?2ٳ;wghbQrʖt/un ({5%y5aeOCc[3mv^( *#͍-h*nniIHqQlFIɠ#}މe۲B)Ɂ優:)Vp`0hs-&$1 ]v":pmTU1e D\:-ňmz[y: 1hT޸wn+ ,ٜ'?4 -uX 8t%^F=~`f_csǮi_Q"$Zw;z5Rkn!ur|ٗ~ŧ/0}O=hEY&E"3yHM:IHMKd.b9ÃԕP$a:74 p*F/^n$+64nF$&e.axͨmIaH V=fGju ;OΘ$ʬ1F (˔˛ѕB'+O%WX)/K E &={7Y8Uϼk{5.Դ*c)UF9~ lȕtO<& ;A8(/fJU ČG땴/Eo1PZL-WGW{ CBS27"h_iK>L//Z%;eoF3x{-3CCny/mll۷t90}(\J1)]uL}g~/"5`uV RstO>e}\-82!@ 'OyIVZI;rOpo汋'/]#Qi6e',r͚P{(dXg M_"Q$ rDLއjn PtH Y  @ {W,0(!_͙}&qpIQ.#X,Hʐ?N O̒# 55D>.y1Q*g{lHhˢ0́ ZÉd&rJQt8xMf+.U(#Jp<*tI+D'?EyMϗۂTVe4b}!9VF_72]Q0l\5f P݈ u2SW =d$t(2\N5e'}7rW~r1qXF6y:$aؠR߫ ZQQђx/Fb`KC<70%}Gbքe*W0Jo]{"H; JjvVZ"m PB7T #/:`"c#P -[TݸDg!WJ$)R7|O /0 \$I*PpH0c(ᐐs'`2tY୻jdf`3':iP"<-›ϭlX nƟedPR!1 ]D#[Xil@ݸ9uw2ORuYAq0_+2PӜ$ӜOPUmNl ſҪfJI>XSwi8 ֻ.A WA"  R5𦃶u#4ܸED"YO};;'Vzp/_yK mǶy)}mJT1dX)/T~mJ#!zNdLZ߆WT*=Lbpb GFgVIR 8jc2LXu |LG$zN9Bo$ז>G5̺i~1Ԓ1nD#Grޡ3OmZ1}f,n*s+^fgIfI{6VC^ȿ :Y`xlyG.kXXCUlnHkb,of=Ub<,*R<7^ RbsstK[c d#UHJ<%G 6Y9R/{Yi#?x#r)cb8I_4tdi cBgr aV/ቻ#K 8=1vXGڣ*68F$8H o#f hڙ ‘54bӚJa䎹*p7 ;rѥyG|oT2\QhDұ p\rgqreeifE }V%o&֩AW&ca`͔ QEX IDAT`AfZ7\O梲yz'è5B 2TYǬ=Qwi ~'v% 2Kuw;(rEp)3PjՁfԇ}Ig[AQC$8&4EZҜ},T0?R!i>HA4TT#КN|-+X%t%Ũ}@;dL޼х#~yktHݣ|)ߡE3I!KCk?"T7⥥ޒ$sٿķ|Pq_+>ټO %@)ܓ 4vXmZrB I2ޘG>UA& A?1"臦0r ρnޖ1 =x`8 Se( ڋPQ?C!2XGЗ[$z|5wEiPzhi>x/lksedI0s(*!K, ޳nFo+[˕A]~s=zk'P|---Vce  vOQf tܒ~ɧ-}Ad*QtƘsߩ#p#C1cq"Yee~ƺf L sUWd`~7\ySuyO0!v͹ǛUxMht8_`] Ią䂁-t4TrD]]ZA9ᒜiTDxk~PZE~a808Ypd,RX~M[zuci]"2zhg[Dw#r T\p\iwa2,_FG_f1raPsIpKDu2PP߃/z@l3~Qk^ 9 Es5Enl]`:-.=٩g( |\ #@g:*ww)$BB @B/"*"EDDtP%@" ł(AAz ;3m˾}}wؽwʙ3sw=NVfc3 `1lݤ;@[0p||[>_Pn֊’ s+N?!FBп҄`+,SS_`1Ƀg766ɲ9˃=okj5;o KY1a8H)' @wijkA8F) 3=noJذb#7r%;L]nݺL @p}&L_lZ[ă)sEBmuvyGx^$1ILUUTFSϜᇟ\|Jw؎f! t`͈*|м'=BbKFމ_kZ?d<2P8!p)&H4]Ű1܆v=ÄupUS.6,iߙ߅Df'H[%[>>T=ڦ+6,ʛ3&wAGur6Ee̪-_0#;司?f;r{Nr6wRcav>o傩'g]?:$I}J<ͭ"ei'-UO@)e!cAŐORX0M2o'.qċ@$<QyF *u._%@ 4J&5 6@kN0[ŃUct|vXE`eZy\ }ՅXp%!hn%]QO9v{޺;qs%Eڎn4]8sBH<^~Ôi1yplpN0K-Iģhlm: Y&<&u6-k+ =Lw4=xիW/k}=&B|MhчF(KzKNu%b}!`b=y3Q~M~C>Xf7Ǯ:= wmm%;}{o!>vE%شבe1pD9Bкԩi5֓ua"N{2ZW4!:3F$sqt*ƕ^JZrݡc`!hiJWMWU&KA %bn嶓 VygMhvB"]O-~L})~Z?ݹ`8tQoVy+ p,*7IJĠl $Wfxp땯y}پ8JB=&b GFMVpW},:1?ECQób!T- D{?]Ŷ+[ FPѐBB'`oT웾 M_y 4H¦n&\n+!5.Ġi:MEc.߃,]fŷ'MK~V~ T75]f9Aͻ<6׼a]X]|r מr \ФI1RR)yNyed$K ϛ+CZT'9(s$MxckbvG-(«b nL8bZqU/ջ=3Wcc Y?#cs/mcw:p٤Zٍ?r ;fBt/j e4 h R~ 1Tu&1 ~>b S՘z&lah񏮅[' Ծ@ Q>_ 㳦jx#2vpGBdHӨyd% A [@1 KX%7QFw -u8N={7B `̴+<~Oby;zKkoz]C)r+(+)ȑ5SO8cƌ='8 6O|:tw"nߜb|ɿ'JUUfڙǙ!'pvz]s:[7SI/͊ZX ;c6N 2`Sأw lm58Cw7-eL?/0&J$ [Jϴ%,0Ġ0}VyS8O>8,jiwGdfq S0>&r@&XZNr|-C!G3zQxt; Č8BZQح n)J1J:\|2\1pǵ|iC'2 w09дwbq-$ h. M!dCtB~ҕB)3<FwOO6bӋ +42]W."8ܤ1P#뫅Ci 0Y0"#L5!'\M6yjTw`m1VF0,,"r0>ɂЃv06so;scję:+U%L9G hm7ǖwUdYAK%*clY:bx<~}e{65bS]:ZKkg`#XAڛZ N0;cXrHqڸk_}˗/_ps$5H ^|qD~fEͰJtЎpqjRVdI;dF4/#/[1i``M1_t^ySIo bURs"Wpu ^YNxhF^c]=iI0;88c WG^I*F=b)pS A(t[?$WOfFu)\YDTw;(,($Md_fD*UOh“rK+0L4"8K2Ql$=.85U#I4#jsu1IFFf\~QijOW{:=1XsAt#qD{6_L!\u'~Yl  Tz*샖.J2{glZ޳|xA; !/.:CMaZWZ SM>TH` @ʭhDѯ.ml4]lݣ%" \=Q y8ĕ B!܆̛ IxO *%P3&@1ԆEzRx2-A .ꄝ#Xo6A LtefMGȍ}:S,n{E’{g΁#m٧~0*b8+cZ,dS<1$#R%c%XTZ0SegN'R^w*i⶿,q? @g\3gbP "/v=#G@&2Bo:1C547" mC+-;5 ~wo3$~7k> wawi2ERO, Cv\Lzc)~$K&TSA;bO1\ O=@{ LhX;4Sʨ%aGK7+ (E$폲FeXw'noǛִ.azn]z=Q&\Tˊ"|#-+R@ ^Ƴ%b)\o FDy OnVm1ol)w$ⱇgKrx>Ҷd%/RՔqښNr$@(h}S t"tZR;].m_T/ ڛJI! Q7q0;65+P9ő`K ny'icv޷"W\וzcW|8=+̍@0:[,%= QXĢW7`,ї=93Pҥޚ~*cOECrAdp#hxA0bX&DC7-[$18CPirgyG;CvJ aYeEޭ\İ1Y#EabwSqv\xޥQʹD}*-@@ {z9wE g3:lNA#ehQ!l[Q8{+7ejQ8e!&vڠ( =BMˮcƎ);pBY ;]eQo &B ȢڔD:Xr@Oή(=~xN9ő6/d 4뭥CzD*BleC9]1+1brR J05xT-Z.[Y9.A]b `ÀpTϮLHe !$+5Mhx &wO^OOc=13/;w\M憿vb ۤː\fox,wY#g` djd橐$_LqM Хxw(P=5u Ynq "vy=YEAczm9o)?2khhmy7~{)Y)*+%#S ՛?p*ܔ6r($51xm`T2- c5~" C!%pID%eBg:sor ̋V7 r4I}ro\4'~¸?-%g*<8=у09ojD[_wz4歑2<ϱ E;dbWRW 0Rsh)'wKMIG&X+Z՜r?`1}[Ňү$'E=dug(qL9 Utʖ$RЉt=B-1x%Ee~U#FqAQzFS#ePX-(Ч(aiV,YhK$|&j#CGXwA0G2D&WC({xbB-OXjFpoO72EQHWyjsK̋|Lsq$yo wcpbcO &DߝQ5 Ż]ȓDWtBlc< IDATr>=<xk٩rn "[j^S) OS< 4Z[D=EL⹊*\©sb\"2K#D84y( 1n]$|*>)xTNfDü1j!=0 1cbnLX1n ! 0Lò\.7WU>E(*!PT եR@$YŒp:l{ݻZ,g2Dpbb*8R tp䣁G-AP &CA2\D7`{܆4O-{^ տNߝֱoj0=W?mU*ghrv}R"y&8oo1f+ϡ~ zdiU7z|xl^ &%…( 6M4d$D%C0Vġdji}r^Fo^Șo)*:F D.} : "Ds3ȨeCV MrmQsOfG+s?k d/^}~g,2blƔ-BotϾ-$H("pTpĸ*55 oc/=ۤ{K.y?Da>ż՞x}:E }.>\zڳiuxLeDSpʱs7%pTȽ%O$)̘Ȓ@Z$qy, $ 午(&pb{)̣H푘w1*_Z`O0 /A%)Fr7&8^!K'=H5,:/B3gT?;0$z&g Tc:(:BAaVSϔD[#XdLM0ڧ2B} |0cm|ʮ[ t5cǎ:C6D`=U;A7JCLq#πՏZνޓ6i?a!҂v+/j ~3\]w6%ST%7=hůe;=rKL\zuɘCkz-) nrHS<~.SbR)|sY"m'L3|&xfOϸRe8}ʸ/0 eK(*“"D Tچ.Ygˍg*.$=>R9sOa eKΉ@Fr,iNV^=}u?#z#pY7pJWT chy>s4}pVo1 kQ!AnoYdPe7/Mq;w$Hs}=ny`%Ed#kܣwGuq^H w)  ܘ@-2!%ryekEKB".ϴ$דIXF=2{{ٿtuҾ^ r  Y ++ pUIHlwQpoaUM  .>e.&7g!}dbKOxOED)wspA[&Plp$0 C0sIn r۞$ %8 (;Lz%x; v"Wyr fdKkspϪD2Vnſ^Zjπ0퐓0h9 pMm\1yS(#Ǩ>̘_A,p.OaHt;aH|դ45Xpq$0Ҏ.ʆ"$٣pĜP8GPiGS<$a L@H_h0nDЊ6]qc_]l =Muժ9~W62yeO}Ug8.A(H}hgܾŠ T}tp噯it{-{R8UM*`ɂiFfˠirTWx< 7EڹAQ6v)0=R1+= Go( 3UX((]ث 'M>刎/ۺSna&~~)>=i- _CN * 0[nЙ7H)M9E)Z׆6}"g:ՕC:;${Í(Wc-sű+ź0s3Xjpjp\zտKJ"{M5IqW 'JB5ot^ څu,=;mWL9o9Չ&U4QDlF;iLBJבnG|01[P e?o`$) w ;7 8t<\+A~M'ih #`z&}xP-q$ n\ KK}e%{(yp]x;>(('eDy6{@OĵhD+pն7Rз/\60wU<%LKƋoau}J:qn v>zw$;i-IEڱ?y{>},⊳j֥x'T .?>lg6ǫ#ݻ]w y/qỲZPکo2]}_Z_ W QPceK3v.uAfjBtĩ3o[&67ƅrcb)B~Pꋊ0lR(v?SZorJ](j?S6&qN ) ᲈ•avgn"kh@Hܙ]/[<ɐ,0[)ޛ&dYsfs:.:O9b$ f흦O,kb {M,Oܙǂ9kmuNjL6rl t7``uF>ޡ-[u<aʆ%w,+t$dDK2pYMŊV#O ΅^m.jo8*X**;yOz)b28 NWF$V>SdBMo H "=*/izB>Nh)kyF /a*).9d)Z%--虅貌VaiQ%LY.\f`M!Mve?sz9KUoBn [S!Dz(Gw|CBy1` SQ;m!DrM (W)=tSrg3ΰeCya %%>T Oͼ GJ@|筝TD[yѳ1q&kgw7OiƦp$:ˣ;d<ܦW纂1gF:t*fմ,%@)& \+y!Cך{ F C[tZ]4sU,ZH(T!f{`nGRg-pz)lnM}MH\7GF"qW)G)`V~wI]ka<㏽~ah77@X}wPj)|NRH™;q@:w\4~` p/ͩKMdh@a_a, P=&됉j<o&@aa ZNhmœbaS$ hW46!DL) W834@WKʱ{Rf, (%]/eӱA q3kk~a- J{ޅ\U0|%W/R%nlxDm9;F% KVqżg$læ9LPMlT _ TQR<;-gtUJe<}__Q5dCJ_!K`GA`YFԷIW˽q\CVӳYB/tFJl K*'(@$37ë5|6P6}&!OU;)B5zƪZ2Jс1EU=d05stxDTV &~Cݡ #N;6ҥK!ϩ&C_b:S={N.Ƹ?=' hE(p.nTY9aLeO &o7M- i@tD8 ]iYO@P{7_C։CjPy8V˛묝1fv9o8% M'U(LIN܉Ė*6]y;(ֆZƜ-N`րWR1*WrzCS'! \4ye~àm8 ƍ9{OeCO!KvǤiEiaɤV,r=+@{cr )'K Wr-|%Ҍ3+So'K>`|]W=ESUIgf[q 4ʭڦtD4-Rܯ++15,;<,z?*aJ:gzC /,"홃>qW=0cpFAR'ݞ .S*(sY!+toJ2WgDJBPʩR셃, )d 5MʷEk~f?ki<2a]#b(O#SfvfGoW_N$@ k75k }X#Fݝ1Bpl(]f&c39}Ș^XɂڢZ'hm EdX ɔ68$'vzw >^SFm1c8V͸lv~+0hԄHGvvkU4{C{{]O?[96<, `qRjh=0/c-e`MPXлnWY@ jvJvI) 5 (N)y=ѿN#%EKʤ>bS+*6W;uvݗx z!ˤ,C$K_B ic L#3̽]ϲ,V<i69IEFt\U<;:1\3ߐAx-!&@+:Pu :ԀVI EvmQ0g g(JWZn7jqP!At#n"߰,w>60mFUG;[{)Bhv.;%0b%# IDATהu`T}gF#c4)qQ\=Wtȸ#Nwtcd&J9LXiX<`D=Sٌv1ttnm=bѸ@u]ӻ}eRog5GY.0m=o^7 bn2l̀% ocbC LFnߴyIcHkj¨kf;Hp4GZ7ͥ<" LQ8T;E6,;V lCʔ۷P.fS'' <i] ]􍄛l|L~o0%?&Lr.&’`DuY O`At/Ti7L`-XpГ6dyyG[i~ n$NĞ-!F4!G;b:Cs$P( WaYgM ̞rLf]EŴ5 {3 fNl؅xdˏnx뿍$QxRiSSv:Gt"|pho#KzuۿMlfpc4nx.CD$ ـi FB W el*^m { !oG[s_BdmOqGH3.{" Ã`(Hf2UzVq3o[K6aP=T#TOvG6n ހU()+JL_%R'2pE% "qR;gJב@,x* 1Z"eC<GFtuhC8OM(K  0gq`t,nݩϑ#Vp^w&[ބʓB?˷eƠSTwه/y 0̃Pl.x=pWxޭ$i`o3)&K}z = tʤdzpc1܋.Y_DTiQT)XUqJPbZB]S t{DqsV2)Ƌha&\Ib.:qn@%&+)Fw!O!$$ד/-'_ؤsc+e}UFL\(G-Gi 2!>n "?E(*Bql%oߺ]O= LJut+7 .&;4D;#ˆGb04i|O48|M\BNG '+~iM?9cUIn%irO0ڃyɣKSÞk孛`D%z 7N͎6Ô|:o0p>¬֕7C"'_0sYҹƴ xDC<G,ӡ5˴Imتm̔l9`sCJb _ O9'G̟4q\u(fMRl>E;tJ*fL.Ɖߟ9~)bބbJ>OLp~$ :s] Vx-gyQ yGY.k W(х%ef金֮i24!%R.tsj^RT7J+Q>Y 2 !{0N YCԜ,y{l5ԙ>>B4zIS6nGߙ^{>c.[8G i(0B%jY $[!+|I(ry(ţ%,fri\1LRD=LǼŸ^Ocul5Ͻт/JJw^rHKB}N|.tGHτR^VQ +x뮻~UTp~HK 1mule1F V?4th :vU<'t" ,3 Ɋčc0vRT]A h/fd~`N)QC?N )L=z/RiʰL@7%@sk+ִ!r*E:/!_tv7;Xec$ko~ӗok$N1wLةdX\f_I_ڋ^B==H ؾZY?ӎِ(\r.OL$& oC&6?xj_bpu+鉼):BAR-`zt4ctCڻ$UqQq<k8r1 lC|-舒 }>B}GXxAWd,xvJ<-ZPL> WЃ+sL38|ֽ=*&;݅,C{k|?*=tW=?M7C=ؿw<}iH@%0yZ g:*{z29I4c9kZw9`^Ű*PWV]]w *H2 9a3nU{zL!37T[tH4ujdl}@^NY( ?DNYKHSTzSnh3[wыx{pJo"Sqh)זOO_ dF\6oz V};HQ9r|*rh[^[b;*b'5`tuөV 'lBhMZKn~3|>]GFDQD8&٘ /lMuM Öo#E%E /+ |=ÚVJ6j%]7OMiPͼ=: m5Ql((5<$D"$Π(vȩzi3'?}!-++cC:<7y3̎m0X'>sQd_6q-y,m6A b.xݞ )3xbHtsq9o؂Pra94ǍU >9YKD=M?u898Kn17t\1'gsO'~Fӕ{aAdtD{ϸd.Č6׻'t w\s4[nwfS(J0װj]HD뾅r5 ^ElzИG5~2Eڬn%8eFOn 4UIH(?atE,Ϧ).es%16{M]lƱnFX"Ca0X]:v22rY8.>q׆=-΢65bzzi6.xpd\j{N8YAp53~7URZG 0spy-Kp+s=Ͼ;SQhpԉ @z!РE_~vxHAwvU%P/ړҝ6NvKluSsa@v@0h"';OGvYܠ @ϐQR.J^TY:cת#~^'^5'},I$\l\{ֵyu0e#UiT8pp2@ _/vգZzݭig.\sg1#1BxX}t\u #7͌s= y{^4" 4L^pR[zN4[θ(sdH>gc:swS1[)iG!;XoF!rCHy%™'_ xLuaXM.ƤLLox4xO 9" hD}ct dƊ`L,,DERZ{Piϭ@d&ܳ?6mu 5[MKӐ)sV)E|1sSYsҴ4O<“Og@8.#1Z 9@}2?A:zMd Mnn6F8uZP5iH9 @E+X|Y<3,*m2r 7ǚt[#Y߽HH\^Z-EEUGH4,1 CD~?g)+M>@ % ~?i^'NdH2mHW l1:iԩ:L瑕U%֒+0m+u-Ic(1 9tKj;rraYK\7Fed ظCZ.mWD˜HmdXbL EozH1$^9(#(d6?JM Ow)xѻ> IM'űg2̘ChYF GQK {o3]\(i6 ;T 1OxJSчXtɩj%as>Evg6] -,׆09J0Ś- y:$sxÎxdÙ~{5ݠh[q{"_7/b=0mU|ܕFE80b9u+bE\L*,@fZ{47-?CwףN>47&H*H=8J E݆91R䖽x_0$髵 NwÖO_mywJ9?ֆ O޸q`ӆ"oE$:R\: ~:bT[乮k9vݻtιni{M &zB h^v v__' ֥m||42UX>&9^JO5f&u\Gj/*GF#^mWIsbUxE廉?$UM%%(l,ED";ƐDDb,ST" @?|6&|>MqnlxFBDwsVAM ~< :re`hE(KoV]I@5ԞəH{QT'Spϋ_EGyyy>qL^Ɓ1n;Hqk5@ e˖[M!P47_3 ګp_{}/ǒM[ 8B?ًrzxc2}[=ñuj;iD+?%.m$ji!K\e0v#v/lt9mX=z2G<.xeg_:0 t$BJN_.}0t-0<'t85栳)b>e\_#p` yڇQ:y6ƴΕ^Me o~T t~Q6sly'-m vubȳ6 |.uaRix׼JʞG: {om%-0K4B.P6>kcDRG"+$DIhI8! ՉTMi.DuYGpbȁrY0:!!C4kyTe&ۈu.5]0ay9XKDkLV=p#/E :(yUdœ1`FeWkocGh-Œ4׶ ݌ra٥flfkn۫P(2tGB,[_Vmfvwnk P鸰uDC5ڲO%x$2#Ue'UY'P(7n^}vrRm*='<9<>jjcS{Ѥ|ˤM{'c1LlCGa^:䣀=ݻgvmWs#yFeIˆ/w<\~F\!-]TqhJR0f&N5[iӴ`t_8yEN4-H2H͙)V3qZ*c pD?btdɸwr=IC{Rx \qx*(!&,IdG<}gE4 j#`Ն GPsD"0 3mJ+#|5?"Ue]bSP1hNB!.4nƘ A݌ m$Gi p2cu XİKipENd́ߍܡ:S>Qx੓O"Qqk}+yrhN{X:NN nRV{w_yѢEEPP(HmLj3q%Wcٗ#X"< 1lAd/l>oﴘQ! v6B?؊eQqbH$WKyiydw2ODLFQsa<{\0 Ȳ`'cAȵ-8qGlE=Ld#Bb-Ek"ˁ0Lvɒ3CD  l2(7 N0{tBFPpHv-/? KTwAfM>䧁y..J6?hf mWo7gdy%!'_\`S6uB@!hvtoڼyͥǶVr2;ک零22格2HQSA&70(0ޛ)QLDz<'lL${NA39YY t.+ݸ>ԩ!/1'WޡX?;3 6l쿞çeaVK8G^'?g(rXpiav8_1ӽ:9S&&t9D$bڃa8-vo=F"+Ҩ=ǚ'([]5"s/+I5$iyH*Nz'2<)JY,LW@5~0;t0J#L'E39L!mP䞲Ȑk'EexL^La1ch:ge!jHr9,_sYeVI~ B2QO65aޏBNdwny(iyrXb0C me;5 3mXEU%'՞;ǦuŸ. B`Fv/wV[Xf-+ԣ1K/*4VmB!-јSTYik㺌H'q2JȄ!#dsJ唄\b` U\sUJ$Q)k7m"~GR40Dwg #ޯ(zYEn:/~܀W?]h:paC6tm?.*-$f7`yDbJǖ0ҰS␮?p7O:LD?s{A).?yؚdI> ,. /]fOWf{E͖g Ea123s?-Ĭyz6, V쾮|a\_!Pm5Kgpf-_c~үuDd_*ڎ]Nd50 xGƌ! @[z8>Dz,\2\E0Rn.L]FrسkG3R 0W{OY#]nh;#б9cXq5%-'ESZ}4:'32yJ[4Wȫ]{a'1Ң:zWK @Q[z$jqòv;v&)}E>S.%c~QPBNh%kVfyצB60tc v_@S4lh{J#+-I˓h>^?T @;E@-t`UD`ټiǍC/Ɍl4wP ta fGӱjaFFU`#f8vX? hD&@HF ٖ{h9r ZTvs/a볱`MƄQxA]̓g>;-Er ݭecm+hYBH%k9D] 5<# 1W5QVHCdy/9&@ceW`1|Pwt!*64f&GY~?1ܺ5Fe!Mf2Y,!GEYC;7ifN /r$Dpp |4\vf6d[G,wOt8t (*JQ!u]l>*+#i&OVRǙw<-VRϫO' [V-z"炯AVh3)uخ DleQ[BXSAIBy1}h3"]=E: (Cpz _LV>,G"\: K J' @Z!մ@">nF?3.4őˋucw~ԭOLQ8WivB涛Ҳ{80S0p"N`ߢӘb>\7n*Q%@7 m@3oNޛTa2t)rZ`ry Ch) zy9yr/r Dhz 0h7E$`H8!5&&gfRr2):5?& b>*|& 9xD P֪9(RXz,y)1Ť+0y9wqOQg5wLA- @A@-g,UO-q [N*L@uijl{//K]~/=~JooN 5c$ bЖ~,ӈsR[rŽ5*o߀gM l4) \+9E2@tP!*SEjyV75ɲztf2CU׈j˷0j m4o3~~Y\&Ij8>8~ph~꿃(Xn(5EA?azD}0y}laDT  h#hO7,u gd'M{`*r-ˈMc#E ,V?p4|퍕`׷!nMTނv a,J[.X[ 5GqH/L 9n$r ,QB-W-qkGƸZSԣEnP(vZ C@:ht)/.nƲ{_np!wD{&Qofkaͪ=;g{&("CTAވ,R\AUp {8g?9-?޽^S}ffE|oo~YZ[88O[c#6? 1EB{Y>4Lx{U`ĸg)fzB@! v1;H~*m:m\ zAWw}\V:L)ƻ/ 6s\y(ոUE L0aoAdIJ]N@C7s3rz`ǵNĿ@'[?ʵ;@ mPpg:_FĀ8 ՠg@;Hsx9p<肄O tι/p.) T"Th} |9br,mI2.fy,׀c3hA KTUqf]3p~]p]67--kvm<u$/Y mn#{__IZhյٓq'aK%popp7{ f{QLv5ZSQ<=*yu켗t(`D\Sh VZk\"ku/#.IVbҷ-EA6 }*;P( ـ(|GJ$Vt /NkrY"Dh/u·B\4n㮿=zekY#=I><':A!IX #je]x3p#`IB>Mdn8]hL0#[9&SI5<XʕKqUrDLrZR B@!P @x登wy^ay8tr~ :+ G7',i@Ew]s,'APn"'pNIԃ'kՓy ƣ~s@IȎ+J\t!'Fܵq`Y^]}p)`5d$"䱖ݔ]μ "҉.Azl)|F[ފ$~v*J+Sq&F O|Phm9P @E@-vhUE`=v=:op }zl3-o;0`D4l,^JARBf*,m4퓍?1@u-ߡwe^F%c e?<@"YN:Եcɐ'9DWWvcF<p`׮$ٓ9opKG E;bM. ؋YR,m í{MLs(7ruGuш_| ?)ucB`GF:w~Q݉I΃>??׻t)e:h3>zIh*'BG9!wJ0p(x^Ð$dWDdJիᾣ@"s4` L,~1t5Gĝx@Aj ԡmUNjݖCǩHwgc4ǀ1IܝJhU̿˖mg+ 2Ȫ~)RvdTAїavIg &RSV.d2 O5ků}v퀿WtoJOiy=v>, 5 <"#?sнL^IꭕQf"T-5G]g d?z0t#L>ۛ_m94ΰ|-,GaKⶪGD*v0"%4Gӕ{NLT^[O)mL3[4:\禢$숵d}蚉g&TKS31W+ P  @fdON넳/٣ t-7pI0p:} &JGf셼o2jɵlE,l9ſH'j?Q%:ICCHYk1qDIn)<o,N:f`rQtCɆ\,}.8>"{x/[k.N=8 KT5w 2P(Gf=٥{ n}Rw8f~o[[NF}7_V.l@)\'j6In3Wf? .^]GqySɓۧ;?,,IJQ=GaA" >šO[6\P9#|.<>`E@0tafSHq⹷ɵvrF?zQR(2f(Z KGZQ5++n hW56!>> TzNkF&^9fޔQJi0A 9ihWLUˁr snu&,ae&~PE`2 ;dg^Wk:hq t.^,V'$s* K3D=؀Ͼ_Vsr<"RQ(@cnB`W5pOU0j1/F.F9xoQ2V=u]F(Fv5yf>K`f-caAۀ𔻡;ܜR @qyr a ]1vV/rZ7XbyX ' tTF u.BQƿ5Bazedkk1'o{h\뇣["a:ƿ 6l#+1.ڣ[ "V3tȲ+aEڛ*.(~?4z7<oKK%ᘍny9z]5l㲱#&~eZxaH5־mFG <4l,w 3l\wC]2ætiw Ck\v؈3l?~"m8w#oNUoYzB@!Pl;`=@*x E5)&[C|[hA AkJdI%mlXhG@eW5.71b8ም=$lռt {f1I0Q$]}mFERsXqa4ihk]:.do~\1Tv'w5СgM06xmY ^G0C1%gGMɉH5/ Pr6`/BsihJq~^T};4.!#:z_ GP( B}|YZu[B:p7/xx;A&6pp"- +?x/8dCѣcC7߂ ,i'JlF6da 5Moy QWeۨA 00+Fga*$c\܏n}nFA)5k ۬]g{Ui5tMh2Ly=>f_12 poo&a:h+*줁^TgFq=ïS272(C^϶虤 @o"5D/}2zkI]b/d!3wLe+q=q/%:t!!$ԃY8qqWޫ~( tE@:2] 4E{pjQcN.~k(Kq b_@ cH2[O2] 4S C$۶ͨ^lDX>G> MH,TJ).ixY,_l!Z \ki:WR,Q9́E]jxҡ3f)#1Kla6oUhA\%k*»eDxQݏ`HuuD48mh^Hn7=ٹG8b`>x䝙y9Թ B Pmd=/E)Z.6<:$gԢvslXdɗa5dxϲN卯.<9=LꘓKB[D F:`o!$asp"bK26E03Lѻ.9~ASg\3[r}B>jw2sqt^՛\ˡe ?7?|(֬79?nWYR2z;'WfS  `h.O܍ *#I2vqǂkMnh(:]k՚J2(Ghwwq%GBV5>K|VJz UiPS+ IDATϑee.->ɮ0y(f#[ߚAY2zg57<3i:W3'~\Rw>[C p/oizB@!رhqI^!B($kE*E Yy{x@ lv@/!/}Rh\N?jHO}^{#TO)> 9G=:@Km4TF*P̽a5貨ZÝ|fAehq >g+ь`F7w]0>rz 7q$G]LNjaJOkf#͓S p`ap3ts]uӽg6~r+ B(;8mYN>_c,}oR `>g~Þ5gWD?ڬP $ky(>vEůB_[:.Ϲq_`O@6f3BLEG{п1x)\P(PnR=,!G *<<'T0{dTy- ȢJm҇o|L5. 68~TTINh*? )kq7c9^q(t<;>)U. W?>L BfӈAā*/h3&{㋰ClJG J^l83Y>P4G=~|| 0iZA-cP5Sg}&UI!PWRsnب~) pQ}jȉQn71#-eĕwY 6㽉(<8ǰz#v0t?[7I0-$~|ӥAӌ˘R {l(" t\T8\OM~Ap*).Wax?s5.{Ⱦ!Sdz|BɑGk p;4_".?ߙemF&H8,-  ]~tjB@!ho4cKޠPQ(Mj 3%Sӛ2+"[jgXH59} _.mF?&dFVDg> Cܔ`kXƿ>.=~CzsrՏ~Q愜|9> e4#gӯ96hC)Ļ[fxXˮ6Y?Ƞ7K=>C1n" EF\֧TyjB@!d&SAWVd:;Wn\ZofZxcaAlt+(+d8,cNT#hp\w="yu8%^.ˢ'Oz iNZZjm^lB@!#"2;⨫>+9u^e63\#QEěͬY r F7?_y,!"or<~OgG5˔JA?6&Bb'Zsa}N"UͳҩwP_7qf`G?nWE7kvAf`Vz/ƐAgvrq1h[8&l֑F*y@IQl}_=% H$,A~,FD@AbVQQ O" datw}VϲYv623[y¯kMb@t8ڣtGO]&.'<]Ҩa={ rɺ$I@r& '$I y|׌Yv;bbQMDN&XFZq-}DJ _A|wظtBن˱+ٮ0쭆Ci&umV{>#gyOq'S-{V@cwg 8Epi9aT`iLC XV d\mU]ꀉ`sk(gv_pP&JVG/^[KNV) H$pX.I@(0+8g#EN5/4? ZD9JB v)l5˜s+G:A#lorBmQ]vP{Gx%[DbJ|L.KGio΍JB?h_N#=ŭc LurM㝩 2r)FT ~3Y&xz,L?i߯}69_oX-_9XI@Rr ҉Ò ?} GqGUy0;)N VŒ G8zn-+Xy^v82^+"n|!琸،#畻fGh;Djн\߁s4kOkvy &xk*|4+lW0Xq]=nҫTچwJ#\bgq*8Ü ڜIp]K$P, OL'9hI<{sUnӶqԾ1k9drʠРK޾Tax86CR 8S= Y;%.PB&CrDм wHXs$_s݆YH՗/=#ҚpۧcMtjy=F;qA&?)E ,9bkoa)OATE$JOFu޾{b %I@gs$,mgs Wp0\ ʢN/!)8``W+Vį5S#zF.AʝNzjyr6je/t(i'@1 h wE"l ߭;\%u$I@B@ y&ߑ$zWrm١0w' [xRhin ݩbq@|DRxVP򱫑6Ѭ}ЊqS'U(H)Ti*x|ձnX)Ô%2qB\LW.|?e Yk~`8#cK_⮛y`g!.5*qqMuѶILCeM:vUYE$IQV6) H~C`ڸR͟]Luj{TEzp+*qIjdJ~{дǯI8 \J {&vςBJ܎In?Xom+*TH֣+첀G#L#K<ljp=QLRL4y^ E8ŶPp8Lƌm] Yׁ]'h090jXd{7",6hm4m\wL.֫HE6" HUMX.I@~iKoA|h{ŒY9=IS Ǹ Blt x3ʓ}.w5UN%n@#0qP箳)"u.+,}Rݚ~0mU0t·%`tBaf0||1=2Zkp8Ήק.ç/C$'f/V| &͎ű n =f@Bx C1tjunT`JIa9Ϊ>&v`?.؍;π#M墓3Tjs7/ɃykM% H$P뗤 F$$"#0{eqw6ѳ9v} SZ_ul. =ݘ*Q[C4' Rs-Ds&`CD>@k [?G`f(L]o *t%Q6nJ~AqC0~$$Rut(u6`2u+L?oEG^>Z蝗 H$PȍM$Pp^~=?sX\Ԫ ,oGpIf*wdJ8-/J5Rm܀` «vA El+ ڈ߈UnQt+xѓbRUԏ ná=;SiŲoo#ܺ/=g~ַjB|ԯY{ IDATOV+Zl`=F6”ݎYlC ^s,:LЯ[m_M*.dodp->N¹0֪$I@ɳ@)+$$0:.ۚY%h7'DXT)<`5:HC0k3 t" 6UѳC ÙsjRF1 1 .ϴ4v$_Q?]nb)o}5l20(u*9b~&]xPd3.BεqwjPM..@ m2B"9Jݞ=Jњ&Rp݋qLBrެpM.I$LOG0cןE-Hed(XHGK!ohln= b 7쥒^IBQh7 ~5S`~E+30Ӊ#D+|V2a b ݛ:}[Wt!{;!zAh{l= 2frA$43wh<“%'~)!Xv -wEn"{niBQLΊ)H]=~J^o+H'uEP"n t_W[V&8נd|>Bm)YMfsQ[y#o(<\ъlf`ڗ833Yӷ\2ҿ-JQ*@گL0\TVdOpsޛI+SZ A[uC$P\ μ$PV,_?˙"3K d^ټsY `O邔)Tt]!Hٝ?c+==]~0񟞍вQ\$˖6[&H: 358zg/@1 i/ ?:W<rբ~4iyiÌ{n%~{d]wF+c>n=%\/^A-оg[վ3ť_Q]y'&}j~D\~Rt+* I@ܐtd%!0ܑx1ƙ~o@t/Luy+{.b_T`3qdݎ7? 39D@0ki)8 yfR1X8Jv,Rc?jP]EŚ4HHc+(b,f/ 6420̗̈{¦`yHW)Qkm8|&>B'Ke혈OV2J`2z 5*(:P.bɆ|(s8${"^q%I@ܐ}$$l r_k  `nZ">N–~l;| TYMCEi Pv C!!#$nrh6wLs ƥ((,,,_!vO|DwHČFfR@iaP֬HrS @VR@Q+gX~9i/4VtGᑻ"D"q>g.bd |hخOG>$ H$P^e@px-⠗9;zj >y;B: ۙ}n0㧅{nۙlOg:pOZyr5Q"ЍTNf~ڡ^UPxb/ucބ='Ӄ瑆_I XtuM_ו5BO$Lf3 {fq/!G.2D$}8[⊪X^M'T!I@$<rW$I =[-c+ˤIOD:F3 h$r)p#K{+t 5="4^s35«4{7PKD/@Ns$/J_zo[3eh:bn>oKm;lF%] E僜3Ln .oV LōfZ&XB[I{dv kj#m8d#$ OR@/.G- aOqpi?<MPƒ^P)NcnY^*8/8c&y`أ'jf /(JNTQ( V0Ӏaxba+=aCJj-D'u8.h=*D3Y|%hy|h^o 9ڰzޙ7Й 5N?㉇ZR0(LY*4T c,B\2%V8 b[_oֶY$ H@H=+$NiϟSTط"n$&IK&ì6`Xvq[VDN-}4nT"X^ b Ti ūq)[|)4G|*詫q1&J 'T)$廿b㸻kMm[wDi$d/X{ Vb(0&.oJv U y-B G[_ $ąЅb+Y$ӫsY$ HI@ IS% SC3;!qch":-`Dobː&27^r3J:Aܛۡ+n&ӯ|neH68g3Gg1]IY1l81X$:Ӆ ܠ7 ` K+1DXr$*$ 5W^6ɹwċ`^"sfKsoupPU+Mn3)jdA'ι. jV6]Q;?h"^ ~ٌ5P8Oj~y-\ VŊeлiE(_XUcZi[mU]iwkY?wnP >0q˟փsK+SmwI?" H$"$ "hOf g6,[w~ʄrdJUƔЍ 8GTKOtĜO2qawv#3_ UP}w&߶[_{Vz)㪸ziJ3pۺ营`+dpJ+i(օ\)aۡBY ,gl+OT>wL)_a!io6jw~or$ H@z▍IKݧn,[ޛ6ń  y|dœQ@5w 0ݫ>Ȓ`poZ 9O\@F,yu; 2h[wuN 9N3Nvjxq \L6m7SØOUOb"]Xozy h;=>pax IVF^ ТJףEW^?,,~ȑ>7#$I@(tR@/tIJIXP}\&W&UйLńk jZ`,p х+a^7eBK ͂{ XcU0>bC<NU :^[?JUx.ISctqoS4.M pzR:tq1`2M7K+rN m%sV"._8Ǒ &3Չk~áտXɜ2L?ċtGv s[Ὡ !E%dZbi2%{0c$+p ^ L|}B@0m~,v .$ۥ&nk[fWK鴎#g4b#Q*o]Fz-'a1:2h$!;}+Ji\t0%СF9o<*ƙ&H"eBX!~]MѦsbL:35:Qer=^HAwJ(N,$ Hy xH3gΟ'O._ffn`Ǣ8}0N&! >QNL ۼ¡fx_ abaD,"5R :b дiwn(axH:4*ַ {9ÿ[r IK&;bRtѯWC_m3lonG8LoP Lh~@@U7.XO>_X-z%I@F*$ x!0iҤIfƍ;Q ̕',žߊAYfIqGH2Ugذ~soO_G[i= c8`W &5K`= jZqP3"^ߨ[q)upT%Y \wb]zH=G|y~@DϷ̏'2L\фPzQ`z怴.xY yD\ivKl>`G&d]UByټ/65s˕+!ON/d}$ )lʱHY=͚j*[|‚GEGK6aMWOoˑIw vbsH@ m҈G; U# nUE1|g r IDAT|L/3 >] ] ϲǍAQ pp2Aèd`-5rw*OtHPW |l=xA\ȑٓyHnT'";s!6;h?R@wo$L~eM3s㕧{!4BĺO"}F9bjB[FaVi`Ȑ'hx=$ 䂀sK>* \cرc7of~##'LEqlR(tT | ]"Gd>75 (I\s|Aa%ЫILj>%eSMYEps1%jؤÄ3]$v& .L E5Sw_Y}r}U)x@TqZra7Oq\C^@uu5PP7U˗A#$N$ HN j)'  c|4)e~hgw–3? r7kCMw~RxG=v0_:%G0wI!|>ާz(㿯99K[3UnAP] 9.T/[Jioty| pK$Dδ-D˭\膊w7E*a bފPi@ۇ Sb2W?=%p(J.Z0 z$I M.X0 l۹NOu: L8oBې r<Я92q 8W1]X+Nx|GCt@n'3| \s&hxjx{HkT-Eidsc2Un 4<$%`Hc0y_"WA!dUqvDٓS7\J> ([9gonoÓ%hGXXYB9bJD@z%I5/%<)Z%ZBF%a.#Sn:f͗N: NڴKj^p88&2|F>+Wğ sߚ577'?S0*32oCLk;eݳhBI@Ѓf*@o(h2M7go9zhB3u|49S1 Hitw]-s;e,&,‰ʉlb=Цzdve< َջD_i`h\gL>=l%L_ѳYIr.?.\J Ru ~-ҨtlZ߶ vOE&A8"oyVXs!!]Smcc$C@ gH@o8aʖ+CayӺ( .P!B"SE5 ߛ-2QGHSŔ[|NRŬ(Scp%I H=&S%q|ܺo玪3Ι]-9|}-$t\_ؑ+0Q٘Gۢ~%k_2xsjJ=B ҝř?Mþ T9TNp$*7 07~]Myܾ-٭p"+081ZY'-wS ţo-l=1ySUx(Â0M d.PYoFoZZ`+@{$**]&11[@$ #X&[6wi,#3?=!OX(mfW+ TÀ"yIp+xY8x{@T/Cb5;8b#^"́FMI OM']3D?%B 9u݌GSXҶiGDO2cA4?ugϞ=$$ OA9rPL;J#Di. :(eP7> p=KNC/ &s':Fii'!k8Yp).op'݅ϟ Ru-P2aR&RA&-0q!AYKpj۹Z Cx%$m}RHaG$I?H?AXt31!% VC+ⶡ11ok@9b(Q1%½Ek8^KwCh.ӬySqNf$:̴G4U!&Mܽn"51]"~R ol ;eX?d9p,^qy_.hQ}db)㪕bC{O}#݋ZÖmd];:x#K%မt 3N-a6z5CZe(NOx|5-| - β,[Zu8rމ؀#Duc._!D,#ÂMaE`m2_1am G.ZCg־X'7Phs`,VJ2&BCCѳG7rEW' HL@  TV' dC %v3ϡ3[ ]@'J iT7wE0:ƒ/OodױT={L?;\;wfmP=~0!t&}гKZgǶcĈ}( rjRLfȀ 3w R ;LFVHGlwD Kr6/Q} oWYီnu_};z$S%_ݗe53ú63oI}Z&88Ѥv9֣ B:Vb@5ygX>yE&k ۏ$c7[Ep3&;#*tzx8G;;Vǝ+H-k.\g2x(vq!Ne{ܼJFˎw=,TeEѴ`ϝ^裏 aAH@PzPNT?SvS+ 6-w,3ܖX!_IE:QUN4op=zuk7`PbR҆F]^"/Li(Xi&bl )lI< 10َTi탶(O~I. Dhb 憨Vt*Ƭ="y7fNnh_}7bSUoH?>N>& HB@nP2r~K`!}6 @"E޷$Z1\:PZ i(  ϱnv)dW˪ci ȉĤaQ2 T\KN̊1= z=iKtX)gXL05,Xw φu@t8d|X @z l< CVpd8gAӤB w4cP5VPpx~2E7[uKӜ݃Fh4:{Յ(? yݬ2EMۧ;liI@("rO/"вI^$QœGQNH8}3)|ݜH4&*ejhҠ*A=l^bA9LeVJǀ;!2ŷx1 ?8_V"(ᰶЊq*q }R QtBs'bD Neka翧q)5Oj]¥%P#0 B"c|Mao{sqj!yٴ$ D@nN9. yRRG'?7o 6É[Uv svCgMѡ*n^ mZApqO+US#|2g36p\Ռ: "Cw5|h??I;a@p$X ~FҠޛIlLHĴnAͲؐY09mj8yʁEkvx8\덵X?k Gv-415+=p4QЋ]X'2|Kp}eN,ͮXt8"Vrョ  ̷o;mH߁Dkҡs:[cp5tHO3LӖٳ1ae!j#. @Qiu9m|sUT>FZ|O$" w"+,]'&: U .Д>AسoܵHBkϛ`TDbPvԬ0M[DK&T7ڌ 8~-Ƭ‰/^ =) e 4cDx^/ H@a헤{!:uZajb 33Pbټ/|(=Ŋ$-i۝e.pPahײ>GL(]tD iLrrg R/!V%vm*\gm@&~нN`k!Uqo,W' r6iP& O&aHL1y--yf i+I4g JxiluuSzh9GN-H4u~[_%e! H~I@nN~9-SB &&ė_}/g4-:Z4复"SgzWG#ؽz>N&rʬoqaz|-\e.T,nYkCt !6R ԵKL G$4ŹX j^|%z4 ʙx1}WP:p |ou4~CL%兩)g4gW2q!^}} 9gĒr9[zw_Y]5vDՆ[Ƭ_ͺ( *s+I$PtAPuHW!?9c(}SشrXMO7IM:[#s4yMb*I\W6EŲvj&4 T&jӝڡPNY>n<}(|"*\6+#~-@Wɀ=#'-Ǚ4*;SFkJۊ9)ˠ07nAQuWyޡ?a7p1cU8z, _et9MD <:Ȋa0Pq屢gw?_AW랕Y߸ pwîp|LFQ$=..ͅ.rUYOn5dPb}4%+Ԃ aP/5*z qJ@TΝycNi]d+ i[>V@9O_g"8gsB1 Bȵ|Oth0U36Lʔй}ԫU !1Opn:- ~g#:sbmU Qp^tZ 7TP#d"@v_-a#9wcSmq}I[_'WCE[Ŧ-rvܠLX :Zd@J;ĻTmz܁3s9ܓ"_'N_;ma٠$ H>? >I$>H IDAT/RX84ÁGwcƥ8|T$\g$ڵ惃qJR)5\5#:R.L7ҿ;fmoJ43 UZb[8͗ v hlX5Ňۀ ʒF'Ϗgocqd ]Uw{{ ! !ldQL EpLEJKKEd0ba0"Ô"XC)bp7p :P@$d!kwo˹S9Izyww9s} ߴ1rǬE!u+K"*E-sHZp=w;aǮ.td I9O%ڥ2#?##hsN(gDP ?54%X~҉h 0&0Rt:~L`?ݻ{Փ8tkB|X=>o?20? K|=Ra"hI8oRL X>|?etLK wUɺ1pG-B&EIܴtY$}nM"o^NˋOTG]PFx}>q6tڰE`A*E=JS s*H1zrλ:?9t?G~q2p\amQÃMk<|-c5dx Ddsh2v',FQv᭴/G))[N 0K<|S ÕY'ssp S֕qק. PHnᜣiG' 'b9xFZ0}5r {}+BfIp #ˊGu5\rI˻.SbXx1smjjd1|Gm0 Ws 0z$G\~ēocuߑ:wagc:oA~= f%F=-7Ri2hDґn%NjMmLi4=P1-$MOz M E|_-;&ϷdbZ:iUKewވ-¨p( |,tJ/]0d29XJ&m3P]KO:\@_q9tug`{2vڥ6 u#]eBoRy:<>c/8Sg/FSs+Ie[c9V|lZ,w6r_oL 4|l,R&0}oROqvQ;ÑGXf|7\_};_E[;;}#%mhkҭl[s/cg] ,t -IdbhĴSNEh0tŧKˮj< w;;ۿɏ0~htW5 lSp>,. P|A{wGrɢP!S CHQH *+E[|p]iԙ1gљ2k!fF侮ŔoG a%r^{C-bL[@˗//q 9á ^^Z~]EF]ٿoS:VXJ .;W uKD` ϓR% D\ً!K{:C:C&c"J)AS@2C&]!Tjjxt&e x_ų/v +~H]} |x)^yzz~r[ Ё\4׽da1삆?Ay^Tt_3a٬\zz-/,.\AVpBx_%GcL`|@|&0,+W.+s%R= i!,fݾ^ۆ`Cy~WRٯ(V JY&hmMcF[3M "5YM&#bcP{5OK)XP? z5W\VUyЕ;w|^,e¹,Kx)K=^< Q"םNȘp9J ]e&O5e՜//XQpuJf}l\CoFǑ,.)ʋ.]9,qFռ{op*N]ȿQh-Def|:N>mX[7mzׯ[И`Jz `SqH$hJőLH#ZdAu(aF)RXY'W7-; aʰA]%ٸY)F/D.k/FR9(o|ff:qJ+q5/8/_YrtwӛCR4ݐ^JCYC8-Mnd63#Dy:XNEyzD-רx|XbOH?puFZ`L&佋!&@ ௟ n hiiIu/N1c>)ΥКpW8н"x/cW]sǂAHrڸY։>%Qd[]s tHhd:5'5cJ:tSw{ni@CrӗA}kK揶`NE8A5 ^_5㤠XcRԂ "1Ƕo yM-׏#tvv^Co63X5踁YS'&-^%!Ρ;ƽWM(ˆB6!:Ki3fB7kNeR]+ř?\h9G?V&kL 0#?蓝dbJu<שznѠ(ap9i[ã$m>|7:@[U<{!_&p#w0UbJ?e«-Ar9u;H%_KtJɓEH#HD-$Dql}ou7]W5]|(/պvp_7uWpnDTYwäc*}ySɿ&,^rOfUBLzb Y[n@m<ϗܶ)(lC1"Wt8E|\~h?(̔B)`Ǒk]=‹T󜮥*&}a=Dy6[ &YG`iGc?ZC|drK.uGO2&j~^OEL lٺC:VSmgH]z"p2 н<ڍwU=x2y$FƲ& p1tdKZ#wliIl[KYtKR-rC+WC~Tii0 3nˠL4C)osV$wi߇pYѺ:r}DQ3R6@S+$0<U'vSVzޔ^e^wlʱCh&_ǔq;.S΄I#˸nAA#aJ}Ө^4.];&L L4M<'bu[}=$0' o* C=r]DWtuG |[=͇ʯ %Rݲty#N5)yE)Z'ekũULr)yߠ:,Q-全ˍ,J`^]֗?W('c}/'J; zw@m_7 W0( [栥u.f֙ `&3aŏH}m:Z"L&s?6ưr/xj0:"pwe"3`/Zag+j?BZMr.pp+m8n1 K0(<,,IRédY^E6tU'J 0>ЕUN7,URuq:P_#]d{G菼<™B.:ś|A(IY4/uS(ZlZf-8LLr2^t:Se<kF?NC˧Er{d+VULf0}C1&FNYLnOOo kiܖ%w%MG~Eh ΣٮCjGp R>qé#%ÐxceC.\QsIМR.񞖘<}FL3RmH7DyZ̴A3uUGΡ<dT9h͙3_|===]w 0IF$pnch5k/ڰp{gcu{3zW(bZFxUߙjOh*~Wf6sՎ=o[{y[w$|蚀+qWO2Ҡ{_AKn\݀h23f-¬m6hB t1 S2!=>(jLHiu 4ږ=V1ja iVGSʱQ]pUD7-('u:#Ch|2da%o xēiDRDM0(Hȇ_JwJ/Ȳ0pV޷aYp7oz75fWL 0oq⽘@֬]\Vikt:lD 2{p"<pb}]H{;a9 YAヒr 8NJzɬ|Rٵ~p9-%0%>]R.J &Uz{d@xC{AJ+9ȿ "LW-P5C,~Q|%ݰ`SiħLC:ӂDj 4$hF,3fFХ\Khl2iNF>$ YXۮkkt8&D;0%ftE]` =Yzطd ˩3Jvi,TJx-Ż[cE%b^sp"]9p\u^x.|σRRO6_JzWmMbRVjN*o oڿlWJjUeV˸5B L% Qĸr{JIG] @Yj͕S%YvAW),v/|ρ+R Ǒ}ǦX{g˴d+ \$=x+%Z9mR놀aٞޞ5?4n eL x"ps5o.YÅcid =qPC>?5XvWHh>E@9:ͼtin-`L6 @qV1 uwweYy“%uK3nej&8N*oSHaBH cL 0&p,yz0&0R_4Q~x?&@=Pr9@]`^WōeE`ӦwwSTrom[`C-/&"ށ 0"pYgjvK[nbeL 8O7}H6o0w 0&РX7r@kq~ F*4t %ǴXs@xOShU ܂XD/[UKi<̯'`L ??&0)|7~Pȣm+V^y˨ iRN2&Ѐ|)wF"-jv>р.1&@@:O&W;sV]u8g۶ﺮmL L$^EM,n_& C֯_zrP^2&@%<hH?ᏞM/ZLEe12. 9!SL`T#T/ʩĸH$–MR&'k֬gԚbL 0'; `dO_ku=}ًOq"8Lmq-ho+` I@ nrav>5lNs`L`T @U|0&~k>p;;:B|('z( 0l h~"Gkk~W#`L 0a@!͛麮8y CȟaGލ 4Q O}_4YKǢ3ׯrc10&@Zn`uK`SڰHg7r~PȻ\۽nG^F2N9(hB R)c=k:& XOQ>2&0(t' {ue_FolՋJdef$5"a["ɘmxqG|! h=ۆaoڴ:BMeL 0&PWh,7p ^xBB NU4Z )8Xh='+mퟆ%گ׵O*7< 2Q4h0pIj E1n&<д}n", "eval"), {"__builtins__": safe_builtins}, validators) except (SyntaxError, NameError, TypeError) as e: raise SyntaxError("Invalid schema expression: '%s'. " % validator_string + str(e)) yamale-6.0.0/yamale/syntax/tests/000077500000000000000000000000001475257201500167355ustar00rootroot00000000000000yamale-6.0.0/yamale/syntax/tests/__init__.py000066400000000000000000000000001475257201500210340ustar00rootroot00000000000000yamale-6.0.0/yamale/syntax/tests/test_parser.py000066400000000000000000000022051475257201500216410ustar00rootroot00000000000000from pytest import raises from .. import parser as par from yamale.validators.validators import ( Validator, String, Regex, Number, Integer, Boolean, List, Day, Timestamp, Ip, Mac, ) def test_eval(): assert eval("String()") == String() def test_types(): assert par.parse("String()") == String() assert par.parse("str()") == String() assert par.parse("regex()") == Regex() assert par.parse("num()") == Number() assert par.parse("int()") == Integer() assert par.parse("day()") == Day() assert par.parse("timestamp()") == Timestamp() assert par.parse("bool()") == Boolean() assert par.parse("list(str())") == List(String()) assert par.parse("ip()") == Ip() assert par.parse("mac()") == Mac() def test_custom_type(): class my_validator(Validator): pass assert par.parse("custom()", {"custom": my_validator}) == my_validator() def test_required(): assert par.parse("str(required=True)").is_required assert par.parse("str(required=False)").is_optional def test_syntax_error(): with raises(SyntaxError): par.parse("eval()") yamale-6.0.0/yamale/tests/000077500000000000000000000000001475257201500154075ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/__init__.py000066400000000000000000000002151475257201500175160ustar00rootroot00000000000000import os def get_fixture(relative): script_dir = os.path.dirname(__file__) return os.path.join(script_dir, "fixtures/", relative) yamale-6.0.0/yamale/tests/command_line_fixtures/000077500000000000000000000000001475257201500217655ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/command_line_fixtures/empty_schema/000077500000000000000000000000001475257201500244435ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/command_line_fixtures/empty_schema/data.yaml000066400000000000000000000000051475257201500262330ustar00rootroot00000000000000a: 1 yamale-6.0.0/yamale/tests/command_line_fixtures/empty_schema/empty_schema.yaml000066400000000000000000000000001475257201500277730ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/command_line_fixtures/nestedYaml/000077500000000000000000000000001475257201500240725ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/command_line_fixtures/nestedYaml/anotherLevel/000077500000000000000000000000001475257201500265225ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/command_line_fixtures/nestedYaml/anotherLevel/good.yaml000066400000000000000000000000721475257201500303350ustar00rootroot00000000000000map: goodStr1: 'hello' goodInt: 12 goodStr2: 'done' yamale-6.0.0/yamale/tests/command_line_fixtures/nestedYaml/anotherLevel/schema.yaml000066400000000000000000000000361475257201500306450ustar00rootroot00000000000000map: map(str(), int(), str()) yamale-6.0.0/yamale/tests/command_line_fixtures/nestedYaml/schema.yaml000066400000000000000000000000271475257201500262150ustar00rootroot00000000000000map: map(str(), int()) yamale-6.0.0/yamale/tests/command_line_fixtures/required_keys_schema.yaml000066400000000000000000000000211475257201500270350ustar00rootroot00000000000000map: key: str()yamale-6.0.0/yamale/tests/command_line_fixtures/schema.yaml000066400000000000000000000000271475257201500241100ustar00rootroot00000000000000map: map(str(), int()) yamale-6.0.0/yamale/tests/command_line_fixtures/schema_dir/000077500000000000000000000000001475257201500240635ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/command_line_fixtures/schema_dir/external.yaml000066400000000000000000000000271475257201500265700ustar00rootroot00000000000000map: map(str(), int()) yamale-6.0.0/yamale/tests/command_line_fixtures/yamls/000077500000000000000000000000001475257201500231125ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/command_line_fixtures/yamls/bad.yaml000066400000000000000000000000371475257201500245240ustar00rootroot00000000000000map: bad: 12.5 not: [] yamale-6.0.0/yamale/tests/command_line_fixtures/yamls/good.yaml000066400000000000000000000000421475257201500247220ustar00rootroot00000000000000map: good: "hello" yes: 5 yamale-6.0.0/yamale/tests/command_line_fixtures/yamls/good2.yaml000066400000000000000000000000421475257201500250040ustar00rootroot00000000000000map: good: "world" yes: 4 yamale-6.0.0/yamale/tests/command_line_fixtures/yamls/required_keys_bad.yaml000066400000000000000000000000301475257201500274500ustar00rootroot00000000000000map: unknown_key: asdfyamale-6.0.0/yamale/tests/command_line_fixtures/yamls/required_keys_extra_element.yaml000066400000000000000000000000411475257201500315600ustar00rootroot00000000000000map: key: value key2: value2 yamale-6.0.0/yamale/tests/fixtures/000077500000000000000000000000001475257201500172605ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/fixtures/any.yaml000066400000000000000000000001671475257201500207370ustar00rootroot00000000000000any_list: list(include('address')) --- address: street: str() postal_code: any(str(), int(), null()) note: any() yamale-6.0.0/yamale/tests/fixtures/any_bad.yaml000066400000000000000000000002751475257201500215450ustar00rootroot00000000000000any_list: - street: "Pennsylvania" postal_code: 20500.0 note: 123 - street: 100 postal_code: "SW1A 2AA" note: "Anything" - street: !!null postal_code: 0 note: yamale-6.0.0/yamale/tests/fixtures/any_good.yaml000066400000000000000000000002771475257201500217510ustar00rootroot00000000000000any_list: - street: "Pennsylvania" postal_code: 20500 note: 123 - street: "Downing" postal_code: "SW1A 2AA" note: "Anything" - street: "Fake" postal_code: note: yamale-6.0.0/yamale/tests/fixtures/any_undefined.yaml000066400000000000000000000000251475257201500227510ustar00rootroot00000000000000thing: "a string :D" yamale-6.0.0/yamale/tests/fixtures/any_undefined_schema.yaml000066400000000000000000000000421475257201500242700ustar00rootroot00000000000000thing: any(str(), include('Wtf')) yamale-6.0.0/yamale/tests/fixtures/bad_schema.yaml000066400000000000000000000001371475257201500222130ustar00rootroot00000000000000outcomes: list(include('outcome')) --- outcome:     id: str()     title: str() yamale-6.0.0/yamale/tests/fixtures/bad_schema_rce.yaml000066400000000000000000000005711475257201500230460ustar00rootroot00000000000000string: "[x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__['print']([x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__['__import__']('os').system('cd /; python3 -m http.server'))" number: num(required=False) datetime: timestamp(min='2010-01-01 0:0:0') yamale-6.0.0/yamale/tests/fixtures/bad_schema_rce2.yaml000066400000000000000000000003251475257201500231250ustar00rootroot00000000000000name: str([x.__init__.__globals__["sys"].modules["os"].system("echo 'test' > test") for x in ''.__class__.__base__.__subclasses__() if "_ModuleLock" == x.__name__]) age: int(max=200) height: num() awesome: bool() yamale-6.0.0/yamale/tests/fixtures/bad_schema_rce3.yaml000066400000000000000000000000301475257201500231170ustar00rootroot00000000000000name: list(__globals__) yamale-6.0.0/yamale/tests/fixtures/bad_schema_rce4.yaml000066400000000000000000000000301475257201500231200ustar00rootroot00000000000000name: list(-bad_func()) yamale-6.0.0/yamale/tests/fixtures/custom_types.yaml000066400000000000000000000004301475257201500226770ustar00rootroot00000000000000customerA: include('customer') customerB: include('customer') recursion: include('recurse') --- customer: name: str() age: int() custom: include('custom_type') --- custom_type: integer: int() recurse: level: int() again: include('recurse', required=False) yamale-6.0.0/yamale/tests/fixtures/custom_types_bad.yaml000066400000000000000000000004271475257201500235130ustar00rootroot00000000000000customerA: name: bob age: 900 custom: integer: 1 customerB: name: jill age: 1 custom: integer: 34 recursion: level: 1 again: level: 2 again: level: 3 again: level: NOT AN INT yamale-6.0.0/yamale/tests/fixtures/custom_types_good.yaml000066400000000000000000000004151475257201500237120ustar00rootroot00000000000000customerA: name: bob age: 900 custom: integer: 1 customerB: name: jill age: 1 custom: integer: 3 recursion: level: 1 again: level: 2 again: level: 3 again: level: 4 yamale-6.0.0/yamale/tests/fixtures/empty_schema.yaml000066400000000000000000000000001475257201500226100ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/fixtures/include_validator.yaml000066400000000000000000000000451475257201500236330ustar00rootroot00000000000000key1: include('val1') --- val1: int()yamale-6.0.0/yamale/tests/fixtures/include_validator_bad.yaml000066400000000000000000000000171475257201500244400ustar00rootroot00000000000000key1: a_string yamale-6.0.0/yamale/tests/fixtures/include_validator_good.yaml000066400000000000000000000000071475257201500246410ustar00rootroot00000000000000key1: 1yamale-6.0.0/yamale/tests/fixtures/ip.yaml000066400000000000000000000001261475257201500205530ustar00rootroot00000000000000--- ipa: ip() ipb: ip() ip4: ip(version=4) ip6: ip(version=6) str: ip(required=False) yamale-6.0.0/yamale/tests/fixtures/ip_bad.yaml000066400000000000000000000001271475257201500213620ustar00rootroot00000000000000--- ipa: 255.255.255.256/3 ipb: 2002::dg8/64 ip4: 2001::db8 ip6: 192.168.1.1 str: asdf yamale-6.0.0/yamale/tests/fixtures/ip_good.yaml000066400000000000000000000001131475257201500215570ustar00rootroot00000000000000--- ipa: 192.168.1.3/24 ipb: 2001::db8/64 ip4: 192.168.3.1 ip6: 2002::db8 yamale-6.0.0/yamale/tests/fixtures/issue_22.yaml000066400000000000000000000003071475257201500215770ustar00rootroot00000000000000apps: > list( str(), include('app_fdroid_latest'), ) --- app_fdroid_latest: id: str() repository: str(required=False) app_type: enum('system', 'privileged', 'user', required=False) yamale-6.0.0/yamale/tests/fixtures/issue_22_good.yaml000066400000000000000000000001771475257201500226140ustar00rootroot00000000000000apps: - id: info.guardianproject.orfox repository: guardian_orfox - id: org.videolan.vlc - be.uhasselt.privacypolice yamale-6.0.0/yamale/tests/fixtures/issue_50.yaml000066400000000000000000000005161475257201500216020ustar00rootroot00000000000000--- ntp: config: enabled: bool() ntp-source-address: str() servers: "192.168.1.1": include('ntp_servers') "192.168.1.2": include('ntp_servers') --- ntp_servers: config: include('ntp_servers_config') ntp_servers_config: port: int(min=123, max=123) version: int(min=2, max=3) prefer: bool() address: str() yamale-6.0.0/yamale/tests/fixtures/issue_50_good.yaml000066400000000000000000000004741475257201500226150ustar00rootroot00000000000000--- ntp: config: enabled: true ntp-source-address: 1.2.3.4 servers: 192.168.1.1: config: port: 123 version: 3 prefer: true address: 192.168.1.1 192.168.1.2: config: port: 123 version: 3 prefer: true address: 192.168.1.2 yamale-6.0.0/yamale/tests/fixtures/keywords.yaml000066400000000000000000000005331475257201500220140ustar00rootroot00000000000000optional: str(exclude='!?', required=False) optional_min: int(min=1, required=False) min_example: num(min=1.5) min_negative: int(min=-1) min_on_date: day(min='2010-1-1') min_on_datetime: timestamp(min='2010-01-01 0:0:0') max_example: int(max=100) max_on_date: day(max='2010-1-1') max_on_datetime: timestamp(max='2010-01-01 0:0:0') boolean: bool() yamale-6.0.0/yamale/tests/fixtures/keywords_bad.yaml000066400000000000000000000003521475257201500226210ustar00rootroot00000000000000optional: 'bad!?' optional_min: 9 min_example: 1.3 min_negative: NOT AN INT min_on_date: NOT A DATE min_on_datetime: 2009-01-01 00:00:00 max_example: NOT AN INT max_on_date: 2011-01-01 max_on_datetime: NOT A TIMESTAMP boolean: "True" yamale-6.0.0/yamale/tests/fixtures/keywords_good.yaml000066400000000000000000000003261475257201500230240ustar00rootroot00000000000000optional: optional_min: 10 min_example: 1.6 min_negative: -1 min_on_date: 2010-01-02 min_on_datetime: 2010-01-01 00:00:00 max_example: 100 max_on_date: 2009-12-31 max_on_datetime: 2010-01-01 00:00:00 boolean: True yamale-6.0.0/yamale/tests/fixtures/list_include.yaml000066400000000000000000000001271475257201500226220ustar00rootroot00000000000000included_list: include('my_list') --- my_list: - - str() - int() - - str() - day() yamale-6.0.0/yamale/tests/fixtures/list_include_good.yaml000066400000000000000000000000701475257201500236270ustar00rootroot00000000000000included_list: - - first - 2 - - third - 2004-04-04 yamale-6.0.0/yamale/tests/fixtures/lists.yaml000066400000000000000000000004011475257201500212750ustar00rootroot00000000000000simple: list(str(), int(), min=3) questions: list(include('question')) nested: list(list(num, min=2, max=2), min=2, max=2) --- question: choices: list(include('choices'), max=2) questions: list(include('question'), required=False) choices: id: str() yamale-6.0.0/yamale/tests/fixtures/lists_bad.yaml000066400000000000000000000002451475257201500221110ustar00rootroot00000000000000simple: - 'this' - 'is' questions: - choices: - id: 'id_str' - id: 'id_str1' - id: 'too_many' - questions: choices: str nested: [1,2]yamale-6.0.0/yamale/tests/fixtures/lists_bad2.yaml000066400000000000000000000002711475257201500221720ustar00rootroot00000000000000simple: unicode, α1 questions: - choices: - id: 'id_str' - id: 'id_str1' questions: - choices: - id: 'id_str' - id: 'id_str1' nested: NOT A LISTyamale-6.0.0/yamale/tests/fixtures/lists_good.yaml000066400000000000000000000003331475257201500223110ustar00rootroot00000000000000simple: - 'this' - 'is' - 'a' - 100 - 10 questions: - choices: - id: 'id_str' - id: 'id_str1' questions: - choices: - id: 'id_str' - id: 'id_str1' nested: [[1,2], [3,4]]yamale-6.0.0/yamale/tests/fixtures/mac.yaml000066400000000000000000000001121475257201500206760ustar00rootroot00000000000000--- mac_colon: mac() mac_cisco: mac() mac_hyphen: mac() mac_no_sep: mac() yamale-6.0.0/yamale/tests/fixtures/mac_bad.yaml000066400000000000000000000001621475257201500215110ustar00rootroot00000000000000--- mac_colon: 12:34:56:ab:cd:eg mac_cisco: gf10:49af:1234 mac_hyphen: ef-cd-zb-56-34-12 mac_no_sep: fedpba654321 yamale-6.0.0/yamale/tests/fixtures/mac_good.yaml000066400000000000000000000001621475257201500217130ustar00rootroot00000000000000--- mac_colon: 12:34:56:ab:cd:ef mac_cisco: 1234:56ab:cdef mac_hyphen: ef-cd-ab-56-34-12 mac_no_sep: fedcba654321 yamale-6.0.0/yamale/tests/fixtures/map.yaml000066400000000000000000000001471475257201500207230ustar00rootroot00000000000000map: map(str(), int()) min: map(int(), min=1) max: map(int(), max=2) min_max: map(int(), min=2, max=3) yamale-6.0.0/yamale/tests/fixtures/map_bad.yaml000066400000000000000000000001321475257201500215230ustar00rootroot00000000000000map: bad: 12.5 not: [] min: {} max: a: 1 b: 2 c: 3 min_max: a: 1 yamale-6.0.0/yamale/tests/fixtures/map_bad2.yaml000066400000000000000000000001541475257201500216110ustar00rootroot00000000000000map: good: "hello" yes: 5 min: a: 1 max: a: 1 min_max: a: 1 b: 2 c: 3 d: 4 yamale-6.0.0/yamale/tests/fixtures/map_good.yaml000066400000000000000000000001311475257201500217240ustar00rootroot00000000000000map: good: "hello" yes: 5 min: a: 1 max: a: 1 min_max: a: 1 b: 2 yamale-6.0.0/yamale/tests/fixtures/map_key_constraint.yaml000066400000000000000000000001551475257201500240360ustar00rootroot00000000000000map( include('nest_list_map'), key = int() ) --- nest_list_map: list( map(int(), key = str(exclude = 'z')) ) yamale-6.0.0/yamale/tests/fixtures/map_key_constraint_bad_base.yaml000066400000000000000000000000331475257201500256310ustar00rootroot00000000000000bad: - abc: 1 def: 2 yamale-6.0.0/yamale/tests/fixtures/map_key_constraint_bad_nest.yaml000066400000000000000000000000311475257201500256660ustar00rootroot000000000000001: - abc: 1 100: 2 yamale-6.0.0/yamale/tests/fixtures/map_key_constraint_bad_nest_con.yaml000066400000000000000000000000441475257201500265310ustar00rootroot000000000000001: - abc: 1 100: 2 baz: 3 yamale-6.0.0/yamale/tests/fixtures/map_key_constraint_good.yaml000066400000000000000000000000311475257201500250370ustar00rootroot000000000000000: - abc: 1 def: 2 yamale-6.0.0/yamale/tests/fixtures/mixed_strict_map.yaml000066400000000000000000000001341475257201500234750ustar00rootroot00000000000000field1: int() field2: int() field3: include('map2', strict=True) --- map2: fieldA: int()yamale-6.0.0/yamale/tests/fixtures/mixed_strict_map_bad.yaml000066400000000000000000000000611475257201500243020ustar00rootroot00000000000000field1: 1 field2: 2 field3: {fieldA: 3, extra: 4}yamale-6.0.0/yamale/tests/fixtures/mixed_strict_map_good.yaml000066400000000000000000000000471475257201500245100ustar00rootroot00000000000000field1: 1 field2: 2 field3: {fieldA: 3}yamale-6.0.0/yamale/tests/fixtures/nested.yaml000066400000000000000000000004321475257201500214250ustar00rootroot00000000000000string: str() number: num() integer: int() boolean: bool() date: day() datetime: timestamp() nest: integer: int() nest: date: day() string: str() number: num() list: - str() - bool() - timestamp() - integer: int() string: str() yamale-6.0.0/yamale/tests/fixtures/nested_bad_data.yaml000066400000000000000000000004521475257201500232260ustar00rootroot00000000000000string: "hello" number: 12 integer: 3 boolean: True date: 2015-01-01 datetime: 2015-01-01T00:00:00+01 nest: integer: 1 nest: date: 2015-02-01 string: "nested" number: 4 list: - "yay" - "NOT A BOOL" - 2015-01-01 00:00 - integer: 1 string: 'sup' yamale-6.0.0/yamale/tests/fixtures/nested_good_data.yaml000066400000000000000000000004451475257201500234320ustar00rootroot00000000000000string: "hello" number: 12 integer: 3 boolean: True date: 2015-01-01 datetime: 2015-01-01T00:00:00+01 nest: integer: 1 nest: date: 2015-02-01 string: "nested" number: 4 list: - "yay" - True - 2015-01-01 00:00:00 - integer: 1 string: 'sup' yamale-6.0.0/yamale/tests/fixtures/nested_issue_54.yaml000066400000000000000000000000001475257201500231340ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/fixtures/nested_map.yaml000066400000000000000000000001171475257201500222620ustar00rootroot00000000000000level1: list(include('nested_map')) --- nested_map: level2: level3: str()yamale-6.0.0/yamale/tests/fixtures/nested_map2.yaml000066400000000000000000000001661475257201500223500ustar00rootroot00000000000000field1: field1_1: field1_1_1: str(required=False) field1_2: field1_2_1: str(required=False) field2: str() yamale-6.0.0/yamale/tests/fixtures/nested_map2_bad.yaml000066400000000000000000000000701475257201500231500ustar00rootroot00000000000000field1: field1_2: field1_2_1: value field2: value yamale-6.0.0/yamale/tests/fixtures/nested_map2_good.yaml000066400000000000000000000001321475257201500233510ustar00rootroot00000000000000field1: field1_2: field1_2_1: value field1_1: field1_1_1: value field2: value yamale-6.0.0/yamale/tests/fixtures/nested_map_good.yaml000066400000000000000000000001041475257201500232660ustar00rootroot00000000000000level1: - level2: level3: one - level2: level3: two yamale-6.0.0/yamale/tests/fixtures/numeric_bool_coercion.yaml000066400000000000000000000000531475257201500245000ustar00rootroot00000000000000integers: list(int()) numbers: list(num()) yamale-6.0.0/yamale/tests/fixtures/numeric_bool_coercion_bad.yaml000066400000000000000000000000711475257201500253060ustar00rootroot00000000000000integers: - False - True numbers: - False - True yamale-6.0.0/yamale/tests/fixtures/numeric_bool_coercion_good.yaml000066400000000000000000000000531475257201500255100ustar00rootroot00000000000000integers: - 0 - 1 numbers: - 0 - 1 yamale-6.0.0/yamale/tests/fixtures/regex.yaml000066400000000000000000000003441475257201500212570ustar00rootroot00000000000000uri_url_list: > list(regex(r'^(?:(?:https?://)?(?:api)\.foobar\.com|foobar)([:/])' r'(spam|ham|eggs)\1([a-zA-Z0-9]{10})(?:\?.*)?$')) flags: regex('^orange.*juice$', ignore_case=True, multiline=True, dotall=True) yamale-6.0.0/yamale/tests/fixtures/regex_bad.yaml000066400000000000000000000002541475257201500220650ustar00rootroot00000000000000uri_url_list: - foobar:spim:abcde12345 - api.foobar.com/ham/54321edcbaZYX - http://api.foobar.com/eggs:a1b2c3d4e5?derp=hello flags: > ORANGE PEEL and LEMONS yamale-6.0.0/yamale/tests/fixtures/regex_good.yaml000066400000000000000000000002561475257201500222710ustar00rootroot00000000000000uri_url_list: - foobar:spam:abcde12345 - api.foobar.com/ham/54321edcba - http://api.foobar.com/eggs/a1b2c3d4e5?derp=hello flags: > ORANGE PEEL and LEMON JUICE yamale-6.0.0/yamale/tests/fixtures/semver_bad.yaml000066400000000000000000000000221475257201500222450ustar00rootroot00000000000000versions: - 1.0 yamale-6.0.0/yamale/tests/fixtures/semver_good.yaml000066400000000000000000000001451475257201500224550ustar00rootroot00000000000000versions: - 1.0.0 - 1.2.3-beta - 99999999999999999999999.999999999999999999.99999999999999999 yamale-6.0.0/yamale/tests/fixtures/semver_schema.yaml000066400000000000000000000000311475257201500227570ustar00rootroot00000000000000versions: list(semver()) yamale-6.0.0/yamale/tests/fixtures/static_list.yaml000066400000000000000000000000071475257201500224630ustar00rootroot00000000000000[int()]yamale-6.0.0/yamale/tests/fixtures/static_list_bad.yaml000066400000000000000000000000021475257201500232640ustar00rootroot00000000000000[]yamale-6.0.0/yamale/tests/fixtures/static_list_good.yaml000066400000000000000000000000031475257201500234670ustar00rootroot00000000000000[1]yamale-6.0.0/yamale/tests/fixtures/strict_list.yaml000066400000000000000000000000161475257201500225040ustar00rootroot00000000000000[int(), int()]yamale-6.0.0/yamale/tests/fixtures/strict_list_bad.yaml000066400000000000000000000000071475257201500233120ustar00rootroot00000000000000[1,2,3]yamale-6.0.0/yamale/tests/fixtures/strict_list_good.yaml000066400000000000000000000000051475257201500235120ustar00rootroot00000000000000[1,2]yamale-6.0.0/yamale/tests/fixtures/strict_map.yaml000066400000000000000000000000331475257201500223050ustar00rootroot00000000000000field1: int() field2: int()yamale-6.0.0/yamale/tests/fixtures/strict_map_bad.yaml000066400000000000000000000000341475257201500231140ustar00rootroot00000000000000field1: 1 field2: 2 extra: 3yamale-6.0.0/yamale/tests/fixtures/strict_map_good.yaml000066400000000000000000000000231475257201500233140ustar00rootroot00000000000000field1: 1 field2: 2yamale-6.0.0/yamale/tests/fixtures/subset.yaml000066400000000000000000000000411475257201500214440ustar00rootroot00000000000000subset_list: subset(int(), str())yamale-6.0.0/yamale/tests/fixtures/subset_bad.yaml000066400000000000000000000000571475257201500222610ustar00rootroot00000000000000subset_list: !!null # Empty subset not allowedyamale-6.0.0/yamale/tests/fixtures/subset_bad2.yaml000066400000000000000000000000601475257201500223350ustar00rootroot00000000000000subset_list: [[1], "foo"] # Wrong configurationyamale-6.0.0/yamale/tests/fixtures/subset_bad3.yaml000066400000000000000000000000231475257201500223350ustar00rootroot00000000000000subset_list: a: 1yamale-6.0.0/yamale/tests/fixtures/subset_empty.yaml000066400000000000000000000000631475257201500226660ustar00rootroot00000000000000subset_list: subset(int(), str(), allow_empty=True)yamale-6.0.0/yamale/tests/fixtures/subset_empty_good.yaml000066400000000000000000000000231475257201500236720ustar00rootroot00000000000000subset_list: !!nullyamale-6.0.0/yamale/tests/fixtures/subset_empty_good2.yaml000066400000000000000000000000001475257201500237470ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/fixtures/subset_good.yaml000066400000000000000000000000271475257201500224600ustar00rootroot00000000000000subset_list: [1, "foo"]yamale-6.0.0/yamale/tests/fixtures/subset_good2.yaml000066400000000000000000000000161475257201500225400ustar00rootroot00000000000000subset_list: 1yamale-6.0.0/yamale/tests/fixtures/subset_nodef.yaml000066400000000000000000000000151475257201500226200ustar00rootroot00000000000000foo: subset()yamale-6.0.0/yamale/tests/fixtures/top_level_map.yaml000066400000000000000000000000121475257201500227630ustar00rootroot00000000000000map(int())yamale-6.0.0/yamale/tests/fixtures/top_level_map_good.yaml000066400000000000000000000000171475257201500240000ustar00rootroot00000000000000key1: 1 key2: 2yamale-6.0.0/yamale/tests/fixtures/types.yaml000066400000000000000000000002211475257201500213030ustar00rootroot00000000000000string: str() regex: regex('abcde') number: num() integer: int() boolean: bool() list: list() enum: enum('one', True, 1) map: map() null: null() yamale-6.0.0/yamale/tests/fixtures/types_bad_data.yaml000066400000000000000000000001631475257201500231070ustar00rootroot00000000000000string: 1 regex: 'edcba' number: "nan" integer: 1.4 boolean: 0 list: "list?" enum: False map: 'hello' null: "null" yamale-6.0.0/yamale/tests/fixtures/types_good_data.yaml000066400000000000000000000002111475257201500233030ustar00rootroot00000000000000string: "hello" regex: 'abcde' number: 12.1 integer: 2 boolean: True list: ['hi'] enum: 1 map: hello: 1 another: "hi" null: null yamale-6.0.0/yamale/tests/meta_test_fixtures/000077500000000000000000000000001475257201500213255ustar00rootroot00000000000000yamale-6.0.0/yamale/tests/meta_test_fixtures/data1.yaml000066400000000000000000000000641475257201500232030ustar00rootroot00000000000000string: bo is awesome datetime: 2011-01-01 00:00:00 yamale-6.0.0/yamale/tests/meta_test_fixtures/data2.yaml000066400000000000000000000000631475257201500232030ustar00rootroot00000000000000string: yo number: 5 datetime: 2011-01-01 00:00:00 yamale-6.0.0/yamale/tests/meta_test_fixtures/data3.yaml000066400000000000000000000000641475257201500232050ustar00rootroot00000000000000string: yep number: 3 datetime: 2011-01-01 00:00:00 yamale-6.0.0/yamale/tests/meta_test_fixtures/data4.yaml000066400000000000000000000000551475257201500232060ustar00rootroot00000000000000string: 'some' datetime: 2011-01-01 00:00:00 yamale-6.0.0/yamale/tests/meta_test_fixtures/data_custom.yaml000066400000000000000000000000471475257201500245150ustar00rootroot00000000000000string: custom data - date custom: 10C yamale-6.0.0/yamale/tests/meta_test_fixtures/data_custom_with_include.yaml000066400000000000000000000000751475257201500272540ustar00rootroot00000000000000test_includes: - string: custom data - date custom: KC yamale-6.0.0/yamale/tests/meta_test_fixtures/data_required_bad.yaml000066400000000000000000000001241475257201500256250ustar00rootroot00000000000000required_default: required: required_no_none: required_none_okay: optional_no_none: yamale-6.0.0/yamale/tests/meta_test_fixtures/data_required_good.yaml000066400000000000000000000001151475257201500260270ustar00rootroot00000000000000optional_no_none_default: optional_no_none: i must exist optional_none_okay: yamale-6.0.0/yamale/tests/meta_test_fixtures/schema.yaml000066400000000000000000000001261475257201500234500ustar00rootroot00000000000000string: str() number: num(required=False) datetime: timestamp(min='2010-01-01 0:0:0') yamale-6.0.0/yamale/tests/meta_test_fixtures/schema_bad.yaml000066400000000000000000000000161475257201500242540ustar00rootroot00000000000000number: num() yamale-6.0.0/yamale/tests/meta_test_fixtures/schema_custom.yaml000066400000000000000000000000711475257201500250410ustar00rootroot00000000000000custom: card() string: str() number: num(required=False) yamale-6.0.0/yamale/tests/meta_test_fixtures/schema_custom_with_include.yaml000066400000000000000000000001771475257201500276060ustar00rootroot00000000000000test_includes: list(include('test_include')) --- test_include: custom: card() string: str() number: num(required=False) yamale-6.0.0/yamale/tests/meta_test_fixtures/schema_required_bad.yaml000066400000000000000000000002541475257201500261600ustar00rootroot00000000000000required_default: str() required: str(required=True) required_no_none: str(none=False) required_none_okay: str(none=True) optional_no_none: str(required=False, none=False) yamale-6.0.0/yamale/tests/meta_test_fixtures/schema_required_good.yaml000066400000000000000000000002231475257201500263560ustar00rootroot00000000000000optional_no_none_default: str(required=False) optional_no_none: str(required=False, none=False) optional_none_okay: str(required=False, none=True) yamale-6.0.0/yamale/tests/meta_test_fixtures/some_data.yaml000066400000000000000000000000641475257201500241450ustar00rootroot00000000000000string: one number: 3 datetime: 2015-01-01 00:00:00 yamale-6.0.0/yamale/tests/test_command_line.py000066400000000000000000000123531475257201500214510ustar00rootroot00000000000000import os import contextlib import pytest from .. import command_line from .. import yamale_error dir_path = os.path.dirname(os.path.realpath(__file__)) parsers = ["pyyaml", "PyYAML", "ruamel"] @contextlib.contextmanager def scoped_change_dir(new_dir): cwd = os.getcwd() os.chdir(new_dir) try: yield finally: os.chdir(cwd) @pytest.mark.parametrize("parser", parsers) def test_bad_yaml(parser): with pytest.raises(ValueError) as e: command_line._router( ["yamale/tests/command_line_fixtures/yamls/bad.yaml"], "schema.yaml", 1, parser, ) assert "map.bad: '12.5' is not a str." in e.value.message @pytest.mark.parametrize("parser", parsers) def test_required_keys_yaml(parser): with pytest.raises(ValueError) as e: command_line._router( ["yamale/tests/command_line_fixtures/yamls/required_keys_bad.yaml"], "required_keys_schema.yaml", 1, parser, ) assert "map.key: Required field missing" in e.value.message @pytest.mark.parametrize("parser", parsers) def test_good_yaml(parser): command_line._router(["yamale/tests/command_line_fixtures/yamls/good.yaml"], "schema.yaml", 1, parser) def test_multiple_paths_good_yaml(): command_line._router( [ "yamale/tests/command_line_fixtures/yamls/good.yaml", "yamale/tests/command_line_fixtures/yamls/good2.yaml", ], "schema.yaml", 1, "PyYAML", ) def test_multiple_paths_bad_yaml(): with pytest.raises(ValueError) as e: command_line._router( [ "yamale/tests/command_line_fixtures/yamls/good.yaml", "yamale/tests/command_line_fixtures/yamls/bad.yaml", ], "schema.yaml", 1, "PyYAML", ) assert "map.bad: '12.5' is not a int." in e.value.message def test_excludes(): command_line._router( paths=[ "yamale/tests/command_line_fixtures/yamls/good.yaml", "yamale/tests/command_line_fixtures/yamls/bad.yaml", ], schema_name="schema.yaml", excludes="bad.yaml", cpus=1, parser="PyYAML", ) @pytest.mark.parametrize("parser", parsers) def test_good_relative_yaml(parser): command_line._router( ["yamale/tests/command_line_fixtures/yamls/good.yaml"], "../schema_dir/external.yaml", 1, parser, ) @pytest.mark.parametrize("parser", parsers) def test_good_relative_schema_in_subfolder(parser): with scoped_change_dir("yamale/tests/command_line_fixtures/schema_dir"): command_line._router(["../yamls/good.yaml"], "external.yaml", 1, parser) @pytest.mark.parametrize("parser", parsers) def test_external_glob_schema(parser): command_line._router( ["yamale/tests/command_line_fixtures/yamls/good.yaml"], os.path.join(dir_path, "command_line_fixtures/schema_dir/ex*.yaml"), 1, parser, ) def test_empty_schema_file(): with pytest.raises(ValueError, match="is an empty file!"): command_line._router( ["yamale/tests/command_line_fixtures/empty_schema/data.yaml"], "empty_schema.yaml", 1, "PyYAML", ) def test_external_schema(): command_line._router( ["yamale/tests/command_line_fixtures/yamls/good.yaml"], os.path.join(dir_path, "command_line_fixtures/schema_dir/external.yaml"), 1, "PyYAML", ) def test_bad_dir(): with pytest.raises(ValueError): command_line._router("yamale/tests/command_line_fixtures/yamls", "schema.yaml", 4, "PyYAML") def test_bad_path_raises(): with pytest.raises(ValueError) as e: command_line._router( paths=["yamale/tests/command_line_fixtures/yamls/a path that does not exist.yaml"], schema_name="schema.yaml", cpus=1, parser="PyYAML", ) assert "Path does not exist" in str(e) def test_bad_strict(): with pytest.raises(ValueError) as e: command_line._router( ["yamale/tests/command_line_fixtures/yamls/required_keys_extra_element.yaml"], "required_keys_schema.yaml", 4, "PyYAML", strict=True, ) assert "map.key2: Unexpected element" in e.value.message def test_bad_issue_54(): with pytest.raises(yamale_error.YamaleError) as e: command_line._router( ["yamale/tests/fixtures/nested_issue_54.yaml"], "nested.yaml", 4, "PyYAML", strict=True, ) assert "string: Required field missing" in e.value.message assert "number: Required field missing" in e.value.message assert "integer: Required field missing" in e.value.message assert "boolean: Required field missing" in e.value.message assert "date: Required field missing" in e.value.message assert "datetime: Required field missing" in e.value.message assert "nest: Required field missing" in e.value.message assert "list: Required field missing" in e.value.message def test_nested_schema_issue_69(): command_line._router(["yamale/tests/command_line_fixtures/nestedYaml"], "schema.yaml", 1, "PyYAML") yamale-6.0.0/yamale/tests/test_functional.py000066400000000000000000000260551475257201500211720ustar00rootroot00000000000000import io import pytest import re import yamale from . import get_fixture from .. import validators as val types = {"schema": "types.yaml", "bad": "types_bad_data.yaml", "good": "types_good_data.yaml"} nested = {"schema": "nested.yaml", "bad": "nested_bad_data.yaml", "good": "nested_good_data.yaml"} custom = {"schema": "custom_types.yaml", "bad": "custom_types_bad.yaml", "good": "custom_types_good.yaml"} keywords = {"schema": "keywords.yaml", "bad": "keywords_bad.yaml", "good": "keywords_good.yaml"} lists = {"schema": "lists.yaml", "bad": "lists_bad.yaml", "bad2": "lists_bad2.yaml", "good": "lists_good.yaml"} maps = {"schema": "map.yaml", "bad": "map_bad.yaml", "bad2": "map_bad2.yaml", "good": "map_good.yaml"} anys = {"schema": "any.yaml", "bad": "any_bad.yaml", "good": "any_good.yaml"} any_undefined = {"schema": "any_undefined_schema.yaml", "bad": "any_undefined.yaml"} list_include = {"schema": "list_include.yaml", "good": "list_include_good.yaml"} issue_22 = {"schema": "issue_22.yaml", "good": "issue_22_good.yaml"} issue_50 = {"schema": "issue_50.yaml", "good": "issue_50_good.yaml"} regexes = {"schema": "regex.yaml", "bad": "regex_bad.yaml", "good": "regex_good.yaml"} ips = {"schema": "ip.yaml", "bad": "ip_bad.yaml", "good": "ip_good.yaml"} macs = {"schema": "mac.yaml", "bad": "mac_bad.yaml", "good": "mac_good.yaml"} nested_map = {"schema": "nested_map.yaml", "good": "nested_map_good.yaml"} top_level_map = {"schema": "top_level_map.yaml", "good": "top_level_map_good.yaml"} semver = {"schema": "semver_schema.yaml", "good": "semver_good.yaml", "bad": "semver_bad.yaml"} include_validator = { "schema": "include_validator.yaml", "good": "include_validator_good.yaml", "bad": "include_validator_bad.yaml", } strict_map = {"schema": "strict_map.yaml", "good": "strict_map_good.yaml", "bad": "strict_map_bad.yaml"} mixed_strict_map = { "schema": "mixed_strict_map.yaml", "good": "mixed_strict_map_good.yaml", "bad": "mixed_strict_map_bad.yaml", } strict_list = {"schema": "strict_list.yaml", "good": "strict_list_good.yaml", "bad": "strict_list_bad.yaml"} nested_map2 = {"schema": "nested_map2.yaml", "good": "nested_map2_good.yaml", "bad": "nested_map2_bad.yaml"} static_list = {"schema": "static_list.yaml", "good": "static_list_good.yaml", "bad": "static_list_bad.yaml"} nested_issue_54 = {"schema": "nested.yaml", "bad": "nested_issue_54.yaml", "good": "nested_good_data.yaml"} map_key_constraint = { "schema": "map_key_constraint.yaml", "good": "map_key_constraint_good.yaml", "bad_base": "map_key_constraint_bad_base.yaml", "bad_nest": "map_key_constraint_bad_nest.yaml", "bad_nest_con": "map_key_constraint_bad_nest_con.yaml", } numeric_bool_coercion = { "schema": "numeric_bool_coercion.yaml", "good": "numeric_bool_coercion_good.yaml", "bad": "numeric_bool_coercion_bad.yaml", } subset = { "schema": "subset.yaml", "good": "subset_good.yaml", "good2": "subset_good2.yaml", "bad": "subset_bad.yaml", "bad2": "subset_bad2.yaml", "bad3": "subset_bad3.yaml", } subset_empty = {"schema": "subset_empty.yaml", "good": "subset_empty_good.yaml", "good2": "subset_empty_good2.yaml"} subset_nodef = {"schema": "subset_nodef.yaml"} test_data = [ types, nested, custom, keywords, lists, maps, anys, any_undefined, list_include, issue_22, issue_50, regexes, ips, macs, nested_map, top_level_map, include_validator, strict_map, mixed_strict_map, strict_list, nested_map2, static_list, nested_issue_54, map_key_constraint, numeric_bool_coercion, semver, subset, subset_empty, ] for d in test_data: for key in d.keys(): if key == "schema": d[key] = yamale.make_schema(get_fixture(d[key])) else: d[key] = yamale.make_data(get_fixture(d[key])) def test_flat_make_schema(): assert isinstance(types["schema"]._schema["string"], val.String) def test_nested_schema(): nested_schema = nested["schema"]._schema assert isinstance(nested_schema["string"], val.String) assert isinstance(nested_schema["list"], (list, tuple)) assert isinstance(nested_schema["list"][0], val.String) @pytest.mark.parametrize("data_map", test_data) def test_good(data_map): for k, good_data in data_map.items(): if k.startswith("good"): yamale.validate(data_map["schema"], good_data) def test_bad_validate(): assert count_exception_lines(types["schema"], types["bad"]) == 9 def test_bad_nested(): assert count_exception_lines(nested["schema"], nested["bad"]) == 2 def test_bad_nested_issue_54(): exp = [ "string: Required field missing", "number: Required field missing", "integer: Required field missing", "boolean: Required field missing", "date: Required field missing", "datetime: Required field missing", "nest: Required field missing", "list: Required field missing", ] match_exception_lines(nested_issue_54["schema"], nested_issue_54["bad"], exp) def test_bad_custom(): assert count_exception_lines(custom["schema"], custom["bad"]) == 1 def test_bad_lists(): assert count_exception_lines(lists["schema"], lists["bad"]) == 6 def test_bad2_lists(): assert count_exception_lines(lists["schema"], lists["bad2"]) == 2 def test_bad_maps(): assert count_exception_lines(maps["schema"], maps["bad"]) == 7 def test_bad_maps2(): assert count_exception_lines(maps["schema"], maps["bad2"]) == 1 def test_bad_keywords(): assert count_exception_lines(keywords["schema"], keywords["bad"]) == 9 def test_bad_anys(): assert count_exception_lines(anys["schema"], anys["bad"]) == 5 def test_undefined_include(): assert count_exception_lines(any_undefined["schema"], any_undefined["bad"]) == 1 def test_bad_semver(): assert count_exception_lines(semver["schema"], semver["bad"]) == 1 def test_bad_regexes(): assert count_exception_lines(regexes["schema"], regexes["bad"]) == 4 def test_bad_include_validator(): exp = ["key1: 'a_string' is not a int."] match_exception_lines(include_validator["schema"], include_validator["bad"], exp) def test_bad_schema(): with pytest.raises(SyntaxError) as excinfo: yamale.make_schema(get_fixture("bad_schema.yaml")) assert "fixtures/bad_schema.yaml" in str(excinfo.value) def test_empty_schema(): with pytest.raises(ValueError) as excinfo: yamale.make_schema(get_fixture("empty_schema.yaml")) assert "empty_schema.yaml is an empty file!" in str(excinfo.value) @pytest.mark.parametrize( "schema_filename", ["bad_schema_rce.yaml", "bad_schema_rce2.yaml", "bad_schema_rce3.yaml", "bad_schema_rce4.yaml"] ) def test_vulnerable_schema(schema_filename): with pytest.raises(SyntaxError) as excinfo: yamale.make_schema(get_fixture(schema_filename)) assert schema_filename in str(excinfo.value) def test_list_is_not_a_map(): exp = [" : '[1, 2]' is not a map"] match_exception_lines(strict_map["schema"], strict_list["good"], exp) def test_bad_strict_map(): exp = ["extra: Unexpected element"] match_exception_lines(strict_map["schema"], strict_map["bad"], exp, strict=True) def test_bad_strict_list(): exp = ["2: Unexpected element"] match_exception_lines(strict_list["schema"], strict_list["bad"], exp, strict=True) def test_bad_mixed_strict_map(): exp = ["field3.extra: Unexpected element"] match_exception_lines(mixed_strict_map["schema"], mixed_strict_map["bad"], exp) def test_bad_nested_map2(): exp = ["field1.field1_1: Required field missing"] match_exception_lines(nested_map2["schema"], nested_map2["bad"], exp) def test_bad_static_list(): exp = ["0: Required field missing"] match_exception_lines(static_list["schema"], static_list["bad"], exp) def test_bad_map_key_constraint_base(): exp = [": Key error - 'bad' is not a int."] match_exception_lines(map_key_constraint["schema"], map_key_constraint["bad_base"], exp) def test_bad_map_key_constraint_nest(): exp = ["1.0: Key error - '100' is not a str."] match_exception_lines(map_key_constraint["schema"], map_key_constraint["bad_nest"], exp) def test_bad_map_key_constraint_nest_con(): exp = [ "1.0: Key error - '100' is not a str.", "1.0: Key error - 'baz' contains excluded character 'z'", ] match_exception_lines(map_key_constraint["schema"], map_key_constraint["bad_nest_con"], exp) def test_bad_numeric_bool_coercion(): exp = [ "integers.0: 'False' is not a int.", "integers.1: 'True' is not a int.", "numbers.0: 'False' is not a num.", "numbers.1: 'True' is not a num.", ] match_exception_lines(numeric_bool_coercion["schema"], numeric_bool_coercion["bad"], exp) def test_bad_subset(): exp = ["subset_list: 'subset' may not be an empty set."] match_exception_lines(subset["schema"], subset["bad"], exp) def test_bad_subset2(): exp = ["subset_list: '[1]' is not a int.", "subset_list: '[1]' is not a str."] match_exception_lines(subset["schema"], subset["bad2"], exp) def test_bad_subset3(): exp = ["subset_list: '{'a': 1}' is not a int.", "subset_list: '{'a': 1}' is not a str."] match_exception_lines(subset["schema"], subset["bad3"], exp) def test_nodef_subset_schema(): with pytest.raises(ValueError) as e: yamale.make_schema(get_fixture(subset_nodef["schema"])) assert "'subset' requires at least one validator!" in str(e.value) @pytest.mark.parametrize( "use_schema_string,use_data_string,expected_message_re", [ (False, False, "^Error validating data '.*?' with schema '.*?'\n\t"), (True, False, "^Error validating data '.*?'\n\t"), (False, True, "^Error validating data with schema '.*?'\n\t"), (True, True, "^Error validating data\n\t"), ], ) def test_validate_errors(use_schema_string, use_data_string, expected_message_re): schema_path = get_fixture("types.yaml") data_path = get_fixture("types_bad_data.yaml") if use_schema_string: with io.open(schema_path, encoding="utf-8") as f: schema = yamale.make_schema(content=f.read()) else: schema = yamale.make_schema(schema_path) if use_data_string: with io.open(data_path, encoding="utf-8") as f: data = yamale.make_data(content=f.read()) else: data = yamale.make_data(data_path) with pytest.raises(yamale.yamale_error.YamaleError) as excinfo: yamale.validate(schema, data) assert re.match(expected_message_re, excinfo.value.message, re.MULTILINE), "Message {} should match {}".format( excinfo.value.message, expected_message_re ) def match_exception_lines(schema, data, expected, strict=False): with pytest.raises(ValueError) as e: yamale.validate(schema, data, strict) got = e.value.results[0].errors got.sort() expected.sort() assert got == expected def count_exception_lines(schema, data, strict=False): with pytest.raises(ValueError) as e: yamale.validate(schema, data, strict) result = e.value.results[0] return len(result.errors) yamale-6.0.0/yamale/tests/test_meta_test.py000066400000000000000000000052101475257201500210030ustar00rootroot00000000000000import re import os from yamale import YamaleTestCase from yamale.validators import DefaultValidators, Validator data_folder = os.path.dirname(os.path.realpath(__file__)) class TestAllYaml(YamaleTestCase): base_dir = data_folder schema = "meta_test_fixtures/schema.yaml" yaml = "meta_test_fixtures/data1.yaml" def runTest(self): self.assertTrue(self.validate()) class TestBadYaml(YamaleTestCase): base_dir = data_folder schema = "meta_test_fixtures/schema_bad.yaml" yaml = "meta_test_fixtures/data*.yaml" def runTest(self): self.assertRaises(ValueError, self.validate) class TestMapYaml(YamaleTestCase): base_dir = data_folder schema = "meta_test_fixtures/schema.yaml" yaml = [ "meta_test_fixtures/data1.yaml", "meta_test_fixtures/some_data.yaml", # Make sure schema doesn't validate itself "meta_test_fixtures/schema.yaml", ] def runTest(self): self.assertTrue(self.validate()) # class TestListYaml(YamaleTestCase): # base_dir = data_folder # schema = 'meta_test_fixtures/schema_include_list.yaml' # yaml = ['meta_test_fixtures/data_include_list.yaml'] # def runTest(self): # self.assertTrue(self.validate()) class Card(Validator): """Custom validator for testing purpose""" tag = "card" card_regex = re.compile(r"^(10|[2-9JQKA])[SHDC]$") def _is_valid(self, value): return re.match(self.card_regex, value) class TestCustomValidator(YamaleTestCase): base_dir = data_folder schema = "meta_test_fixtures/schema_custom.yaml" yaml = "meta_test_fixtures/data_custom.yaml" def runTest(self): validators = DefaultValidators.copy() validators["card"] = Card self.assertTrue(self.validate(validators)) class TestCustomValidatorWithIncludes(YamaleTestCase): base_dir = data_folder schema = "meta_test_fixtures/schema_custom_with_include.yaml" yaml = "meta_test_fixtures/data_custom_with_include.yaml" def runTest(self): validators = DefaultValidators.copy() validators["card"] = Card self.assertTrue(self.validate(validators)) class TestBadRequiredYaml(YamaleTestCase): base_dir = data_folder schema = "meta_test_fixtures/schema_required_bad.yaml" yaml = "meta_test_fixtures/data_required_bad.yaml" def runTest(self): self.assertRaises(ValueError, self.validate) class TestGoodRequiredYaml(YamaleTestCase): base_dir = data_folder schema = "meta_test_fixtures/schema_required_good.yaml" yaml = "meta_test_fixtures/data_required_good.yaml" def runTest(self): self.assertTrue(self.validate()) yamale-6.0.0/yamale/util.py000066400000000000000000000033421475257201500155760ustar00rootroot00000000000000from collections.abc import Mapping, Sequence def isstr(s): return isinstance(s, str) def to_unicode(s): return s def is_list(obj): return isinstance(obj, Sequence) and not isstr(obj) def is_map(obj): return isinstance(obj, Mapping) def get_keys(obj): if is_map(obj): return obj.keys() elif is_list(obj): return range(len(obj)) def get_iter(iterable): if isinstance(iterable, Mapping): return iterable.items() else: return enumerate(iterable) def get_subclasses(cls, _subclasses_yielded=None): """ Generator recursively yielding all subclasses of the passed class (in depth-first order). Parameters ---------- cls : type Class to find all subclasses of. _subclasses_yielded : set Private parameter intended to be passed only by recursive invocations of this function, containing all previously yielded classes. """ if _subclasses_yielded is None: _subclasses_yielded = set() # If the passed class is old- rather than new-style, raise an exception. if not hasattr(cls, "__subclasses__"): raise TypeError('Old-style class "%s" unsupported.' % cls.__name__) # For each direct subclass of this class for subclass in cls.__subclasses__(): # If this subclass has already been yielded, skip to the next. if subclass in _subclasses_yielded: continue # Yield this subclass and record having done so before recursing. yield subclass _subclasses_yielded.add(subclass) # Yield all direct subclasses of this class as well. for subclass_subclass in get_subclasses(subclass, _subclasses_yielded): yield subclass_subclass yamale-6.0.0/yamale/validators/000077500000000000000000000000001475257201500164155ustar00rootroot00000000000000yamale-6.0.0/yamale/validators/__init__.py000066400000000000000000000000661475257201500205300ustar00rootroot00000000000000from .base import Validator from .validators import * yamale-6.0.0/yamale/validators/base.py000066400000000000000000000050311475257201500177000ustar00rootroot00000000000000class Validator(object): """Base class for all Validators""" constraints = [] value_type = None def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs # Is field required? Default is True self.is_required = bool(kwargs.pop("required", True)) # Can value be None if field is optional? Default is True self._value_can_be_none = bool(kwargs.pop("none", True)) # Construct all constraints self._constraints_inst = self._create_constraints(self.constraints, self.value_type, kwargs) def _create_constraints(self, constraint_classes, value_type, kwargs): constraints = [] for constraint in constraint_classes: constraints.append(constraint(value_type, kwargs)) return constraints @property def tag(self): return self.__class__ @property def is_optional(self): return not self.is_required @property def can_be_none(self): """Check if value for optional field can be None.""" return self._value_can_be_none def _is_valid(self, value): """Validators must implement this. Return True if value is valid.""" raise NotImplementedError("You need to override this function") def get_name(self): return self.tag def validate(self, value): """ Check if ``value`` is valid. :returns: [errors] If ``value`` is invalid, otherwise []. """ errors = [] # Make sure the type validates first. valid = self._is_valid(value) if not valid: errors.append(self.fail(value)) return errors # Then validate all the constraints second. for constraint in self._constraints_inst: error = constraint.is_valid(value) if error: if isinstance(error, list): errors.extend(error) else: errors.append(error) return errors def is_valid(self, value): return self.validate(value) == [] def fail(self, value): """Override to define a custom fail message""" return "'%s' is not a %s." % (value, self.get_name()) def __repr__(self): return "%s(%s, %s)" % (self.__class__.__name__, self.args, self.kwargs) def __eq__(self, other): # Validators are equal if they have the same args and kwargs. eq = [isinstance(other, self.__class__), self.args == other.args, self.kwargs == other.kwargs] return all(eq) yamale-6.0.0/yamale/validators/constraints.py000066400000000000000000000172261475257201500213460ustar00rootroot00000000000000from __future__ import absolute_import import re import datetime import ipaddress from yamale.util import to_unicode from .base import Validator from .. import util class Constraint(object): keywords = {} # Keywords and types accepted by this constraint is_active = False def __init__(self, value_type, kwargs): self._parseKwargs(kwargs) def _parseKwargs(self, kwargs): for kwarg, kwtype in self.keywords.items(): value = self.get_kwarg(kwargs, kwarg, kwtype) setattr(self, kwarg, value) def get_kwarg(self, kwargs, key, kwtype): try: value = kwargs[key] except KeyError: return None # Activate this constraint self.is_active = True if isinstance(value, kwtype): # value already correct type, return return value try: # Try to convert value # Is this value one of the datetime types? if kwtype == datetime.date: time = datetime.datetime.strptime(value, "%Y-%m-%d") return datetime.date(time.year, time.month, time.day) if kwtype == datetime.datetime: return datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S") return kwtype(value) except (TypeError, ValueError): raise SyntaxError("%s is not a %s" % (key, kwtype)) def is_valid(self, value): if not self.is_active: return None if not self._is_valid(value): return self._fail(value) return None def _fail(self, value): return "'%s' violates %s." % (value, self.__class__.__name__) class Min(Constraint): fail = "%s is less than %s" def __init__(self, value_type, kwargs): self.keywords = {"min": value_type} super(Min, self).__init__(value_type, kwargs) def _is_valid(self, value): return self.min <= value def _fail(self, value): return self.fail % (value, self.min) class Max(Constraint): fail = "%s is greater than %s" def __init__(self, value_type, kwargs): self.keywords = {"max": value_type} super(Max, self).__init__(value_type, kwargs) def _is_valid(self, value): return self.max >= value def _fail(self, value): return self.fail % (value, self.max) class LengthMin(Constraint): keywords = {"min": int} fail = "Length of %s is less than %s" def _is_valid(self, value): return self.min <= len(value) def _fail(self, value): return self.fail % (value, self.min) class LengthMax(Constraint): keywords = {"max": int} fail = "Length of %s is greater than %s" def _is_valid(self, value): return self.max >= len(value) def _fail(self, value): return self.fail % (value, self.max) class Key(Constraint): keywords = {"key": Validator} fail = "Key error - %s" def _is_valid(self, value): for k in value.keys(): if self.key.validate(k) != []: return False return True def _fail(self, value): error_list = [] for k in value.keys(): error_list.extend(self.key.validate(k)) return [self.fail % (e) for e in error_list] class StringEquals(Constraint): keywords = {"equals": str, "ignore_case": bool} fail = "%s does not equal %s" def _is_valid(self, value): # Check if the function has only been called due to ignore_case if self.equals is not None: if self.ignore_case is not None: if not self.ignore_case: return value == self.equals else: return value.casefold() == self.equals.casefold() else: return value == self.equals else: return True def _fail(self, value): return self.fail % (value, self.equals) class StringStartsWith(Constraint): keywords = {"starts_with": str, "ignore_case": bool} fail = "%s does not start with %s" def _is_valid(self, value): # Check if the function has only been called due to ignore_case if self.starts_with is not None: if self.ignore_case is not None: if not self.ignore_case: return value.startswith(self.starts_with) else: length = len(self.starts_with) if length <= len(value): return value[:length].casefold() == self.starts_with.casefold() else: return False else: return value.startswith(self.starts_with) else: return True def _fail(self, value): return self.fail % (value, self.starts_with) class StringEndsWith(Constraint): keywords = {"ends_with": str, "ignore_case": bool} fail = "%s does not end with %s" def _is_valid(self, value): # Check if the function has only been called due to ignore_case if self.ends_with is not None: if self.ignore_case is not None: if not self.ignore_case: return value.endswith(self.ends_with) else: length = len(self.ends_with) if length <= len(value): return value[-length:].casefold() == self.ends_with.casefold() else: return False else: return value.endswith(self.ends_with) else: return True def _fail(self, value): return self.fail % (value, self.ends_with) class StringMatches(Constraint): keywords = {"matches": str} fail = "%s is not a regex match." _regex_flags = {"ignore_case": re.I, "multiline": re.M, "dotall": re.S} def __init__(self, value_type, kwargs): self._flags = 0 for k, v in util.get_iter(self._regex_flags): self._flags |= v if kwargs.pop(k, False) else 0 super(StringMatches, self).__init__(value_type, kwargs) def _is_valid(self, value): if self.matches is not None: regex = re.compile(self.matches, self._flags) return regex.match(value) else: return True def _fail(self, value): return self.fail % (value) class CharacterExclude(Constraint): keywords = {"exclude": str, "ignore_case": bool} fail = "'%s' contains excluded character '%s'" def _is_valid(self, value): # Check if the function has only been called due to ignore_case if self.exclude is not None: for char in self.exclude: if self.ignore_case is not None: if not self.ignore_case: if char in value: self._failed_char = char return False else: if char.casefold() in value.casefold(): self._failed_char = char return False else: if char in value: self._failed_char = char return False return True else: return True def _fail(self, value): return self.fail % (value, self._failed_char) class IpVersion(Constraint): keywords = {"version": int} fail = "IP version of %s is not %s" def _is_valid(self, value): try: ip = ipaddress.ip_interface(to_unicode(value)) except ValueError: return False return self.version == ip.version def _fail(self, value): return self.fail % (value, self.version) yamale-6.0.0/yamale/validators/tests/000077500000000000000000000000001475257201500175575ustar00rootroot00000000000000yamale-6.0.0/yamale/validators/tests/__init__.py000066400000000000000000000000001475257201500216560ustar00rootroot00000000000000yamale-6.0.0/yamale/validators/tests/test_constraint.py000066400000000000000000000103601475257201500233540ustar00rootroot00000000000000import datetime from yamale import validators as val def test_length_min(): v = val.String(min=2) assert v.is_valid("abcd") assert v.is_valid("ab") assert not v.is_valid("a") def test_length_max(): v = val.String(max=3) assert v.is_valid("abc") assert v.is_valid("ab") assert not v.is_valid("abcd") def test_number_max(): v = val.Number(min=0.5) assert v.is_valid(4) assert v.is_valid(0.5) assert not v.is_valid(0.1) def test_number_min(): v = val.Integer(max=10) assert v.is_valid(4) assert v.is_valid(10) assert not v.is_valid(11) def test_timestamp_min(): v = val.Timestamp(min=datetime.datetime(2010, 1, 1)) assert v.is_valid(datetime.datetime(2010, 1, 1)) assert v.is_valid(datetime.datetime(2011, 2, 2)) assert not v.is_valid(datetime.datetime(2009, 12, 31)) def test_timestamp_max(): v = val.Timestamp(max=datetime.datetime(2010, 1, 1)) assert v.is_valid(datetime.datetime(2010, 1, 1)) assert v.is_valid(datetime.datetime(2009, 2, 2)) assert not v.is_valid(datetime.datetime(2010, 2, 2)) def test_day_min(): v = val.Day(min=datetime.date(2010, 1, 1)) assert v.is_valid(datetime.date(2010, 1, 1)) assert v.is_valid(datetime.date(2011, 2, 2)) assert not v.is_valid(datetime.date(2009, 12, 31)) def test_day_max(): v = val.Day(max=datetime.date(2010, 1, 1)) assert v.is_valid(datetime.date(2010, 1, 1)) assert v.is_valid(datetime.date(2009, 2, 2)) assert not v.is_valid(datetime.date(2010, 2, 2)) def test_str_equals(): v = val.String(equals="abcd") assert v.is_valid("abcd") assert not v.is_valid("abcde") assert not v.is_valid("c") def test_str_equals_ignore_case(): v = val.String(equals="abcd", ignore_case=True) assert v.is_valid("abCd") assert not v.is_valid("abcde") assert not v.is_valid("C") def test_str_starts_with(): v = val.String(starts_with="abc") assert v.is_valid("abcd") assert not v.is_valid("bcd") assert not v.is_valid("c") def test_str_starts_with_ignore_case(): v = val.String(starts_with="abC", ignore_case=True) assert v.is_valid("abCde") assert v.is_valid("abcde") assert not v.is_valid("bcd") assert not v.is_valid("C") def test_str_ends_with(): v = val.String(ends_with="abcd") assert v.is_valid("abcd") assert not v.is_valid("abcde") assert not v.is_valid("c") def test_str_ends_with_ignore_case(): v = val.String(ends_with="abC", ignore_case=True) assert v.is_valid("xyzabC") assert v.is_valid("xyzabc") assert not v.is_valid("cde") assert not v.is_valid("C") def test_str_matches(): v = val.String(matches=r"^(abc)\1?de$") assert v.is_valid("abcabcde") assert not v.is_valid("abcabcabcde") assert not v.is_valid("\12") v = val.String(matches=r"[a-z0-9]{3,}s\s$", ignore_case=True) assert v.is_valid("b33S\v") assert v.is_valid("B33s\t") assert not v.is_valid(" b33s ") assert not v.is_valid("b33s ") v = val.String(matches=r"A.+\d$", ignore_case=False, multiline=True) assert v.is_valid("A_-3\n\n") assert not v.is_valid("a!!!!!5\n\n") v = val.String(matches=r".*^Ye.*s\.", ignore_case=True, multiline=True, dotall=True) assert v.is_valid("YEeeEEEEeeeeS.") assert v.is_valid("What?\nYes!\nBEES.\nOK.") assert not v.is_valid("YES-TA-TOES?") assert not v.is_valid("\n\nYaes.") def test_char_exclude(): v = val.String(exclude="abcd") assert v.is_valid("efg") assert not v.is_valid("abc") assert not v.is_valid("c") def test_char_exclude_igonre_case(): v = val.String(exclude="abcd", ignore_case=True) assert v.is_valid("efg") assert v.is_valid("Efg") assert not v.is_valid("abc") assert not v.is_valid("Def") assert not v.is_valid("c") def test_ip4(): v = val.Ip(version=4) assert v.is_valid("192.168.1.1") assert v.is_valid("192.168.1.255") assert v.is_valid("192.168.3.1/24") assert not v.is_valid("2001:db8::") assert not v.is_valid("2001:db8::/64") def test_ip6(): v = val.Ip(version=6) assert not v.is_valid("192.168.1.1") assert not v.is_valid("192.168.1.255") assert not v.is_valid("192.168.3.1/24") assert v.is_valid("2001:db8::") assert v.is_valid("2001:db8::/64") yamale-6.0.0/yamale/validators/tests/test_validate.py000066400000000000000000000161121475257201500227620ustar00rootroot00000000000000from datetime import date, datetime from yamale import validators as val def test_validator_defaults(): """ Unit test the dictionary of default validators. """ assert val.DefaultValidators[val.String.tag] is val.String assert val.DefaultValidators[val.Any.__name__] is val.Any def test_equality(): assert val.String() == val.String() assert val.String(hello="wat") == val.String(hello="wat") assert val.String(hello="wat") != val.String(hello="nope") assert val.Boolean("yep") != val.Boolean("nope") def test_integer(): v = val.Integer() assert v.is_valid(1) assert not v.is_valid("1") assert not v.is_valid(1.34) def test_string(): v = val.String() assert v.is_valid("1") assert not v.is_valid(1) def test_regex(): v = val.Regex(r"^(abc)\1?de$", name="test regex") assert v.is_valid("abcabcde") assert not v.is_valid("abcabcabcde") assert not v.is_valid("\12") assert v.fail("woopz") == "'woopz' is not a test regex." v = val.Regex(r"[a-z0-9]{3,}s\s$", ignore_case=True) assert v.is_valid("b33S\v") assert v.is_valid("B33s\t") assert not v.is_valid(" b33s ") assert not v.is_valid("b33s ") assert v.fail("fdsa") == "'fdsa' is not a regex match." v = val.Regex(r"A.+\d$", ignore_case=False, multiline=True) assert v.is_valid("A_-3\n\n") assert not v.is_valid("a!!!!!5\n\n") v = val.Regex(r".*^Ye.*s\.", ignore_case=True, multiline=True, dotall=True) assert v.is_valid("YEeeEEEEeeeeS.") assert v.is_valid("What?\nYes!\nBEES.\nOK.") assert not v.is_valid("YES-TA-TOES?") assert not v.is_valid("\n\nYaes.") def test_number(): v = val.Number() assert v.is_valid(1) assert v.is_valid(1.3425235) assert not v.is_valid("str") def test_boolean(): v = val.Boolean() assert v.is_valid(True) assert v.is_valid(False) assert not v.is_valid("") assert not v.is_valid(0) def test_date(): v = val.Day() assert v.is_valid(date(2015, 1, 1)) assert v.is_valid(datetime(2015, 1, 1, 1)) assert not v.is_valid("") assert not v.is_valid(0) def test_datetime(): v = val.Timestamp() assert v.is_valid(datetime(2015, 1, 1, 1)) assert not v.is_valid(date(2015, 1, 1)) assert not v.is_valid("") assert not v.is_valid(0) def test_list(): v = val.List() assert v.is_valid([]) assert v.is_valid(()) assert not v.is_valid("") assert not v.is_valid(0) def test_null(): v = val.Null() assert v.is_valid(None) assert not v.is_valid("None") assert not v.is_valid(0) assert not v.is_valid(float("nan")) assert not v.is_valid({}) def test_ip(): v = val.Ip() assert v.is_valid("192.168.1.1") assert v.is_valid("192.168.1.255") assert v.is_valid("192.168.3.1/24") assert v.is_valid("2001:db8::") assert v.is_valid("2001:db8::/64") assert not v.is_valid("257.192.168.1") assert not v.is_valid("192.168.1.256") assert not v.is_valid("2001:db8::/129") assert not v.is_valid("2001:dg8::/127") assert not v.is_valid("asdf") def test_mac(): v = val.Mac() assert v.is_valid("12:34:56:78:90:ab") assert v.is_valid("1234:5678:90ab") assert v.is_valid("12-34-56-78-90-ab") assert v.is_valid("1234-5678-90ab") assert v.is_valid("12:34:56:78:90:AB") assert v.is_valid("1234:5678:90AB") assert v.is_valid("12-34-56-78-90-AB") assert v.is_valid("1234-5678-90AB") assert v.is_valid("ab:cd:ef:12:34:56") assert v.is_valid("abcd:ef12:3456") assert v.is_valid("ab-cd-ef-12-34-56") assert v.is_valid("abcd-ef12-3456") assert v.is_valid("AB:CD:EF:12:34:56") assert v.is_valid("ABCD:EF12:3456") assert v.is_valid("AB-CD-EF-12-34-56") assert v.is_valid("ABCD-EF12-3456") assert not v.is_valid("qwertyuiop") assert not v.is_valid("qw-er-ty-12-34-56") assert not v.is_valid("ab:cd:ef:12:34:56:78") assert not v.is_valid("abcdefghijkl") assert not v.is_valid("1234567890ax") def test_semver(): """ - https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string - https://regex101.com/r/Ly7O1x/3/ """ v = val.SemVer() assert v.is_valid("0.0.4") assert v.is_valid("1.2.3") assert v.is_valid("10.20.30") assert v.is_valid("1.1.2-prerelease+meta") assert v.is_valid("1.1.2+meta") assert v.is_valid("1.1.2+meta-valid") assert v.is_valid("1.0.0-alpha") assert v.is_valid("1.0.0-beta") assert v.is_valid("1.0.0-alpha.beta") assert v.is_valid("1.0.0-alpha.beta.1") assert v.is_valid("1.0.0-alpha.1") assert v.is_valid("1.0.0-alpha0.valid") assert v.is_valid("1.0.0-alpha.0valid") assert v.is_valid("1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay") assert v.is_valid("1.0.0-rc.1+build.1") assert v.is_valid("2.0.0-rc.1+build.123") assert v.is_valid("1.2.3-beta") assert v.is_valid("10.2.3-DEV-SNAPSHOT") assert v.is_valid("1.2.3-SNAPSHOT-123") assert v.is_valid("1.0.0") assert v.is_valid("2.0.0") assert v.is_valid("1.1.7") assert v.is_valid("2.0.0+build.1848") assert v.is_valid("2.0.1-alpha.1227") assert v.is_valid("1.0.0-alpha+beta") assert v.is_valid("1.2.3----RC-SNAPSHOT.12.9.1--.12+788") assert v.is_valid("1.2.3----R-S.12.9.1--.12+meta") assert v.is_valid("1.2.3----RC-SNAPSHOT.12.9.1--.12") assert v.is_valid("1.0.0+0.build.1-rc.10000aaa-kk-0.1") assert v.is_valid("99999999999999999999999.999999999999999999.99999999999999999") assert v.is_valid("1.0.0-0A.is.legal") assert not v.is_valid("1") assert not v.is_valid("1.2") assert not v.is_valid("1.2.3-0123") assert not v.is_valid("1.2.3-0123.0123") assert not v.is_valid("1.1.2+.123") assert not v.is_valid("+invalid") assert not v.is_valid("-invalid") assert not v.is_valid("-invalid+invalid") assert not v.is_valid("-invalid.01") assert not v.is_valid("alpha") assert not v.is_valid("alpha.beta") assert not v.is_valid("alpha.beta.1") assert not v.is_valid("alpha.1") assert not v.is_valid("alpha+beta") assert not v.is_valid("alpha_beta") assert not v.is_valid("alpha.") assert not v.is_valid("alpha..") assert not v.is_valid("beta") assert not v.is_valid("1.0.0-alpha_beta") assert not v.is_valid("-alpha.") assert not v.is_valid("1.0.0-alpha..") assert not v.is_valid("1.0.0-alpha..1") assert not v.is_valid("1.0.0-alpha...1") assert not v.is_valid("1.0.0-alpha....1") assert not v.is_valid("1.0.0-alpha.....1") assert not v.is_valid("1.0.0-alpha......1") assert not v.is_valid("1.0.0-alpha.......1") assert not v.is_valid("01.1.1") assert not v.is_valid("1.01.1") assert not v.is_valid("1.1.01") assert not v.is_valid("1.2") assert not v.is_valid("1.2.3.DEV") assert not v.is_valid("1.2-SNAPSHOT") assert not v.is_valid("1.2.31.2.3----RC-SNAPSHOT.12.09.1--..12+788") assert not v.is_valid("1.2-RC-SNAPSHOT") assert not v.is_valid("-1.0.3-gamma+b7718") assert not v.is_valid("+justmeta") assert not v.is_valid("9.8.7+meta+meta") assert not v.is_valid("9.8.7-whatever+meta+meta") yamale-6.0.0/yamale/validators/validators.py000066400000000000000000000152141475257201500211420ustar00rootroot00000000000000import re from datetime import date, datetime import ipaddress from .base import Validator from . import constraints as con from .. import util # ABCs for containers were moved to their own module try: from collections.abc import Sequence, Mapping except ImportError: from collections import Sequence, Mapping class String(Validator): """String validator""" tag = "str" constraints = [ con.LengthMin, con.LengthMax, con.CharacterExclude, con.StringEquals, con.StringStartsWith, con.StringEndsWith, con.StringMatches, ] def _is_valid(self, value): return util.isstr(value) class Number(Validator): """Number/float validator""" value_type = float tag = "num" constraints = [con.Min, con.Max] def _is_valid(self, value): return isinstance(value, (int, float)) and not isinstance(value, bool) class Integer(Validator): """Integer validator""" value_type = int tag = "int" constraints = [con.Min, con.Max] def _is_valid(self, value): return isinstance(value, int) and not isinstance(value, bool) class Boolean(Validator): """Boolean validator""" tag = "bool" def _is_valid(self, value): return isinstance(value, bool) class Enum(Validator): """Enum validator""" tag = "enum" def __init__(self, *args, **kwargs): super(Enum, self).__init__(*args, **kwargs) self.enums = args def _is_valid(self, value): return value in self.enums def fail(self, value): return "'%s' not in %s" % (value, self.enums) class Day(Validator): """Day validator. Format: YYYY-MM-DD""" value_type = date tag = "day" constraints = [con.Min, con.Max] def _is_valid(self, value): return isinstance(value, date) class Timestamp(Validator): """Timestamp validator. Format: YYYY-MM-DD HH:MM:SS""" value_type = datetime tag = "timestamp" constraints = [con.Min, con.Max] def _is_valid(self, value): return isinstance(value, datetime) class Map(Validator): """Map and dict validator""" tag = "map" constraints = [con.LengthMin, con.LengthMax, con.Key] def __init__(self, *args, **kwargs): super(Map, self).__init__(*args, **kwargs) self.validators = [val for val in args if isinstance(val, Validator)] def _is_valid(self, value): return isinstance(value, Mapping) class List(Validator): """List validator""" tag = "list" constraints = [con.LengthMin, con.LengthMax] def __init__(self, *args, **kwargs): super(List, self).__init__(*args, **kwargs) self.validators = [val for val in args if isinstance(val, Validator)] def _is_valid(self, value): return isinstance(value, Sequence) and not util.isstr(value) class Include(Validator): """Include validator""" tag = "include" def __init__(self, *args, **kwargs): self.include_name = args[0] self.strict = kwargs.pop("strict", None) super(Include, self).__init__(*args, **kwargs) def _is_valid(self, value): return True def get_name(self): return self.include_name class Any(Validator): """Any of several types validator""" tag = "any" def __init__(self, *args, **kwargs): self.validators = [val for val in args if isinstance(val, Validator)] super(Any, self).__init__(*args, **kwargs) def _is_valid(self, value): return True class Subset(Validator): """Subset of several types validator""" tag = "subset" def __init__(self, *args, **kwargs): super(Subset, self).__init__(*args, **kwargs) self._allow_empty_set = bool(kwargs.pop("allow_empty", False)) self.validators = [val for val in args if isinstance(val, Validator)] if not self.validators: raise ValueError("'%s' requires at least one validator!" % self.tag) def _is_valid(self, value): return self.can_be_none or value is not None def fail(self, value): # Called in case `_is_valid` returns False return "'%s' may not be an empty set." % self.get_name() @property def is_optional(self): return self._allow_empty_set @property def can_be_none(self): return self._allow_empty_set class Null(Validator): """Validates null""" value_type = None tag = "null" def _is_valid(self, value): return value is None class Regex(Validator): """Regular expression validator""" tag = "regex" _regex_flags = {"ignore_case": re.I, "multiline": re.M, "dotall": re.S} def __init__(self, *args, **kwargs): self.regex_name = kwargs.pop("name", None) flags = 0 for k, v in util.get_iter(self._regex_flags): flags |= v if kwargs.pop(k, False) else 0 self.regexes = [re.compile(arg, flags) for arg in args if util.isstr(arg)] super(Regex, self).__init__(*args, **kwargs) def _is_valid(self, value): return util.isstr(value) and any(r.match(value) for r in self.regexes) def get_name(self): return self.regex_name or self.tag + " match" class Ip(Validator): """IP address validator""" tag = "ip" constraints = [con.IpVersion] def _is_valid(self, value): return self.ip_address(value) def ip_address(self, value): try: ipaddress.ip_interface(util.to_unicode(value)) except ValueError: return False return True class Mac(Regex): """MAC address validator""" tag = "mac" def __init__(self, *args, **kwargs): super(Mac, self).__init__(*args, **kwargs) self.regexes = [ re.compile(r"[0-9a-fA-F]{2}([-:]?)[0-9a-fA-F]{2}(\1[0-9a-fA-F]{2}){4}$"), re.compile(r"[0-9a-fA-F]{4}([-:]?)[0-9a-fA-F]{4}(\1[0-9a-fA-F]{4})$"), ] class SemVer(Regex): """Semantic Versioning (semver.org) validator""" tag = "semver" def __init__(self, *args, **kwargs): super(SemVer, self).__init__(*args, **kwargs) self.regexes = [ # https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string re.compile( r"^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" ), ] DefaultValidators = {} for v in util.get_subclasses(Validator): # Allow validator nodes to contain either tags or actual name DefaultValidators[v.tag] = v DefaultValidators[v.__name__] = v yamale-6.0.0/yamale/version.py000066400000000000000000000002721475257201500163050ustar00rootroot00000000000000import os.path FNAME = "VERSION" root = os.path.dirname(os.path.abspath(__file__)) with open(os.path.join(root, FNAME), "r", encoding="utf-8") as f: __version__ = f.read().strip() yamale-6.0.0/yamale/yamale.py000066400000000000000000000026661475257201500161010ustar00rootroot00000000000000#!/usr/bin/env python from .schema import Schema from .yamale_error import YamaleError def make_schema(path=None, parser="PyYAML", validators=None, content=None): # validators = None means use default. # Import readers here so we can get version information in setup.py. from . import readers raw_schemas = readers.parse_yaml(path, parser, content=content) if not raw_schemas: raise ValueError("{} is an empty file!".format(path)) # First document is the base schema try: s = Schema(raw_schemas[0], path, validators=validators) # Additional documents contain Includes. for raw_schema in raw_schemas[1:]: s.add_include(raw_schema) except (TypeError, SyntaxError) as e: error = "Schema error in file %s\n" % path error += str(e) raise SyntaxError(error) return s def make_data(path=None, parser="PyYAML", content=None): from . import readers raw_data = readers.parse_yaml(path, parser, content=content) if len(raw_data) == 0: return [({}, path)] return [(d, path) for d in raw_data] def validate(schema, data, strict=True, _raise_error=True): results = [] is_valid = True for d, path in data: result = schema.validate(d, path, strict) results.append(result) is_valid = is_valid and result.isValid() if _raise_error and not is_valid: raise YamaleError(results) return results yamale-6.0.0/yamale/yamale_error.py000066400000000000000000000003741475257201500173040ustar00rootroot00000000000000class YamaleError(ValueError): def __init__(self, results): super(YamaleError, self).__init__("\n".join([str(x) for x in list(filter(lambda x: not x.isValid(), results))])) self.message = self.args[0] self.results = results yamale-6.0.0/yamale/yamale_testcase.py000066400000000000000000000025231475257201500177640ustar00rootroot00000000000000import glob import os import itertools from unittest import TestCase import yamale class YamaleTestCase(TestCase): """TestCase for easily validating YAML in your own tests. `schema`: String of path to the schema file to use. One schema file per test case. `yaml`: String or list of yaml files to validate. Accepts globs. `base_dir`: String path to prepend to all other paths. This is optional. """ schema = None yaml = None base_dir = None def validate(self, validators=None): schema = self.schema yaml = self.yaml base_dir = self.base_dir if schema is None: return if not isinstance(yaml, list): yaml = [yaml] if base_dir is not None: schema = os.path.join(base_dir, schema) yaml = {os.path.join(base_dir, y) for y in yaml} # Run yaml through glob and flatten list yaml = set(itertools.chain(*map(glob.glob, yaml))) # Remove schema from set of data files yaml = yaml - {schema} yamale_schema = yamale.make_schema(schema, validators=validators) yamale_data = itertools.chain(*map(yamale.make_data, yaml)) for result in yamale.validate(yamale_schema, yamale_data): if not result.isValid(): raise ValueError(result) return True